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

Side by Side Diff: tests/test_packagerChrome.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 import re
6 import json
7 import zipfile
8
9 from xml.etree import ElementTree
10 from itertools import product
11
12 import pytest
13
14 from buildtools import packager, packagerChrome
15
16 ICON_SIZES = [32, 48, 64, 256, 53]
17
18 TR_FA = [True, False]
Vasily Kuznetsov 2017/08/03 16:52:29 Not sure having this constant is worth it. TR_FA i
tlucas 2017/08/03 21:26:01 This will be gotten rid of by proper parametrizati
tlucas 2017/08/04 14:51:57 Done.
19
20 MINIMUM_MANIFEST_JSON = [
Vasily Kuznetsov 2017/08/03 16:52:29 Isn't this name a bit confusing given that the con
tlucas 2017/08/03 21:26:01 Acknowledged.
tlucas 2017/08/04 14:51:57 Done.
21 ('manifest_version', 2),
Vasily Kuznetsov 2017/08/03 16:52:28 For consistency with other code, it would be bette
tlucas 2017/08/03 21:26:00 Acknowledged.
tlucas 2017/08/04 14:51:57 Done.
22 ('author', 'Eyeo GmbH'),
23 ('permissions', ['tabs', '<all_urls>', 'contextMenus', 'webRequest',
24 'webRequestBlocking', 'webNavigation', 'storage',
25 'unlimitedStorage', 'notifications']),
26 ('minimum_chrome_version', '49.0'),
27 ('minimum_opera_version', '36.0'),
28 ('devtools_page', 'devtools.html'),
29 ('description', '__MSG_description__'),
30 ('default_locale', 'en_US'),
31 ('short_name', '__MSG_name__'),
32 ('storage', {'managed_schema': 'managed-storage-schema.json'}),
33 ('options_ui', {'open_in_tab': True, 'page': 'options.html'}),
34 ]
35
36
37 @pytest.fixture
38 def icons(tmpdir):
39 """Valid .png files for testing make_icons"""
40 try:
Vasily Kuznetsov 2017/08/03 16:52:31 Since this runs in tests, we probably know which b
tlucas 2017/08/03 21:26:01 We actually do, i just added this try/except befor
tlucas 2017/08/04 14:51:58 Done.
41 from PIL import Image
42 except:
43 import Image
44
45 paths = []
46 icon_dir = tmpdir.mkdir('tmp_icons')
47
48 for size in ICON_SIZES:
49 img = Image.new('1', (size, size if size != 53 else size + 1), 0)
50 paths += [str(icon_dir.join('abp-{}.png'.format(size)))]
Vasily Kuznetsov 2017/08/03 16:52:31 What do you think about rewriting this as follows?
tlucas 2017/08/03 21:26:00 I agree, this would be a lot more readable. Regar
tlucas 2017/08/04 14:51:57 Done / as discussed, not changing the str()-thing
51 img.save(paths[-1])
52
53 return paths
54
55
56 @pytest.fixture
57 def keyfile(tmpdir):
58 """Test-privatekey for signing files"""
59
60 content = """-----BEGIN RSA PRIVATE KEY-----
61 MIIEowIBAAKCAQEA0P06DVxOWZ97cvBZWz7DV0DYTFF7Cdrxnu/sCxnHp8IEq+sM
62 rqodp2i8eTsddnthTnA93wiFiFXz6/9liQKrSBtogEGG2tmrT73jy5mdOehm7h6m
63 Ujy6wLuZQiuY/RWJ6453/0H3bKCA8IlIdU8Pkkn5DJWH+YiiSUD01U5ZMLn8m/+O
64 D/r9CLsgWoJV4VCXyzMItcc8hlRbiSe/3DQmZOPbF0Bd1Jv6lNA4RG0U8oA6q5s1
65 5w3n//FjNOreVocyxgWWWGk/awlkJme1xn3yB3yh74b51FHsr9vhiTjcs+QNO1BS
66 9fA/oavzDOs1Q4fLnTbKn6Jlg5OAjWtiq4vjSQIDAQABAoH/fojTnUNGLP1iwTTE
67 5Xoay7l3PL4YwN7PbGvXfuEdAXV3Xp/yDc7yJWpEsyIXtKT/RX6v91oxf1qLVVhN
68 Iad8DSyLGRyTie5Aywct5RgdGfKcX5AvI5uhdxAeuvGqr5Fa8ERSYzqNlDeZ2glE
69 1cIIq4oeQIBI08zmdXPeyUemuNjK8TEWKOTMOjDLhav/DMviI1cvqp5VIh3RseMr
70 1dwprXe0/LWuCh0BrCZZNH/0smd2etXEq06RhgnE2sZkowktNhSgc2pqls92FT88
71 ObjI/jRXf6OwK7HxIJ1tMKlk/VCvAI2PNWi6E7IZbqN7Rg7859uWybGZkP/h1Qf5
72 fRitAoGBAOJnP3kgavnrUJ482R8MNjOwtqbLf4obS5Y/olOHUi+mu2x+EwxgDtaE
73 sXeMjoIAuZvDoAIG0Hn7+J5ZSYkXT9aXQy/odVWDIpFNFFXNFnS73sAWay/FsMJc
74 NvgbbWJk9fCq23O7ihuSkfM+zh8dAZoHzV4aw3DsZj37yzuTmTJbAoGBAOxPM6Wy
75 fENT8ECGl9d/j8QBV4LvjrfIbz/RcCxgZHG50ELnxCo7FiYRg3d2DjR6Q+EpjclX
76 CC+IwCGGf+RBz53WzJPOBkz+plPZzrhhhtpBuWgegeF+TmYT9pPd9XRHJs5qFCak
77 J3xxgBur3NDtejNLWBc4bgFfrv8hdYeuIKorAoGBAJplWNbssadvv1G6I0NWG5yS
78 lW0X+Akh5iE3kiaucPDIHqa1L55P366RXUku1Hx5rBo6hWL8bK3TlM/ACjLwb+Ti
79 0NHaEDJZtHgsfYKp0veWqyiJ4Vz5zzosktwOMEFaopIWooPBUETPZrLgkMaNDGuT
80 iIz1aXUX8f2xOf6OAHpjAoGBAMNqq9c2xrQW0fNKWn8HKih4w5mv6WHqCrXHyO+p
81 tualNqhdaUdTHXnVudYsdorHISMubeY2ZrqIZ/pRc6mbEsoAO6VvFp7NZ1aoI98u
82 J4qOF3kW4WlMPiEEGUEmqDjELj88UfWygkTSx5Iaibzs5cVNZUeujqnsKpcpYDwX
83 r0OJAoGBAIWgnx72WjcFmL1kgOu2kH8tH5+cIAb/THX8lnCulQIlxss8n26NMMDa
84 Kmh5gC2SOAe92cXG6jCYHZqZtl5gM6xGky1B9j7TDrXVPj+QDcItCuNN4zrdtiah
85 US0KNMZKEMjxsaaMDPHj/bP9ULLbMHvtfvt4EnBQoVCDSZdfeBvZ
86 -----END RSA PRIVATE KEY-----"""
87
88 keyfile_path = str(tmpdir.mkdir('rsakey').join('keyfile'))
89
90 with open(keyfile_path, 'wb') as key_fp:
91 key_fp.write(content)
92
93 return keyfile_path
94
95
96 @pytest.mark.parametrize(
Vasily Kuznetsov 2017/08/03 16:52:28 What do you think about creating 3 fixtures instea
tlucas 2017/08/03 21:26:00 This would also reduce the amount of readMetadata-
tlucas 2017/08/04 14:51:58 Done.
97 'metadata_files',
98 [['metadata.chrome', 'metadata.gecko-webext']],
99 indirect=True)
100 @pytest.mark.usefixtures('metadata_files')
101 def test_create_manifest(srcdir, files):
102 for release, devenv, ext_type in product(
103 TR_FA, TR_FA, ['chrome', 'gecko-webext']):
104
105 metadata = packagerChrome.readMetadata(str(srcdir), ext_type)
106
107 version = packager.getBuildVersion(str(srcdir), metadata, release)
108 params = {
109 'type': ext_type,
110 'baseDir': str(srcdir),
111 'releaseBuild': release,
112 'version': version,
113 'devenv': devenv,
114 'metadata': metadata,
115 }
116 manifest = json.loads(packagerChrome.createManifest(params, files))
117
118 expected_values = MINIMUM_MANIFEST_JSON + [
119 ('name', '__MSG_name_' + ('devbuild__' if not release else '_')),
120 ('version', '1.2.3' + ('.0' if not release else '')),
121 ]
122
123 if ext_type == 'gecko-webext':
124 expected_values += [
125 ('applications', {
126 'gecko': {
127 'id': '{d10d0bf8-f5b5-c8b4-a8b2-2b9879e08c5d}',
128 'strict_min_version': '50.0',
129 }
130 })
131 ]
132 if not release:
133 expected_values[-1][1]['gecko'].update({
134 'update_url': ''.join((
135 'https://downloads.adblockplus.org/devbuilds/',
136 'adblockplusfirefox/updates.json'))
137 })
138
139 for key, value in expected_values:
140 assert manifest.get(key, None) == value
141
142
143 def test_sign_binary(files, keyfile):
144 from Crypto.Hash import SHA
145 from Crypto.PublicKey import RSA
146 from Crypto.Signature import PKCS1_v1_5
147
148 digest = SHA.new()
149
150 signature = packagerChrome.signBinary(files.zipToString(), keyfile)
151
152 with open(keyfile, 'r') as fp:
153 rsa_key = RSA.importKey(fp.read())
154
155 signer = PKCS1_v1_5.new(rsa_key)
156
157 digest.update(files.zipToString())
158 assert signer.verify(digest, signature)
159
160
161 def test_get_public_key(keyfile):
162 expected = ''.join((
Vasily Kuznetsov 2017/08/03 16:52:31 You can actually write this as follows: expec
tlucas 2017/08/03 21:26:02 Acknowledged.
tlucas 2017/08/04 14:51:57 Done.
163 '30820122300d06092a864886f70d01010105000382010f003082010a0282010100d0',
164 'fd3a0d5c4e599f7b72f0595b3ec35740d84c517b09daf19eefec0b19c7a7c204abeb',
165 '0caeaa1da768bc793b1d767b614e703ddf08858855f3ebff658902ab481b68804186',
166 'dad9ab4fbde3cb999d39e866ee1ea6523cbac0bb99422b98fd1589eb8e77ff41f76c',
167 'a080f08948754f0f9249f90c9587f988a24940f4d54e5930b9fc9bff8e0ffafd08bb',
168 '205a8255e15097cb3308b5c73c86545b8927bfdc342664e3db17405dd49bfa94d038',
169 '446d14f2803aab9b35e70de7fff16334eade568732c6059658693f6b09642667b5c6',
170 '7df2077ca1ef86f9d451ecafdbe18938dcb3e40d3b5052f5f03fa1abf30ceb354387',
171 'cb9d36ca9fa2658393808d6b62ab8be3490203010001'))
172
173 publickey = packagerChrome.getPublicKey(keyfile)
174 assert publickey.encode('hex') == expected
175
176
177 @pytest.mark.parametrize('metadata_files', ['metadata.chrome'], indirect=True)
178 @pytest.mark.usefixtures('metadata_files')
179 def test_get_package_files(srcdir):
180 extensions = ['html', 'js', 'json', 'xml']
Vasily Kuznetsov 2017/08/03 16:52:31 What do you think about replacing this with:
tlucas 2017/08/03 21:26:00 Acknowledged.
tlucas 2017/08/04 14:51:58 Done.
181 for extension in extensions:
182 srcdir.join(''.join(('foo.', extension))).write('', ensure=True)
183
184 for devenv in [True, False]:
Vasily Kuznetsov 2017/08/03 16:52:31 What do you think about making devenv a parameter
tlucas 2017/08/03 21:26:00 Acknowledged.
tlucas 2017/08/04 14:51:59 Done.
185 params = {
186 'baseDir': str(srcdir),
187 'devenv': devenv,
188 }
189
190 files = packagerChrome.getPackageFiles(params)
191
192 assert devenv == ('qunit' in files)
Vasily Kuznetsov 2017/08/03 16:52:31 This is clever and compact, but I'm wondering if i
tlucas 2017/08/03 21:26:01 In this case i'll choose your reordered approach -
tlucas 2017/08/04 14:51:58 Done.
193
194 for expected in ['icons', 'ui', 'skin', 'ext', '_locales', 'lib',
195 'jquery-ui'] + ['foo.' + ext for ext in extensions]:
196 assert expected in files
197
198
199 def test_make_icons(icons, capsys):
200 files = packager.Files(set(), set())
201 for path in icons:
202 files[path] = open(path, 'r').read()
203 result = packagerChrome.makeIcons(files, icons)
204
205 out, err = capsys.readouterr()
206
207 assert 'should be square' in err
208 assert not any(size not in result for size in ICON_SIZES)
Vasily Kuznetsov 2017/08/03 16:52:28 Is this the same as `assert all(size in result for
tlucas 2017/08/03 21:26:02 The result would be the same - but all(..) is more
tlucas 2017/08/04 14:51:57 Done.
209
210
211 @pytest.mark.parametrize('metadata_files', ['metadata.chrome'], indirect=True)
212 @pytest.mark.usefixtures('metadata_files')
213 def test_create_script_page(srcdir):
214 metadata = packagerChrome.readMetadata(str(srcdir), 'chrome')
215 params = {'metadata': metadata}
216
217 template = packagerChrome.createScriptPage(
Vasily Kuznetsov 2017/08/03 16:52:29 Could you please reformat this as follows: te
tlucas 2017/08/03 21:26:01 Acknowledged.
tlucas 2017/08/04 14:51:59 Done.
218 params, 'testIndex.html.tmpl', ('general', 'testScripts'))
219
220 template_scripts = [elem.attrib['src'] for elem in
Vasily Kuznetsov 2017/08/03 16:52:31 Not that it matters for performance, but to improv
tlucas 2017/08/03 21:26:01 Acknowledged.
tlucas 2017/08/04 14:51:58 Done.
221 ElementTree.fromstring(template).iter('script')]
222
223 for src in metadata.get('general', 'testScripts').split():
224 assert src in template_scripts
225
226
227 @pytest.mark.parametrize('metadata_files', ['metadata.chrome'], indirect=True)
228 @pytest.mark.usefixtures('metadata_files')
229 def test_convert_js(srcdir, files):
230 metadata = packagerChrome.readMetadata(str(srcdir), 'chrome')
231 params = {
232 'type': 'chrome',
233 'metadata': metadata,
234 }
235
236 packagerChrome.convertJS(params, files)
237 source = files['lib/foo.js']
238
239 assert 'var foo;' in source
240 assert 'var bar;' in source
241
242
243 def test_to_json():
244 data = {'bar': ['foo', 'foobar', 1, True]}
245 data_json = packagerChrome.toJson(data)
246
247 assert data_json[-1] == '\n'
Vasily Kuznetsov 2017/08/03 16:52:31 Maybe `data_json.endswith('\n')`?
tlucas 2017/08/03 21:26:01 Acknowledged.
tlucas 2017/08/04 14:51:57 Done.
248 json.loads(data_json)
249
250
251 @pytest.mark.parametrize('metadata_files', ['metadata.chrome'], indirect=True)
252 @pytest.mark.usefixtures('metadata_files')
253 def test_import_gecko_locales(tmp_dir, srcdir, files):
254 metadata = packagerChrome.readMetadata(str(srcdir), 'chrome')
255 version = packager.getBuildVersion(str(srcdir), metadata, False)
Vasily Kuznetsov 2017/08/03 16:52:28 Here and in other places: it's better to do it thi
tlucas 2017/08/03 21:26:01 Please see comment above
tlucas 2017/08/04 14:51:58 As discussed
256 params = {
257 'type': 'chrome',
258 'baseDir': str(srcdir),
259 'releaseBuild': False,
260 'version': version,
261 'devenv': False,
262 'metadata': metadata,
263 }
264
265 data = {'name': 'foo', 'name_devbuild': 'bar'}
266
267 t_dir = tmp_dir.mkdir('_trans').mkdir('en-US')
268 t_dir.join('test.properties').write(
269 '\n'.join(
270 '='.join((k, v)) for k, v in data.iteritems()))
Vasily Kuznetsov 2017/08/03 16:52:31 What do you think about '{}={}'.format(k, v)
tlucas 2017/08/03 21:26:00 Acknowledged.
tlucas 2017/08/04 14:51:59 Done.
271
272 packagerChrome.importGeckoLocales(params, files)
273 trans_data = json.loads(files['_locales/en_US/messages.json'])
274
275 for key, value in data.iteritems():
276 assert trans_data.get('test_{}'.format(key), {})\
Vasily Kuznetsov 2017/08/03 16:52:28 Flake8 should have told you that `'test_' + key` i
tlucas 2017/08/03 21:26:00 Acknowledged, although flake8 / tox did not inform
tlucas 2017/08/04 14:51:59 Done. No idea why flake8 didn't bother though
277 .get('message', '') == value
278
279
280 def test_fix_translations_for_cws(files):
281 files['_locales/de/messages.json'] = packagerChrome.toJson({})
282 files['manifest.json'] = packagerChrome.toJson(
283 {k: v for k, v in MINIMUM_MANIFEST_JSON})
Vasily Kuznetsov 2017/08/03 16:52:30 You can just use `dict(MINIMUM_MANIFEST_JUST)` her
tlucas 2017/08/03 21:26:00 Acknowledged.
tlucas 2017/08/04 14:51:59 Done.
284 packagerChrome.fixTranslationsForCWS(files)
285
286 ger_messages = json.loads(files['_locales/de/messages.json'])
287 eng_messages = json.loads(files['_locales/en_US/messages.json'])
288 for match in re.finditer(r'__MSG_(\S+)__', files['manifest.json']):
289 name = match.group(1)
290 assert ger_messages[name]['message'] == eng_messages[name]['message']
291
292 assert len(ger_messages['description']['message']) <= 132
Vasily Kuznetsov 2017/08/03 16:52:28 This is a curious assertion. What exactly are we c
tlucas 2017/08/03 21:26:02 ChromeWebStore enforces a max-length to be applied
tlucas 2017/08/04 14:51:58 Done.
293 assert len(ger_messages['name']['message']) <= 12
294
295
296 @pytest.mark.parametrize(
297 'metadata_files',
298 [['metadata.chrome', 'metadata.gecko-webext']],
299 indirect=True)
300 @pytest.mark.usefixtures('metadata_files', 'files')
301 def test_create_build(srcdir, keyfile, tmp_dir):
302
303 basefiles = [
304 'manifest.json',
305 'lib/foo.js',
306 'foo/logo_50.png',
307 '_locales/en_US/messages.json',
308 '_locales/en-US/test.properties',
309 'logo_44.png',
310 'qunit/index.html',
311 'icons/logo_150.png',
312 ]
313
314 for release, devenv, ext_type, key in product(
Vasily Kuznetsov 2017/08/03 16:52:31 Perhaps it would be better to make this a parametr
tlucas 2017/08/03 21:26:01 Totally agreed!
tlucas 2017/08/04 14:51:57 Done.
315 TR_FA, TR_FA, ['chrome', 'gecko-webext'], [None, keyfile]):
316
317 out_file = str(tmp_dir.join('out'))
318
319 packagerChrome.createBuild(
320 outFile=out_file,
321 baseDir=str(srcdir),
322 type=ext_type,
323 releaseBuild=release,
324 keyFile=key,
325 devenv=devenv)
326
327 with zipfile.ZipFile(out_file, 'r') as zipfp:
328 zipfp.testzip()
329
330 filenames = [zipinfo.filename for zipinfo in zipfp.infolist()]
331 for filename in basefiles if not devenv else basefiles + [
332 'devenvPoller__.js',
333 'devenvVersion__',
334 ]:
335 assert filename in filenames
OLDNEW

Powered by Google App Engine
This is Rietveld