Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Delta Between Two Patch Sets: tests/test_packagerWebExt.py

Issue 29501558: Issue 5383 - Add tests for the Chrome and Firefox packagers (Closed)
Left Patch Set: Adjusting tests to recent changes Created Oct. 11, 2017, 4:01 p.m.
Right Patch Set: Addressing Vasily's comments Created Oct. 22, 2017, 11:11 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « tests/test_packagerEdge.py ('k') | tox.ini » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 # This Source Code Form is subject to the terms of the Mozilla Public 1 # This Source Code Form is subject to the terms of the Mozilla Public
2 # License, v. 2.0. If a copy of the MPL was not distributed with this 2 # License, v. 2.0. If a copy of the MPL was not distributed with this
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/. 3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
4 4
5 import difflib
6 import json
5 import os 7 import os
8 import re
6 import shutil 9 import shutil
7 import zipfile 10 import zipfile
8 import json 11 from xml.etree import ElementTree
9 import re
10 from struct import unpack 12 from struct import unpack
11 import difflib
12 13
13 import pytest 14 import pytest
15 from Crypto.Signature import PKCS1_v1_5
16 from Crypto.PublicKey import RSA
14 from Crypto.Hash import SHA 17 from Crypto.Hash import SHA
15 from Crypto.PublicKey import RSA
16 from Crypto.Signature import PKCS1_v1_5
17 from xml.etree import ElementTree
18
19 18
20 from buildtools import packager 19 from buildtools import packager
21 from buildtools.packagerChrome import defaultLocale 20 from buildtools.packagerChrome import defaultLocale
22 from buildtools.build import processArgs 21 from buildtools.build import processArgs
23 22
24 LOCALES_MODULE = { 23 LOCALES_MODULE = {
25 'test.Foobar': { 24 'test.Foobar': {
26 'message': 'Ensuring dict-copy from modules for $domain$', 25 'message': 'Ensuring dict-copy from modules for $domain$',
27 'description': 'test description', 26 'description': 'test description',
28 'placeholders': {'content': '$1', 'example': 'www.adblockplus.org'} 27 'placeholders': {'content': '$1', 'example': 'www.adblockplus.org'}
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
120 return content 119 return content
121 120
122 121
123 def copy_metadata(filename, tmpdir): 122 def copy_metadata(filename, tmpdir):
124 """Copy the used metadata to the used temporary directory.""" 123 """Copy the used metadata to the used temporary directory."""
125 path = os.path.join(os.path.dirname(__file__), filename) 124 path = os.path.join(os.path.dirname(__file__), filename)
126 destination = str(tmpdir.join(filename)) 125 destination = str(tmpdir.join(filename))
127 shutil.copy(path, destination) 126 shutil.copy(path, destination)
128 127
129 128
130 def run_webext_build(ext_type, build_opt, srcdir, buildnum=None, keyfile=None): 129 def run_webext_build(ext_type, build_opt, srcdir, keyfile=None):
131 """Run a build process.""" 130 """Run a build process."""
132 if build_opt == 'build': 131 cmd_mapping = {
133 build_args = ['build'] 132 'devenv': ['devenv'],
134 elif build_opt == 'release': 133 'development_build': ['build', '-b', '1337'],
135 build_args = ['build', '-r'] 134 'release_build': ['build', '-r'],
136 else: 135 }
137 build_args = ['devenv'] 136
138 137 args = ['build.py', '-t', ext_type] + cmd_mapping[build_opt]
139 args = ['build.py', '-t', ext_type] + build_args
140 138
141 if keyfile: 139 if keyfile:
142 args += ['-k', keyfile] 140 args += ['-k', keyfile]
143 if buildnum:
144 args += ['-b', buildnum]
145 141
146 processArgs(str(srcdir), args) 142 processArgs(str(srcdir), args)
147 143
148 144
149 def locale_files(languages, rootfolder, srcdir): 145 def locale_files(languages, rootfolder, srcdir):
150 """Generate example locales. 146 """Generate example locales.
151 147
152 languages: tuple, list or set of languages to include 148 languages: tuple, list or set of languages to include
153 rootdir: folder-name to create the locale-folders in 149 rootdir: folder-name to create the locale-folders in
154 """ 150 """
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
225 221
226 @pytest.fixture 222 @pytest.fixture
227 def keyfile(tmpdir): 223 def keyfile(tmpdir):
228 """Test-privatekey for signing chrome release-package.""" 224 """Test-privatekey for signing chrome release-package."""
229 return os.path.join(os.path.dirname(__file__), 'chrome_rsa.pem') 225 return os.path.join(os.path.dirname(__file__), 'chrome_rsa.pem')
230 226
231 227
232 @pytest.fixture 228 @pytest.fixture
233 def lib_files(tmpdir): 229 def lib_files(tmpdir):
234 files = packager.Files(['lib'], set()) 230 files = packager.Files(['lib'], set())
235 files['ext/a.js'] = 'var bar;' 231 files['ext/a.js'] = 'require("./c.js");\nvar bar;'
236 files['lib/b.js'] = 'var foo;' 232 files['lib/b.js'] = 'var foo;'
233 files['ext/c.js'] = 'var this_is_c;'
237 234
238 tmpdir.mkdir('lib').join('b.js').write(files['lib/b.js']) 235 tmpdir.mkdir('lib').join('b.js').write(files['lib/b.js'])
239 tmpdir.mkdir('ext').join('a.js').write(files['ext/a.js']) 236 ext_dir = tmpdir.mkdir('ext')
237 ext_dir.join('a.js').write(files['ext/a.js'])
238 ext_dir.join('c.js').write(files['ext/c.js'])
240 239
241 return files 240 return files
242 241
243 242
244 def comparable_xml(xml): 243 def comparable_xml(xml):
245 """Create a nonambiguous representation of a given XML tree.""" 244 """Create a nonambiguous representation of a given XML tree.
245
246 Note that this function is not safe against ambiguous tags
247 containing differently distributed children, e.g.:
248
249 '<a><b><c/></b><b><d/></b></a>'
250 vs.
251 '<a><b/><b><c/><d/></b></a>'
252
253 This is irrelevant for comparing the XML used by the tests of this
254 module.
255 """
246 def get_leafs_string(tree): 256 def get_leafs_string(tree):
247 """Recursively build a string representing all xml leaf-nodes.""" 257 """Recursively build a string representing all xml leaf-nodes."""
248 root_str = '{}|{}|{}'.format(tree.tag, tree.tail, tree.text).strip() 258 root_str = '{}|{}|{}'.format(tree.tag, tree.tail, tree.text).strip()
249 result = [] 259 result = []
250 260
251 if len(tree) > 0: 261 if len(tree) > 0:
252 for subtree in tree: 262 for subtree in tree:
253 for leaf in get_leafs_string(subtree): 263 for leaf in get_leafs_string(subtree):
254 result.append('{}__{}'.format(root_str, leaf)) 264 result.append('{}__{}'.format(root_str, leaf))
255 for k, v in tree.attrib.items(): 265 for k, v in tree.attrib.items():
(...skipping 29 matching lines...) Expand all
285 assert len(diff) == 0, '\n'.join(diff) 295 assert len(diff) == 0, '\n'.join(diff)
286 296
287 297
288 def assert_webpack_bundle(package, prefix, excluded=False): 298 def assert_webpack_bundle(package, prefix, excluded=False):
289 libfoo = package.read(os.path.join(prefix, 'lib/foo.js')) 299 libfoo = package.read(os.path.join(prefix, 'lib/foo.js'))
290 libfoomap = package.read(os.path.join(prefix, 'lib/foo.js.map')) 300 libfoomap = package.read(os.path.join(prefix, 'lib/foo.js.map'))
291 301
292 assert 'var bar;' in libfoo 302 assert 'var bar;' in libfoo
293 assert 'webpack:///./ext/a.js' in libfoomap 303 assert 'webpack:///./ext/a.js' in libfoomap
294 304
305 assert 'var this_is_c;' in libfoo
306 assert 'webpack:///./ext/c.js' in libfoomap
307
295 assert ('var foo;' in libfoo) != excluded 308 assert ('var foo;' in libfoo) != excluded
296 assert ('webpack:///./lib/b.js' in libfoomap) != excluded 309 assert ('webpack:///./lib/b.js' in libfoomap) != excluded
297 310
298 311
299 def assert_devenv_scripts(package, devenv): 312 def assert_devenv_scripts(package, prefix, devenv):
300 manifest = json.loads(package.read('manifest.json')) 313 manifest = json.loads(package.read(os.path.join(prefix, 'manifest.json')))
301 filenames = package.namelist() 314 filenames = package.namelist()
302 scripts = [ 315 scripts = [
303 'ext/common.js', 316 'ext/common.js',
304 'ext/background.js', 317 'ext/background.js',
305 ] 318 ]
306 319
307 assert ('qunit/index.html' in filenames) == devenv 320 assert (os.path.join(prefix, 'qunit/index.html') in filenames) == devenv
308 assert ('devenvPoller__.js' in filenames) == devenv 321 assert (os.path.join(prefix, 'devenvPoller__.js') in filenames) == devenv
309 assert ('devenvVersion__' in filenames) == devenv 322 assert (os.path.join(prefix, 'devenvVersion__') in filenames) == devenv
310 323
311 if devenv: 324 if devenv:
312 assert '../ext/common.js' in package.read('qunit/index.html') 325 quint_index = package.read(os.path.join(prefix, 'qunit/index.html'))
313 assert '../ext/background.js' in package.read('qunit/index.html') 326 assert '../ext/common.js' in quint_index
327 assert '../ext/background.js' in quint_index
314 328
315 assert set(manifest['background']['scripts']) == set( 329 assert set(manifest['background']['scripts']) == set(
316 scripts + ['devenvPoller__.js'] 330 scripts + ['devenvPoller__.js']
317 ) 331 )
318 else: 332 else:
319 assert set(manifest['background']['scripts']) == set(scripts) 333 assert set(manifest['background']['scripts']) == set(scripts)
320 334
321 335
322 def assert_base_files(package, platform): 336 def assert_base_files(package, platform, prefix):
323 filenames = set(package.namelist()) 337 filenames = set(package.namelist())
324 338
325 if platform in {'chrome', 'gecko'}: 339 if platform == 'edge':
326 assert 'bar.json' in filenames
327 assert 'manifest.json' in filenames
328 assert 'lib/foo.js' in filenames
329 assert 'foo/logo_50.png' in filenames
330 assert 'icons/logo_150.png' in filenames
331 else:
332 assert 'AppxManifest.xml' in filenames 340 assert 'AppxManifest.xml' in filenames
333 assert 'AppxBlockMap.xml' in filenames 341 assert 'AppxBlockMap.xml' in filenames
334 assert '[Content_Types].xml' in filenames 342 assert '[Content_Types].xml' in filenames
335 343
336 assert 'Extension/bar.json' in filenames
337 assert 'Extension/lib/foo.js' in filenames
338
339 assert package.read('Assets/logo_44.png') == '44' 344 assert package.read('Assets/logo_44.png') == '44'
340 assert package.read('Extension/icons/abp-44.png') == '44' 345 assert package.read('Extension/icons/abp-44.png') == '44'
346
347 assert os.path.join(prefix, 'bar.json') in filenames
348 assert os.path.join(prefix, 'manifest.json') in filenames
349 assert os.path.join(prefix, 'lib/foo.js') in filenames
350 assert os.path.join(prefix, 'foo/logo_50.png') in filenames
351 assert os.path.join(prefix, 'icons/logo_150.png') in filenames
341 352
342 353
343 def assert_chrome_signature(filename, keyfile): 354 def assert_chrome_signature(filename, keyfile):
344 with open(filename, 'r') as fp: 355 with open(filename, 'r') as fp:
345 content = fp.read() 356 content = fp.read()
346 357
347 _, _, l_pubkey, l_signature = unpack('<4sIII', content[:16]) 358 _, _, l_pubkey, l_signature = unpack('<4sIII', content[:16])
348 signature = content[16 + l_pubkey: 16 + l_pubkey + l_signature] 359 signature = content[16 + l_pubkey: 16 + l_pubkey + l_signature]
349 360
350 digest = SHA.new() 361 digest = SHA.new()
(...skipping 25 matching lines...) Expand all
376 387
377 @pytest.mark.usefixtures( 388 @pytest.mark.usefixtures(
378 'all_lang_locales', 389 'all_lang_locales',
379 'locale_modules', 390 'locale_modules',
380 'icons', 391 'icons',
381 'lib_files', 392 'lib_files',
382 'chrome_metadata', 393 'chrome_metadata',
383 'gecko_webext_metadata', 394 'gecko_webext_metadata',
384 'edge_metadata', 395 'edge_metadata',
385 ) 396 )
386 @pytest.mark.parametrize('platform,dev_build_release,buildnum', [ 397 @pytest.mark.parametrize('platform,command', [
387 ('chrome', 'build', '1337'), 398 ('chrome', 'development_build'),
388 ('chrome', 'devenv', None), 399 ('chrome', 'devenv'),
389 ('chrome', 'release', None), 400 ('chrome', 'release_build'),
390 ('gecko', 'build', '1337'), 401 ('gecko', 'development_build'),
391 ('gecko', 'devenv', None), 402 ('gecko', 'devenv'),
392 ('gecko', 'release', None), 403 ('gecko', 'release_build'),
393 ('edge', 'build', '1337'), 404 ('edge', 'development_build'),
394 pytest.param('edge', 'devenv', None, marks=pytest.mark.xfail), 405 ('edge', 'devenv'),
395 ('edge', 'release', None), 406 ('edge', 'release_build'),
396 ]) 407 ])
397 def test_build_webext(platform, dev_build_release, keyfile, tmpdir, srcdir, 408 def test_build_webext(platform, command, keyfile, tmpdir, srcdir, capsys):
398 buildnum, capsys): 409 release = command == 'release_build'
399 release = dev_build_release == 'release' 410 devenv = command == 'devenv'
400 devenv = dev_build_release == 'devenv'
401 411
402 if platform == 'chrome' and release: 412 if platform == 'chrome' and release:
403 key = keyfile 413 key = keyfile
404 else: 414 else:
405 key = None 415 key = None
406 416
407 manifests = { 417 manifests = {
408 'gecko': [('', 'manifest', 'json')], 418 'gecko': [('', 'manifest', 'json')],
409 'chrome': [('', 'manifest', 'json')], 419 'chrome': [('', 'manifest', 'json')],
410 'edge': [('', 'AppxManifest', 'xml'), 420 'edge': [('', 'AppxManifest', 'xml'),
411 ('Extension', 'manifest', 'json')], 421 ('Extension', 'manifest', 'json')],
412 } 422 }
413 423
414 filenames = { 424 filenames = {
415 'gecko': 'adblockplusfirefox-1.2.3{}.xpi', 425 'gecko': 'adblockplusfirefox-1.2.3{}.xpi',
416 'chrome': 'adblockpluschrome-1.2.3{{}}.{}'.format( 426 'chrome': 'adblockpluschrome-1.2.3{{}}.{}'.format(
417 {True: 'crx', False: 'zip'}[release] 427 {True: 'crx', False: 'zip'}[release]
418 ), 428 ),
419 'edge': 'adblockplusedge-1.2.3{}.appx', 429 'edge': 'adblockplusedge-1.2.3{}.appx',
420 } 430 }
421 431
422 if platform == 'edge': 432 if platform == 'edge':
423 prefix = 'Extension' 433 prefix = 'Extension'
424 else: 434 else:
425 prefix = '' 435 prefix = ''
426 436
427 run_webext_build(platform, dev_build_release, srcdir, buildnum=buildnum, 437 run_webext_build(platform, command, srcdir, keyfile=key)
428 keyfile=key)
429 438
430 # The makeIcons() in packagerChrome.py should warn about non-square 439 # The makeIcons() in packagerChrome.py should warn about non-square
431 # icons via stderr. 440 # icons via stderr.
432 if platform in {'chrome', 'gecko'}: 441 out, err = capsys.readouterr()
433 out, err = capsys.readouterr() 442 assert 'icon should be square' in err
434 assert 'icon should be square' in err
435 443
436 if devenv: 444 if devenv:
437 content_class = DirContent 445 content_class = DirContent
438 out_file_path = os.path.join(str(srcdir), 'devenv.' + platform) 446 out_file_path = os.path.join(str(srcdir), 'devenv.' + platform)
439 else: 447 else:
440 content_class = ZipContent 448 content_class = ZipContent
441 449
442 if release: 450 if release:
443 add_version = '' 451 add_version = ''
444 else: 452 else:
445 add_version = '.' + buildnum 453 add_version = '.1337'
446 454
447 out_file = filenames[platform].format(add_version) 455 out_file = filenames[platform].format(add_version)
448 456
449 out_file_path = os.path.abspath(os.path.join( 457 out_file_path = os.path.abspath(os.path.join(
450 os.path.dirname(__file__), os.pardir, out_file)) 458 os.path.dirname(__file__), os.pardir, out_file))
451 assert os.path.exists(out_file_path) 459 assert os.path.exists(out_file_path)
452 460
453 if release and platform == 'chrome': 461 if release and platform == 'chrome':
454 assert_chrome_signature(out_file_path, keyfile) 462 assert_chrome_signature(out_file_path, keyfile)
455 463
456 with content_class(out_file_path) as package: 464 with content_class(out_file_path) as package:
457 assert_base_files(package, platform) 465 assert_base_files(package, platform, prefix)
458 assert_all_locales_present(package, prefix) 466 assert_all_locales_present(package, prefix)
459 assert_webpack_bundle(package, prefix, platform == 'gecko') 467 assert_webpack_bundle(package, prefix, platform == 'gecko')
460 468
461 if platform == 'chrome': 469 if platform == 'chrome':
462 assert_locale_upfix(package) 470 assert_locale_upfix(package)
463 if platform in {'chrome', 'gecko'}: 471
464 assert_devenv_scripts(package, devenv) 472 assert_devenv_scripts(package, prefix, devenv)
465 473
466 for folder, name, ext in manifests[platform]: 474 for folder, name, ext in manifests[platform]:
467 filename = '{{}}_{}_{}.{{}}'.format(platform, dev_build_release) 475 filename = '{{}}_{}_{}.{{}}'.format(platform, command)
468 expected = os.path.join( 476 expected = os.path.join(
469 os.path.dirname(__file__), 477 os.path.dirname(__file__),
470 'expecteddata', 478 'expecteddata',
471 filename.format(name, ext), 479 filename.format(name, ext),
472 ) 480 )
473 481
474 assert_manifest_content( 482 assert_manifest_content(
475 package.read(os.path.join(folder, '{}.{}'.format(name, ext))), 483 package.read(os.path.join(folder, '{}.{}'.format(name, ext))),
476 expected, 484 expected,
477 ) 485 )
LEFTRIGHT

Powered by Google App Engine
This is Rietveld