toolkit/crashreporter/tools/unit-symbolstore.py

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 #!/usr/bin/env python
michael@0 2 # This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 # License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
michael@0 5
michael@0 6 import os, tempfile, unittest, shutil, struct, platform, subprocess, multiprocessing.dummy
michael@0 7 import mock
michael@0 8 from mock import patch
michael@0 9 import symbolstore
michael@0 10
michael@0 11 # Some simple functions to mock out files that the platform-specific dumpers will accept.
michael@0 12 # dump_syms itself will not be run (we mock that call out), but we can't override
michael@0 13 # the ShouldProcessFile method since we actually want to test that.
michael@0 14 def write_elf(filename):
michael@0 15 open(filename, "wb").write(struct.pack("<7B45x", 0x7f, ord("E"), ord("L"), ord("F"), 1, 1, 1))
michael@0 16
michael@0 17 def write_macho(filename):
michael@0 18 open(filename, "wb").write(struct.pack("<I28x", 0xfeedface))
michael@0 19
michael@0 20 def write_pdb(filename):
michael@0 21 open(filename, "w").write("aaa")
michael@0 22 # write out a fake DLL too
michael@0 23 open(os.path.splitext(filename)[0] + ".dll", "w").write("aaa")
michael@0 24
michael@0 25 writer = {'Windows': write_pdb,
michael@0 26 'Microsoft': write_pdb,
michael@0 27 'Linux': write_elf,
michael@0 28 'Sunos5': write_elf,
michael@0 29 'Darwin': write_macho}[platform.system()]
michael@0 30 extension = {'Windows': ".pdb",
michael@0 31 'Microsoft': ".pdb",
michael@0 32 'Linux': ".so",
michael@0 33 'Sunos5': ".so",
michael@0 34 'Darwin': ".dylib"}[platform.system()]
michael@0 35
michael@0 36 def add_extension(files):
michael@0 37 return [f + extension for f in files]
michael@0 38
michael@0 39 class HelperMixin(object):
michael@0 40 """
michael@0 41 Test that passing filenames to exclude from processing works.
michael@0 42 """
michael@0 43 def setUp(self):
michael@0 44 self.test_dir = tempfile.mkdtemp()
michael@0 45 if not self.test_dir.endswith("/"):
michael@0 46 self.test_dir += "/"
michael@0 47 symbolstore.srcdirRepoInfo = {}
michael@0 48 symbolstore.vcsFileInfoCache = {}
michael@0 49
michael@0 50 def tearDown(self):
michael@0 51 shutil.rmtree(self.test_dir)
michael@0 52 symbolstore.srcdirRepoInfo = {}
michael@0 53 symbolstore.vcsFileInfoCache = {}
michael@0 54
michael@0 55 def add_test_files(self, files):
michael@0 56 for f in files:
michael@0 57 f = os.path.join(self.test_dir, f)
michael@0 58 d = os.path.dirname(f)
michael@0 59 if d and not os.path.exists(d):
michael@0 60 os.makedirs(d)
michael@0 61 writer(f)
michael@0 62
michael@0 63 class TestExclude(HelperMixin, unittest.TestCase):
michael@0 64 def test_exclude_wildcard(self):
michael@0 65 """
michael@0 66 Test that using an exclude list with a wildcard pattern works.
michael@0 67 """
michael@0 68 processed = []
michael@0 69 def mock_process_file(filenames):
michael@0 70 for filename in filenames:
michael@0 71 processed.append((filename[len(self.test_dir):] if filename.startswith(self.test_dir) else filename).replace('\\', '/'))
michael@0 72 return True
michael@0 73 self.add_test_files(add_extension(["foo", "bar", "abc/xyz", "abc/fooxyz", "def/asdf", "def/xyzfoo"]))
michael@0 74 d = symbolstore.GetPlatformSpecificDumper(dump_syms="dump_syms",
michael@0 75 symbol_path="symbol_path",
michael@0 76 exclude=["*foo*"])
michael@0 77 d.ProcessFiles = mock_process_file
michael@0 78 d.Process(self.test_dir)
michael@0 79 d.Finish(stop_pool=False)
michael@0 80 processed.sort()
michael@0 81 expected = add_extension(["bar", "abc/xyz", "def/asdf"])
michael@0 82 expected.sort()
michael@0 83 self.assertEqual(processed, expected)
michael@0 84
michael@0 85 def test_exclude_filenames(self):
michael@0 86 """
michael@0 87 Test that excluding a filename without a wildcard works.
michael@0 88 """
michael@0 89 processed = []
michael@0 90 def mock_process_file(filenames):
michael@0 91 for filename in filenames:
michael@0 92 processed.append((filename[len(self.test_dir):] if filename.startswith(self.test_dir) else filename).replace('\\', '/'))
michael@0 93 return True
michael@0 94 self.add_test_files(add_extension(["foo", "bar", "abc/foo", "abc/bar", "def/foo", "def/bar"]))
michael@0 95 d = symbolstore.GetPlatformSpecificDumper(dump_syms="dump_syms",
michael@0 96 symbol_path="symbol_path",
michael@0 97 exclude=add_extension(["foo"]))
michael@0 98 d.ProcessFiles = mock_process_file
michael@0 99 d.Process(self.test_dir)
michael@0 100 d.Finish(stop_pool=False)
michael@0 101 processed.sort()
michael@0 102 expected = add_extension(["bar", "abc/bar", "def/bar"])
michael@0 103 expected.sort()
michael@0 104 self.assertEqual(processed, expected)
michael@0 105
michael@0 106 def popen_factory(stdouts):
michael@0 107 """
michael@0 108 Generate a class that can mock subprocess.Popen. |stdouts| is an iterable that
michael@0 109 should return an iterable for the stdout of each process in turn.
michael@0 110 """
michael@0 111 class mock_popen(object):
michael@0 112 def __init__(self, args, *args_rest, **kwargs):
michael@0 113 self.stdout = stdouts.next()
michael@0 114
michael@0 115 def wait(self):
michael@0 116 return 0
michael@0 117 return mock_popen
michael@0 118
michael@0 119 def mock_dump_syms(module_id, filename):
michael@0 120 return ["MODULE os x86 %s %s" % (module_id, filename),
michael@0 121 "FILE 0 foo.c",
michael@0 122 "PUBLIC xyz 123"]
michael@0 123
michael@0 124 class TestCopyDebugUniversal(HelperMixin, unittest.TestCase):
michael@0 125 """
michael@0 126 Test that CopyDebug does the right thing when dumping multiple architectures.
michael@0 127 """
michael@0 128 def setUp(self):
michael@0 129 HelperMixin.setUp(self)
michael@0 130 self.symbol_dir = tempfile.mkdtemp()
michael@0 131 self._subprocess_call = subprocess.call
michael@0 132 subprocess.call = self.mock_call
michael@0 133 self._subprocess_popen = subprocess.Popen
michael@0 134 subprocess.Popen = popen_factory(self.next_mock_stdout())
michael@0 135 self.stdouts = []
michael@0 136 self._shutil_rmtree = shutil.rmtree
michael@0 137 shutil.rmtree = self.mock_rmtree
michael@0 138
michael@0 139 def tearDown(self):
michael@0 140 HelperMixin.tearDown(self)
michael@0 141 shutil.rmtree = self._shutil_rmtree
michael@0 142 shutil.rmtree(self.symbol_dir)
michael@0 143 subprocess.call = self._subprocess_call
michael@0 144 subprocess.Popen = self._subprocess_popen
michael@0 145
michael@0 146 def mock_rmtree(self, path):
michael@0 147 pass
michael@0 148
michael@0 149 def mock_call(self, args, **kwargs):
michael@0 150 if args[0].endswith("dsymutil"):
michael@0 151 filename = args[-1]
michael@0 152 os.makedirs(filename + ".dSYM")
michael@0 153 return 0
michael@0 154
michael@0 155 def next_mock_stdout(self):
michael@0 156 if not self.stdouts:
michael@0 157 yield iter([])
michael@0 158 for s in self.stdouts:
michael@0 159 yield iter(s)
michael@0 160
michael@0 161 def test_copy_debug_universal(self):
michael@0 162 """
michael@0 163 Test that dumping symbols for multiple architectures only copies debug symbols once
michael@0 164 per file.
michael@0 165 """
michael@0 166 copied = []
michael@0 167 def mock_copy_debug(filename, debug_file, guid):
michael@0 168 copied.append(filename[len(self.symbol_dir):] if filename.startswith(self.symbol_dir) else filename)
michael@0 169 self.add_test_files(add_extension(["foo"]))
michael@0 170 self.stdouts.append(mock_dump_syms("X" * 33, add_extension(["foo"])[0]))
michael@0 171 self.stdouts.append(mock_dump_syms("Y" * 33, add_extension(["foo"])[0]))
michael@0 172 d = symbolstore.GetPlatformSpecificDumper(dump_syms="dump_syms",
michael@0 173 symbol_path=self.symbol_dir,
michael@0 174 copy_debug=True,
michael@0 175 archs="abc xyz")
michael@0 176 d.CopyDebug = mock_copy_debug
michael@0 177 d.Process(self.test_dir)
michael@0 178 d.Finish(stop_pool=False)
michael@0 179 self.assertEqual(1, len(copied))
michael@0 180
michael@0 181 class TestGetVCSFilename(HelperMixin, unittest.TestCase):
michael@0 182 def setUp(self):
michael@0 183 HelperMixin.setUp(self)
michael@0 184
michael@0 185 def tearDown(self):
michael@0 186 HelperMixin.tearDown(self)
michael@0 187
michael@0 188 @patch("subprocess.Popen")
michael@0 189 def testVCSFilenameHg(self, mock_Popen):
michael@0 190 # mock calls to `hg parent` and `hg showconfig paths.default`
michael@0 191 mock_communicate = mock_Popen.return_value.communicate
michael@0 192 mock_communicate.side_effect = [("abcd1234", ""),
michael@0 193 ("http://example.com/repo", "")]
michael@0 194 os.mkdir(os.path.join(self.test_dir, ".hg"))
michael@0 195 filename = os.path.join(self.test_dir, "foo.c")
michael@0 196 self.assertEqual("hg:example.com/repo:foo.c:abcd1234",
michael@0 197 symbolstore.GetVCSFilename(filename, [self.test_dir])[0])
michael@0 198
michael@0 199 @patch("subprocess.Popen")
michael@0 200 def testVCSFilenameHgMultiple(self, mock_Popen):
michael@0 201 # mock calls to `hg parent` and `hg showconfig paths.default`
michael@0 202 mock_communicate = mock_Popen.return_value.communicate
michael@0 203 mock_communicate.side_effect = [("abcd1234", ""),
michael@0 204 ("http://example.com/repo", ""),
michael@0 205 ("0987ffff", ""),
michael@0 206 ("http://example.com/other", "")]
michael@0 207 srcdir1 = os.path.join(self.test_dir, "one")
michael@0 208 srcdir2 = os.path.join(self.test_dir, "two")
michael@0 209 os.makedirs(os.path.join(srcdir1, ".hg"))
michael@0 210 os.makedirs(os.path.join(srcdir2, ".hg"))
michael@0 211 filename1 = os.path.join(srcdir1, "foo.c")
michael@0 212 filename2 = os.path.join(srcdir2, "bar.c")
michael@0 213 self.assertEqual("hg:example.com/repo:foo.c:abcd1234",
michael@0 214 symbolstore.GetVCSFilename(filename1, [srcdir1, srcdir2])[0])
michael@0 215 self.assertEqual("hg:example.com/other:bar.c:0987ffff",
michael@0 216 symbolstore.GetVCSFilename(filename2, [srcdir1, srcdir2])[0])
michael@0 217
michael@0 218 class TestRepoManifest(HelperMixin, unittest.TestCase):
michael@0 219 def testRepoManifest(self):
michael@0 220 manifest = os.path.join(self.test_dir, "sources.xml")
michael@0 221 open(manifest, "w").write("""<?xml version="1.0" encoding="UTF-8"?>
michael@0 222 <manifest>
michael@0 223 <remote fetch="http://example.com/foo/" name="foo"/>
michael@0 224 <remote fetch="git://example.com/bar/" name="bar"/>
michael@0 225 <default remote="bar"/>
michael@0 226 <project name="projects/one" revision="abcd1234"/>
michael@0 227 <project name="projects/two" path="projects/another" revision="ffffffff" remote="foo"/>
michael@0 228 <project name="something_else" revision="00000000" remote="bar"/>
michael@0 229 </manifest>
michael@0 230 """)
michael@0 231 # Use a source file from each of the three projects
michael@0 232 file1 = os.path.join(self.test_dir, "projects", "one", "src1.c")
michael@0 233 file2 = os.path.join(self.test_dir, "projects", "another", "src2.c")
michael@0 234 file3 = os.path.join(self.test_dir, "something_else", "src3.c")
michael@0 235 d = symbolstore.Dumper("dump_syms", "symbol_path",
michael@0 236 repo_manifest=manifest)
michael@0 237 self.assertEqual("git:example.com/bar/projects/one:src1.c:abcd1234",
michael@0 238 symbolstore.GetVCSFilename(file1, d.srcdirs)[0])
michael@0 239 self.assertEqual("git:example.com/foo/projects/two:src2.c:ffffffff",
michael@0 240 symbolstore.GetVCSFilename(file2, d.srcdirs)[0])
michael@0 241 self.assertEqual("git:example.com/bar/something_else:src3.c:00000000",
michael@0 242 symbolstore.GetVCSFilename(file3, d.srcdirs)[0])
michael@0 243
michael@0 244 if platform.system() in ("Windows", "Microsoft"):
michael@0 245 class TestSourceServer(HelperMixin, unittest.TestCase):
michael@0 246 @patch("subprocess.call")
michael@0 247 @patch("subprocess.Popen")
michael@0 248 def test_HGSERVER(self, mock_Popen, mock_call):
michael@0 249 """
michael@0 250 Test that HGSERVER gets set correctly in the source server index.
michael@0 251 """
michael@0 252 symbolpath = os.path.join(self.test_dir, "symbols")
michael@0 253 os.makedirs(symbolpath)
michael@0 254 srcdir = os.path.join(self.test_dir, "srcdir")
michael@0 255 os.makedirs(os.path.join(srcdir, ".hg"))
michael@0 256 sourcefile = os.path.join(srcdir, "foo.c")
michael@0 257 test_files = add_extension(["foo"])
michael@0 258 self.add_test_files(test_files)
michael@0 259 # srcsrv needs PDBSTR_PATH set
michael@0 260 os.environ["PDBSTR_PATH"] = "pdbstr"
michael@0 261 # mock calls to `dump_syms`, `hg parent` and
michael@0 262 # `hg showconfig paths.default`
michael@0 263 mock_Popen.return_value.stdout = iter([
michael@0 264 "MODULE os x86 %s %s" % ("X" * 33, test_files[0]),
michael@0 265 "FILE 0 %s" % sourcefile,
michael@0 266 "PUBLIC xyz 123"
michael@0 267 ])
michael@0 268 mock_communicate = mock_Popen.return_value.communicate
michael@0 269 mock_communicate.side_effect = [("abcd1234", ""),
michael@0 270 ("http://example.com/repo", ""),
michael@0 271 ]
michael@0 272 # And mock the call to pdbstr to capture the srcsrv stream data.
michael@0 273 global srcsrv_stream
michael@0 274 srcsrv_stream = None
michael@0 275 def mock_pdbstr(args, cwd="", **kwargs):
michael@0 276 for arg in args:
michael@0 277 if arg.startswith("-i:"):
michael@0 278 global srcsrv_stream
michael@0 279 srcsrv_stream = open(os.path.join(cwd, arg[3:]), 'r').read()
michael@0 280 return 0
michael@0 281 mock_call.side_effect = mock_pdbstr
michael@0 282 d = symbolstore.GetPlatformSpecificDumper(dump_syms="dump_syms",
michael@0 283 symbol_path=symbolpath,
michael@0 284 srcdirs=[srcdir],
michael@0 285 vcsinfo=True,
michael@0 286 srcsrv=True,
michael@0 287 copy_debug=True)
michael@0 288 # stub out CopyDebug
michael@0 289 d.CopyDebug = lambda *args: True
michael@0 290 d.Process(self.test_dir)
michael@0 291 d.Finish(stop_pool=False)
michael@0 292 self.assertNotEqual(srcsrv_stream, None)
michael@0 293 hgserver = [x.rstrip() for x in srcsrv_stream.splitlines() if x.startswith("HGSERVER=")]
michael@0 294 self.assertEqual(len(hgserver), 1)
michael@0 295 self.assertEqual(hgserver[0].split("=")[1], "http://example.com/repo")
michael@0 296
michael@0 297 if __name__ == '__main__':
michael@0 298 # use the multiprocessing.dummy module to use threading wrappers so
michael@0 299 # that our mocking/module-patching works
michael@0 300 symbolstore.Dumper.GlobalInit(module=multiprocessing.dummy)
michael@0 301
michael@0 302 unittest.main()
michael@0 303
michael@0 304 symbolstore.Dumper.pool.close()
michael@0 305 symbolstore.Dumper.pool.join()

mercurial