blob: 38faf64aa64432324c66cb41eb3499cf7e077bb5 [file] [log] [blame]
Tao Bao481bab82017-12-21 11:23:09 -08001#
2# Copyright (C) 2018 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
16
17import copy
Tao Baoc7b403a2018-01-30 18:19:04 -080018import os
Tao Baofabe0832018-01-17 15:52:28 -080019import os.path
Tao Baoc7b403a2018-01-30 18:19:04 -080020import zipfile
Tao Bao481bab82017-12-21 11:23:09 -080021
22import common
Tao Bao04e1f012018-02-04 12:13:35 -080023import test_utils
Tao Bao481bab82017-12-21 11:23:09 -080024from ota_from_target_files import (
Tao Bao1c320f82019-10-04 23:25:12 -070025 _LoadOemDicts, AbOtaPropertyFiles, FinalizeMetadata,
Tao Bao3bf8c652018-03-16 12:59:42 -070026 GetPackageMetadata, GetTargetFilesZipForSecondaryImages,
Tao Baoc0746f42018-02-21 13:17:22 -080027 GetTargetFilesZipWithoutPostinstallConfig, NonAbOtaPropertyFiles,
Tao Bao69203522018-03-08 16:09:01 -080028 Payload, PayloadSigner, POSTINSTALL_CONFIG, PropertyFiles,
29 StreamingPropertyFiles, WriteFingerprintAssertion)
Tao Baofabe0832018-01-17 15:52:28 -080030
31
Tao Baof7140c02018-01-30 17:09:24 -080032def construct_target_files(secondary=False):
33 """Returns a target-files.zip file for generating OTA packages."""
34 target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
35 with zipfile.ZipFile(target_files, 'w') as target_files_zip:
36 # META/update_engine_config.txt
37 target_files_zip.writestr(
38 'META/update_engine_config.txt',
39 "PAYLOAD_MAJOR_VERSION=2\nPAYLOAD_MINOR_VERSION=4\n")
40
Tao Bao15a146a2018-02-21 16:06:59 -080041 # META/postinstall_config.txt
42 target_files_zip.writestr(
43 POSTINSTALL_CONFIG,
44 '\n'.join([
45 "RUN_POSTINSTALL_system=true",
46 "POSTINSTALL_PATH_system=system/bin/otapreopt_script",
47 "FILESYSTEM_TYPE_system=ext4",
48 "POSTINSTALL_OPTIONAL_system=true",
49 ]))
50
Tao Bao5277d102018-04-17 23:47:21 -070051 ab_partitions = [
52 ('IMAGES', 'boot'),
53 ('IMAGES', 'system'),
54 ('IMAGES', 'vendor'),
55 ('RADIO', 'bootloader'),
56 ('RADIO', 'modem'),
57 ]
Tao Baof7140c02018-01-30 17:09:24 -080058 # META/ab_partitions.txt
Tao Baof7140c02018-01-30 17:09:24 -080059 target_files_zip.writestr(
60 'META/ab_partitions.txt',
Tao Bao5277d102018-04-17 23:47:21 -070061 '\n'.join([partition[1] for partition in ab_partitions]))
Tao Baof7140c02018-01-30 17:09:24 -080062
63 # Create dummy images for each of them.
Tao Bao5277d102018-04-17 23:47:21 -070064 for path, partition in ab_partitions:
65 target_files_zip.writestr(
66 '{}/{}.img'.format(path, partition),
67 os.urandom(len(partition)))
Tao Baof7140c02018-01-30 17:09:24 -080068
Tao Bao5277d102018-04-17 23:47:21 -070069 # system_other shouldn't appear in META/ab_partitions.txt.
Tao Baof7140c02018-01-30 17:09:24 -080070 if secondary:
71 target_files_zip.writestr('IMAGES/system_other.img',
72 os.urandom(len("system_other")))
73
74 return target_files
75
76
Tao Bao65b94e92018-10-11 21:57:26 -070077class LoadOemDictsTest(test_utils.ReleaseToolsTestCase):
Tao Bao481bab82017-12-21 11:23:09 -080078
79 def test_NoneDict(self):
80 self.assertIsNone(_LoadOemDicts(None))
81
82 def test_SingleDict(self):
83 dict_file = common.MakeTempFile()
84 with open(dict_file, 'w') as dict_fp:
85 dict_fp.write('abc=1\ndef=2\nxyz=foo\na.b.c=bar\n')
86
87 oem_dicts = _LoadOemDicts([dict_file])
88 self.assertEqual(1, len(oem_dicts))
89 self.assertEqual('foo', oem_dicts[0]['xyz'])
90 self.assertEqual('bar', oem_dicts[0]['a.b.c'])
91
92 def test_MultipleDicts(self):
93 oem_source = []
94 for i in range(3):
95 dict_file = common.MakeTempFile()
96 with open(dict_file, 'w') as dict_fp:
97 dict_fp.write(
98 'ro.build.index={}\ndef=2\nxyz=foo\na.b.c=bar\n'.format(i))
99 oem_source.append(dict_file)
100
101 oem_dicts = _LoadOemDicts(oem_source)
102 self.assertEqual(3, len(oem_dicts))
103 for i, oem_dict in enumerate(oem_dicts):
104 self.assertEqual('2', oem_dict['def'])
105 self.assertEqual('foo', oem_dict['xyz'])
106 self.assertEqual('bar', oem_dict['a.b.c'])
107 self.assertEqual('{}'.format(i), oem_dict['ro.build.index'])
Tao Baodf3a48b2018-01-10 16:30:43 -0800108
109
Tao Bao65b94e92018-10-11 21:57:26 -0700110class OtaFromTargetFilesTest(test_utils.ReleaseToolsTestCase):
Tao Baodf3a48b2018-01-10 16:30:43 -0800111
112 TEST_TARGET_INFO_DICT = {
113 'build.prop' : {
114 'ro.product.device' : 'product-device',
115 'ro.build.fingerprint' : 'build-fingerprint-target',
116 'ro.build.version.incremental' : 'build-version-incremental-target',
Tao Bao35dc2552018-02-01 13:18:00 -0800117 'ro.build.version.sdk' : '27',
118 'ro.build.version.security_patch' : '2017-12-01',
Tao Baodf3a48b2018-01-10 16:30:43 -0800119 'ro.build.date.utc' : '1500000000',
120 },
121 }
122
123 TEST_SOURCE_INFO_DICT = {
124 'build.prop' : {
125 'ro.product.device' : 'product-device',
126 'ro.build.fingerprint' : 'build-fingerprint-source',
127 'ro.build.version.incremental' : 'build-version-incremental-source',
Tao Bao35dc2552018-02-01 13:18:00 -0800128 'ro.build.version.sdk' : '25',
129 'ro.build.version.security_patch' : '2016-12-01',
Tao Baodf3a48b2018-01-10 16:30:43 -0800130 'ro.build.date.utc' : '1400000000',
131 },
132 }
133
Tao Bao1c320f82019-10-04 23:25:12 -0700134 TEST_INFO_DICT_USES_OEM_PROPS = {
135 'build.prop' : {
136 'ro.product.name' : 'product-name',
137 'ro.build.thumbprint' : 'build-thumbprint',
138 'ro.build.bar' : 'build-bar',
139 },
140 'vendor.build.prop' : {
141 'ro.vendor.build.fingerprint' : 'vendor-build-fingerprint',
142 },
143 'property1' : 'value1',
144 'property2' : 4096,
145 'oem_fingerprint_properties' : 'ro.product.device ro.product.brand',
146 }
147
148 TEST_OEM_DICTS = [
149 {
150 'ro.product.brand' : 'brand1',
151 'ro.product.device' : 'device1',
152 },
153 {
154 'ro.product.brand' : 'brand2',
155 'ro.product.device' : 'device2',
156 },
157 {
158 'ro.product.brand' : 'brand3',
159 'ro.product.device' : 'device3',
160 },
161 ]
162
Tao Baodf3a48b2018-01-10 16:30:43 -0800163 def setUp(self):
Tao Bao3bf8c652018-03-16 12:59:42 -0700164 self.testdata_dir = test_utils.get_testdata_dir()
165 self.assertTrue(os.path.exists(self.testdata_dir))
166
Tao Baodf3a48b2018-01-10 16:30:43 -0800167 # Reset the global options as in ota_from_target_files.py.
168 common.OPTIONS.incremental_source = None
169 common.OPTIONS.downgrade = False
Tao Bao393eeb42019-03-06 16:00:38 -0800170 common.OPTIONS.retrofit_dynamic_partitions = False
Tao Baodf3a48b2018-01-10 16:30:43 -0800171 common.OPTIONS.timestamp = False
172 common.OPTIONS.wipe_user_data = False
Tao Bao3bf8c652018-03-16 12:59:42 -0700173 common.OPTIONS.no_signing = False
174 common.OPTIONS.package_key = os.path.join(self.testdata_dir, 'testkey')
175 common.OPTIONS.key_passwords = {
176 common.OPTIONS.package_key : None,
177 }
178
179 common.OPTIONS.search_path = test_utils.get_search_path()
Tao Baodf3a48b2018-01-10 16:30:43 -0800180
181 def test_GetPackageMetadata_abOta_full(self):
182 target_info_dict = copy.deepcopy(self.TEST_TARGET_INFO_DICT)
183 target_info_dict['ab_update'] = 'true'
Tao Bao1c320f82019-10-04 23:25:12 -0700184 target_info = common.BuildInfo(target_info_dict, None)
Tao Baodf3a48b2018-01-10 16:30:43 -0800185 metadata = GetPackageMetadata(target_info)
186 self.assertDictEqual(
187 {
188 'ota-type' : 'AB',
189 'ota-required-cache' : '0',
190 'post-build' : 'build-fingerprint-target',
191 'post-build-incremental' : 'build-version-incremental-target',
Tao Bao35dc2552018-02-01 13:18:00 -0800192 'post-sdk-level' : '27',
193 'post-security-patch-level' : '2017-12-01',
Tao Baodf3a48b2018-01-10 16:30:43 -0800194 'post-timestamp' : '1500000000',
195 'pre-device' : 'product-device',
196 },
197 metadata)
198
199 def test_GetPackageMetadata_abOta_incremental(self):
200 target_info_dict = copy.deepcopy(self.TEST_TARGET_INFO_DICT)
201 target_info_dict['ab_update'] = 'true'
Tao Bao1c320f82019-10-04 23:25:12 -0700202 target_info = common.BuildInfo(target_info_dict, None)
203 source_info = common.BuildInfo(self.TEST_SOURCE_INFO_DICT, None)
Tao Baodf3a48b2018-01-10 16:30:43 -0800204 common.OPTIONS.incremental_source = ''
205 metadata = GetPackageMetadata(target_info, source_info)
206 self.assertDictEqual(
207 {
208 'ota-type' : 'AB',
209 'ota-required-cache' : '0',
210 'post-build' : 'build-fingerprint-target',
211 'post-build-incremental' : 'build-version-incremental-target',
Tao Bao35dc2552018-02-01 13:18:00 -0800212 'post-sdk-level' : '27',
213 'post-security-patch-level' : '2017-12-01',
Tao Baodf3a48b2018-01-10 16:30:43 -0800214 'post-timestamp' : '1500000000',
215 'pre-device' : 'product-device',
216 'pre-build' : 'build-fingerprint-source',
217 'pre-build-incremental' : 'build-version-incremental-source',
218 },
219 metadata)
220
221 def test_GetPackageMetadata_nonAbOta_full(self):
Tao Bao1c320f82019-10-04 23:25:12 -0700222 target_info = common.BuildInfo(self.TEST_TARGET_INFO_DICT, None)
Tao Baodf3a48b2018-01-10 16:30:43 -0800223 metadata = GetPackageMetadata(target_info)
224 self.assertDictEqual(
225 {
226 'ota-type' : 'BLOCK',
227 'post-build' : 'build-fingerprint-target',
228 'post-build-incremental' : 'build-version-incremental-target',
Tao Bao35dc2552018-02-01 13:18:00 -0800229 'post-sdk-level' : '27',
230 'post-security-patch-level' : '2017-12-01',
Tao Baodf3a48b2018-01-10 16:30:43 -0800231 'post-timestamp' : '1500000000',
232 'pre-device' : 'product-device',
233 },
234 metadata)
235
236 def test_GetPackageMetadata_nonAbOta_incremental(self):
Tao Bao1c320f82019-10-04 23:25:12 -0700237 target_info = common.BuildInfo(self.TEST_TARGET_INFO_DICT, None)
238 source_info = common.BuildInfo(self.TEST_SOURCE_INFO_DICT, None)
Tao Baodf3a48b2018-01-10 16:30:43 -0800239 common.OPTIONS.incremental_source = ''
240 metadata = GetPackageMetadata(target_info, source_info)
241 self.assertDictEqual(
242 {
243 'ota-type' : 'BLOCK',
244 'post-build' : 'build-fingerprint-target',
245 'post-build-incremental' : 'build-version-incremental-target',
Tao Bao35dc2552018-02-01 13:18:00 -0800246 'post-sdk-level' : '27',
247 'post-security-patch-level' : '2017-12-01',
Tao Baodf3a48b2018-01-10 16:30:43 -0800248 'post-timestamp' : '1500000000',
249 'pre-device' : 'product-device',
250 'pre-build' : 'build-fingerprint-source',
251 'pre-build-incremental' : 'build-version-incremental-source',
252 },
253 metadata)
254
255 def test_GetPackageMetadata_wipe(self):
Tao Bao1c320f82019-10-04 23:25:12 -0700256 target_info = common.BuildInfo(self.TEST_TARGET_INFO_DICT, None)
Tao Baodf3a48b2018-01-10 16:30:43 -0800257 common.OPTIONS.wipe_user_data = True
258 metadata = GetPackageMetadata(target_info)
259 self.assertDictEqual(
260 {
261 'ota-type' : 'BLOCK',
262 'ota-wipe' : 'yes',
263 'post-build' : 'build-fingerprint-target',
264 'post-build-incremental' : 'build-version-incremental-target',
Tao Bao35dc2552018-02-01 13:18:00 -0800265 'post-sdk-level' : '27',
266 'post-security-patch-level' : '2017-12-01',
Tao Baodf3a48b2018-01-10 16:30:43 -0800267 'post-timestamp' : '1500000000',
268 'pre-device' : 'product-device',
269 },
270 metadata)
271
Tao Bao393eeb42019-03-06 16:00:38 -0800272 def test_GetPackageMetadata_retrofitDynamicPartitions(self):
Tao Bao1c320f82019-10-04 23:25:12 -0700273 target_info = common.BuildInfo(self.TEST_TARGET_INFO_DICT, None)
Tao Bao393eeb42019-03-06 16:00:38 -0800274 common.OPTIONS.retrofit_dynamic_partitions = True
275 metadata = GetPackageMetadata(target_info)
276 self.assertDictEqual(
277 {
278 'ota-retrofit-dynamic-partitions' : 'yes',
279 'ota-type' : 'BLOCK',
280 'post-build' : 'build-fingerprint-target',
281 'post-build-incremental' : 'build-version-incremental-target',
282 'post-sdk-level' : '27',
283 'post-security-patch-level' : '2017-12-01',
284 'post-timestamp' : '1500000000',
285 'pre-device' : 'product-device',
286 },
287 metadata)
288
Tao Baodf3a48b2018-01-10 16:30:43 -0800289 @staticmethod
290 def _test_GetPackageMetadata_swapBuildTimestamps(target_info, source_info):
291 (target_info['build.prop']['ro.build.date.utc'],
292 source_info['build.prop']['ro.build.date.utc']) = (
293 source_info['build.prop']['ro.build.date.utc'],
294 target_info['build.prop']['ro.build.date.utc'])
295
296 def test_GetPackageMetadata_unintentionalDowngradeDetected(self):
297 target_info_dict = copy.deepcopy(self.TEST_TARGET_INFO_DICT)
298 source_info_dict = copy.deepcopy(self.TEST_SOURCE_INFO_DICT)
299 self._test_GetPackageMetadata_swapBuildTimestamps(
300 target_info_dict, source_info_dict)
301
Tao Bao1c320f82019-10-04 23:25:12 -0700302 target_info = common.BuildInfo(target_info_dict, None)
303 source_info = common.BuildInfo(source_info_dict, None)
Tao Baodf3a48b2018-01-10 16:30:43 -0800304 common.OPTIONS.incremental_source = ''
305 self.assertRaises(RuntimeError, GetPackageMetadata, target_info,
306 source_info)
307
308 def test_GetPackageMetadata_downgrade(self):
309 target_info_dict = copy.deepcopy(self.TEST_TARGET_INFO_DICT)
310 source_info_dict = copy.deepcopy(self.TEST_SOURCE_INFO_DICT)
311 self._test_GetPackageMetadata_swapBuildTimestamps(
312 target_info_dict, source_info_dict)
313
Tao Bao1c320f82019-10-04 23:25:12 -0700314 target_info = common.BuildInfo(target_info_dict, None)
315 source_info = common.BuildInfo(source_info_dict, None)
Tao Baodf3a48b2018-01-10 16:30:43 -0800316 common.OPTIONS.incremental_source = ''
317 common.OPTIONS.downgrade = True
318 common.OPTIONS.wipe_user_data = True
319 metadata = GetPackageMetadata(target_info, source_info)
320 self.assertDictEqual(
321 {
322 'ota-downgrade' : 'yes',
323 'ota-type' : 'BLOCK',
324 'ota-wipe' : 'yes',
325 'post-build' : 'build-fingerprint-target',
326 'post-build-incremental' : 'build-version-incremental-target',
Tao Bao35dc2552018-02-01 13:18:00 -0800327 'post-sdk-level' : '27',
328 'post-security-patch-level' : '2017-12-01',
Tao Baofaa8e0b2018-04-12 14:31:43 -0700329 'post-timestamp' : '1400000000',
Tao Baodf3a48b2018-01-10 16:30:43 -0800330 'pre-device' : 'product-device',
331 'pre-build' : 'build-fingerprint-source',
332 'pre-build-incremental' : 'build-version-incremental-source',
333 },
334 metadata)
Tao Baofabe0832018-01-17 15:52:28 -0800335
Tao Bao82490d32019-04-09 00:12:30 -0700336 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baof7140c02018-01-30 17:09:24 -0800337 def test_GetTargetFilesZipForSecondaryImages(self):
338 input_file = construct_target_files(secondary=True)
339 target_file = GetTargetFilesZipForSecondaryImages(input_file)
340
341 with zipfile.ZipFile(target_file) as verify_zip:
342 namelist = verify_zip.namelist()
Tao Bao615b65d2019-10-06 22:59:45 -0700343 ab_partitions = verify_zip.read('META/ab_partitions.txt').decode()
Tao Baof7140c02018-01-30 17:09:24 -0800344
345 self.assertIn('META/ab_partitions.txt', namelist)
Tao Baof7140c02018-01-30 17:09:24 -0800346 self.assertIn('IMAGES/system.img', namelist)
Tao Bao12489802018-07-12 14:47:38 -0700347 self.assertIn('RADIO/bootloader.img', namelist)
Tao Bao15a146a2018-02-21 16:06:59 -0800348 self.assertIn(POSTINSTALL_CONFIG, namelist)
Tao Baof7140c02018-01-30 17:09:24 -0800349
Tao Bao3e759462019-09-17 22:43:11 -0700350 self.assertNotIn('IMAGES/boot.img', namelist)
Tao Baof7140c02018-01-30 17:09:24 -0800351 self.assertNotIn('IMAGES/system_other.img', namelist)
352 self.assertNotIn('IMAGES/system.map', namelist)
Tao Bao3e759462019-09-17 22:43:11 -0700353 self.assertNotIn('RADIO/modem.img', namelist)
Tao Baof7140c02018-01-30 17:09:24 -0800354
Tao Bao3e759462019-09-17 22:43:11 -0700355 expected_ab_partitions = ['system', 'bootloader']
Tianjie Xu1c808002019-09-11 00:29:26 -0700356 self.assertEqual('\n'.join(expected_ab_partitions), ab_partitions)
357
Tao Bao82490d32019-04-09 00:12:30 -0700358 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao15a146a2018-02-21 16:06:59 -0800359 def test_GetTargetFilesZipForSecondaryImages_skipPostinstall(self):
360 input_file = construct_target_files(secondary=True)
361 target_file = GetTargetFilesZipForSecondaryImages(
362 input_file, skip_postinstall=True)
363
364 with zipfile.ZipFile(target_file) as verify_zip:
365 namelist = verify_zip.namelist()
366
367 self.assertIn('META/ab_partitions.txt', namelist)
Tao Bao15a146a2018-02-21 16:06:59 -0800368 self.assertIn('IMAGES/system.img', namelist)
Tao Bao12489802018-07-12 14:47:38 -0700369 self.assertIn('RADIO/bootloader.img', namelist)
Tao Bao15a146a2018-02-21 16:06:59 -0800370
Tao Bao3e759462019-09-17 22:43:11 -0700371 self.assertNotIn('IMAGES/boot.img', namelist)
Tao Bao15a146a2018-02-21 16:06:59 -0800372 self.assertNotIn('IMAGES/system_other.img', namelist)
373 self.assertNotIn('IMAGES/system.map', namelist)
Tao Bao3e759462019-09-17 22:43:11 -0700374 self.assertNotIn('RADIO/modem.img', namelist)
Tao Bao15a146a2018-02-21 16:06:59 -0800375 self.assertNotIn(POSTINSTALL_CONFIG, namelist)
376
Tao Bao82490d32019-04-09 00:12:30 -0700377 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao12489802018-07-12 14:47:38 -0700378 def test_GetTargetFilesZipForSecondaryImages_withoutRadioImages(self):
379 input_file = construct_target_files(secondary=True)
380 common.ZipDelete(input_file, 'RADIO/bootloader.img')
381 common.ZipDelete(input_file, 'RADIO/modem.img')
382 target_file = GetTargetFilesZipForSecondaryImages(input_file)
383
384 with zipfile.ZipFile(target_file) as verify_zip:
385 namelist = verify_zip.namelist()
386
387 self.assertIn('META/ab_partitions.txt', namelist)
Tao Bao12489802018-07-12 14:47:38 -0700388 self.assertIn('IMAGES/system.img', namelist)
Tao Bao12489802018-07-12 14:47:38 -0700389 self.assertIn(POSTINSTALL_CONFIG, namelist)
390
Tao Bao3e759462019-09-17 22:43:11 -0700391 self.assertNotIn('IMAGES/boot.img', namelist)
Tao Bao12489802018-07-12 14:47:38 -0700392 self.assertNotIn('IMAGES/system_other.img', namelist)
393 self.assertNotIn('IMAGES/system.map', namelist)
394 self.assertNotIn('RADIO/bootloader.img', namelist)
395 self.assertNotIn('RADIO/modem.img', namelist)
396
Tao Bao82490d32019-04-09 00:12:30 -0700397 @test_utils.SkipIfExternalToolsUnavailable()
Tianjie Xu1c808002019-09-11 00:29:26 -0700398 def test_GetTargetFilesZipForSecondaryImages_dynamicPartitions(self):
399 input_file = construct_target_files(secondary=True)
400 misc_info = '\n'.join([
401 'use_dynamic_partition_size=true',
402 'use_dynamic_partitions=true',
403 'dynamic_partition_list=system vendor product',
404 'super_partition_groups=google_dynamic_partitions',
405 'super_google_dynamic_partitions_group_size=4873781248',
406 'super_google_dynamic_partitions_partition_list=system vendor product',
407 ])
408 dynamic_partitions_info = '\n'.join([
409 'super_partition_groups=google_dynamic_partitions',
410 'super_google_dynamic_partitions_group_size=4873781248',
411 'super_google_dynamic_partitions_partition_list=system vendor product',
412 ])
413
414 with zipfile.ZipFile(input_file, 'a') as append_zip:
415 common.ZipWriteStr(append_zip, 'META/misc_info.txt', misc_info)
416 common.ZipWriteStr(append_zip, 'META/dynamic_partitions_info.txt',
417 dynamic_partitions_info)
418
419 target_file = GetTargetFilesZipForSecondaryImages(input_file)
420
421 with zipfile.ZipFile(target_file) as verify_zip:
422 namelist = verify_zip.namelist()
Tao Bao615b65d2019-10-06 22:59:45 -0700423 updated_misc_info = verify_zip.read('META/misc_info.txt').decode()
Tianjie Xu1c808002019-09-11 00:29:26 -0700424 updated_dynamic_partitions_info = verify_zip.read(
Tao Bao615b65d2019-10-06 22:59:45 -0700425 'META/dynamic_partitions_info.txt').decode()
Tianjie Xu1c808002019-09-11 00:29:26 -0700426
427 self.assertIn('META/ab_partitions.txt', namelist)
Tianjie Xu1c808002019-09-11 00:29:26 -0700428 self.assertIn('IMAGES/system.img', namelist)
429 self.assertIn(POSTINSTALL_CONFIG, namelist)
430 self.assertIn('META/misc_info.txt', namelist)
431 self.assertIn('META/dynamic_partitions_info.txt', namelist)
432
Tao Bao3e759462019-09-17 22:43:11 -0700433 self.assertNotIn('IMAGES/boot.img', namelist)
Tianjie Xu1c808002019-09-11 00:29:26 -0700434 self.assertNotIn('IMAGES/system_other.img', namelist)
435 self.assertNotIn('IMAGES/system.map', namelist)
436
437 # Check the vendor & product are removed from the partitions list.
438 expected_misc_info = misc_info.replace('system vendor product',
439 'system')
440 expected_dynamic_partitions_info = dynamic_partitions_info.replace(
441 'system vendor product', 'system')
442 self.assertEqual(expected_misc_info, updated_misc_info)
443 self.assertEqual(expected_dynamic_partitions_info,
444 updated_dynamic_partitions_info)
445
446 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao15a146a2018-02-21 16:06:59 -0800447 def test_GetTargetFilesZipWithoutPostinstallConfig(self):
448 input_file = construct_target_files()
449 target_file = GetTargetFilesZipWithoutPostinstallConfig(input_file)
450 with zipfile.ZipFile(target_file) as verify_zip:
451 self.assertNotIn(POSTINSTALL_CONFIG, verify_zip.namelist())
452
Tao Bao82490d32019-04-09 00:12:30 -0700453 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao15a146a2018-02-21 16:06:59 -0800454 def test_GetTargetFilesZipWithoutPostinstallConfig_missingEntry(self):
455 input_file = construct_target_files()
456 common.ZipDelete(input_file, POSTINSTALL_CONFIG)
457 target_file = GetTargetFilesZipWithoutPostinstallConfig(input_file)
458 with zipfile.ZipFile(target_file) as verify_zip:
459 self.assertNotIn(POSTINSTALL_CONFIG, verify_zip.namelist())
460
Tao Bao3bf8c652018-03-16 12:59:42 -0700461 def _test_FinalizeMetadata(self, large_entry=False):
462 entries = [
463 'required-entry1',
464 'required-entry2',
465 ]
466 zip_file = PropertyFilesTest.construct_zip_package(entries)
467 # Add a large entry of 1 GiB if requested.
468 if large_entry:
469 with zipfile.ZipFile(zip_file, 'a') as zip_fp:
470 zip_fp.writestr(
471 # Using 'zoo' so that the entry stays behind others after signing.
472 'zoo',
473 'A' * 1024 * 1024 * 1024,
474 zipfile.ZIP_STORED)
475
476 metadata = {}
477 output_file = common.MakeTempFile(suffix='.zip')
478 needed_property_files = (
479 TestPropertyFiles(),
480 )
481 FinalizeMetadata(metadata, zip_file, output_file, needed_property_files)
482 self.assertIn('ota-test-property-files', metadata)
483
Tao Bao82490d32019-04-09 00:12:30 -0700484 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao3bf8c652018-03-16 12:59:42 -0700485 def test_FinalizeMetadata(self):
486 self._test_FinalizeMetadata()
487
Tao Bao82490d32019-04-09 00:12:30 -0700488 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao3bf8c652018-03-16 12:59:42 -0700489 def test_FinalizeMetadata_withNoSigning(self):
490 common.OPTIONS.no_signing = True
491 self._test_FinalizeMetadata()
492
Tao Bao82490d32019-04-09 00:12:30 -0700493 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao3bf8c652018-03-16 12:59:42 -0700494 def test_FinalizeMetadata_largeEntry(self):
495 self._test_FinalizeMetadata(large_entry=True)
496
Tao Bao82490d32019-04-09 00:12:30 -0700497 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao3bf8c652018-03-16 12:59:42 -0700498 def test_FinalizeMetadata_largeEntry_withNoSigning(self):
499 common.OPTIONS.no_signing = True
500 self._test_FinalizeMetadata(large_entry=True)
501
Tao Bao82490d32019-04-09 00:12:30 -0700502 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao3bf8c652018-03-16 12:59:42 -0700503 def test_FinalizeMetadata_insufficientSpace(self):
504 entries = [
505 'required-entry1',
506 'required-entry2',
507 'optional-entry1',
508 'optional-entry2',
509 ]
510 zip_file = PropertyFilesTest.construct_zip_package(entries)
511 with zipfile.ZipFile(zip_file, 'a') as zip_fp:
512 zip_fp.writestr(
513 # 'foo-entry1' will appear ahead of all other entries (in alphabetical
514 # order) after the signing, which will in turn trigger the
515 # InsufficientSpaceException and an automatic retry.
516 'foo-entry1',
517 'A' * 1024 * 1024,
518 zipfile.ZIP_STORED)
519
520 metadata = {}
521 needed_property_files = (
522 TestPropertyFiles(),
523 )
524 output_file = common.MakeTempFile(suffix='.zip')
525 FinalizeMetadata(metadata, zip_file, output_file, needed_property_files)
526 self.assertIn('ota-test-property-files', metadata)
527
Tao Bao1c320f82019-10-04 23:25:12 -0700528 def test_WriteFingerprintAssertion_without_oem_props(self):
529 target_info = common.BuildInfo(self.TEST_TARGET_INFO_DICT, None)
530 source_info_dict = copy.deepcopy(self.TEST_TARGET_INFO_DICT)
531 source_info_dict['build.prop']['ro.build.fingerprint'] = (
532 'source-build-fingerprint')
533 source_info = common.BuildInfo(source_info_dict, None)
534
535 script_writer = test_utils.MockScriptWriter()
536 WriteFingerprintAssertion(script_writer, target_info, source_info)
537 self.assertEqual(
538 [('AssertSomeFingerprint', 'source-build-fingerprint',
539 'build-fingerprint-target')],
540 script_writer.lines)
541
542 def test_WriteFingerprintAssertion_with_source_oem_props(self):
543 target_info = common.BuildInfo(self.TEST_TARGET_INFO_DICT, None)
544 source_info = common.BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
545 self.TEST_OEM_DICTS)
546
547 script_writer = test_utils.MockScriptWriter()
548 WriteFingerprintAssertion(script_writer, target_info, source_info)
549 self.assertEqual(
550 [('AssertFingerprintOrThumbprint', 'build-fingerprint-target',
551 'build-thumbprint')],
552 script_writer.lines)
553
554 def test_WriteFingerprintAssertion_with_target_oem_props(self):
555 target_info = common.BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
556 self.TEST_OEM_DICTS)
557 source_info = common.BuildInfo(self.TEST_TARGET_INFO_DICT, None)
558
559 script_writer = test_utils.MockScriptWriter()
560 WriteFingerprintAssertion(script_writer, target_info, source_info)
561 self.assertEqual(
562 [('AssertFingerprintOrThumbprint', 'build-fingerprint-target',
563 'build-thumbprint')],
564 script_writer.lines)
565
566 def test_WriteFingerprintAssertion_with_both_oem_props(self):
567 target_info = common.BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
568 self.TEST_OEM_DICTS)
569 source_info_dict = copy.deepcopy(self.TEST_INFO_DICT_USES_OEM_PROPS)
570 source_info_dict['build.prop']['ro.build.thumbprint'] = (
571 'source-build-thumbprint')
572 source_info = common.BuildInfo(source_info_dict, self.TEST_OEM_DICTS)
573
574 script_writer = test_utils.MockScriptWriter()
575 WriteFingerprintAssertion(script_writer, target_info, source_info)
576 self.assertEqual(
577 [('AssertSomeThumbprint', 'build-thumbprint',
578 'source-build-thumbprint')],
579 script_writer.lines)
580
Tao Baoae5e4c32018-03-01 19:30:00 -0800581
Tao Bao69203522018-03-08 16:09:01 -0800582class TestPropertyFiles(PropertyFiles):
583 """A class that extends PropertyFiles for testing purpose."""
584
585 def __init__(self):
586 super(TestPropertyFiles, self).__init__()
587 self.name = 'ota-test-property-files'
588 self.required = (
589 'required-entry1',
590 'required-entry2',
591 )
592 self.optional = (
593 'optional-entry1',
594 'optional-entry2',
595 )
596
597
Tao Bao65b94e92018-10-11 21:57:26 -0700598class PropertyFilesTest(test_utils.ReleaseToolsTestCase):
Tao Baoae5e4c32018-03-01 19:30:00 -0800599
Tao Bao3bf8c652018-03-16 12:59:42 -0700600 def setUp(self):
601 common.OPTIONS.no_signing = False
602
Tao Baof5110492018-03-02 09:47:43 -0800603 @staticmethod
Tao Bao3bf8c652018-03-16 12:59:42 -0700604 def construct_zip_package(entries):
Tao Baof5110492018-03-02 09:47:43 -0800605 zip_file = common.MakeTempFile(suffix='.zip')
606 with zipfile.ZipFile(zip_file, 'w') as zip_fp:
607 for entry in entries:
608 zip_fp.writestr(
609 entry,
610 entry.replace('.', '-').upper(),
611 zipfile.ZIP_STORED)
612 return zip_file
613
614 @staticmethod
Tao Bao69203522018-03-08 16:09:01 -0800615 def _parse_property_files_string(data):
Tao Baof5110492018-03-02 09:47:43 -0800616 result = {}
617 for token in data.split(','):
618 name, info = token.split(':', 1)
619 result[name] = info
620 return result
621
622 def _verify_entries(self, input_file, tokens, entries):
623 for entry in entries:
624 offset, size = map(int, tokens[entry].split(':'))
625 with open(input_file, 'rb') as input_fp:
626 input_fp.seek(offset)
627 if entry == 'metadata':
628 expected = b'META-INF/COM/ANDROID/METADATA'
629 else:
630 expected = entry.replace('.', '-').upper().encode()
631 self.assertEqual(expected, input_fp.read(size))
632
Tao Bao82490d32019-04-09 00:12:30 -0700633 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoae5e4c32018-03-01 19:30:00 -0800634 def test_Compute(self):
Tao Baof5110492018-03-02 09:47:43 -0800635 entries = (
Tao Bao69203522018-03-08 16:09:01 -0800636 'required-entry1',
637 'required-entry2',
Tao Baof5110492018-03-02 09:47:43 -0800638 )
Tao Bao3bf8c652018-03-16 12:59:42 -0700639 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800640 property_files = TestPropertyFiles()
Tao Baof5110492018-03-02 09:47:43 -0800641 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
Tao Bao69203522018-03-08 16:09:01 -0800642 property_files_string = property_files.Compute(zip_fp)
Tao Baof5110492018-03-02 09:47:43 -0800643
Tao Bao69203522018-03-08 16:09:01 -0800644 tokens = self._parse_property_files_string(property_files_string)
Tao Baof5110492018-03-02 09:47:43 -0800645 self.assertEqual(3, len(tokens))
646 self._verify_entries(zip_file, tokens, entries)
647
Tao Bao69203522018-03-08 16:09:01 -0800648 def test_Compute_withOptionalEntries(self):
Tao Baof5110492018-03-02 09:47:43 -0800649 entries = (
Tao Bao69203522018-03-08 16:09:01 -0800650 'required-entry1',
651 'required-entry2',
652 'optional-entry1',
653 'optional-entry2',
Tao Baof5110492018-03-02 09:47:43 -0800654 )
Tao Bao3bf8c652018-03-16 12:59:42 -0700655 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800656 property_files = TestPropertyFiles()
Tao Baof5110492018-03-02 09:47:43 -0800657 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
Tao Bao69203522018-03-08 16:09:01 -0800658 property_files_string = property_files.Compute(zip_fp)
Tao Baof5110492018-03-02 09:47:43 -0800659
Tao Bao69203522018-03-08 16:09:01 -0800660 tokens = self._parse_property_files_string(property_files_string)
Tao Baof5110492018-03-02 09:47:43 -0800661 self.assertEqual(5, len(tokens))
662 self._verify_entries(zip_file, tokens, entries)
663
Tao Bao69203522018-03-08 16:09:01 -0800664 def test_Compute_missingRequiredEntry(self):
665 entries = (
666 'required-entry2',
667 )
Tao Bao3bf8c652018-03-16 12:59:42 -0700668 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800669 property_files = TestPropertyFiles()
670 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
671 self.assertRaises(KeyError, property_files.Compute, zip_fp)
672
Tao Bao82490d32019-04-09 00:12:30 -0700673 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoae5e4c32018-03-01 19:30:00 -0800674 def test_Finalize(self):
Tao Baof5110492018-03-02 09:47:43 -0800675 entries = [
Tao Bao69203522018-03-08 16:09:01 -0800676 'required-entry1',
677 'required-entry2',
Tao Baof5110492018-03-02 09:47:43 -0800678 'META-INF/com/android/metadata',
679 ]
Tao Bao3bf8c652018-03-16 12:59:42 -0700680 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800681 property_files = TestPropertyFiles()
Tao Baof5110492018-03-02 09:47:43 -0800682 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -0700683 raw_metadata = property_files.GetPropertyFilesString(
Tao Baoae5e4c32018-03-01 19:30:00 -0800684 zip_fp, reserve_space=False)
685 streaming_metadata = property_files.Finalize(zip_fp, len(raw_metadata))
Tao Bao69203522018-03-08 16:09:01 -0800686 tokens = self._parse_property_files_string(streaming_metadata)
Tao Baof5110492018-03-02 09:47:43 -0800687
688 self.assertEqual(3, len(tokens))
689 # 'META-INF/com/android/metadata' will be key'd as 'metadata' in the
690 # streaming metadata.
691 entries[2] = 'metadata'
692 self._verify_entries(zip_file, tokens, entries)
693
Tao Bao82490d32019-04-09 00:12:30 -0700694 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoae5e4c32018-03-01 19:30:00 -0800695 def test_Finalize_assertReservedLength(self):
Tao Baof5110492018-03-02 09:47:43 -0800696 entries = (
Tao Bao69203522018-03-08 16:09:01 -0800697 'required-entry1',
698 'required-entry2',
699 'optional-entry1',
700 'optional-entry2',
Tao Baof5110492018-03-02 09:47:43 -0800701 'META-INF/com/android/metadata',
702 )
Tao Bao3bf8c652018-03-16 12:59:42 -0700703 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800704 property_files = TestPropertyFiles()
Tao Baof5110492018-03-02 09:47:43 -0800705 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
706 # First get the raw metadata string (i.e. without padding space).
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -0700707 raw_metadata = property_files.GetPropertyFilesString(
Tao Baoae5e4c32018-03-01 19:30:00 -0800708 zip_fp, reserve_space=False)
Tao Baof5110492018-03-02 09:47:43 -0800709 raw_length = len(raw_metadata)
710
711 # Now pass in the exact expected length.
Tao Baoae5e4c32018-03-01 19:30:00 -0800712 streaming_metadata = property_files.Finalize(zip_fp, raw_length)
Tao Baof5110492018-03-02 09:47:43 -0800713 self.assertEqual(raw_length, len(streaming_metadata))
714
715 # Or pass in insufficient length.
716 self.assertRaises(
Tao Bao3bf8c652018-03-16 12:59:42 -0700717 PropertyFiles.InsufficientSpaceException,
Tao Baoae5e4c32018-03-01 19:30:00 -0800718 property_files.Finalize,
Tao Baof5110492018-03-02 09:47:43 -0800719 zip_fp,
Tao Baoae5e4c32018-03-01 19:30:00 -0800720 raw_length - 1)
Tao Baof5110492018-03-02 09:47:43 -0800721
722 # Or pass in a much larger size.
Tao Baoae5e4c32018-03-01 19:30:00 -0800723 streaming_metadata = property_files.Finalize(
Tao Baof5110492018-03-02 09:47:43 -0800724 zip_fp,
Tao Baoae5e4c32018-03-01 19:30:00 -0800725 raw_length + 20)
Tao Baof5110492018-03-02 09:47:43 -0800726 self.assertEqual(raw_length + 20, len(streaming_metadata))
727 self.assertEqual(' ' * 20, streaming_metadata[raw_length:])
728
Tao Baoae5e4c32018-03-01 19:30:00 -0800729 def test_Verify(self):
730 entries = (
Tao Bao69203522018-03-08 16:09:01 -0800731 'required-entry1',
732 'required-entry2',
733 'optional-entry1',
734 'optional-entry2',
735 'META-INF/com/android/metadata',
736 )
Tao Bao3bf8c652018-03-16 12:59:42 -0700737 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800738 property_files = TestPropertyFiles()
739 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
740 # First get the raw metadata string (i.e. without padding space).
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -0700741 raw_metadata = property_files.GetPropertyFilesString(
Tao Bao69203522018-03-08 16:09:01 -0800742 zip_fp, reserve_space=False)
743
744 # Should pass the test if verification passes.
745 property_files.Verify(zip_fp, raw_metadata)
746
747 # Or raise on verification failure.
748 self.assertRaises(
749 AssertionError, property_files.Verify, zip_fp, raw_metadata + 'x')
750
751
752class StreamingPropertyFilesTest(PropertyFilesTest):
753 """Additional sanity checks specialized for StreamingPropertyFiles."""
754
755 def test_init(self):
756 property_files = StreamingPropertyFiles()
757 self.assertEqual('ota-streaming-property-files', property_files.name)
758 self.assertEqual(
759 (
760 'payload.bin',
761 'payload_properties.txt',
762 ),
763 property_files.required)
764 self.assertEqual(
765 (
Tianjie Xu4c05f4a2018-09-14 16:24:41 -0700766 'care_map.pb',
Tao Bao69203522018-03-08 16:09:01 -0800767 'care_map.txt',
768 'compatibility.zip',
769 ),
770 property_files.optional)
771
772 def test_Compute(self):
773 entries = (
Tao Baoae5e4c32018-03-01 19:30:00 -0800774 'payload.bin',
775 'payload_properties.txt',
776 'care_map.txt',
Tao Bao69203522018-03-08 16:09:01 -0800777 'compatibility.zip',
778 )
Tao Bao3bf8c652018-03-16 12:59:42 -0700779 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800780 property_files = StreamingPropertyFiles()
781 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
782 property_files_string = property_files.Compute(zip_fp)
783
784 tokens = self._parse_property_files_string(property_files_string)
785 self.assertEqual(5, len(tokens))
786 self._verify_entries(zip_file, tokens, entries)
787
788 def test_Finalize(self):
789 entries = [
790 'payload.bin',
791 'payload_properties.txt',
792 'care_map.txt',
793 'compatibility.zip',
794 'META-INF/com/android/metadata',
795 ]
Tao Bao3bf8c652018-03-16 12:59:42 -0700796 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800797 property_files = StreamingPropertyFiles()
798 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -0700799 raw_metadata = property_files.GetPropertyFilesString(
Tao Bao69203522018-03-08 16:09:01 -0800800 zip_fp, reserve_space=False)
801 streaming_metadata = property_files.Finalize(zip_fp, len(raw_metadata))
802 tokens = self._parse_property_files_string(streaming_metadata)
803
804 self.assertEqual(5, len(tokens))
805 # 'META-INF/com/android/metadata' will be key'd as 'metadata' in the
806 # streaming metadata.
807 entries[4] = 'metadata'
808 self._verify_entries(zip_file, tokens, entries)
809
810 def test_Verify(self):
811 entries = (
812 'payload.bin',
813 'payload_properties.txt',
814 'care_map.txt',
815 'compatibility.zip',
Tao Baoae5e4c32018-03-01 19:30:00 -0800816 'META-INF/com/android/metadata',
817 )
Tao Bao3bf8c652018-03-16 12:59:42 -0700818 zip_file = self.construct_zip_package(entries)
Tao Baoae5e4c32018-03-01 19:30:00 -0800819 property_files = StreamingPropertyFiles()
820 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
821 # First get the raw metadata string (i.e. without padding space).
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -0700822 raw_metadata = property_files.GetPropertyFilesString(
Tao Baoae5e4c32018-03-01 19:30:00 -0800823 zip_fp, reserve_space=False)
824
825 # Should pass the test if verification passes.
826 property_files.Verify(zip_fp, raw_metadata)
827
828 # Or raise on verification failure.
829 self.assertRaises(
830 AssertionError, property_files.Verify, zip_fp, raw_metadata + 'x')
831
Tao Baofabe0832018-01-17 15:52:28 -0800832
Tao Baob6304672018-03-08 16:28:33 -0800833class AbOtaPropertyFilesTest(PropertyFilesTest):
834 """Additional sanity checks specialized for AbOtaPropertyFiles."""
835
836 # The size for payload and metadata signature size.
837 SIGNATURE_SIZE = 256
838
839 def setUp(self):
840 self.testdata_dir = test_utils.get_testdata_dir()
841 self.assertTrue(os.path.exists(self.testdata_dir))
842
843 common.OPTIONS.wipe_user_data = False
844 common.OPTIONS.payload_signer = None
845 common.OPTIONS.payload_signer_args = None
846 common.OPTIONS.package_key = os.path.join(self.testdata_dir, 'testkey')
847 common.OPTIONS.key_passwords = {
848 common.OPTIONS.package_key : None,
849 }
850
851 def test_init(self):
852 property_files = AbOtaPropertyFiles()
853 self.assertEqual('ota-property-files', property_files.name)
854 self.assertEqual(
855 (
856 'payload.bin',
857 'payload_properties.txt',
858 ),
859 property_files.required)
860 self.assertEqual(
861 (
Tianjie Xu4c05f4a2018-09-14 16:24:41 -0700862 'care_map.pb',
Tao Baob6304672018-03-08 16:28:33 -0800863 'care_map.txt',
864 'compatibility.zip',
865 ),
866 property_files.optional)
867
Tao Bao82490d32019-04-09 00:12:30 -0700868 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baob6304672018-03-08 16:28:33 -0800869 def test_GetPayloadMetadataOffsetAndSize(self):
870 target_file = construct_target_files()
871 payload = Payload()
872 payload.Generate(target_file)
873
874 payload_signer = PayloadSigner()
875 payload.Sign(payload_signer)
876
877 output_file = common.MakeTempFile(suffix='.zip')
878 with zipfile.ZipFile(output_file, 'w') as output_zip:
879 payload.WriteToZip(output_zip)
880
881 # Find out the payload metadata offset and size.
882 property_files = AbOtaPropertyFiles()
883 with zipfile.ZipFile(output_file) as input_zip:
884 # pylint: disable=protected-access
885 payload_offset, metadata_total = (
886 property_files._GetPayloadMetadataOffsetAndSize(input_zip))
887
Tianjie Xu21e6deb2019-10-07 18:01:00 -0700888 # The signature proto has the following format (details in
889 # /platform/system/update_engine/update_metadata.proto):
890 # message Signature {
891 # optional uint32 version = 1;
892 # optional bytes data = 2;
893 # optional fixed32 unpadded_signature_size = 3;
894 # }
895 #
896 # According to the protobuf encoding, the tail of the signature message will
897 # be [signature string(256 bytes) + encoding of the fixed32 number 256]. And
898 # 256 is encoded as 'x1d\x00\x01\x00\x00':
899 # [3 (field number) << 3 | 5 (type) + byte reverse of 0x100 (256)].
900 # Details in (https://developers.google.com/protocol-buffers/docs/encoding)
901 signature_tail_length = self.SIGNATURE_SIZE + 5
902 self.assertGreater(metadata_total, signature_tail_length)
Tao Baob6304672018-03-08 16:28:33 -0800903 with open(output_file, 'rb') as verify_fp:
Tianjie Xu21e6deb2019-10-07 18:01:00 -0700904 verify_fp.seek(payload_offset + metadata_total - signature_tail_length)
905 metadata_signature_proto_tail = verify_fp.read(signature_tail_length)
906
907 self.assertEqual(b'\x1d\x00\x01\x00\x00',
908 metadata_signature_proto_tail[-5:])
909 metadata_signature = metadata_signature_proto_tail[:-5]
Tao Baob6304672018-03-08 16:28:33 -0800910
911 # Now we extract the metadata hash via brillo_update_payload script, which
912 # will serve as the oracle result.
913 payload_sig_file = common.MakeTempFile(prefix="sig-", suffix=".bin")
914 metadata_sig_file = common.MakeTempFile(prefix="sig-", suffix=".bin")
915 cmd = ['brillo_update_payload', 'hash',
916 '--unsigned_payload', payload.payload_file,
917 '--signature_size', str(self.SIGNATURE_SIZE),
918 '--metadata_hash_file', metadata_sig_file,
919 '--payload_hash_file', payload_sig_file]
Tao Bao73dd4f42018-10-04 16:25:33 -0700920 proc = common.Run(cmd)
Tao Baob6304672018-03-08 16:28:33 -0800921 stdoutdata, _ = proc.communicate()
922 self.assertEqual(
923 0, proc.returncode,
Tao Bao73dd4f42018-10-04 16:25:33 -0700924 'Failed to run brillo_update_payload:\n{}'.format(stdoutdata))
Tao Baob6304672018-03-08 16:28:33 -0800925
926 signed_metadata_sig_file = payload_signer.Sign(metadata_sig_file)
927
928 # Finally we can compare the two signatures.
929 with open(signed_metadata_sig_file, 'rb') as verify_fp:
930 self.assertEqual(verify_fp.read(), metadata_signature)
931
932 @staticmethod
Tao Bao3bf8c652018-03-16 12:59:42 -0700933 def construct_zip_package_withValidPayload(with_metadata=False):
934 # Cannot use construct_zip_package() since we need a "valid" payload.bin.
Tao Baob6304672018-03-08 16:28:33 -0800935 target_file = construct_target_files()
936 payload = Payload()
937 payload.Generate(target_file)
938
939 payload_signer = PayloadSigner()
940 payload.Sign(payload_signer)
941
942 zip_file = common.MakeTempFile(suffix='.zip')
943 with zipfile.ZipFile(zip_file, 'w') as zip_fp:
944 # 'payload.bin',
945 payload.WriteToZip(zip_fp)
946
947 # Other entries.
948 entries = ['care_map.txt', 'compatibility.zip']
949
950 # Put META-INF/com/android/metadata if needed.
951 if with_metadata:
952 entries.append('META-INF/com/android/metadata')
953
954 for entry in entries:
955 zip_fp.writestr(
956 entry, entry.replace('.', '-').upper(), zipfile.ZIP_STORED)
957
958 return zip_file
959
Tao Bao82490d32019-04-09 00:12:30 -0700960 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baob6304672018-03-08 16:28:33 -0800961 def test_Compute(self):
Tao Bao3bf8c652018-03-16 12:59:42 -0700962 zip_file = self.construct_zip_package_withValidPayload()
Tao Baob6304672018-03-08 16:28:33 -0800963 property_files = AbOtaPropertyFiles()
964 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
965 property_files_string = property_files.Compute(zip_fp)
966
967 tokens = self._parse_property_files_string(property_files_string)
968 # "6" indcludes the four entries above, one metadata entry, and one entry
969 # for payload-metadata.bin.
970 self.assertEqual(6, len(tokens))
971 self._verify_entries(
972 zip_file, tokens, ('care_map.txt', 'compatibility.zip'))
973
Tao Bao82490d32019-04-09 00:12:30 -0700974 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baob6304672018-03-08 16:28:33 -0800975 def test_Finalize(self):
Tao Bao3bf8c652018-03-16 12:59:42 -0700976 zip_file = self.construct_zip_package_withValidPayload(with_metadata=True)
Tao Baob6304672018-03-08 16:28:33 -0800977 property_files = AbOtaPropertyFiles()
978 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -0700979 raw_metadata = property_files.GetPropertyFilesString(
Tao Baob6304672018-03-08 16:28:33 -0800980 zip_fp, reserve_space=False)
981 property_files_string = property_files.Finalize(zip_fp, len(raw_metadata))
982
983 tokens = self._parse_property_files_string(property_files_string)
984 # "6" indcludes the four entries above, one metadata entry, and one entry
985 # for payload-metadata.bin.
986 self.assertEqual(6, len(tokens))
987 self._verify_entries(
988 zip_file, tokens, ('care_map.txt', 'compatibility.zip'))
989
Tao Bao82490d32019-04-09 00:12:30 -0700990 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baob6304672018-03-08 16:28:33 -0800991 def test_Verify(self):
Tao Bao3bf8c652018-03-16 12:59:42 -0700992 zip_file = self.construct_zip_package_withValidPayload(with_metadata=True)
Tao Baob6304672018-03-08 16:28:33 -0800993 property_files = AbOtaPropertyFiles()
994 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -0700995 raw_metadata = property_files.GetPropertyFilesString(
Tao Baob6304672018-03-08 16:28:33 -0800996 zip_fp, reserve_space=False)
997
998 property_files.Verify(zip_fp, raw_metadata)
999
1000
Tao Baoc0746f42018-02-21 13:17:22 -08001001class NonAbOtaPropertyFilesTest(PropertyFilesTest):
1002 """Additional sanity checks specialized for NonAbOtaPropertyFiles."""
1003
1004 def test_init(self):
1005 property_files = NonAbOtaPropertyFiles()
1006 self.assertEqual('ota-property-files', property_files.name)
1007 self.assertEqual((), property_files.required)
1008 self.assertEqual((), property_files.optional)
1009
1010 def test_Compute(self):
1011 entries = ()
Tao Bao3bf8c652018-03-16 12:59:42 -07001012 zip_file = self.construct_zip_package(entries)
Tao Baoc0746f42018-02-21 13:17:22 -08001013 property_files = NonAbOtaPropertyFiles()
1014 with zipfile.ZipFile(zip_file) as zip_fp:
1015 property_files_string = property_files.Compute(zip_fp)
1016
1017 tokens = self._parse_property_files_string(property_files_string)
1018 self.assertEqual(1, len(tokens))
1019 self._verify_entries(zip_file, tokens, entries)
1020
1021 def test_Finalize(self):
1022 entries = [
1023 'META-INF/com/android/metadata',
1024 ]
Tao Bao3bf8c652018-03-16 12:59:42 -07001025 zip_file = self.construct_zip_package(entries)
Tao Baoc0746f42018-02-21 13:17:22 -08001026 property_files = NonAbOtaPropertyFiles()
1027 with zipfile.ZipFile(zip_file) as zip_fp:
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -07001028 raw_metadata = property_files.GetPropertyFilesString(
Tao Baoc0746f42018-02-21 13:17:22 -08001029 zip_fp, reserve_space=False)
1030 property_files_string = property_files.Finalize(zip_fp, len(raw_metadata))
1031 tokens = self._parse_property_files_string(property_files_string)
1032
1033 self.assertEqual(1, len(tokens))
1034 # 'META-INF/com/android/metadata' will be key'd as 'metadata'.
1035 entries[0] = 'metadata'
1036 self._verify_entries(zip_file, tokens, entries)
1037
1038 def test_Verify(self):
1039 entries = (
1040 'META-INF/com/android/metadata',
1041 )
Tao Bao3bf8c652018-03-16 12:59:42 -07001042 zip_file = self.construct_zip_package(entries)
Tao Baoc0746f42018-02-21 13:17:22 -08001043 property_files = NonAbOtaPropertyFiles()
1044 with zipfile.ZipFile(zip_file) as zip_fp:
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -07001045 raw_metadata = property_files.GetPropertyFilesString(
Tao Baoc0746f42018-02-21 13:17:22 -08001046 zip_fp, reserve_space=False)
1047
1048 property_files.Verify(zip_fp, raw_metadata)
1049
1050
Tao Bao65b94e92018-10-11 21:57:26 -07001051class PayloadSignerTest(test_utils.ReleaseToolsTestCase):
Tao Baofabe0832018-01-17 15:52:28 -08001052
1053 SIGFILE = 'sigfile.bin'
1054 SIGNED_SIGFILE = 'signed-sigfile.bin'
1055
1056 def setUp(self):
Tao Bao04e1f012018-02-04 12:13:35 -08001057 self.testdata_dir = test_utils.get_testdata_dir()
Tao Baofabe0832018-01-17 15:52:28 -08001058 self.assertTrue(os.path.exists(self.testdata_dir))
1059
1060 common.OPTIONS.payload_signer = None
1061 common.OPTIONS.payload_signer_args = []
1062 common.OPTIONS.package_key = os.path.join(self.testdata_dir, 'testkey')
1063 common.OPTIONS.key_passwords = {
1064 common.OPTIONS.package_key : None,
1065 }
1066
Tao Baofabe0832018-01-17 15:52:28 -08001067 def _assertFilesEqual(self, file1, file2):
1068 with open(file1, 'rb') as fp1, open(file2, 'rb') as fp2:
1069 self.assertEqual(fp1.read(), fp2.read())
1070
Tianjie Xu21e6deb2019-10-07 18:01:00 -07001071 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baofabe0832018-01-17 15:52:28 -08001072 def test_init(self):
1073 payload_signer = PayloadSigner()
1074 self.assertEqual('openssl', payload_signer.signer)
Tianjie Xu21e6deb2019-10-07 18:01:00 -07001075 self.assertEqual(256, payload_signer.maximum_signature_size)
Tao Baofabe0832018-01-17 15:52:28 -08001076
Tianjie Xu21e6deb2019-10-07 18:01:00 -07001077 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baofabe0832018-01-17 15:52:28 -08001078 def test_init_withPassword(self):
1079 common.OPTIONS.package_key = os.path.join(
1080 self.testdata_dir, 'testkey_with_passwd')
1081 common.OPTIONS.key_passwords = {
1082 common.OPTIONS.package_key : 'foo',
1083 }
1084 payload_signer = PayloadSigner()
1085 self.assertEqual('openssl', payload_signer.signer)
1086
1087 def test_init_withExternalSigner(self):
1088 common.OPTIONS.payload_signer = 'abc'
1089 common.OPTIONS.payload_signer_args = ['arg1', 'arg2']
Tianjie Xu21e6deb2019-10-07 18:01:00 -07001090 common.OPTIONS.payload_signer_maximum_signature_size = '512'
Tao Baofabe0832018-01-17 15:52:28 -08001091 payload_signer = PayloadSigner()
1092 self.assertEqual('abc', payload_signer.signer)
1093 self.assertEqual(['arg1', 'arg2'], payload_signer.signer_args)
Tianjie Xu21e6deb2019-10-07 18:01:00 -07001094 self.assertEqual(512, payload_signer.maximum_signature_size)
xunchang376cc7c2019-04-08 23:04:58 -07001095
Tianjie Xu21e6deb2019-10-07 18:01:00 -07001096 @test_utils.SkipIfExternalToolsUnavailable()
1097 def test_GetMaximumSignatureSizeInBytes_512Bytes(self):
xunchang376cc7c2019-04-08 23:04:58 -07001098 signing_key = os.path.join(self.testdata_dir, 'testkey_RSA4096.key')
Tao Bao82490d32019-04-09 00:12:30 -07001099 # pylint: disable=protected-access
Tianjie Xu21e6deb2019-10-07 18:01:00 -07001100 signature_size = PayloadSigner._GetMaximumSignatureSizeInBytes(signing_key)
1101 self.assertEqual(512, signature_size)
Tao Baofabe0832018-01-17 15:52:28 -08001102
Tianjie Xu21e6deb2019-10-07 18:01:00 -07001103 @test_utils.SkipIfExternalToolsUnavailable()
1104 def test_GetMaximumSignatureSizeInBytes_ECKey(self):
1105 signing_key = os.path.join(self.testdata_dir, 'testkey_EC.key')
1106 # pylint: disable=protected-access
1107 signature_size = PayloadSigner._GetMaximumSignatureSizeInBytes(signing_key)
1108 self.assertEqual(72, signature_size)
1109
1110 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baofabe0832018-01-17 15:52:28 -08001111 def test_Sign(self):
1112 payload_signer = PayloadSigner()
1113 input_file = os.path.join(self.testdata_dir, self.SIGFILE)
1114 signed_file = payload_signer.Sign(input_file)
1115
1116 verify_file = os.path.join(self.testdata_dir, self.SIGNED_SIGFILE)
1117 self._assertFilesEqual(verify_file, signed_file)
1118
1119 def test_Sign_withExternalSigner_openssl(self):
1120 """Uses openssl as the external payload signer."""
1121 common.OPTIONS.payload_signer = 'openssl'
1122 common.OPTIONS.payload_signer_args = [
1123 'pkeyutl', '-sign', '-keyform', 'DER', '-inkey',
1124 os.path.join(self.testdata_dir, 'testkey.pk8'),
1125 '-pkeyopt', 'digest:sha256']
1126 payload_signer = PayloadSigner()
1127 input_file = os.path.join(self.testdata_dir, self.SIGFILE)
1128 signed_file = payload_signer.Sign(input_file)
1129
1130 verify_file = os.path.join(self.testdata_dir, self.SIGNED_SIGFILE)
1131 self._assertFilesEqual(verify_file, signed_file)
1132
1133 def test_Sign_withExternalSigner_script(self):
1134 """Uses testdata/payload_signer.sh as the external payload signer."""
1135 common.OPTIONS.payload_signer = os.path.join(
1136 self.testdata_dir, 'payload_signer.sh')
Tao Bao30e31142019-04-09 00:12:30 -07001137 os.chmod(common.OPTIONS.payload_signer, 0o700)
Tao Baofabe0832018-01-17 15:52:28 -08001138 common.OPTIONS.payload_signer_args = [
1139 os.path.join(self.testdata_dir, 'testkey.pk8')]
1140 payload_signer = PayloadSigner()
1141 input_file = os.path.join(self.testdata_dir, self.SIGFILE)
1142 signed_file = payload_signer.Sign(input_file)
1143
1144 verify_file = os.path.join(self.testdata_dir, self.SIGNED_SIGFILE)
1145 self._assertFilesEqual(verify_file, signed_file)
Tao Baoc7b403a2018-01-30 18:19:04 -08001146
1147
Tao Bao65b94e92018-10-11 21:57:26 -07001148class PayloadTest(test_utils.ReleaseToolsTestCase):
Tao Baoc7b403a2018-01-30 18:19:04 -08001149
1150 def setUp(self):
Tao Bao04e1f012018-02-04 12:13:35 -08001151 self.testdata_dir = test_utils.get_testdata_dir()
Tao Baoc7b403a2018-01-30 18:19:04 -08001152 self.assertTrue(os.path.exists(self.testdata_dir))
1153
1154 common.OPTIONS.wipe_user_data = False
1155 common.OPTIONS.payload_signer = None
1156 common.OPTIONS.payload_signer_args = None
1157 common.OPTIONS.package_key = os.path.join(self.testdata_dir, 'testkey')
1158 common.OPTIONS.key_passwords = {
1159 common.OPTIONS.package_key : None,
1160 }
1161
Tao Baoc7b403a2018-01-30 18:19:04 -08001162 @staticmethod
Tao Baof7140c02018-01-30 17:09:24 -08001163 def _create_payload_full(secondary=False):
1164 target_file = construct_target_files(secondary)
Tao Bao667ff572018-02-10 00:02:40 -08001165 payload = Payload(secondary)
Tao Baoc7b403a2018-01-30 18:19:04 -08001166 payload.Generate(target_file)
1167 return payload
1168
Tao Baof7140c02018-01-30 17:09:24 -08001169 @staticmethod
1170 def _create_payload_incremental():
1171 target_file = construct_target_files()
1172 source_file = construct_target_files()
Tao Baoc7b403a2018-01-30 18:19:04 -08001173 payload = Payload()
1174 payload.Generate(target_file, source_file)
1175 return payload
1176
Tao Bao82490d32019-04-09 00:12:30 -07001177 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001178 def test_Generate_full(self):
1179 payload = self._create_payload_full()
1180 self.assertTrue(os.path.exists(payload.payload_file))
1181
Tao Bao82490d32019-04-09 00:12:30 -07001182 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001183 def test_Generate_incremental(self):
1184 payload = self._create_payload_incremental()
1185 self.assertTrue(os.path.exists(payload.payload_file))
1186
Tao Bao82490d32019-04-09 00:12:30 -07001187 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001188 def test_Generate_additionalArgs(self):
Tao Baof7140c02018-01-30 17:09:24 -08001189 target_file = construct_target_files()
1190 source_file = construct_target_files()
Tao Baoc7b403a2018-01-30 18:19:04 -08001191 payload = Payload()
1192 # This should work the same as calling payload.Generate(target_file,
1193 # source_file).
1194 payload.Generate(
1195 target_file, additional_args=["--source_image", source_file])
1196 self.assertTrue(os.path.exists(payload.payload_file))
1197
Tao Bao82490d32019-04-09 00:12:30 -07001198 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001199 def test_Generate_invalidInput(self):
Tao Baof7140c02018-01-30 17:09:24 -08001200 target_file = construct_target_files()
Tao Baoc7b403a2018-01-30 18:19:04 -08001201 common.ZipDelete(target_file, 'IMAGES/vendor.img')
1202 payload = Payload()
Tao Baobec89c12018-10-15 11:53:28 -07001203 self.assertRaises(common.ExternalError, payload.Generate, target_file)
Tao Baoc7b403a2018-01-30 18:19:04 -08001204
Tao Bao82490d32019-04-09 00:12:30 -07001205 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001206 def test_Sign_full(self):
1207 payload = self._create_payload_full()
1208 payload.Sign(PayloadSigner())
1209
1210 output_file = common.MakeTempFile(suffix='.zip')
1211 with zipfile.ZipFile(output_file, 'w') as output_zip:
1212 payload.WriteToZip(output_zip)
1213
1214 import check_ota_package_signature
1215 check_ota_package_signature.VerifyAbOtaPayload(
1216 os.path.join(self.testdata_dir, 'testkey.x509.pem'),
1217 output_file)
1218
Tao Bao82490d32019-04-09 00:12:30 -07001219 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001220 def test_Sign_incremental(self):
1221 payload = self._create_payload_incremental()
1222 payload.Sign(PayloadSigner())
1223
1224 output_file = common.MakeTempFile(suffix='.zip')
1225 with zipfile.ZipFile(output_file, 'w') as output_zip:
1226 payload.WriteToZip(output_zip)
1227
1228 import check_ota_package_signature
1229 check_ota_package_signature.VerifyAbOtaPayload(
1230 os.path.join(self.testdata_dir, 'testkey.x509.pem'),
1231 output_file)
1232
Tao Bao82490d32019-04-09 00:12:30 -07001233 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001234 def test_Sign_withDataWipe(self):
1235 common.OPTIONS.wipe_user_data = True
1236 payload = self._create_payload_full()
1237 payload.Sign(PayloadSigner())
1238
1239 with open(payload.payload_properties) as properties_fp:
1240 self.assertIn("POWERWASH=1", properties_fp.read())
1241
Tao Bao82490d32019-04-09 00:12:30 -07001242 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao667ff572018-02-10 00:02:40 -08001243 def test_Sign_secondary(self):
1244 payload = self._create_payload_full(secondary=True)
1245 payload.Sign(PayloadSigner())
1246
1247 with open(payload.payload_properties) as properties_fp:
1248 self.assertIn("SWITCH_SLOT_ON_REBOOT=0", properties_fp.read())
1249
Tao Bao82490d32019-04-09 00:12:30 -07001250 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001251 def test_Sign_badSigner(self):
1252 """Tests that signing failure can be captured."""
1253 payload = self._create_payload_full()
1254 payload_signer = PayloadSigner()
1255 payload_signer.signer_args.append('bad-option')
Tao Baobec89c12018-10-15 11:53:28 -07001256 self.assertRaises(common.ExternalError, payload.Sign, payload_signer)
Tao Baoc7b403a2018-01-30 18:19:04 -08001257
Tao Bao82490d32019-04-09 00:12:30 -07001258 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001259 def test_WriteToZip(self):
1260 payload = self._create_payload_full()
1261 payload.Sign(PayloadSigner())
1262
1263 output_file = common.MakeTempFile(suffix='.zip')
1264 with zipfile.ZipFile(output_file, 'w') as output_zip:
1265 payload.WriteToZip(output_zip)
1266
1267 with zipfile.ZipFile(output_file) as verify_zip:
1268 # First make sure we have the essential entries.
1269 namelist = verify_zip.namelist()
1270 self.assertIn(Payload.PAYLOAD_BIN, namelist)
1271 self.assertIn(Payload.PAYLOAD_PROPERTIES_TXT, namelist)
1272
1273 # Then assert these entries are stored.
1274 for entry_info in verify_zip.infolist():
1275 if entry_info.filename not in (Payload.PAYLOAD_BIN,
1276 Payload.PAYLOAD_PROPERTIES_TXT):
1277 continue
1278 self.assertEqual(zipfile.ZIP_STORED, entry_info.compress_type)
1279
Tao Bao82490d32019-04-09 00:12:30 -07001280 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001281 def test_WriteToZip_unsignedPayload(self):
1282 """Unsigned payloads should not be allowed to be written to zip."""
1283 payload = self._create_payload_full()
1284
1285 output_file = common.MakeTempFile(suffix='.zip')
1286 with zipfile.ZipFile(output_file, 'w') as output_zip:
1287 self.assertRaises(AssertionError, payload.WriteToZip, output_zip)
1288
1289 # Also test with incremental payload.
1290 payload = self._create_payload_incremental()
1291
1292 output_file = common.MakeTempFile(suffix='.zip')
1293 with zipfile.ZipFile(output_file, 'w') as output_zip:
1294 self.assertRaises(AssertionError, payload.WriteToZip, output_zip)
Tao Baof7140c02018-01-30 17:09:24 -08001295
Tao Bao82490d32019-04-09 00:12:30 -07001296 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baof7140c02018-01-30 17:09:24 -08001297 def test_WriteToZip_secondary(self):
1298 payload = self._create_payload_full(secondary=True)
1299 payload.Sign(PayloadSigner())
1300
1301 output_file = common.MakeTempFile(suffix='.zip')
1302 with zipfile.ZipFile(output_file, 'w') as output_zip:
Tao Bao667ff572018-02-10 00:02:40 -08001303 payload.WriteToZip(output_zip)
Tao Baof7140c02018-01-30 17:09:24 -08001304
1305 with zipfile.ZipFile(output_file) as verify_zip:
1306 # First make sure we have the essential entries.
1307 namelist = verify_zip.namelist()
1308 self.assertIn(Payload.SECONDARY_PAYLOAD_BIN, namelist)
1309 self.assertIn(Payload.SECONDARY_PAYLOAD_PROPERTIES_TXT, namelist)
1310
1311 # Then assert these entries are stored.
1312 for entry_info in verify_zip.infolist():
1313 if entry_info.filename not in (
1314 Payload.SECONDARY_PAYLOAD_BIN,
1315 Payload.SECONDARY_PAYLOAD_PROPERTIES_TXT):
1316 continue
1317 self.assertEqual(zipfile.ZIP_STORED, entry_info.compress_type)