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

Side by Side 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.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
5
6 import pytest
7
8 import json
9
10 from zipfile import ZipFile
11
12 from xml.etree import ElementTree
13 from itertools import product
14
15 from buildtools import packagerGecko
16 from buildtools import localeTools
17
18 from buildtools.packager import readMetadata, getBuildVersion, Files
19 from functools import reduce
20
21 TR_FA = [True, False]
22
23 MESSAGES = '\n'.join((
24 'name=Name {0}',
25 'description=Awesome description {0}',
26 ))
27
28
29 @pytest.fixture
30 def scripts(tmp_dir):
31 """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.
32 lib_dir = tmp_dir.mkdir('lib')
33 lib_dir.join('ext.js').write('require("hooks");')
34
35 content_dir = tmp_dir.mkdir('chrome').mkdir('content')
36 content_dir.join('common.js').write('require("hooks");')
37
38
39 @pytest.fixture
40 def prefs_json(tmp_dir):
41 """Minimal .json file for testing processJSONFiles"""
42 lib_dir = tmp_dir.mkdir('lib')
43 lib_dir.join('prefs.json').write(json.dumps(
44 {'foo': 'bar'}
45 ))
46
47
48 @pytest.fixture
49 def locales(tmp_dir):
50 """Minimal locales for testing locale-processing"""
51 chrome_dir = tmp_dir.mkdir('chrome')
52 locale_dir = chrome_dir.mkdir('locale')
53
54 data = {
55 'name': {'message': 'Name translated'},
56 '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.
57 }
58
59 for locale in ['en-US', 'de', 'kn']:
60 new_dir = locale_dir.mkdir(locale)
61 new_dir.join('meta.properties').write(MESSAGES.format(locale))
62 new_dir.join('test.json').write(json.dumps(data))
63 if locale == 'kn':
64 new_dir.join('.incomplete').write('')
65
66
67 @pytest.fixture
68 def subscriptions(tmp_dir):
69 """Examplary sbuscription-configuration"""
70 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.
71 '<subscriptions>',
72 '<subscription title="EasyList"',
73 'specialization="English"',
74 'url="https://easylist-downloads.adblockplus.org/easylist.txt"',
75 'homepage="https://easylist.adblockplus.org/"',
76 'prefixes="en"',
77 'author="fanboy, MonztA, Famlam, Khrin"',
78 'type="ads"/>',
79 '</subscriptions>',
80 )))
81
82
83 def test_package_files(tmpdir):
84 tmpdir.join('foo.xml').write('')
85 tmpdir.join('foo.txt').write('')
86 tmpdir.join('foo.js').write('')
87
88 params = {
89 'baseDir': str(tmpdir)
90 }
91
92 files = packagerGecko.getPackageFiles(params)
93 assert 'foo.xml' in files
94 assert 'foo.js' in files
95 assert 'foo.txt' not in files
96
97
98 @pytest.mark.usefixtures('locales')
99 def test_get_locales(tmp_dir):
100 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.
101 locales = packagerGecko.getLocales(str(tmp_dir), incomplete)
102
103 assert 'de' in locales
104 assert 'en-US' in locales
105 assert ('kn' in locales) == incomplete
106
107
108 @pytest.mark.parametrize('metadata_files', ['metadata.gecko'], indirect=True)
109 @pytest.mark.usefixtures('locales', 'metadata_files', 'subscriptions')
110 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.
111 def first(elem):
112 return elem[0]
113
114 def text(elem):
115 return elem.text
116
117 def iteritems(func=None):
118 def wrapper(elements):
119 for elem in elements:
120 if func:
121 yield func(elem)
122 else:
123 yield elem
124 return wrapper
125
126 metadata = readMetadata(str(tmp_dir), 'gecko')
127 locales = packagerGecko.getLocales(str(tmp_dir))
128 contributors = packagerGecko.getContributors(metadata)
129
130 namespaces = {
131 'em': 'http://www.mozilla.org/2004/em-rdf#',
132 'ns': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
133 }
134
135 base = [
136 ('.//*', [len], 54),
137 ('./ns:Description/em:id', [first, text],
138 '{d10d0bf8-f5b5-c8b4-a8b2-2b9879e08c5d}'),
139 ('./ns:Description/em:optionsURL', [first, text],
140 'chrome://adblockplus/content/ui/settings.xul'),
141 ('./ns:Description/em:optionsType', [first, text], '2'),
142 ('./ns:Description/em:bootstrap', [first, text], 'true'),
143 ('./ns:Description/em:multiprocessCompatible', [first, text], 'true'),
144 ('./ns:Description/em:homepageURL', [first, text],
145 'http://adblockplus.org/'),
146 ('./ns:Description/em:creator', [first, text], 'Wladimir Palant'),
147 ('./ns:Description/em:contributor', [iteritems(text)],
148 ['Pety Pete', 'Neil Armstrong', 'Famlam', 'fanboy', 'Khrin',
149 'MonztA']),
150 ]
151
152 base += [
153 ('./ns:Description/em:localized/ns:Description[em:locale="{}"]/em:{}'
154 .format(locale, tag),
155 [first, text],
156 value.format(locale))
157 for locale in locales
158 for tag, value in [
159 ('name', 'Name {}'),
160 ('description', 'Awesome description {}')
161 ]
162 ]
163
164 tags = ['minVersion', 'maxVersion']
165 apps = metadata.items('compat')
166 comp = [
167 (
168 packagerGecko.KNOWN_APPS.get(app[0]),
169 tags[i],
170 app[1].split('/')[i]
171 ) for app in apps for i in range(2)
172 ]
173
174 base += [
175 (''.join((
176 './ns:Description/em:targetApplication/',
177 'ns:Description[em:id="{}"]/em:{}'
178 ))
179 .format(mapped_id, tag),
180 [first, text],
181 value)
182 for mapped_id, tag, value in comp
183 ]
184
185 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.
186 version = getBuildVersion(str(tmp_dir), metadata, release, None)
187 expected = base + [
188 ('./ns:Description/em:version', [first, text], version),
189 ]
190 params = {
191 'baseDir': str(tmp_dir),
192 'locales': locales,
193 'metadata': metadata,
194 'version': version.encode('utf-8'),
195 'multicompartment': multicompartment,
196 'contributors': contributors
197 }
198 manifest = packagerGecko.createManifest(params)
199
200 tree = ElementTree.fromstring(manifest)
201
202 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).
203 fp.write(manifest)
204
205 for expression, modifiers, value in expected:
206 res = reduce(
207 lambda val, func: func(val),
208 modifiers,
209 tree.findall(expression, namespaces=namespaces))
210
211 from collections import Iterable
212
213 if isinstance(res, Iterable) and not isinstance(res, str):
214 res = list(res)
215 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.
216 assert x in value
217 for x in value:
218 assert x in res
219 assert res == value
220
221
222 @pytest.mark.parametrize('metadata_files', ['metadata.gecko'], indirect=True)
223 @pytest.mark.usefixtures('locales', 'metadata_files')
224 def test_fixup_import_locales(files, tmp_dir):
225 locale_dir = tmp_dir.dirpath(tmp_dir.basename, 'chrome', 'locale')
226 locale_dir.mkdir('fr').join('meta.properties')\
227 .write(MESSAGES.format('fr'))
228
229 metadata = readMetadata(str(tmp_dir), 'gecko')
230 locales = packagerGecko.getLocales(str(tmp_dir), False)
231
232 params = {
233 'metadata': metadata,
234 'locales': locales,
235 'baseDir': str(tmp_dir)
236 }
237
238 # Should add missing fr/test.properties to files
239 packagerGecko.fixupLocales(params, files)
240
241 packagerGecko.importLocales(params, files)
242 for locale in locales:
243 properties = files['chrome/locale/{}/test.properties'.format(locale)]
244 translation_data = list(
245 localeTools.parsePropertiesString(properties, ''))
246
247 for trans in [
248 ('name', None, 'Name translated'),
249 ('description', None, 'Description translated')]:
250 assert trans in translation_data
251
252
253 def test_process_json_files(tmp_dir, prefs_json):
254 params = {
255 'baseDir': str(tmp_dir),
256 'jsonRequires': {},
257 }
258
259 files = Files(packagerGecko.getPackageFiles(params), set())
260 files.read(str(tmp_dir))
261
262 packagerGecko.processJSONFiles(params, files)
263
264 assert params['jsonRequires'] == {'prefs.json': {'foo': 'bar'}}
265
266
267 @pytest.mark.parametrize('metadata_files', ['metadata.gecko'], indirect=True)
268 @pytest.mark.usefixtures('scripts', 'metadata_files')
269 def test_add_missing_files(tmp_dir):
270 metadata = readMetadata(str(tmp_dir), 'gecko')
271
272 params = {
273 'baseDir': str(tmp_dir),
274 'metadata': metadata,
275 'jsonRequires': {},
276 'multicompartment': True,
277 'hasWebExtension': False,
278 }
279
280 files = Files(packagerGecko.getPackageFiles(params), set())
281 files.read(str(tmp_dir))
282
283 packagerGecko.addMissingFiles(params, files)
284
285 assert 'let shutdownHandlers = [];' in files['bootstrap.js']
286 assert 'Services.obs.addObserver(' in files['bootstrap.js']
287 for filename in ['bootstrap.js', 'chrome/content/common.js',
288 'lib/ext.js', 'lib/hooks.js']:
289 assert filename in files
290
291
292 @pytest.mark.parametrize('metadata_files', ['metadata.gecko'], indirect=True)
293 @pytest.mark.usefixtures('metadata_files', 'locales', 'subscriptions')
294 def test_create_build(tmp_dir, capsys):
295 base_files = [
296 'bootstrap.js',
297 'chrome/locale/de/test.json',
298 'chrome/locale/de/test.properties',
299 'chrome/locale/en-US/test.json',
300 'chrome/locale/en-US/test.properties',
301 'install.rdf',
302 'subs.xml'
303 ]
304
305 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.
306 ['all', None], TR_FA, TR_FA):
307
308 if all_locales is None:
309 expected = base_files
310 else:
311 expected = base_files + [
312 'chrome/locale/kn/test.json',
313 'chrome/locale/kn/test.properties'
314 ]
315
316 out_file = tmp_dir.join('{}_{}_{}.zip'.format(
317 all_locales, release, multicompartment))
318
319 out_file = str(out_file)
320
321 packagerGecko.createBuild(
322 str(tmp_dir),
323 locales=all_locales,
324 outFile=out_file,
325 releaseBuild=release,
326 multicompartment=multicompartment)
327
328 out, err = capsys.readouterr()
329
330 assert err ==\
331 "Warning: Mapped file adblockplusui/firstRun.html doesn't exist\n"
332
333 with ZipFile(out_file, 'r') as zipfp:
334 zipfp.testzip()
335
336 filenames = [zipinfo.filename for zipinfo in zipfp.infolist()]
337
338 for name in expected:
339 assert name in filenames
OLDNEW

Powered by Google App Engine
This is Rietveld