blob: e0078632c76e666f1211bbd0a6ddba22680a362e [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,
Greg Kaiserb21e48b2020-05-09 00:30:33 +000029 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 TEST_TARGET_INFO_DICT = {
Tianjie Xu0fde41e2020-05-09 05:24:18 +0000112 'build.prop': common.PartitionBuildProps.FromDictionary(
113 'system', {
114 'ro.product.device': 'product-device',
115 'ro.build.fingerprint': 'build-fingerprint-target',
116 'ro.build.version.incremental': 'build-version-incremental-target',
117 'ro.build.version.sdk': '27',
118 'ro.build.version.security_patch': '2017-12-01',
119 'ro.build.date.utc': '1500000000'}
120 )
Tao Baodf3a48b2018-01-10 16:30:43 -0800121 }
122
123 TEST_SOURCE_INFO_DICT = {
Tianjie Xu0fde41e2020-05-09 05:24:18 +0000124 'build.prop': common.PartitionBuildProps.FromDictionary(
125 'system', {
126 'ro.product.device': 'product-device',
127 'ro.build.fingerprint': 'build-fingerprint-source',
128 'ro.build.version.incremental': 'build-version-incremental-source',
129 'ro.build.version.sdk': '25',
130 'ro.build.version.security_patch': '2016-12-01',
131 'ro.build.date.utc': '1400000000'}
132 )
Tao Baodf3a48b2018-01-10 16:30:43 -0800133 }
134
Tao Bao1c320f82019-10-04 23:25:12 -0700135 TEST_INFO_DICT_USES_OEM_PROPS = {
Tianjie Xu0fde41e2020-05-09 05:24:18 +0000136 'build.prop': common.PartitionBuildProps.FromDictionary(
137 'system', {
138 'ro.product.name': 'product-name',
139 'ro.build.thumbprint': 'build-thumbprint',
140 'ro.build.bar': 'build-bar'}
141 ),
142 'vendor.build.prop': common.PartitionBuildProps.FromDictionary(
143 'vendor', {
144 'ro.vendor.build.fingerprint': 'vendor-build-fingerprint'}
145 ),
146 'property1': 'value1',
147 'property2': 4096,
148 'oem_fingerprint_properties': 'ro.product.device ro.product.brand',
Tao Bao1c320f82019-10-04 23:25:12 -0700149 }
150
151 TEST_OEM_DICTS = [
152 {
Tianjie Xu0fde41e2020-05-09 05:24:18 +0000153 'ro.product.brand': 'brand1',
154 'ro.product.device': 'device1',
Tao Bao1c320f82019-10-04 23:25:12 -0700155 },
156 {
Tianjie Xu0fde41e2020-05-09 05:24:18 +0000157 'ro.product.brand': 'brand2',
158 'ro.product.device': 'device2',
Tao Bao1c320f82019-10-04 23:25:12 -0700159 },
160 {
Tianjie Xu0fde41e2020-05-09 05:24:18 +0000161 'ro.product.brand': 'brand3',
162 'ro.product.device': 'device3',
Tao Bao1c320f82019-10-04 23:25:12 -0700163 },
164 ]
165
Tao Baodf3a48b2018-01-10 16:30:43 -0800166 def setUp(self):
Tao Bao3bf8c652018-03-16 12:59:42 -0700167 self.testdata_dir = test_utils.get_testdata_dir()
168 self.assertTrue(os.path.exists(self.testdata_dir))
169
Tao Baodf3a48b2018-01-10 16:30:43 -0800170 # Reset the global options as in ota_from_target_files.py.
171 common.OPTIONS.incremental_source = None
172 common.OPTIONS.downgrade = False
Tao Bao393eeb42019-03-06 16:00:38 -0800173 common.OPTIONS.retrofit_dynamic_partitions = False
Tao Baodf3a48b2018-01-10 16:30:43 -0800174 common.OPTIONS.timestamp = False
175 common.OPTIONS.wipe_user_data = False
Tao Bao3bf8c652018-03-16 12:59:42 -0700176 common.OPTIONS.no_signing = False
177 common.OPTIONS.package_key = os.path.join(self.testdata_dir, 'testkey')
178 common.OPTIONS.key_passwords = {
179 common.OPTIONS.package_key : None,
180 }
181
182 common.OPTIONS.search_path = test_utils.get_search_path()
Tao Baodf3a48b2018-01-10 16:30:43 -0800183
184 def test_GetPackageMetadata_abOta_full(self):
185 target_info_dict = copy.deepcopy(self.TEST_TARGET_INFO_DICT)
186 target_info_dict['ab_update'] = 'true'
Tao Bao1c320f82019-10-04 23:25:12 -0700187 target_info = common.BuildInfo(target_info_dict, None)
Tao Baodf3a48b2018-01-10 16:30:43 -0800188 metadata = GetPackageMetadata(target_info)
189 self.assertDictEqual(
190 {
191 'ota-type' : 'AB',
192 'ota-required-cache' : '0',
193 'post-build' : 'build-fingerprint-target',
194 'post-build-incremental' : 'build-version-incremental-target',
Tao Bao35dc2552018-02-01 13:18:00 -0800195 'post-sdk-level' : '27',
196 'post-security-patch-level' : '2017-12-01',
Tao Baodf3a48b2018-01-10 16:30:43 -0800197 'post-timestamp' : '1500000000',
198 'pre-device' : 'product-device',
199 },
200 metadata)
201
202 def test_GetPackageMetadata_abOta_incremental(self):
203 target_info_dict = copy.deepcopy(self.TEST_TARGET_INFO_DICT)
204 target_info_dict['ab_update'] = 'true'
Tao Bao1c320f82019-10-04 23:25:12 -0700205 target_info = common.BuildInfo(target_info_dict, None)
206 source_info = common.BuildInfo(self.TEST_SOURCE_INFO_DICT, None)
Tao Baodf3a48b2018-01-10 16:30:43 -0800207 common.OPTIONS.incremental_source = ''
208 metadata = GetPackageMetadata(target_info, source_info)
209 self.assertDictEqual(
210 {
211 'ota-type' : 'AB',
212 'ota-required-cache' : '0',
213 'post-build' : 'build-fingerprint-target',
214 'post-build-incremental' : 'build-version-incremental-target',
Tao Bao35dc2552018-02-01 13:18:00 -0800215 'post-sdk-level' : '27',
216 'post-security-patch-level' : '2017-12-01',
Tao Baodf3a48b2018-01-10 16:30:43 -0800217 'post-timestamp' : '1500000000',
218 'pre-device' : 'product-device',
219 'pre-build' : 'build-fingerprint-source',
220 'pre-build-incremental' : 'build-version-incremental-source',
221 },
222 metadata)
223
224 def test_GetPackageMetadata_nonAbOta_full(self):
Tao Bao1c320f82019-10-04 23:25:12 -0700225 target_info = common.BuildInfo(self.TEST_TARGET_INFO_DICT, None)
Tao Baodf3a48b2018-01-10 16:30:43 -0800226 metadata = GetPackageMetadata(target_info)
227 self.assertDictEqual(
228 {
229 'ota-type' : 'BLOCK',
230 'post-build' : 'build-fingerprint-target',
231 'post-build-incremental' : 'build-version-incremental-target',
Tao Bao35dc2552018-02-01 13:18:00 -0800232 'post-sdk-level' : '27',
233 'post-security-patch-level' : '2017-12-01',
Tao Baodf3a48b2018-01-10 16:30:43 -0800234 'post-timestamp' : '1500000000',
235 'pre-device' : 'product-device',
236 },
237 metadata)
238
239 def test_GetPackageMetadata_nonAbOta_incremental(self):
Tao Bao1c320f82019-10-04 23:25:12 -0700240 target_info = common.BuildInfo(self.TEST_TARGET_INFO_DICT, None)
241 source_info = common.BuildInfo(self.TEST_SOURCE_INFO_DICT, None)
Tao Baodf3a48b2018-01-10 16:30:43 -0800242 common.OPTIONS.incremental_source = ''
243 metadata = GetPackageMetadata(target_info, source_info)
244 self.assertDictEqual(
245 {
246 'ota-type' : 'BLOCK',
247 'post-build' : 'build-fingerprint-target',
248 'post-build-incremental' : 'build-version-incremental-target',
Tao Bao35dc2552018-02-01 13:18:00 -0800249 'post-sdk-level' : '27',
250 'post-security-patch-level' : '2017-12-01',
Tao Baodf3a48b2018-01-10 16:30:43 -0800251 'post-timestamp' : '1500000000',
252 'pre-device' : 'product-device',
253 'pre-build' : 'build-fingerprint-source',
254 'pre-build-incremental' : 'build-version-incremental-source',
255 },
256 metadata)
257
258 def test_GetPackageMetadata_wipe(self):
Tao Bao1c320f82019-10-04 23:25:12 -0700259 target_info = common.BuildInfo(self.TEST_TARGET_INFO_DICT, None)
Tao Baodf3a48b2018-01-10 16:30:43 -0800260 common.OPTIONS.wipe_user_data = True
261 metadata = GetPackageMetadata(target_info)
262 self.assertDictEqual(
263 {
264 'ota-type' : 'BLOCK',
265 'ota-wipe' : 'yes',
266 'post-build' : 'build-fingerprint-target',
267 'post-build-incremental' : 'build-version-incremental-target',
Tao Bao35dc2552018-02-01 13:18:00 -0800268 'post-sdk-level' : '27',
269 'post-security-patch-level' : '2017-12-01',
Tao Baodf3a48b2018-01-10 16:30:43 -0800270 'post-timestamp' : '1500000000',
271 'pre-device' : 'product-device',
272 },
273 metadata)
274
Tao Bao393eeb42019-03-06 16:00:38 -0800275 def test_GetPackageMetadata_retrofitDynamicPartitions(self):
Tao Bao1c320f82019-10-04 23:25:12 -0700276 target_info = common.BuildInfo(self.TEST_TARGET_INFO_DICT, None)
Tao Bao393eeb42019-03-06 16:00:38 -0800277 common.OPTIONS.retrofit_dynamic_partitions = True
278 metadata = GetPackageMetadata(target_info)
279 self.assertDictEqual(
280 {
281 'ota-retrofit-dynamic-partitions' : 'yes',
282 'ota-type' : 'BLOCK',
283 'post-build' : 'build-fingerprint-target',
284 'post-build-incremental' : 'build-version-incremental-target',
285 'post-sdk-level' : '27',
286 'post-security-patch-level' : '2017-12-01',
287 'post-timestamp' : '1500000000',
288 'pre-device' : 'product-device',
289 },
290 metadata)
291
Tao Baodf3a48b2018-01-10 16:30:43 -0800292 @staticmethod
293 def _test_GetPackageMetadata_swapBuildTimestamps(target_info, source_info):
Tianjie Xu0fde41e2020-05-09 05:24:18 +0000294 (target_info['build.prop'].build_props['ro.build.date.utc'],
295 source_info['build.prop'].build_props['ro.build.date.utc']) = (
296 source_info['build.prop'].build_props['ro.build.date.utc'],
297 target_info['build.prop'].build_props['ro.build.date.utc'])
Tao Baodf3a48b2018-01-10 16:30:43 -0800298
299 def test_GetPackageMetadata_unintentionalDowngradeDetected(self):
300 target_info_dict = copy.deepcopy(self.TEST_TARGET_INFO_DICT)
301 source_info_dict = copy.deepcopy(self.TEST_SOURCE_INFO_DICT)
302 self._test_GetPackageMetadata_swapBuildTimestamps(
303 target_info_dict, source_info_dict)
304
Tao Bao1c320f82019-10-04 23:25:12 -0700305 target_info = common.BuildInfo(target_info_dict, None)
306 source_info = common.BuildInfo(source_info_dict, None)
Tao Baodf3a48b2018-01-10 16:30:43 -0800307 common.OPTIONS.incremental_source = ''
308 self.assertRaises(RuntimeError, GetPackageMetadata, target_info,
309 source_info)
310
311 def test_GetPackageMetadata_downgrade(self):
312 target_info_dict = copy.deepcopy(self.TEST_TARGET_INFO_DICT)
313 source_info_dict = copy.deepcopy(self.TEST_SOURCE_INFO_DICT)
314 self._test_GetPackageMetadata_swapBuildTimestamps(
315 target_info_dict, source_info_dict)
316
Tao Bao1c320f82019-10-04 23:25:12 -0700317 target_info = common.BuildInfo(target_info_dict, None)
318 source_info = common.BuildInfo(source_info_dict, None)
Tao Baodf3a48b2018-01-10 16:30:43 -0800319 common.OPTIONS.incremental_source = ''
320 common.OPTIONS.downgrade = True
321 common.OPTIONS.wipe_user_data = True
322 metadata = GetPackageMetadata(target_info, source_info)
323 self.assertDictEqual(
324 {
325 'ota-downgrade' : 'yes',
326 'ota-type' : 'BLOCK',
327 'ota-wipe' : 'yes',
328 'post-build' : 'build-fingerprint-target',
329 'post-build-incremental' : 'build-version-incremental-target',
Tao Bao35dc2552018-02-01 13:18:00 -0800330 'post-sdk-level' : '27',
331 'post-security-patch-level' : '2017-12-01',
Tao Baofaa8e0b2018-04-12 14:31:43 -0700332 'post-timestamp' : '1400000000',
Tao Baodf3a48b2018-01-10 16:30:43 -0800333 'pre-device' : 'product-device',
334 'pre-build' : 'build-fingerprint-source',
335 'pre-build-incremental' : 'build-version-incremental-source',
336 },
337 metadata)
Tao Baofabe0832018-01-17 15:52:28 -0800338
Tao Bao82490d32019-04-09 00:12:30 -0700339 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baof7140c02018-01-30 17:09:24 -0800340 def test_GetTargetFilesZipForSecondaryImages(self):
341 input_file = construct_target_files(secondary=True)
342 target_file = GetTargetFilesZipForSecondaryImages(input_file)
343
344 with zipfile.ZipFile(target_file) as verify_zip:
345 namelist = verify_zip.namelist()
Tao Bao615b65d2019-10-06 22:59:45 -0700346 ab_partitions = verify_zip.read('META/ab_partitions.txt').decode()
Tao Baof7140c02018-01-30 17:09:24 -0800347
348 self.assertIn('META/ab_partitions.txt', namelist)
Tao Baof7140c02018-01-30 17:09:24 -0800349 self.assertIn('IMAGES/system.img', namelist)
Tao Bao12489802018-07-12 14:47:38 -0700350 self.assertIn('RADIO/bootloader.img', namelist)
Tao Bao15a146a2018-02-21 16:06:59 -0800351 self.assertIn(POSTINSTALL_CONFIG, namelist)
Tao Baof7140c02018-01-30 17:09:24 -0800352
Tao Bao3e759462019-09-17 22:43:11 -0700353 self.assertNotIn('IMAGES/boot.img', namelist)
Tao Baof7140c02018-01-30 17:09:24 -0800354 self.assertNotIn('IMAGES/system_other.img', namelist)
355 self.assertNotIn('IMAGES/system.map', namelist)
Tao Bao3e759462019-09-17 22:43:11 -0700356 self.assertNotIn('RADIO/modem.img', namelist)
Tao Baof7140c02018-01-30 17:09:24 -0800357
Tao Bao3e759462019-09-17 22:43:11 -0700358 expected_ab_partitions = ['system', 'bootloader']
Tianjie Xu1c808002019-09-11 00:29:26 -0700359 self.assertEqual('\n'.join(expected_ab_partitions), ab_partitions)
360
Tao Bao82490d32019-04-09 00:12:30 -0700361 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao15a146a2018-02-21 16:06:59 -0800362 def test_GetTargetFilesZipForSecondaryImages_skipPostinstall(self):
363 input_file = construct_target_files(secondary=True)
364 target_file = GetTargetFilesZipForSecondaryImages(
365 input_file, skip_postinstall=True)
366
367 with zipfile.ZipFile(target_file) as verify_zip:
368 namelist = verify_zip.namelist()
369
370 self.assertIn('META/ab_partitions.txt', namelist)
Tao Bao15a146a2018-02-21 16:06:59 -0800371 self.assertIn('IMAGES/system.img', namelist)
Tao Bao12489802018-07-12 14:47:38 -0700372 self.assertIn('RADIO/bootloader.img', namelist)
Tao Bao15a146a2018-02-21 16:06:59 -0800373
Tao Bao3e759462019-09-17 22:43:11 -0700374 self.assertNotIn('IMAGES/boot.img', namelist)
Tao Bao15a146a2018-02-21 16:06:59 -0800375 self.assertNotIn('IMAGES/system_other.img', namelist)
376 self.assertNotIn('IMAGES/system.map', namelist)
Tao Bao3e759462019-09-17 22:43:11 -0700377 self.assertNotIn('RADIO/modem.img', namelist)
Tao Bao15a146a2018-02-21 16:06:59 -0800378 self.assertNotIn(POSTINSTALL_CONFIG, namelist)
379
Tao Bao82490d32019-04-09 00:12:30 -0700380 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao12489802018-07-12 14:47:38 -0700381 def test_GetTargetFilesZipForSecondaryImages_withoutRadioImages(self):
382 input_file = construct_target_files(secondary=True)
383 common.ZipDelete(input_file, 'RADIO/bootloader.img')
384 common.ZipDelete(input_file, 'RADIO/modem.img')
385 target_file = GetTargetFilesZipForSecondaryImages(input_file)
386
387 with zipfile.ZipFile(target_file) as verify_zip:
388 namelist = verify_zip.namelist()
389
390 self.assertIn('META/ab_partitions.txt', namelist)
Tao Bao12489802018-07-12 14:47:38 -0700391 self.assertIn('IMAGES/system.img', namelist)
Tao Bao12489802018-07-12 14:47:38 -0700392 self.assertIn(POSTINSTALL_CONFIG, namelist)
393
Tao Bao3e759462019-09-17 22:43:11 -0700394 self.assertNotIn('IMAGES/boot.img', namelist)
Tao Bao12489802018-07-12 14:47:38 -0700395 self.assertNotIn('IMAGES/system_other.img', namelist)
396 self.assertNotIn('IMAGES/system.map', namelist)
397 self.assertNotIn('RADIO/bootloader.img', namelist)
398 self.assertNotIn('RADIO/modem.img', namelist)
399
Tao Bao82490d32019-04-09 00:12:30 -0700400 @test_utils.SkipIfExternalToolsUnavailable()
Tianjie Xu1c808002019-09-11 00:29:26 -0700401 def test_GetTargetFilesZipForSecondaryImages_dynamicPartitions(self):
402 input_file = construct_target_files(secondary=True)
403 misc_info = '\n'.join([
404 'use_dynamic_partition_size=true',
405 'use_dynamic_partitions=true',
406 'dynamic_partition_list=system vendor product',
407 'super_partition_groups=google_dynamic_partitions',
408 'super_google_dynamic_partitions_group_size=4873781248',
409 'super_google_dynamic_partitions_partition_list=system vendor product',
410 ])
411 dynamic_partitions_info = '\n'.join([
412 'super_partition_groups=google_dynamic_partitions',
413 'super_google_dynamic_partitions_group_size=4873781248',
414 'super_google_dynamic_partitions_partition_list=system vendor product',
415 ])
416
417 with zipfile.ZipFile(input_file, 'a') as append_zip:
418 common.ZipWriteStr(append_zip, 'META/misc_info.txt', misc_info)
419 common.ZipWriteStr(append_zip, 'META/dynamic_partitions_info.txt',
420 dynamic_partitions_info)
421
422 target_file = GetTargetFilesZipForSecondaryImages(input_file)
423
424 with zipfile.ZipFile(target_file) as verify_zip:
425 namelist = verify_zip.namelist()
Tao Bao615b65d2019-10-06 22:59:45 -0700426 updated_misc_info = verify_zip.read('META/misc_info.txt').decode()
Tianjie Xu1c808002019-09-11 00:29:26 -0700427 updated_dynamic_partitions_info = verify_zip.read(
Tao Bao615b65d2019-10-06 22:59:45 -0700428 'META/dynamic_partitions_info.txt').decode()
Tianjie Xu1c808002019-09-11 00:29:26 -0700429
430 self.assertIn('META/ab_partitions.txt', namelist)
Tianjie Xu1c808002019-09-11 00:29:26 -0700431 self.assertIn('IMAGES/system.img', namelist)
432 self.assertIn(POSTINSTALL_CONFIG, namelist)
433 self.assertIn('META/misc_info.txt', namelist)
434 self.assertIn('META/dynamic_partitions_info.txt', namelist)
435
Tao Bao3e759462019-09-17 22:43:11 -0700436 self.assertNotIn('IMAGES/boot.img', namelist)
Tianjie Xu1c808002019-09-11 00:29:26 -0700437 self.assertNotIn('IMAGES/system_other.img', namelist)
438 self.assertNotIn('IMAGES/system.map', namelist)
439
440 # Check the vendor & product are removed from the partitions list.
441 expected_misc_info = misc_info.replace('system vendor product',
442 'system')
443 expected_dynamic_partitions_info = dynamic_partitions_info.replace(
444 'system vendor product', 'system')
445 self.assertEqual(expected_misc_info, updated_misc_info)
446 self.assertEqual(expected_dynamic_partitions_info,
447 updated_dynamic_partitions_info)
448
449 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao15a146a2018-02-21 16:06:59 -0800450 def test_GetTargetFilesZipWithoutPostinstallConfig(self):
451 input_file = construct_target_files()
452 target_file = GetTargetFilesZipWithoutPostinstallConfig(input_file)
453 with zipfile.ZipFile(target_file) as verify_zip:
454 self.assertNotIn(POSTINSTALL_CONFIG, verify_zip.namelist())
455
Tao Bao82490d32019-04-09 00:12:30 -0700456 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao15a146a2018-02-21 16:06:59 -0800457 def test_GetTargetFilesZipWithoutPostinstallConfig_missingEntry(self):
458 input_file = construct_target_files()
459 common.ZipDelete(input_file, POSTINSTALL_CONFIG)
460 target_file = GetTargetFilesZipWithoutPostinstallConfig(input_file)
461 with zipfile.ZipFile(target_file) as verify_zip:
462 self.assertNotIn(POSTINSTALL_CONFIG, verify_zip.namelist())
463
Tao Bao3bf8c652018-03-16 12:59:42 -0700464 def _test_FinalizeMetadata(self, large_entry=False):
465 entries = [
466 'required-entry1',
467 'required-entry2',
468 ]
469 zip_file = PropertyFilesTest.construct_zip_package(entries)
470 # Add a large entry of 1 GiB if requested.
471 if large_entry:
472 with zipfile.ZipFile(zip_file, 'a') as zip_fp:
473 zip_fp.writestr(
474 # Using 'zoo' so that the entry stays behind others after signing.
475 'zoo',
476 'A' * 1024 * 1024 * 1024,
477 zipfile.ZIP_STORED)
478
479 metadata = {}
480 output_file = common.MakeTempFile(suffix='.zip')
481 needed_property_files = (
482 TestPropertyFiles(),
483 )
484 FinalizeMetadata(metadata, zip_file, output_file, needed_property_files)
485 self.assertIn('ota-test-property-files', metadata)
486
Tao Bao82490d32019-04-09 00:12:30 -0700487 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao3bf8c652018-03-16 12:59:42 -0700488 def test_FinalizeMetadata(self):
489 self._test_FinalizeMetadata()
490
Tao Bao82490d32019-04-09 00:12:30 -0700491 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao3bf8c652018-03-16 12:59:42 -0700492 def test_FinalizeMetadata_withNoSigning(self):
493 common.OPTIONS.no_signing = True
494 self._test_FinalizeMetadata()
495
Tao Bao82490d32019-04-09 00:12:30 -0700496 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao3bf8c652018-03-16 12:59:42 -0700497 def test_FinalizeMetadata_largeEntry(self):
498 self._test_FinalizeMetadata(large_entry=True)
499
Tao Bao82490d32019-04-09 00:12:30 -0700500 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao3bf8c652018-03-16 12:59:42 -0700501 def test_FinalizeMetadata_largeEntry_withNoSigning(self):
502 common.OPTIONS.no_signing = True
503 self._test_FinalizeMetadata(large_entry=True)
504
Tao Bao82490d32019-04-09 00:12:30 -0700505 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao3bf8c652018-03-16 12:59:42 -0700506 def test_FinalizeMetadata_insufficientSpace(self):
507 entries = [
508 'required-entry1',
509 'required-entry2',
510 'optional-entry1',
511 'optional-entry2',
512 ]
513 zip_file = PropertyFilesTest.construct_zip_package(entries)
514 with zipfile.ZipFile(zip_file, 'a') as zip_fp:
515 zip_fp.writestr(
516 # 'foo-entry1' will appear ahead of all other entries (in alphabetical
517 # order) after the signing, which will in turn trigger the
518 # InsufficientSpaceException and an automatic retry.
519 'foo-entry1',
520 'A' * 1024 * 1024,
521 zipfile.ZIP_STORED)
522
523 metadata = {}
524 needed_property_files = (
525 TestPropertyFiles(),
526 )
527 output_file = common.MakeTempFile(suffix='.zip')
528 FinalizeMetadata(metadata, zip_file, output_file, needed_property_files)
529 self.assertIn('ota-test-property-files', metadata)
530
Tao Bao1c320f82019-10-04 23:25:12 -0700531 def test_WriteFingerprintAssertion_without_oem_props(self):
532 target_info = common.BuildInfo(self.TEST_TARGET_INFO_DICT, None)
533 source_info_dict = copy.deepcopy(self.TEST_TARGET_INFO_DICT)
Tianjie Xu0fde41e2020-05-09 05:24:18 +0000534 source_info_dict['build.prop'].build_props['ro.build.fingerprint'] = (
Tao Bao1c320f82019-10-04 23:25:12 -0700535 'source-build-fingerprint')
536 source_info = common.BuildInfo(source_info_dict, None)
537
538 script_writer = test_utils.MockScriptWriter()
539 WriteFingerprintAssertion(script_writer, target_info, source_info)
540 self.assertEqual(
541 [('AssertSomeFingerprint', 'source-build-fingerprint',
542 'build-fingerprint-target')],
543 script_writer.lines)
544
545 def test_WriteFingerprintAssertion_with_source_oem_props(self):
546 target_info = common.BuildInfo(self.TEST_TARGET_INFO_DICT, None)
547 source_info = common.BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
548 self.TEST_OEM_DICTS)
549
550 script_writer = test_utils.MockScriptWriter()
551 WriteFingerprintAssertion(script_writer, target_info, source_info)
552 self.assertEqual(
553 [('AssertFingerprintOrThumbprint', 'build-fingerprint-target',
554 'build-thumbprint')],
555 script_writer.lines)
556
557 def test_WriteFingerprintAssertion_with_target_oem_props(self):
558 target_info = common.BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
559 self.TEST_OEM_DICTS)
560 source_info = common.BuildInfo(self.TEST_TARGET_INFO_DICT, None)
561
562 script_writer = test_utils.MockScriptWriter()
563 WriteFingerprintAssertion(script_writer, target_info, source_info)
564 self.assertEqual(
565 [('AssertFingerprintOrThumbprint', 'build-fingerprint-target',
566 'build-thumbprint')],
567 script_writer.lines)
568
569 def test_WriteFingerprintAssertion_with_both_oem_props(self):
570 target_info = common.BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
571 self.TEST_OEM_DICTS)
572 source_info_dict = copy.deepcopy(self.TEST_INFO_DICT_USES_OEM_PROPS)
Tianjie Xu0fde41e2020-05-09 05:24:18 +0000573 source_info_dict['build.prop'].build_props['ro.build.thumbprint'] = (
Tao Bao1c320f82019-10-04 23:25:12 -0700574 'source-build-thumbprint')
575 source_info = common.BuildInfo(source_info_dict, self.TEST_OEM_DICTS)
576
577 script_writer = test_utils.MockScriptWriter()
578 WriteFingerprintAssertion(script_writer, target_info, source_info)
579 self.assertEqual(
580 [('AssertSomeThumbprint', 'build-thumbprint',
581 'source-build-thumbprint')],
582 script_writer.lines)
583
Tao Baoae5e4c32018-03-01 19:30:00 -0800584
Tao Bao69203522018-03-08 16:09:01 -0800585class TestPropertyFiles(PropertyFiles):
586 """A class that extends PropertyFiles for testing purpose."""
587
588 def __init__(self):
589 super(TestPropertyFiles, self).__init__()
590 self.name = 'ota-test-property-files'
591 self.required = (
592 'required-entry1',
593 'required-entry2',
594 )
595 self.optional = (
596 'optional-entry1',
597 'optional-entry2',
598 )
599
600
Tao Bao65b94e92018-10-11 21:57:26 -0700601class PropertyFilesTest(test_utils.ReleaseToolsTestCase):
Tao Baoae5e4c32018-03-01 19:30:00 -0800602
Tao Bao3bf8c652018-03-16 12:59:42 -0700603 def setUp(self):
604 common.OPTIONS.no_signing = False
605
Tao Baof5110492018-03-02 09:47:43 -0800606 @staticmethod
Tao Bao3bf8c652018-03-16 12:59:42 -0700607 def construct_zip_package(entries):
Tao Baof5110492018-03-02 09:47:43 -0800608 zip_file = common.MakeTempFile(suffix='.zip')
609 with zipfile.ZipFile(zip_file, 'w') as zip_fp:
610 for entry in entries:
611 zip_fp.writestr(
612 entry,
613 entry.replace('.', '-').upper(),
614 zipfile.ZIP_STORED)
615 return zip_file
616
617 @staticmethod
Tao Bao69203522018-03-08 16:09:01 -0800618 def _parse_property_files_string(data):
Tao Baof5110492018-03-02 09:47:43 -0800619 result = {}
620 for token in data.split(','):
621 name, info = token.split(':', 1)
622 result[name] = info
623 return result
624
625 def _verify_entries(self, input_file, tokens, entries):
626 for entry in entries:
627 offset, size = map(int, tokens[entry].split(':'))
628 with open(input_file, 'rb') as input_fp:
629 input_fp.seek(offset)
630 if entry == 'metadata':
631 expected = b'META-INF/COM/ANDROID/METADATA'
632 else:
633 expected = entry.replace('.', '-').upper().encode()
634 self.assertEqual(expected, input_fp.read(size))
635
Tao Bao82490d32019-04-09 00:12:30 -0700636 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoae5e4c32018-03-01 19:30:00 -0800637 def test_Compute(self):
Tao Baof5110492018-03-02 09:47:43 -0800638 entries = (
Tao Bao69203522018-03-08 16:09:01 -0800639 'required-entry1',
640 'required-entry2',
Tao Baof5110492018-03-02 09:47:43 -0800641 )
Tao Bao3bf8c652018-03-16 12:59:42 -0700642 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800643 property_files = TestPropertyFiles()
Tao Baof5110492018-03-02 09:47:43 -0800644 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
Tao Bao69203522018-03-08 16:09:01 -0800645 property_files_string = property_files.Compute(zip_fp)
Tao Baof5110492018-03-02 09:47:43 -0800646
Tao Bao69203522018-03-08 16:09:01 -0800647 tokens = self._parse_property_files_string(property_files_string)
Tao Baof5110492018-03-02 09:47:43 -0800648 self.assertEqual(3, len(tokens))
649 self._verify_entries(zip_file, tokens, entries)
650
Tao Bao69203522018-03-08 16:09:01 -0800651 def test_Compute_withOptionalEntries(self):
Tao Baof5110492018-03-02 09:47:43 -0800652 entries = (
Tao Bao69203522018-03-08 16:09:01 -0800653 'required-entry1',
654 'required-entry2',
655 'optional-entry1',
656 'optional-entry2',
Tao Baof5110492018-03-02 09:47:43 -0800657 )
Tao Bao3bf8c652018-03-16 12:59:42 -0700658 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800659 property_files = TestPropertyFiles()
Tao Baof5110492018-03-02 09:47:43 -0800660 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
Tao Bao69203522018-03-08 16:09:01 -0800661 property_files_string = property_files.Compute(zip_fp)
Tao Baof5110492018-03-02 09:47:43 -0800662
Tao Bao69203522018-03-08 16:09:01 -0800663 tokens = self._parse_property_files_string(property_files_string)
Tao Baof5110492018-03-02 09:47:43 -0800664 self.assertEqual(5, len(tokens))
665 self._verify_entries(zip_file, tokens, entries)
666
Tao Bao69203522018-03-08 16:09:01 -0800667 def test_Compute_missingRequiredEntry(self):
668 entries = (
669 'required-entry2',
670 )
Tao Bao3bf8c652018-03-16 12:59:42 -0700671 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800672 property_files = TestPropertyFiles()
673 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
674 self.assertRaises(KeyError, property_files.Compute, zip_fp)
675
Tao Bao82490d32019-04-09 00:12:30 -0700676 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoae5e4c32018-03-01 19:30:00 -0800677 def test_Finalize(self):
Tao Baof5110492018-03-02 09:47:43 -0800678 entries = [
Tao Bao69203522018-03-08 16:09:01 -0800679 'required-entry1',
680 'required-entry2',
Tao Baof5110492018-03-02 09:47:43 -0800681 'META-INF/com/android/metadata',
682 ]
Tao Bao3bf8c652018-03-16 12:59:42 -0700683 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800684 property_files = TestPropertyFiles()
Tao Baof5110492018-03-02 09:47:43 -0800685 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -0700686 raw_metadata = property_files.GetPropertyFilesString(
Tao Baoae5e4c32018-03-01 19:30:00 -0800687 zip_fp, reserve_space=False)
688 streaming_metadata = property_files.Finalize(zip_fp, len(raw_metadata))
Tao Bao69203522018-03-08 16:09:01 -0800689 tokens = self._parse_property_files_string(streaming_metadata)
Tao Baof5110492018-03-02 09:47:43 -0800690
691 self.assertEqual(3, len(tokens))
692 # 'META-INF/com/android/metadata' will be key'd as 'metadata' in the
693 # streaming metadata.
694 entries[2] = 'metadata'
695 self._verify_entries(zip_file, tokens, entries)
696
Tao Bao82490d32019-04-09 00:12:30 -0700697 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoae5e4c32018-03-01 19:30:00 -0800698 def test_Finalize_assertReservedLength(self):
Tao Baof5110492018-03-02 09:47:43 -0800699 entries = (
Tao Bao69203522018-03-08 16:09:01 -0800700 'required-entry1',
701 'required-entry2',
702 'optional-entry1',
703 'optional-entry2',
Tao Baof5110492018-03-02 09:47:43 -0800704 'META-INF/com/android/metadata',
705 )
Tao Bao3bf8c652018-03-16 12:59:42 -0700706 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800707 property_files = TestPropertyFiles()
Tao Baof5110492018-03-02 09:47:43 -0800708 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
709 # First get the raw metadata string (i.e. without padding space).
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -0700710 raw_metadata = property_files.GetPropertyFilesString(
Tao Baoae5e4c32018-03-01 19:30:00 -0800711 zip_fp, reserve_space=False)
Tao Baof5110492018-03-02 09:47:43 -0800712 raw_length = len(raw_metadata)
713
714 # Now pass in the exact expected length.
Tao Baoae5e4c32018-03-01 19:30:00 -0800715 streaming_metadata = property_files.Finalize(zip_fp, raw_length)
Tao Baof5110492018-03-02 09:47:43 -0800716 self.assertEqual(raw_length, len(streaming_metadata))
717
718 # Or pass in insufficient length.
719 self.assertRaises(
Tao Bao3bf8c652018-03-16 12:59:42 -0700720 PropertyFiles.InsufficientSpaceException,
Tao Baoae5e4c32018-03-01 19:30:00 -0800721 property_files.Finalize,
Tao Baof5110492018-03-02 09:47:43 -0800722 zip_fp,
Tao Baoae5e4c32018-03-01 19:30:00 -0800723 raw_length - 1)
Tao Baof5110492018-03-02 09:47:43 -0800724
725 # Or pass in a much larger size.
Tao Baoae5e4c32018-03-01 19:30:00 -0800726 streaming_metadata = property_files.Finalize(
Tao Baof5110492018-03-02 09:47:43 -0800727 zip_fp,
Tao Baoae5e4c32018-03-01 19:30:00 -0800728 raw_length + 20)
Tao Baof5110492018-03-02 09:47:43 -0800729 self.assertEqual(raw_length + 20, len(streaming_metadata))
730 self.assertEqual(' ' * 20, streaming_metadata[raw_length:])
731
Tao Baoae5e4c32018-03-01 19:30:00 -0800732 def test_Verify(self):
733 entries = (
Tao Bao69203522018-03-08 16:09:01 -0800734 'required-entry1',
735 'required-entry2',
736 'optional-entry1',
737 'optional-entry2',
738 'META-INF/com/android/metadata',
739 )
Tao Bao3bf8c652018-03-16 12:59:42 -0700740 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800741 property_files = TestPropertyFiles()
742 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
743 # First get the raw metadata string (i.e. without padding space).
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -0700744 raw_metadata = property_files.GetPropertyFilesString(
Tao Bao69203522018-03-08 16:09:01 -0800745 zip_fp, reserve_space=False)
746
747 # Should pass the test if verification passes.
748 property_files.Verify(zip_fp, raw_metadata)
749
750 # Or raise on verification failure.
751 self.assertRaises(
752 AssertionError, property_files.Verify, zip_fp, raw_metadata + 'x')
753
754
755class StreamingPropertyFilesTest(PropertyFilesTest):
756 """Additional sanity checks specialized for StreamingPropertyFiles."""
757
758 def test_init(self):
759 property_files = StreamingPropertyFiles()
760 self.assertEqual('ota-streaming-property-files', property_files.name)
761 self.assertEqual(
762 (
763 'payload.bin',
764 'payload_properties.txt',
765 ),
766 property_files.required)
767 self.assertEqual(
768 (
Tianjie Xu4c05f4a2018-09-14 16:24:41 -0700769 'care_map.pb',
Tao Bao69203522018-03-08 16:09:01 -0800770 'care_map.txt',
771 'compatibility.zip',
772 ),
773 property_files.optional)
774
775 def test_Compute(self):
776 entries = (
Tao Baoae5e4c32018-03-01 19:30:00 -0800777 'payload.bin',
778 'payload_properties.txt',
779 'care_map.txt',
Tao Bao69203522018-03-08 16:09:01 -0800780 'compatibility.zip',
781 )
Tao Bao3bf8c652018-03-16 12:59:42 -0700782 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800783 property_files = StreamingPropertyFiles()
784 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
785 property_files_string = property_files.Compute(zip_fp)
786
787 tokens = self._parse_property_files_string(property_files_string)
788 self.assertEqual(5, len(tokens))
789 self._verify_entries(zip_file, tokens, entries)
790
791 def test_Finalize(self):
792 entries = [
793 'payload.bin',
794 'payload_properties.txt',
795 'care_map.txt',
796 'compatibility.zip',
797 'META-INF/com/android/metadata',
798 ]
Tao Bao3bf8c652018-03-16 12:59:42 -0700799 zip_file = self.construct_zip_package(entries)
Tao Bao69203522018-03-08 16:09:01 -0800800 property_files = StreamingPropertyFiles()
801 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -0700802 raw_metadata = property_files.GetPropertyFilesString(
Tao Bao69203522018-03-08 16:09:01 -0800803 zip_fp, reserve_space=False)
804 streaming_metadata = property_files.Finalize(zip_fp, len(raw_metadata))
805 tokens = self._parse_property_files_string(streaming_metadata)
806
807 self.assertEqual(5, len(tokens))
808 # 'META-INF/com/android/metadata' will be key'd as 'metadata' in the
809 # streaming metadata.
810 entries[4] = 'metadata'
811 self._verify_entries(zip_file, tokens, entries)
812
813 def test_Verify(self):
814 entries = (
815 'payload.bin',
816 'payload_properties.txt',
817 'care_map.txt',
818 'compatibility.zip',
Tao Baoae5e4c32018-03-01 19:30:00 -0800819 'META-INF/com/android/metadata',
820 )
Tao Bao3bf8c652018-03-16 12:59:42 -0700821 zip_file = self.construct_zip_package(entries)
Tao Baoae5e4c32018-03-01 19:30:00 -0800822 property_files = StreamingPropertyFiles()
823 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
824 # First get the raw metadata string (i.e. without padding space).
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -0700825 raw_metadata = property_files.GetPropertyFilesString(
Tao Baoae5e4c32018-03-01 19:30:00 -0800826 zip_fp, reserve_space=False)
827
828 # Should pass the test if verification passes.
829 property_files.Verify(zip_fp, raw_metadata)
830
831 # Or raise on verification failure.
832 self.assertRaises(
833 AssertionError, property_files.Verify, zip_fp, raw_metadata + 'x')
834
Tao Baofabe0832018-01-17 15:52:28 -0800835
Tao Baob6304672018-03-08 16:28:33 -0800836class AbOtaPropertyFilesTest(PropertyFilesTest):
837 """Additional sanity checks specialized for AbOtaPropertyFiles."""
838
839 # The size for payload and metadata signature size.
840 SIGNATURE_SIZE = 256
841
842 def setUp(self):
843 self.testdata_dir = test_utils.get_testdata_dir()
844 self.assertTrue(os.path.exists(self.testdata_dir))
845
846 common.OPTIONS.wipe_user_data = False
847 common.OPTIONS.payload_signer = None
848 common.OPTIONS.payload_signer_args = None
849 common.OPTIONS.package_key = os.path.join(self.testdata_dir, 'testkey')
850 common.OPTIONS.key_passwords = {
851 common.OPTIONS.package_key : None,
852 }
853
854 def test_init(self):
855 property_files = AbOtaPropertyFiles()
856 self.assertEqual('ota-property-files', property_files.name)
857 self.assertEqual(
858 (
859 'payload.bin',
860 'payload_properties.txt',
861 ),
862 property_files.required)
863 self.assertEqual(
864 (
Tianjie Xu4c05f4a2018-09-14 16:24:41 -0700865 'care_map.pb',
Tao Baob6304672018-03-08 16:28:33 -0800866 'care_map.txt',
867 'compatibility.zip',
868 ),
869 property_files.optional)
870
Tao Bao82490d32019-04-09 00:12:30 -0700871 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baob6304672018-03-08 16:28:33 -0800872 def test_GetPayloadMetadataOffsetAndSize(self):
873 target_file = construct_target_files()
874 payload = Payload()
875 payload.Generate(target_file)
876
877 payload_signer = PayloadSigner()
878 payload.Sign(payload_signer)
879
880 output_file = common.MakeTempFile(suffix='.zip')
881 with zipfile.ZipFile(output_file, 'w') as output_zip:
882 payload.WriteToZip(output_zip)
883
884 # Find out the payload metadata offset and size.
885 property_files = AbOtaPropertyFiles()
886 with zipfile.ZipFile(output_file) as input_zip:
887 # pylint: disable=protected-access
888 payload_offset, metadata_total = (
889 property_files._GetPayloadMetadataOffsetAndSize(input_zip))
890
Tianjie Xu21e6deb2019-10-07 18:01:00 -0700891 # The signature proto has the following format (details in
892 # /platform/system/update_engine/update_metadata.proto):
893 # message Signature {
894 # optional uint32 version = 1;
895 # optional bytes data = 2;
896 # optional fixed32 unpadded_signature_size = 3;
897 # }
898 #
899 # According to the protobuf encoding, the tail of the signature message will
900 # be [signature string(256 bytes) + encoding of the fixed32 number 256]. And
901 # 256 is encoded as 'x1d\x00\x01\x00\x00':
902 # [3 (field number) << 3 | 5 (type) + byte reverse of 0x100 (256)].
903 # Details in (https://developers.google.com/protocol-buffers/docs/encoding)
904 signature_tail_length = self.SIGNATURE_SIZE + 5
905 self.assertGreater(metadata_total, signature_tail_length)
Tao Baob6304672018-03-08 16:28:33 -0800906 with open(output_file, 'rb') as verify_fp:
Tianjie Xu21e6deb2019-10-07 18:01:00 -0700907 verify_fp.seek(payload_offset + metadata_total - signature_tail_length)
908 metadata_signature_proto_tail = verify_fp.read(signature_tail_length)
909
910 self.assertEqual(b'\x1d\x00\x01\x00\x00',
911 metadata_signature_proto_tail[-5:])
912 metadata_signature = metadata_signature_proto_tail[:-5]
Tao Baob6304672018-03-08 16:28:33 -0800913
914 # Now we extract the metadata hash via brillo_update_payload script, which
915 # will serve as the oracle result.
916 payload_sig_file = common.MakeTempFile(prefix="sig-", suffix=".bin")
917 metadata_sig_file = common.MakeTempFile(prefix="sig-", suffix=".bin")
918 cmd = ['brillo_update_payload', 'hash',
919 '--unsigned_payload', payload.payload_file,
920 '--signature_size', str(self.SIGNATURE_SIZE),
921 '--metadata_hash_file', metadata_sig_file,
922 '--payload_hash_file', payload_sig_file]
Tao Bao73dd4f42018-10-04 16:25:33 -0700923 proc = common.Run(cmd)
Tao Baob6304672018-03-08 16:28:33 -0800924 stdoutdata, _ = proc.communicate()
925 self.assertEqual(
926 0, proc.returncode,
Tao Bao73dd4f42018-10-04 16:25:33 -0700927 'Failed to run brillo_update_payload:\n{}'.format(stdoutdata))
Tao Baob6304672018-03-08 16:28:33 -0800928
929 signed_metadata_sig_file = payload_signer.Sign(metadata_sig_file)
930
931 # Finally we can compare the two signatures.
932 with open(signed_metadata_sig_file, 'rb') as verify_fp:
933 self.assertEqual(verify_fp.read(), metadata_signature)
934
935 @staticmethod
Tao Bao3bf8c652018-03-16 12:59:42 -0700936 def construct_zip_package_withValidPayload(with_metadata=False):
937 # Cannot use construct_zip_package() since we need a "valid" payload.bin.
Tao Baob6304672018-03-08 16:28:33 -0800938 target_file = construct_target_files()
939 payload = Payload()
940 payload.Generate(target_file)
941
942 payload_signer = PayloadSigner()
943 payload.Sign(payload_signer)
944
945 zip_file = common.MakeTempFile(suffix='.zip')
946 with zipfile.ZipFile(zip_file, 'w') as zip_fp:
947 # 'payload.bin',
948 payload.WriteToZip(zip_fp)
949
950 # Other entries.
951 entries = ['care_map.txt', 'compatibility.zip']
952
953 # Put META-INF/com/android/metadata if needed.
954 if with_metadata:
955 entries.append('META-INF/com/android/metadata')
956
957 for entry in entries:
958 zip_fp.writestr(
959 entry, entry.replace('.', '-').upper(), zipfile.ZIP_STORED)
960
961 return zip_file
962
Tao Bao82490d32019-04-09 00:12:30 -0700963 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baob6304672018-03-08 16:28:33 -0800964 def test_Compute(self):
Tao Bao3bf8c652018-03-16 12:59:42 -0700965 zip_file = self.construct_zip_package_withValidPayload()
Tao Baob6304672018-03-08 16:28:33 -0800966 property_files = AbOtaPropertyFiles()
967 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
968 property_files_string = property_files.Compute(zip_fp)
969
970 tokens = self._parse_property_files_string(property_files_string)
971 # "6" indcludes the four entries above, one metadata entry, and one entry
972 # for payload-metadata.bin.
973 self.assertEqual(6, len(tokens))
974 self._verify_entries(
975 zip_file, tokens, ('care_map.txt', 'compatibility.zip'))
976
Tao Bao82490d32019-04-09 00:12:30 -0700977 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baob6304672018-03-08 16:28:33 -0800978 def test_Finalize(self):
Tao Bao3bf8c652018-03-16 12:59:42 -0700979 zip_file = self.construct_zip_package_withValidPayload(with_metadata=True)
Tao Baob6304672018-03-08 16:28:33 -0800980 property_files = AbOtaPropertyFiles()
981 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -0700982 raw_metadata = property_files.GetPropertyFilesString(
Tao Baob6304672018-03-08 16:28:33 -0800983 zip_fp, reserve_space=False)
984 property_files_string = property_files.Finalize(zip_fp, len(raw_metadata))
985
986 tokens = self._parse_property_files_string(property_files_string)
987 # "6" indcludes the four entries above, one metadata entry, and one entry
988 # for payload-metadata.bin.
989 self.assertEqual(6, len(tokens))
990 self._verify_entries(
991 zip_file, tokens, ('care_map.txt', 'compatibility.zip'))
992
Tao Bao82490d32019-04-09 00:12:30 -0700993 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baob6304672018-03-08 16:28:33 -0800994 def test_Verify(self):
Tao Bao3bf8c652018-03-16 12:59:42 -0700995 zip_file = self.construct_zip_package_withValidPayload(with_metadata=True)
Tao Baob6304672018-03-08 16:28:33 -0800996 property_files = AbOtaPropertyFiles()
997 with zipfile.ZipFile(zip_file, 'r') as zip_fp:
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -0700998 raw_metadata = property_files.GetPropertyFilesString(
Tao Baob6304672018-03-08 16:28:33 -0800999 zip_fp, reserve_space=False)
1000
1001 property_files.Verify(zip_fp, raw_metadata)
1002
1003
Tao Baoc0746f42018-02-21 13:17:22 -08001004class NonAbOtaPropertyFilesTest(PropertyFilesTest):
1005 """Additional sanity checks specialized for NonAbOtaPropertyFiles."""
1006
1007 def test_init(self):
1008 property_files = NonAbOtaPropertyFiles()
1009 self.assertEqual('ota-property-files', property_files.name)
1010 self.assertEqual((), property_files.required)
1011 self.assertEqual((), property_files.optional)
1012
1013 def test_Compute(self):
1014 entries = ()
Tao Bao3bf8c652018-03-16 12:59:42 -07001015 zip_file = self.construct_zip_package(entries)
Tao Baoc0746f42018-02-21 13:17:22 -08001016 property_files = NonAbOtaPropertyFiles()
1017 with zipfile.ZipFile(zip_file) as zip_fp:
1018 property_files_string = property_files.Compute(zip_fp)
1019
1020 tokens = self._parse_property_files_string(property_files_string)
1021 self.assertEqual(1, len(tokens))
1022 self._verify_entries(zip_file, tokens, entries)
1023
1024 def test_Finalize(self):
1025 entries = [
1026 'META-INF/com/android/metadata',
1027 ]
Tao Bao3bf8c652018-03-16 12:59:42 -07001028 zip_file = self.construct_zip_package(entries)
Tao Baoc0746f42018-02-21 13:17:22 -08001029 property_files = NonAbOtaPropertyFiles()
1030 with zipfile.ZipFile(zip_file) as zip_fp:
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -07001031 raw_metadata = property_files.GetPropertyFilesString(
Tao Baoc0746f42018-02-21 13:17:22 -08001032 zip_fp, reserve_space=False)
1033 property_files_string = property_files.Finalize(zip_fp, len(raw_metadata))
1034 tokens = self._parse_property_files_string(property_files_string)
1035
1036 self.assertEqual(1, len(tokens))
1037 # 'META-INF/com/android/metadata' will be key'd as 'metadata'.
1038 entries[0] = 'metadata'
1039 self._verify_entries(zip_file, tokens, entries)
1040
1041 def test_Verify(self):
1042 entries = (
1043 'META-INF/com/android/metadata',
1044 )
Tao Bao3bf8c652018-03-16 12:59:42 -07001045 zip_file = self.construct_zip_package(entries)
Tao Baoc0746f42018-02-21 13:17:22 -08001046 property_files = NonAbOtaPropertyFiles()
1047 with zipfile.ZipFile(zip_file) as zip_fp:
Zhomart Mukhamejanov603655f2018-05-04 12:35:09 -07001048 raw_metadata = property_files.GetPropertyFilesString(
Tao Baoc0746f42018-02-21 13:17:22 -08001049 zip_fp, reserve_space=False)
1050
1051 property_files.Verify(zip_fp, raw_metadata)
1052
1053
Tao Bao65b94e92018-10-11 21:57:26 -07001054class PayloadSignerTest(test_utils.ReleaseToolsTestCase):
Tao Baofabe0832018-01-17 15:52:28 -08001055
1056 SIGFILE = 'sigfile.bin'
1057 SIGNED_SIGFILE = 'signed-sigfile.bin'
1058
1059 def setUp(self):
Tao Bao04e1f012018-02-04 12:13:35 -08001060 self.testdata_dir = test_utils.get_testdata_dir()
Tao Baofabe0832018-01-17 15:52:28 -08001061 self.assertTrue(os.path.exists(self.testdata_dir))
1062
1063 common.OPTIONS.payload_signer = None
1064 common.OPTIONS.payload_signer_args = []
1065 common.OPTIONS.package_key = os.path.join(self.testdata_dir, 'testkey')
1066 common.OPTIONS.key_passwords = {
1067 common.OPTIONS.package_key : None,
1068 }
1069
Tao Baofabe0832018-01-17 15:52:28 -08001070 def _assertFilesEqual(self, file1, file2):
1071 with open(file1, 'rb') as fp1, open(file2, 'rb') as fp2:
1072 self.assertEqual(fp1.read(), fp2.read())
1073
Tianjie Xu21e6deb2019-10-07 18:01:00 -07001074 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baofabe0832018-01-17 15:52:28 -08001075 def test_init(self):
1076 payload_signer = PayloadSigner()
1077 self.assertEqual('openssl', payload_signer.signer)
Tianjie Xu21e6deb2019-10-07 18:01:00 -07001078 self.assertEqual(256, payload_signer.maximum_signature_size)
Tao Baofabe0832018-01-17 15:52:28 -08001079
Tianjie Xu21e6deb2019-10-07 18:01:00 -07001080 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baofabe0832018-01-17 15:52:28 -08001081 def test_init_withPassword(self):
1082 common.OPTIONS.package_key = os.path.join(
1083 self.testdata_dir, 'testkey_with_passwd')
1084 common.OPTIONS.key_passwords = {
1085 common.OPTIONS.package_key : 'foo',
1086 }
1087 payload_signer = PayloadSigner()
1088 self.assertEqual('openssl', payload_signer.signer)
1089
1090 def test_init_withExternalSigner(self):
1091 common.OPTIONS.payload_signer = 'abc'
1092 common.OPTIONS.payload_signer_args = ['arg1', 'arg2']
Tianjie Xu21e6deb2019-10-07 18:01:00 -07001093 common.OPTIONS.payload_signer_maximum_signature_size = '512'
Tao Baofabe0832018-01-17 15:52:28 -08001094 payload_signer = PayloadSigner()
1095 self.assertEqual('abc', payload_signer.signer)
1096 self.assertEqual(['arg1', 'arg2'], payload_signer.signer_args)
Tianjie Xu21e6deb2019-10-07 18:01:00 -07001097 self.assertEqual(512, payload_signer.maximum_signature_size)
xunchang376cc7c2019-04-08 23:04:58 -07001098
Tianjie Xu21e6deb2019-10-07 18:01:00 -07001099 @test_utils.SkipIfExternalToolsUnavailable()
1100 def test_GetMaximumSignatureSizeInBytes_512Bytes(self):
xunchang376cc7c2019-04-08 23:04:58 -07001101 signing_key = os.path.join(self.testdata_dir, 'testkey_RSA4096.key')
Tao Bao82490d32019-04-09 00:12:30 -07001102 # pylint: disable=protected-access
Tianjie Xu21e6deb2019-10-07 18:01:00 -07001103 signature_size = PayloadSigner._GetMaximumSignatureSizeInBytes(signing_key)
1104 self.assertEqual(512, signature_size)
Tao Baofabe0832018-01-17 15:52:28 -08001105
Tianjie Xu21e6deb2019-10-07 18:01:00 -07001106 @test_utils.SkipIfExternalToolsUnavailable()
1107 def test_GetMaximumSignatureSizeInBytes_ECKey(self):
1108 signing_key = os.path.join(self.testdata_dir, 'testkey_EC.key')
1109 # pylint: disable=protected-access
1110 signature_size = PayloadSigner._GetMaximumSignatureSizeInBytes(signing_key)
1111 self.assertEqual(72, signature_size)
1112
1113 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baofabe0832018-01-17 15:52:28 -08001114 def test_Sign(self):
1115 payload_signer = PayloadSigner()
1116 input_file = os.path.join(self.testdata_dir, self.SIGFILE)
1117 signed_file = payload_signer.Sign(input_file)
1118
1119 verify_file = os.path.join(self.testdata_dir, self.SIGNED_SIGFILE)
1120 self._assertFilesEqual(verify_file, signed_file)
1121
1122 def test_Sign_withExternalSigner_openssl(self):
1123 """Uses openssl as the external payload signer."""
1124 common.OPTIONS.payload_signer = 'openssl'
1125 common.OPTIONS.payload_signer_args = [
1126 'pkeyutl', '-sign', '-keyform', 'DER', '-inkey',
1127 os.path.join(self.testdata_dir, 'testkey.pk8'),
1128 '-pkeyopt', 'digest:sha256']
1129 payload_signer = PayloadSigner()
1130 input_file = os.path.join(self.testdata_dir, self.SIGFILE)
1131 signed_file = payload_signer.Sign(input_file)
1132
1133 verify_file = os.path.join(self.testdata_dir, self.SIGNED_SIGFILE)
1134 self._assertFilesEqual(verify_file, signed_file)
1135
1136 def test_Sign_withExternalSigner_script(self):
1137 """Uses testdata/payload_signer.sh as the external payload signer."""
1138 common.OPTIONS.payload_signer = os.path.join(
1139 self.testdata_dir, 'payload_signer.sh')
Tao Bao30e31142019-04-09 00:12:30 -07001140 os.chmod(common.OPTIONS.payload_signer, 0o700)
Tao Baofabe0832018-01-17 15:52:28 -08001141 common.OPTIONS.payload_signer_args = [
1142 os.path.join(self.testdata_dir, 'testkey.pk8')]
1143 payload_signer = PayloadSigner()
1144 input_file = os.path.join(self.testdata_dir, self.SIGFILE)
1145 signed_file = payload_signer.Sign(input_file)
1146
1147 verify_file = os.path.join(self.testdata_dir, self.SIGNED_SIGFILE)
1148 self._assertFilesEqual(verify_file, signed_file)
Tao Baoc7b403a2018-01-30 18:19:04 -08001149
1150
Tao Bao65b94e92018-10-11 21:57:26 -07001151class PayloadTest(test_utils.ReleaseToolsTestCase):
Tao Baoc7b403a2018-01-30 18:19:04 -08001152
1153 def setUp(self):
Tao Bao04e1f012018-02-04 12:13:35 -08001154 self.testdata_dir = test_utils.get_testdata_dir()
Tao Baoc7b403a2018-01-30 18:19:04 -08001155 self.assertTrue(os.path.exists(self.testdata_dir))
1156
1157 common.OPTIONS.wipe_user_data = False
1158 common.OPTIONS.payload_signer = None
1159 common.OPTIONS.payload_signer_args = None
1160 common.OPTIONS.package_key = os.path.join(self.testdata_dir, 'testkey')
1161 common.OPTIONS.key_passwords = {
1162 common.OPTIONS.package_key : None,
1163 }
1164
Tao Baoc7b403a2018-01-30 18:19:04 -08001165 @staticmethod
Tao Baof7140c02018-01-30 17:09:24 -08001166 def _create_payload_full(secondary=False):
1167 target_file = construct_target_files(secondary)
Tao Bao667ff572018-02-10 00:02:40 -08001168 payload = Payload(secondary)
Tao Baoc7b403a2018-01-30 18:19:04 -08001169 payload.Generate(target_file)
1170 return payload
1171
Tao Baof7140c02018-01-30 17:09:24 -08001172 @staticmethod
1173 def _create_payload_incremental():
1174 target_file = construct_target_files()
1175 source_file = construct_target_files()
Tao Baoc7b403a2018-01-30 18:19:04 -08001176 payload = Payload()
1177 payload.Generate(target_file, source_file)
1178 return payload
1179
Tao Bao82490d32019-04-09 00:12:30 -07001180 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001181 def test_Generate_full(self):
1182 payload = self._create_payload_full()
1183 self.assertTrue(os.path.exists(payload.payload_file))
1184
Tao Bao82490d32019-04-09 00:12:30 -07001185 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001186 def test_Generate_incremental(self):
1187 payload = self._create_payload_incremental()
1188 self.assertTrue(os.path.exists(payload.payload_file))
1189
Tao Bao82490d32019-04-09 00:12:30 -07001190 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001191 def test_Generate_additionalArgs(self):
Tao Baof7140c02018-01-30 17:09:24 -08001192 target_file = construct_target_files()
1193 source_file = construct_target_files()
Tao Baoc7b403a2018-01-30 18:19:04 -08001194 payload = Payload()
1195 # This should work the same as calling payload.Generate(target_file,
1196 # source_file).
1197 payload.Generate(
1198 target_file, additional_args=["--source_image", source_file])
1199 self.assertTrue(os.path.exists(payload.payload_file))
1200
Tao Bao82490d32019-04-09 00:12:30 -07001201 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001202 def test_Generate_invalidInput(self):
Tao Baof7140c02018-01-30 17:09:24 -08001203 target_file = construct_target_files()
Tao Baoc7b403a2018-01-30 18:19:04 -08001204 common.ZipDelete(target_file, 'IMAGES/vendor.img')
1205 payload = Payload()
Tao Baobec89c12018-10-15 11:53:28 -07001206 self.assertRaises(common.ExternalError, payload.Generate, target_file)
Tao Baoc7b403a2018-01-30 18:19:04 -08001207
Tao Bao82490d32019-04-09 00:12:30 -07001208 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001209 def test_Sign_full(self):
1210 payload = self._create_payload_full()
1211 payload.Sign(PayloadSigner())
1212
1213 output_file = common.MakeTempFile(suffix='.zip')
1214 with zipfile.ZipFile(output_file, 'w') as output_zip:
1215 payload.WriteToZip(output_zip)
1216
1217 import check_ota_package_signature
1218 check_ota_package_signature.VerifyAbOtaPayload(
1219 os.path.join(self.testdata_dir, 'testkey.x509.pem'),
1220 output_file)
1221
Tao Bao82490d32019-04-09 00:12:30 -07001222 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001223 def test_Sign_incremental(self):
1224 payload = self._create_payload_incremental()
1225 payload.Sign(PayloadSigner())
1226
1227 output_file = common.MakeTempFile(suffix='.zip')
1228 with zipfile.ZipFile(output_file, 'w') as output_zip:
1229 payload.WriteToZip(output_zip)
1230
1231 import check_ota_package_signature
1232 check_ota_package_signature.VerifyAbOtaPayload(
1233 os.path.join(self.testdata_dir, 'testkey.x509.pem'),
1234 output_file)
1235
Tao Bao82490d32019-04-09 00:12:30 -07001236 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001237 def test_Sign_withDataWipe(self):
1238 common.OPTIONS.wipe_user_data = True
1239 payload = self._create_payload_full()
1240 payload.Sign(PayloadSigner())
1241
1242 with open(payload.payload_properties) as properties_fp:
1243 self.assertIn("POWERWASH=1", properties_fp.read())
1244
Tao Bao82490d32019-04-09 00:12:30 -07001245 @test_utils.SkipIfExternalToolsUnavailable()
Tao Bao667ff572018-02-10 00:02:40 -08001246 def test_Sign_secondary(self):
1247 payload = self._create_payload_full(secondary=True)
1248 payload.Sign(PayloadSigner())
1249
1250 with open(payload.payload_properties) as properties_fp:
1251 self.assertIn("SWITCH_SLOT_ON_REBOOT=0", properties_fp.read())
1252
Tao Bao82490d32019-04-09 00:12:30 -07001253 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001254 def test_Sign_badSigner(self):
1255 """Tests that signing failure can be captured."""
1256 payload = self._create_payload_full()
1257 payload_signer = PayloadSigner()
1258 payload_signer.signer_args.append('bad-option')
Tao Baobec89c12018-10-15 11:53:28 -07001259 self.assertRaises(common.ExternalError, payload.Sign, payload_signer)
Tao Baoc7b403a2018-01-30 18:19:04 -08001260
Tao Bao82490d32019-04-09 00:12:30 -07001261 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001262 def test_WriteToZip(self):
1263 payload = self._create_payload_full()
1264 payload.Sign(PayloadSigner())
1265
1266 output_file = common.MakeTempFile(suffix='.zip')
1267 with zipfile.ZipFile(output_file, 'w') as output_zip:
1268 payload.WriteToZip(output_zip)
1269
1270 with zipfile.ZipFile(output_file) as verify_zip:
1271 # First make sure we have the essential entries.
1272 namelist = verify_zip.namelist()
1273 self.assertIn(Payload.PAYLOAD_BIN, namelist)
1274 self.assertIn(Payload.PAYLOAD_PROPERTIES_TXT, namelist)
1275
1276 # Then assert these entries are stored.
1277 for entry_info in verify_zip.infolist():
1278 if entry_info.filename not in (Payload.PAYLOAD_BIN,
1279 Payload.PAYLOAD_PROPERTIES_TXT):
1280 continue
1281 self.assertEqual(zipfile.ZIP_STORED, entry_info.compress_type)
1282
Tao Bao82490d32019-04-09 00:12:30 -07001283 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc7b403a2018-01-30 18:19:04 -08001284 def test_WriteToZip_unsignedPayload(self):
1285 """Unsigned payloads should not be allowed to be written to zip."""
1286 payload = self._create_payload_full()
1287
1288 output_file = common.MakeTempFile(suffix='.zip')
1289 with zipfile.ZipFile(output_file, 'w') as output_zip:
1290 self.assertRaises(AssertionError, payload.WriteToZip, output_zip)
1291
1292 # Also test with incremental payload.
1293 payload = self._create_payload_incremental()
1294
1295 output_file = common.MakeTempFile(suffix='.zip')
1296 with zipfile.ZipFile(output_file, 'w') as output_zip:
1297 self.assertRaises(AssertionError, payload.WriteToZip, output_zip)
Tao Baof7140c02018-01-30 17:09:24 -08001298
Tao Bao82490d32019-04-09 00:12:30 -07001299 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baof7140c02018-01-30 17:09:24 -08001300 def test_WriteToZip_secondary(self):
1301 payload = self._create_payload_full(secondary=True)
1302 payload.Sign(PayloadSigner())
1303
1304 output_file = common.MakeTempFile(suffix='.zip')
1305 with zipfile.ZipFile(output_file, 'w') as output_zip:
Tao Bao667ff572018-02-10 00:02:40 -08001306 payload.WriteToZip(output_zip)
Tao Baof7140c02018-01-30 17:09:24 -08001307
1308 with zipfile.ZipFile(output_file) as verify_zip:
1309 # First make sure we have the essential entries.
1310 namelist = verify_zip.namelist()
1311 self.assertIn(Payload.SECONDARY_PAYLOAD_BIN, namelist)
1312 self.assertIn(Payload.SECONDARY_PAYLOAD_PROPERTIES_TXT, namelist)
1313
1314 # Then assert these entries are stored.
1315 for entry_info in verify_zip.infolist():
1316 if entry_info.filename not in (
1317 Payload.SECONDARY_PAYLOAD_BIN,
1318 Payload.SECONDARY_PAYLOAD_PROPERTIES_TXT):
1319 continue
1320 self.assertEqual(zipfile.ZIP_STORED, entry_info.compress_type)