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

Unified Diff: tests/test_packagerGecko.py

Issue 29501558: Issue 5383 - Add tests for the Chrome and Firefox packagers (Closed)
Patch Set: Created July 31, 2017, 12:07 p.m.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: tests/test_packagerGecko.py
diff --git a/tests/test_packagerGecko.py b/tests/test_packagerGecko.py
new file mode 100644
index 0000000000000000000000000000000000000000..f7df16734762a8b63a7cf3a2d2f9f408adc4faef
--- /dev/null
+++ b/tests/test_packagerGecko.py
@@ -0,0 +1,339 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+import pytest
+
+import json
+
+from zipfile import ZipFile
+
+from xml.etree import ElementTree
+from itertools import product
+
+from buildtools import packagerGecko
+from buildtools import localeTools
+
+from buildtools.packager import readMetadata, getBuildVersion, Files
+from functools import reduce
+
+TR_FA = [True, False]
+
+MESSAGES = '\n'.join((
+ 'name=Name {0}',
+ 'description=Awesome description {0}',
+))
+
+
+@pytest.fixture
+def scripts(tmp_dir):
+ """Examplary scripts for testing addMissingFiles"""
Vasily Kuznetsov 2017/08/03 16:52:32 AFAIK "examplary" nowadays is usually spelled "exe
tlucas 2017/08/03 21:26:02 Your are right - but i like the "outstanding" part
tlucas 2017/08/04 14:52:00 Done.
+ lib_dir = tmp_dir.mkdir('lib')
+ lib_dir.join('ext.js').write('require("hooks");')
+
+ content_dir = tmp_dir.mkdir('chrome').mkdir('content')
+ content_dir.join('common.js').write('require("hooks");')
+
+
+@pytest.fixture
+def prefs_json(tmp_dir):
+ """Minimal .json file for testing processJSONFiles"""
+ lib_dir = tmp_dir.mkdir('lib')
+ lib_dir.join('prefs.json').write(json.dumps(
+ {'foo': 'bar'}
+ ))
+
+
+@pytest.fixture
+def locales(tmp_dir):
+ """Minimal locales for testing locale-processing"""
+ chrome_dir = tmp_dir.mkdir('chrome')
+ locale_dir = chrome_dir.mkdir('locale')
+
+ data = {
+ 'name': {'message': 'Name translated'},
+ 'description': {'message': 'Description translated'}
Vasily Kuznetsov 2017/08/03 16:52:32 When you use multiline layout for lists, sets and
tlucas 2017/08/03 21:26:03 As you can see in other collection-defintions, i n
tlucas 2017/08/04 14:51:59 Done.
+ }
+
+ for locale in ['en-US', 'de', 'kn']:
+ new_dir = locale_dir.mkdir(locale)
+ new_dir.join('meta.properties').write(MESSAGES.format(locale))
+ new_dir.join('test.json').write(json.dumps(data))
+ if locale == 'kn':
+ new_dir.join('.incomplete').write('')
+
+
+@pytest.fixture
+def subscriptions(tmp_dir):
+ """Examplary sbuscription-configuration"""
+ tmp_dir.join('subs.xml').write('\n'.join((
Vasily Kuznetsov 2017/08/03 16:52:32 Wouldn't it be easier to just use a string literal
tlucas 2017/08/03 21:26:03 Acknowledged.
tlucas 2017/08/04 14:52:00 Done.
+ '<subscriptions>',
+ '<subscription title="EasyList"',
+ 'specialization="English"',
+ 'url="https://easylist-downloads.adblockplus.org/easylist.txt"',
+ 'homepage="https://easylist.adblockplus.org/"',
+ 'prefixes="en"',
+ 'author="fanboy, MonztA, Famlam, Khrin"',
+ 'type="ads"/>',
+ '</subscriptions>',
+ )))
+
+
+def test_package_files(tmpdir):
+ tmpdir.join('foo.xml').write('')
+ tmpdir.join('foo.txt').write('')
+ tmpdir.join('foo.js').write('')
+
+ params = {
+ 'baseDir': str(tmpdir)
+ }
+
+ files = packagerGecko.getPackageFiles(params)
+ assert 'foo.xml' in files
+ assert 'foo.js' in files
+ assert 'foo.txt' not in files
+
+
+@pytest.mark.usefixtures('locales')
+def test_get_locales(tmp_dir):
+ for incomplete in [True, False]:
Vasily Kuznetsov 2017/08/03 16:52:32 This could also be done via parametrize perhaps.
tlucas 2017/08/03 21:26:02 Acknowledged.
tlucas 2017/08/04 14:52:00 Done.
+ locales = packagerGecko.getLocales(str(tmp_dir), incomplete)
+
+ assert 'de' in locales
+ assert 'en-US' in locales
+ assert ('kn' in locales) == incomplete
+
+
+@pytest.mark.parametrize('metadata_files', ['metadata.gecko'], indirect=True)
+@pytest.mark.usefixtures('locales', 'metadata_files', 'subscriptions')
+def test_create_manifest(tmp_dir):
Vasily Kuznetsov 2017/08/03 16:52:32 All this code is pretty cool and clever, but it ma
tlucas 2017/08/03 21:26:02 The cool- and cleverness could be a result of foll
tlucas 2017/08/04 14:51:59 Done.
Vasily Kuznetsov 2017/08/10 19:48:27 Acknowledged.
+ def first(elem):
+ return elem[0]
+
+ def text(elem):
+ return elem.text
+
+ def iteritems(func=None):
+ def wrapper(elements):
+ for elem in elements:
+ if func:
+ yield func(elem)
+ else:
+ yield elem
+ return wrapper
+
+ metadata = readMetadata(str(tmp_dir), 'gecko')
+ locales = packagerGecko.getLocales(str(tmp_dir))
+ contributors = packagerGecko.getContributors(metadata)
+
+ namespaces = {
+ 'em': 'http://www.mozilla.org/2004/em-rdf#',
+ 'ns': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
+ }
+
+ base = [
+ ('.//*', [len], 54),
+ ('./ns:Description/em:id', [first, text],
+ '{d10d0bf8-f5b5-c8b4-a8b2-2b9879e08c5d}'),
+ ('./ns:Description/em:optionsURL', [first, text],
+ 'chrome://adblockplus/content/ui/settings.xul'),
+ ('./ns:Description/em:optionsType', [first, text], '2'),
+ ('./ns:Description/em:bootstrap', [first, text], 'true'),
+ ('./ns:Description/em:multiprocessCompatible', [first, text], 'true'),
+ ('./ns:Description/em:homepageURL', [first, text],
+ 'http://adblockplus.org/'),
+ ('./ns:Description/em:creator', [first, text], 'Wladimir Palant'),
+ ('./ns:Description/em:contributor', [iteritems(text)],
+ ['Pety Pete', 'Neil Armstrong', 'Famlam', 'fanboy', 'Khrin',
+ 'MonztA']),
+ ]
+
+ base += [
+ ('./ns:Description/em:localized/ns:Description[em:locale="{}"]/em:{}'
+ .format(locale, tag),
+ [first, text],
+ value.format(locale))
+ for locale in locales
+ for tag, value in [
+ ('name', 'Name {}'),
+ ('description', 'Awesome description {}')
+ ]
+ ]
+
+ tags = ['minVersion', 'maxVersion']
+ apps = metadata.items('compat')
+ comp = [
+ (
+ packagerGecko.KNOWN_APPS.get(app[0]),
+ tags[i],
+ app[1].split('/')[i]
+ ) for app in apps for i in range(2)
+ ]
+
+ base += [
+ (''.join((
+ './ns:Description/em:targetApplication/',
+ 'ns:Description[em:id="{}"]/em:{}'
+ ))
+ .format(mapped_id, tag),
+ [first, text],
+ value)
+ for mapped_id, tag, value in comp
+ ]
+
+ for release, multicompartment in product(TR_FA, TR_FA):
Vasily Kuznetsov 2017/08/03 16:52:32 Maybe better do this with parametrization?
tlucas 2017/08/03 21:26:02 Acknowledged.
tlucas 2017/08/04 14:52:00 Done.
+ version = getBuildVersion(str(tmp_dir), metadata, release, None)
+ expected = base + [
+ ('./ns:Description/em:version', [first, text], version),
+ ]
+ params = {
+ 'baseDir': str(tmp_dir),
+ 'locales': locales,
+ 'metadata': metadata,
+ 'version': version.encode('utf-8'),
+ 'multicompartment': multicompartment,
+ 'contributors': contributors
+ }
+ manifest = packagerGecko.createManifest(params)
+
+ tree = ElementTree.fromstring(manifest)
+
+ with open('/tmp/test.xml', 'w') as fp:
Vasily Kuznetsov 2017/08/03 16:52:32 Why use '/tmp' instead of tmpdir fixture? Also kee
tlucas 2017/08/03 21:26:02 Acknowledged.
tlucas 2017/08/04 14:52:00 Done (removed).
+ fp.write(manifest)
+
+ for expression, modifiers, value in expected:
+ res = reduce(
+ lambda val, func: func(val),
+ modifiers,
+ tree.findall(expression, namespaces=namespaces))
+
+ from collections import Iterable
+
+ if isinstance(res, Iterable) and not isinstance(res, str):
+ res = list(res)
+ for x in res:
Vasily Kuznetsov 2017/08/03 16:52:32 Seems like you just want to compare `res` to `valu
tlucas 2017/08/03 21:26:02 I agree with the assert set() == set() part, but o
tlucas 2017/08/04 14:52:00 I totally missed something. Done.
+ assert x in value
+ for x in value:
+ assert x in res
+ assert res == value
+
+
+@pytest.mark.parametrize('metadata_files', ['metadata.gecko'], indirect=True)
+@pytest.mark.usefixtures('locales', 'metadata_files')
+def test_fixup_import_locales(files, tmp_dir):
+ locale_dir = tmp_dir.dirpath(tmp_dir.basename, 'chrome', 'locale')
+ locale_dir.mkdir('fr').join('meta.properties')\
+ .write(MESSAGES.format('fr'))
+
+ metadata = readMetadata(str(tmp_dir), 'gecko')
+ locales = packagerGecko.getLocales(str(tmp_dir), False)
+
+ params = {
+ 'metadata': metadata,
+ 'locales': locales,
+ 'baseDir': str(tmp_dir)
+ }
+
+ # Should add missing fr/test.properties to files
+ packagerGecko.fixupLocales(params, files)
+
+ packagerGecko.importLocales(params, files)
+ for locale in locales:
+ properties = files['chrome/locale/{}/test.properties'.format(locale)]
+ translation_data = list(
+ localeTools.parsePropertiesString(properties, ''))
+
+ for trans in [
+ ('name', None, 'Name translated'),
+ ('description', None, 'Description translated')]:
+ assert trans in translation_data
+
+
+def test_process_json_files(tmp_dir, prefs_json):
+ params = {
+ 'baseDir': str(tmp_dir),
+ 'jsonRequires': {},
+ }
+
+ files = Files(packagerGecko.getPackageFiles(params), set())
+ files.read(str(tmp_dir))
+
+ packagerGecko.processJSONFiles(params, files)
+
+ assert params['jsonRequires'] == {'prefs.json': {'foo': 'bar'}}
+
+
+@pytest.mark.parametrize('metadata_files', ['metadata.gecko'], indirect=True)
+@pytest.mark.usefixtures('scripts', 'metadata_files')
+def test_add_missing_files(tmp_dir):
+ metadata = readMetadata(str(tmp_dir), 'gecko')
+
+ params = {
+ 'baseDir': str(tmp_dir),
+ 'metadata': metadata,
+ 'jsonRequires': {},
+ 'multicompartment': True,
+ 'hasWebExtension': False,
+ }
+
+ files = Files(packagerGecko.getPackageFiles(params), set())
+ files.read(str(tmp_dir))
+
+ packagerGecko.addMissingFiles(params, files)
+
+ assert 'let shutdownHandlers = [];' in files['bootstrap.js']
+ assert 'Services.obs.addObserver(' in files['bootstrap.js']
+ for filename in ['bootstrap.js', 'chrome/content/common.js',
+ 'lib/ext.js', 'lib/hooks.js']:
+ assert filename in files
+
+
+@pytest.mark.parametrize('metadata_files', ['metadata.gecko'], indirect=True)
+@pytest.mark.usefixtures('metadata_files', 'locales', 'subscriptions')
+def test_create_build(tmp_dir, capsys):
+ base_files = [
+ 'bootstrap.js',
+ 'chrome/locale/de/test.json',
+ 'chrome/locale/de/test.properties',
+ 'chrome/locale/en-US/test.json',
+ 'chrome/locale/en-US/test.properties',
+ 'install.rdf',
+ 'subs.xml'
+ ]
+
+ for all_locales, release, multicompartment in product(
Vasily Kuznetsov 2017/08/03 16:52:32 Also maybe parametrization?
tlucas 2017/08/03 21:26:03 Acknowledged.
tlucas 2017/08/04 14:51:59 Done.
+ ['all', None], TR_FA, TR_FA):
+
+ if all_locales is None:
+ expected = base_files
+ else:
+ expected = base_files + [
+ 'chrome/locale/kn/test.json',
+ 'chrome/locale/kn/test.properties'
+ ]
+
+ out_file = tmp_dir.join('{}_{}_{}.zip'.format(
+ all_locales, release, multicompartment))
+
+ out_file = str(out_file)
+
+ packagerGecko.createBuild(
+ str(tmp_dir),
+ locales=all_locales,
+ outFile=out_file,
+ releaseBuild=release,
+ multicompartment=multicompartment)
+
+ out, err = capsys.readouterr()
+
+ assert err ==\
+ "Warning: Mapped file adblockplusui/firstRun.html doesn't exist\n"
+
+ with ZipFile(out_file, 'r') as zipfp:
+ zipfp.testzip()
+
+ filenames = [zipinfo.filename for zipinfo in zipfp.infolist()]
+
+ for name in expected:
+ assert name in filenames

Powered by Google App Engine
This is Rietveld