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

Side by Side Diff: tests/test_packagerWebExt.py

Issue 29501558: Issue 5383 - Add tests for the Chrome and Firefox packagers (Closed)
Patch Set: Completely purge PIL / Pillow, added edge-extension fixture / assert Created Sept. 11, 2017, 8:43 a.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 os
6 import shutil
7 import json
8 import re
9
10 import pytest
11
12 from buildtools import packager
13 from buildtools.tests.tools import DirContent
Vasily Kuznetsov 2017/09/11 12:50:07 These imports also can be combined.
tlucas 2017/09/12 11:32:10 Acknowledged.
tlucas 2017/09/13 13:43:24 Done.
14 from buildtools.tests.tools import ZipContent
15 from buildtools.tests.tools import copy_metadata
16 from buildtools.tests.tools import run_webext_build
17 from buildtools.tests.tools import assert_all_locales_present
18 from buildtools.tests.tools import assert_manifest_content
19 from buildtools.tests.tools import locale_files
20 from buildtools.tests.conftest import ALL_LANGUAGES
21
22
23 LOCALES_MODULE = {
24 'test.Foobar': {
25 'message': 'Ensuring dict-copy from modules for $domain$',
26 'description': 'test description',
27 'placeholders': {'content': '$1', 'example': 'www.adblockplus.org'}
28 }
29 }
30
31 DTD_TEST = ('<!ENTITY access.key "access key(&amp;a)">'
32 '<!ENTITY ampersand "foo &amp;-bar">')
33
34 PROPERTIES_TEST = 'description=very descriptive!'
35
36
37 @pytest.fixture
38 def gecko_import(tmpdir):
39 tmpdir.mkdir('_imp').mkdir('en-US').join('gecko.dtd').write(DTD_TEST)
40
41
42 @pytest.fixture
43 def locale_modules(tmpdir):
44 mod_dir = tmpdir.mkdir('_modules')
45 lang_dir = mod_dir.mkdir('en-US')
46 lang_dir.join('module.json').write(json.dumps(LOCALES_MODULE))
47 lang_dir.join('unit.properties').write(json.dumps(PROPERTIES_TEST))
48
49
50 @pytest.fixture
51 def icons(srcdir):
52 icons_dir = srcdir.mkdir('icons')
53 for filename in ['abp-16.png', 'abp-19.png', 'abp-53.png']:
54 shutil.copy(
55 os.path.join(os.path.dirname(__file__), filename),
56 os.path.join(str(icons_dir), filename),
57 )
58
59
60 @pytest.fixture
61 def all_lang_locales(tmpdir):
62 return locale_files(ALL_LANGUAGES, '_locales', tmpdir)
63
64
65 @pytest.fixture
66 def chrome_metadata(tmpdir):
67 filename = 'metadata.chrome'
68 copy_metadata(filename, tmpdir)
69
70
71 @pytest.fixture
72 def gecko_webext_metadata(tmpdir, chrome_metadata):
73 filename = 'metadata.gecko-webext'
74 copy_metadata(filename, tmpdir)
75
76
77 @pytest.fixture
78 def keyfile(tmpdir):
79 """Test-privatekey for signing chrome release-package"""
80 return os.path.join(os.path.dirname(__file__), 'chrome_rsa.pem')
81
82
83 @pytest.fixture
84 def lib_files(tmpdir):
85 files = packager.Files(['lib'], set())
86 files['ext/a.js'] = 'var bar;'
87 files['lib/b.js'] = 'var foo;'
88
89 tmpdir.mkdir('lib').join('b.js').write(files['lib/b.js'])
90 tmpdir.mkdir('ext').join('a.js').write(files['ext/a.js'])
91
92 return files
93
94
95 def assert_gecko_locale_conversion(package):
96 locale = json.loads(package.read('_locales/en_US/messages.json'))
97
98 assert locale.get('test_Foobar', {}) == LOCALES_MODULE['test.Foobar']
99 assert locale.get('access_key', {}) == {'message': 'access key'}
100 assert locale.get('ampersand', {}) == {'message': 'foo -bar'}
101 assert locale.get('_description', {}) == {'message': 'very descriptive!"'}
102
103
104 def assert_convert_js(package, excluded=False):
105 libfoo = package.read('lib/foo.js')
106
107 assert 'var bar;' in libfoo
108 assert 'require.modules["ext_a"]' in libfoo
109
110 assert ('var foo;' in libfoo) != excluded
111 assert ('require.modules["b"]' in libfoo) != excluded
112
113
114 def assert_devenv_scripts(package, devenv):
115 manifest = json.loads(package.read('manifest.json'))
116 filenames = package.namelist()
117 scripts = [
118 'ext/common.js',
119 'ext/background.js',
120 ]
121
122 if devenv:
123 assert 'qunit/index.html' in filenames
124 assert 'devenvPoller__.js' in filenames
125 assert 'devenvVersion__' in filenames
126
127 assert '../ext/common.js' in package.read('qunit/index.html')
128 assert '../ext/background.js' in package.read('qunit/index.html')
129
130 assert set(manifest['background']['scripts']) == set(
131 scripts + ['devenvPoller__.js']
132 )
133 else:
134 assert 'qunit/index.html' not in filenames
135
136 assert set(manifest['background']['scripts']) == set(scripts)
137
138
139 def assert_base_files(package):
140 filenames = set(package.namelist())
141
142 assert 'bar.json' in filenames
143 assert 'manifest.json' in filenames
144 assert 'lib/foo.js' in filenames
145 assert 'foo/logo_50.png' in filenames
146 assert 'icons/logo_150.png' in filenames
147
148
149 def assert_chrome_signature(filename, keyfile):
150 from struct import unpack
Vasily Kuznetsov 2017/09/11 12:50:07 Is there any specific reason to have these imports
tlucas 2017/09/12 11:32:11 Not at all - merely a result of a speedy adjustmen
tlucas 2017/09/13 13:43:25 Done.
151 from Crypto.Hash import SHA
152 from Crypto.PublicKey import RSA
153 from Crypto.Signature import PKCS1_v1_5
154
155 with open(filename, 'r') as fp:
156 content = fp.read()
157
158 _, _, l_pubkey, l_signature = unpack('<4sIII', content[:16])
159 signature = content[16 + l_pubkey: 16 + l_pubkey + l_signature]
160
161 digest = SHA.new()
162 with open(keyfile, 'r') as fp:
163 rsa_key = RSA.importKey(fp.read())
164
165 signer = PKCS1_v1_5.new(rsa_key)
166
167 digest.update(content[16 + l_pubkey + l_signature:])
168 assert signer.verify(digest, signature)
169
170
171 def assert_locale_upfix(package):
172 translations = [
173 json.loads(package.read('_locales/{}/messages.json'.format(lang)))
174 for lang in ALL_LANGUAGES
175 ]
176
177 manifest = package.read('manifest.json')
178
179 # Chrome Web Store requires descriptive translations to be present in
180 # every language.
181 for match in re.finditer(r'__MSG_(\S+)__', manifest):
182 name = match.group(1)
183
184 for other in translations[1:]:
185 assert translations[0][name]['message'] == other[name]['message']
186
187
188 @pytest.mark.usefixtures(
189 'all_lang_locales',
190 'gecko_import',
191 'locale_modules',
192 'icons',
193 'lib_files',
194 'chrome_metadata',
195 )
196 @pytest.mark.parametrize('dev_build_release', ['build', 'devenv', 'release'])
197 def test_build_chrome(dev_build_release, keyfile, tmpdir, srcdir, capsys):
198 from buildtools import packagerChrome
199 release = dev_build_release == 'release'
200 devenv = dev_build_release == 'devenv'
201
202 run_webext_build('chrome', dev_build_release, srcdir, packagerChrome,
203 keyfile if release else None)
204
205 # The makeIcons() in packagerChrome.py should warn about non-square
206 # icons via stderr.
207 out, err = capsys.readouterr()
208 assert 'icon should be square' in err
209
210 if devenv:
211 content_class = DirContent
212 out_file_path = os.path.join(str(srcdir), 'devenv.chrome')
213 else:
214 content_class = ZipContent
215 out_file = 'adblockpluschrome-1.2.3'
216 if not release:
217 out_file += '.0'
218
219 if release:
220 out_file += '.crx'
221 else:
222 out_file += '.zip'
223
224 out_file_path = os.path.abspath(os.path.join(
225 os.path.dirname(__file__), os.pardir, out_file))
226
227 assert os.path.exists(out_file_path)
228
229 if release:
230 assert_chrome_signature(out_file_path, keyfile)
231
232 with content_class(out_file_path) as package:
233 assert_base_files(package)
234 assert_devenv_scripts(package, devenv)
235 assert_all_locales_present(package, '_locales')
236 assert_locale_upfix(package)
237 assert_gecko_locale_conversion(package)
238 assert_convert_js(package)
239 expected = os.path.join(
240 os.path.dirname(__file__),
241 'expecteddata',
242 'manifest_chrome_{}.json'.format(dev_build_release),
243 )
244 assert_manifest_content(package.read('manifest.json'), expected)
245
246
247 @pytest.mark.usefixtures(
248 'all_lang_locales',
249 'locale_modules',
250 'gecko_import',
251 'icons',
252 'lib_files',
253 'gecko_webext_metadata',
254 )
255 @pytest.mark.parametrize('dev_build_release', ['build', 'devenv', 'release'])
256 def test_build_gecko_webext(dev_build_release, tmpdir, srcdir, capsys):
Vasily Kuznetsov 2017/09/11 12:50:07 This test seems very similar to the previous one a
tlucas 2017/09/12 11:32:11 I agree - will do (also i fear the complexity of t
tlucas 2017/09/13 13:43:25 Done.
257 from buildtools import packagerChrome
258 release = dev_build_release == 'release'
259 devenv = dev_build_release == 'devenv'
260
261 run_webext_build('gecko-webext', dev_build_release, srcdir, packagerChrome)
262
263 # The makeIcons() in packagerChrome.py should warn about non-square
264 # icons via stderr.
265 out, err = capsys.readouterr()
266 assert 'icon should be square' in err
267
268 if devenv:
269 content_class = DirContent
270 out_file_path = os.path.join(str(srcdir), 'devenv.gecko-webext')
271 else:
272 content_class = ZipContent
273 out_file = 'adblockplusfirefox-1.2.3{}.xpi'.format(
274 '.0' if not release else ''
275 )
276
277 out_file_path = os.path.abspath(os.path.join(
278 os.path.dirname(__file__), os.pardir, out_file))
279
280 assert os.path.exists(out_file_path)
281
282 with content_class(out_file_path) as package:
283 assert_base_files(package)
284 assert_devenv_scripts(package, devenv)
285 assert_all_locales_present(package, '_locales')
286 assert_gecko_locale_conversion(package)
287 assert_convert_js(package, True)
288
289 expected = os.path.join(
290 os.path.dirname(__file__),
291 'expecteddata',
292 'manifest_gecko-webext_{}.json'.format(dev_build_release),
293 )
294 assert_manifest_content(package.read('manifest.json'), expected)
OLDNEW

Powered by Google App Engine
This is Rietveld