Left: | ||
Right: |
OLD | NEW |
---|---|
(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 | |
OLD | NEW |