Sat, 03 Jan 2015 20:18:00 +0100
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() |