xref: /aosp_15_r20/build/make/tools/releasetools/test_common.py (revision 9e94795a3d4ef5c1d47486f9a02bb378756cea8a)
1*9e94795aSAndroid Build Coastguard Worker#
2*9e94795aSAndroid Build Coastguard Worker# Copyright (C) 2015 The Android Open Source Project
3*9e94795aSAndroid Build Coastguard Worker#
4*9e94795aSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
5*9e94795aSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
6*9e94795aSAndroid Build Coastguard Worker# You may obtain a copy of the License at
7*9e94795aSAndroid Build Coastguard Worker#
8*9e94795aSAndroid Build Coastguard Worker#      http://www.apache.org/licenses/LICENSE-2.0
9*9e94795aSAndroid Build Coastguard Worker#
10*9e94795aSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
11*9e94795aSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
12*9e94795aSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*9e94795aSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
14*9e94795aSAndroid Build Coastguard Worker# limitations under the License.
15*9e94795aSAndroid Build Coastguard Worker#
16*9e94795aSAndroid Build Coastguard Worker
17*9e94795aSAndroid Build Coastguard Workerimport copy
18*9e94795aSAndroid Build Coastguard Workerimport os
19*9e94795aSAndroid Build Coastguard Workerimport subprocess
20*9e94795aSAndroid Build Coastguard Workerimport tempfile
21*9e94795aSAndroid Build Coastguard Workerimport unittest
22*9e94795aSAndroid Build Coastguard Workerimport zipfile
23*9e94795aSAndroid Build Coastguard Workerfrom hashlib import sha1
24*9e94795aSAndroid Build Coastguard Workerfrom typing import BinaryIO
25*9e94795aSAndroid Build Coastguard Worker
26*9e94795aSAndroid Build Coastguard Workerimport common
27*9e94795aSAndroid Build Coastguard Workerimport test_utils
28*9e94795aSAndroid Build Coastguard Workerimport validate_target_files
29*9e94795aSAndroid Build Coastguard Workerfrom images import EmptyImage, DataImage
30*9e94795aSAndroid Build Coastguard Workerfrom rangelib import RangeSet
31*9e94795aSAndroid Build Coastguard Worker
32*9e94795aSAndroid Build Coastguard Worker
33*9e94795aSAndroid Build Coastguard WorkerKiB = 1024
34*9e94795aSAndroid Build Coastguard WorkerMiB = 1024 * KiB
35*9e94795aSAndroid Build Coastguard WorkerGiB = 1024 * MiB
36*9e94795aSAndroid Build Coastguard Worker
37*9e94795aSAndroid Build Coastguard Worker
38*9e94795aSAndroid Build Coastguard Workerdef get_2gb_file():
39*9e94795aSAndroid Build Coastguard Worker  size = int(2 * GiB + 1)
40*9e94795aSAndroid Build Coastguard Worker  block_size = 4 * KiB
41*9e94795aSAndroid Build Coastguard Worker  step_size = 4 * MiB
42*9e94795aSAndroid Build Coastguard Worker  tmpfile = tempfile.NamedTemporaryFile()
43*9e94795aSAndroid Build Coastguard Worker  tmpfile.truncate(size)
44*9e94795aSAndroid Build Coastguard Worker  for _ in range(0, size, step_size):
45*9e94795aSAndroid Build Coastguard Worker    tmpfile.write(os.urandom(block_size))
46*9e94795aSAndroid Build Coastguard Worker    tmpfile.seek(step_size - block_size, os.SEEK_CUR)
47*9e94795aSAndroid Build Coastguard Worker  return tmpfile
48*9e94795aSAndroid Build Coastguard Worker
49*9e94795aSAndroid Build Coastguard Worker
50*9e94795aSAndroid Build Coastguard Workerdef hash_file(filename):
51*9e94795aSAndroid Build Coastguard Worker  sha1_hash = sha1()
52*9e94795aSAndroid Build Coastguard Worker  with open(filename, "rb") as fp:
53*9e94795aSAndroid Build Coastguard Worker    for data in iter(lambda: fp.read(4*MiB), b''):
54*9e94795aSAndroid Build Coastguard Worker      sha1_hash.update(data)
55*9e94795aSAndroid Build Coastguard Worker  return sha1_hash
56*9e94795aSAndroid Build Coastguard Worker
57*9e94795aSAndroid Build Coastguard Worker
58*9e94795aSAndroid Build Coastguard Workerclass BuildInfoTest(test_utils.ReleaseToolsTestCase):
59*9e94795aSAndroid Build Coastguard Worker
60*9e94795aSAndroid Build Coastguard Worker  TEST_INFO_FINGERPRINT_DICT = {
61*9e94795aSAndroid Build Coastguard Worker      'build.prop': common.PartitionBuildProps.FromDictionary(
62*9e94795aSAndroid Build Coastguard Worker          'system', {
63*9e94795aSAndroid Build Coastguard Worker              'ro.product.brand': 'product-brand',
64*9e94795aSAndroid Build Coastguard Worker              'ro.product.name': 'product-name',
65*9e94795aSAndroid Build Coastguard Worker              'ro.product.device': 'product-device',
66*9e94795aSAndroid Build Coastguard Worker              'ro.build.version.release': 'version-release',
67*9e94795aSAndroid Build Coastguard Worker              'ro.build.id': 'build-id',
68*9e94795aSAndroid Build Coastguard Worker              'ro.build.version.incremental': 'version-incremental',
69*9e94795aSAndroid Build Coastguard Worker              'ro.build.type': 'build-type',
70*9e94795aSAndroid Build Coastguard Worker              'ro.build.tags': 'build-tags',
71*9e94795aSAndroid Build Coastguard Worker              'ro.build.version.sdk': 30,
72*9e94795aSAndroid Build Coastguard Worker          }
73*9e94795aSAndroid Build Coastguard Worker      ),
74*9e94795aSAndroid Build Coastguard Worker  }
75*9e94795aSAndroid Build Coastguard Worker
76*9e94795aSAndroid Build Coastguard Worker  TEST_INFO_DICT = {
77*9e94795aSAndroid Build Coastguard Worker      'build.prop': common.PartitionBuildProps.FromDictionary(
78*9e94795aSAndroid Build Coastguard Worker          'system', {
79*9e94795aSAndroid Build Coastguard Worker              'ro.product.device': 'product-device',
80*9e94795aSAndroid Build Coastguard Worker              'ro.product.name': 'product-name',
81*9e94795aSAndroid Build Coastguard Worker              'ro.build.fingerprint': 'build-fingerprint',
82*9e94795aSAndroid Build Coastguard Worker              'ro.build.foo': 'build-foo'}
83*9e94795aSAndroid Build Coastguard Worker      ),
84*9e94795aSAndroid Build Coastguard Worker      'system.build.prop': common.PartitionBuildProps.FromDictionary(
85*9e94795aSAndroid Build Coastguard Worker          'system', {
86*9e94795aSAndroid Build Coastguard Worker              'ro.product.system.brand': 'product-brand',
87*9e94795aSAndroid Build Coastguard Worker              'ro.product.system.name': 'product-name',
88*9e94795aSAndroid Build Coastguard Worker              'ro.product.system.device': 'product-device',
89*9e94795aSAndroid Build Coastguard Worker              'ro.system.build.version.release': 'version-release',
90*9e94795aSAndroid Build Coastguard Worker              'ro.system.build.id': 'build-id',
91*9e94795aSAndroid Build Coastguard Worker              'ro.system.build.version.incremental': 'version-incremental',
92*9e94795aSAndroid Build Coastguard Worker              'ro.system.build.type': 'build-type',
93*9e94795aSAndroid Build Coastguard Worker              'ro.system.build.tags': 'build-tags',
94*9e94795aSAndroid Build Coastguard Worker              'ro.system.build.foo': 'build-foo'}
95*9e94795aSAndroid Build Coastguard Worker      ),
96*9e94795aSAndroid Build Coastguard Worker      'vendor.build.prop': common.PartitionBuildProps.FromDictionary(
97*9e94795aSAndroid Build Coastguard Worker          'vendor', {
98*9e94795aSAndroid Build Coastguard Worker              'ro.product.vendor.brand': 'vendor-product-brand',
99*9e94795aSAndroid Build Coastguard Worker              'ro.product.vendor.name': 'vendor-product-name',
100*9e94795aSAndroid Build Coastguard Worker              'ro.product.vendor.device': 'vendor-product-device',
101*9e94795aSAndroid Build Coastguard Worker              'ro.vendor.build.version.release': 'vendor-version-release',
102*9e94795aSAndroid Build Coastguard Worker              'ro.vendor.build.id': 'vendor-build-id',
103*9e94795aSAndroid Build Coastguard Worker              'ro.vendor.build.version.incremental':
104*9e94795aSAndroid Build Coastguard Worker              'vendor-version-incremental',
105*9e94795aSAndroid Build Coastguard Worker              'ro.vendor.build.type': 'vendor-build-type',
106*9e94795aSAndroid Build Coastguard Worker              'ro.vendor.build.tags': 'vendor-build-tags'}
107*9e94795aSAndroid Build Coastguard Worker      ),
108*9e94795aSAndroid Build Coastguard Worker      'property1': 'value1',
109*9e94795aSAndroid Build Coastguard Worker      'property2': 4096,
110*9e94795aSAndroid Build Coastguard Worker  }
111*9e94795aSAndroid Build Coastguard Worker
112*9e94795aSAndroid Build Coastguard Worker  TEST_INFO_DICT_USES_OEM_PROPS = {
113*9e94795aSAndroid Build Coastguard Worker      'build.prop': common.PartitionBuildProps.FromDictionary(
114*9e94795aSAndroid Build Coastguard Worker          'system', {
115*9e94795aSAndroid Build Coastguard Worker              'ro.product.name': 'product-name',
116*9e94795aSAndroid Build Coastguard Worker              'ro.build.thumbprint': 'build-thumbprint',
117*9e94795aSAndroid Build Coastguard Worker              'ro.build.bar': 'build-bar'}
118*9e94795aSAndroid Build Coastguard Worker      ),
119*9e94795aSAndroid Build Coastguard Worker      'vendor.build.prop': common.PartitionBuildProps.FromDictionary(
120*9e94795aSAndroid Build Coastguard Worker          'vendor', {
121*9e94795aSAndroid Build Coastguard Worker              'ro.vendor.build.fingerprint': 'vendor-build-fingerprint'}
122*9e94795aSAndroid Build Coastguard Worker      ),
123*9e94795aSAndroid Build Coastguard Worker      'property1': 'value1',
124*9e94795aSAndroid Build Coastguard Worker      'property2': 4096,
125*9e94795aSAndroid Build Coastguard Worker      'oem_fingerprint_properties': 'ro.product.device ro.product.brand',
126*9e94795aSAndroid Build Coastguard Worker  }
127*9e94795aSAndroid Build Coastguard Worker
128*9e94795aSAndroid Build Coastguard Worker  TEST_OEM_DICTS = [
129*9e94795aSAndroid Build Coastguard Worker      {
130*9e94795aSAndroid Build Coastguard Worker          'ro.product.brand': 'brand1',
131*9e94795aSAndroid Build Coastguard Worker          'ro.product.device': 'device1',
132*9e94795aSAndroid Build Coastguard Worker      },
133*9e94795aSAndroid Build Coastguard Worker      {
134*9e94795aSAndroid Build Coastguard Worker          'ro.product.brand': 'brand2',
135*9e94795aSAndroid Build Coastguard Worker          'ro.product.device': 'device2',
136*9e94795aSAndroid Build Coastguard Worker      },
137*9e94795aSAndroid Build Coastguard Worker      {
138*9e94795aSAndroid Build Coastguard Worker          'ro.product.brand': 'brand3',
139*9e94795aSAndroid Build Coastguard Worker          'ro.product.device': 'device3',
140*9e94795aSAndroid Build Coastguard Worker      },
141*9e94795aSAndroid Build Coastguard Worker  ]
142*9e94795aSAndroid Build Coastguard Worker
143*9e94795aSAndroid Build Coastguard Worker  TEST_INFO_DICT_PROPERTY_SOURCE_ORDER = {
144*9e94795aSAndroid Build Coastguard Worker      'build.prop': common.PartitionBuildProps.FromDictionary(
145*9e94795aSAndroid Build Coastguard Worker          'system', {
146*9e94795aSAndroid Build Coastguard Worker              'ro.build.fingerprint': 'build-fingerprint',
147*9e94795aSAndroid Build Coastguard Worker              'ro.product.property_source_order':
148*9e94795aSAndroid Build Coastguard Worker                  'product,odm,vendor,system_ext,system'}
149*9e94795aSAndroid Build Coastguard Worker      ),
150*9e94795aSAndroid Build Coastguard Worker      'system.build.prop': common.PartitionBuildProps.FromDictionary(
151*9e94795aSAndroid Build Coastguard Worker          'system', {
152*9e94795aSAndroid Build Coastguard Worker              'ro.product.system.device': 'system-product-device'}
153*9e94795aSAndroid Build Coastguard Worker      ),
154*9e94795aSAndroid Build Coastguard Worker      'vendor.build.prop': common.PartitionBuildProps.FromDictionary(
155*9e94795aSAndroid Build Coastguard Worker          'vendor', {
156*9e94795aSAndroid Build Coastguard Worker              'ro.product.vendor.device': 'vendor-product-device'}
157*9e94795aSAndroid Build Coastguard Worker      ),
158*9e94795aSAndroid Build Coastguard Worker  }
159*9e94795aSAndroid Build Coastguard Worker
160*9e94795aSAndroid Build Coastguard Worker  TEST_INFO_DICT_PROPERTY_SOURCE_ORDER_ANDROID_10 = {
161*9e94795aSAndroid Build Coastguard Worker      'build.prop': common.PartitionBuildProps.FromDictionary(
162*9e94795aSAndroid Build Coastguard Worker          'system', {
163*9e94795aSAndroid Build Coastguard Worker              'ro.build.fingerprint': 'build-fingerprint',
164*9e94795aSAndroid Build Coastguard Worker              'ro.product.property_source_order':
165*9e94795aSAndroid Build Coastguard Worker                  'product,product_services,odm,vendor,system',
166*9e94795aSAndroid Build Coastguard Worker              'ro.build.version.release': '10',
167*9e94795aSAndroid Build Coastguard Worker              'ro.build.version.codename': 'REL'}
168*9e94795aSAndroid Build Coastguard Worker      ),
169*9e94795aSAndroid Build Coastguard Worker      'system.build.prop': common.PartitionBuildProps.FromDictionary(
170*9e94795aSAndroid Build Coastguard Worker          'system', {
171*9e94795aSAndroid Build Coastguard Worker              'ro.product.system.device': 'system-product-device'}
172*9e94795aSAndroid Build Coastguard Worker      ),
173*9e94795aSAndroid Build Coastguard Worker      'vendor.build.prop': common.PartitionBuildProps.FromDictionary(
174*9e94795aSAndroid Build Coastguard Worker          'vendor', {
175*9e94795aSAndroid Build Coastguard Worker              'ro.product.vendor.device': 'vendor-product-device'}
176*9e94795aSAndroid Build Coastguard Worker      ),
177*9e94795aSAndroid Build Coastguard Worker  }
178*9e94795aSAndroid Build Coastguard Worker
179*9e94795aSAndroid Build Coastguard Worker  TEST_INFO_DICT_PROPERTY_SOURCE_ORDER_ANDROID_9 = {
180*9e94795aSAndroid Build Coastguard Worker      'build.prop': common.PartitionBuildProps.FromDictionary(
181*9e94795aSAndroid Build Coastguard Worker          'system', {
182*9e94795aSAndroid Build Coastguard Worker              'ro.product.device': 'product-device',
183*9e94795aSAndroid Build Coastguard Worker              'ro.build.fingerprint': 'build-fingerprint',
184*9e94795aSAndroid Build Coastguard Worker              'ro.build.version.release': '9',
185*9e94795aSAndroid Build Coastguard Worker              'ro.build.version.codename': 'REL'}
186*9e94795aSAndroid Build Coastguard Worker      ),
187*9e94795aSAndroid Build Coastguard Worker      'system.build.prop': common.PartitionBuildProps.FromDictionary(
188*9e94795aSAndroid Build Coastguard Worker          'system', {
189*9e94795aSAndroid Build Coastguard Worker              'ro.product.system.device': 'system-product-device'}
190*9e94795aSAndroid Build Coastguard Worker      ),
191*9e94795aSAndroid Build Coastguard Worker      'vendor.build.prop': common.PartitionBuildProps.FromDictionary(
192*9e94795aSAndroid Build Coastguard Worker          'vendor', {
193*9e94795aSAndroid Build Coastguard Worker              'ro.product.vendor.device': 'vendor-product-device'}
194*9e94795aSAndroid Build Coastguard Worker      ),
195*9e94795aSAndroid Build Coastguard Worker  }
196*9e94795aSAndroid Build Coastguard Worker
197*9e94795aSAndroid Build Coastguard Worker  def test_init(self):
198*9e94795aSAndroid Build Coastguard Worker    target_info = common.BuildInfo(self.TEST_INFO_DICT, None)
199*9e94795aSAndroid Build Coastguard Worker    self.assertEqual('product-device', target_info.device)
200*9e94795aSAndroid Build Coastguard Worker    self.assertEqual('build-fingerprint', target_info.fingerprint)
201*9e94795aSAndroid Build Coastguard Worker    self.assertFalse(target_info.is_ab)
202*9e94795aSAndroid Build Coastguard Worker    self.assertIsNone(target_info.oem_props)
203*9e94795aSAndroid Build Coastguard Worker
204*9e94795aSAndroid Build Coastguard Worker  def test_init_with_oem_props(self):
205*9e94795aSAndroid Build Coastguard Worker    target_info = common.BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
206*9e94795aSAndroid Build Coastguard Worker                                   self.TEST_OEM_DICTS)
207*9e94795aSAndroid Build Coastguard Worker    self.assertEqual('device1', target_info.device)
208*9e94795aSAndroid Build Coastguard Worker    self.assertEqual('brand1/product-name/device1:build-thumbprint',
209*9e94795aSAndroid Build Coastguard Worker                     target_info.fingerprint)
210*9e94795aSAndroid Build Coastguard Worker
211*9e94795aSAndroid Build Coastguard Worker    # Swap the order in oem_dicts, which would lead to different BuildInfo.
212*9e94795aSAndroid Build Coastguard Worker    oem_dicts = copy.copy(self.TEST_OEM_DICTS)
213*9e94795aSAndroid Build Coastguard Worker    oem_dicts[0], oem_dicts[2] = oem_dicts[2], oem_dicts[0]
214*9e94795aSAndroid Build Coastguard Worker    target_info = common.BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
215*9e94795aSAndroid Build Coastguard Worker                                   oem_dicts)
216*9e94795aSAndroid Build Coastguard Worker    self.assertEqual('device3', target_info.device)
217*9e94795aSAndroid Build Coastguard Worker    self.assertEqual('brand3/product-name/device3:build-thumbprint',
218*9e94795aSAndroid Build Coastguard Worker                     target_info.fingerprint)
219*9e94795aSAndroid Build Coastguard Worker
220*9e94795aSAndroid Build Coastguard Worker  def test_init_badFingerprint(self):
221*9e94795aSAndroid Build Coastguard Worker    info_dict = copy.deepcopy(self.TEST_INFO_DICT)
222*9e94795aSAndroid Build Coastguard Worker    info_dict['build.prop'].build_props[
223*9e94795aSAndroid Build Coastguard Worker        'ro.build.fingerprint'] = 'bad fingerprint'
224*9e94795aSAndroid Build Coastguard Worker    self.assertRaises(ValueError, common.BuildInfo, info_dict, None)
225*9e94795aSAndroid Build Coastguard Worker
226*9e94795aSAndroid Build Coastguard Worker    info_dict['build.prop'].build_props[
227*9e94795aSAndroid Build Coastguard Worker        'ro.build.fingerprint'] = 'bad\x80fingerprint'
228*9e94795aSAndroid Build Coastguard Worker    self.assertRaises(ValueError, common.BuildInfo, info_dict, None)
229*9e94795aSAndroid Build Coastguard Worker
230*9e94795aSAndroid Build Coastguard Worker  def test_init_goodFingerprint(self):
231*9e94795aSAndroid Build Coastguard Worker    info_dict = copy.deepcopy(self.TEST_INFO_FINGERPRINT_DICT)
232*9e94795aSAndroid Build Coastguard Worker    build_info = common.BuildInfo(info_dict)
233*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(
234*9e94795aSAndroid Build Coastguard Worker        'product-brand/product-name/product-device:version-release/build-id/'
235*9e94795aSAndroid Build Coastguard Worker        'version-incremental:build-type/build-tags', build_info.fingerprint)
236*9e94795aSAndroid Build Coastguard Worker
237*9e94795aSAndroid Build Coastguard Worker    build_props = info_dict['build.prop'].build_props
238*9e94795aSAndroid Build Coastguard Worker    del build_props['ro.build.id']
239*9e94795aSAndroid Build Coastguard Worker    build_props['ro.build.legacy.id'] = 'legacy-build-id'
240*9e94795aSAndroid Build Coastguard Worker    build_info = common.BuildInfo(info_dict, use_legacy_id=True)
241*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(
242*9e94795aSAndroid Build Coastguard Worker        'product-brand/product-name/product-device:version-release/'
243*9e94795aSAndroid Build Coastguard Worker        'legacy-build-id/version-incremental:build-type/build-tags',
244*9e94795aSAndroid Build Coastguard Worker        build_info.fingerprint)
245*9e94795aSAndroid Build Coastguard Worker
246*9e94795aSAndroid Build Coastguard Worker    self.assertRaises(common.ExternalError, common.BuildInfo, info_dict, None,
247*9e94795aSAndroid Build Coastguard Worker                      False)
248*9e94795aSAndroid Build Coastguard Worker
249*9e94795aSAndroid Build Coastguard Worker    info_dict['avb_enable'] = 'true'
250*9e94795aSAndroid Build Coastguard Worker    info_dict['vbmeta_digest'] = 'abcde12345'
251*9e94795aSAndroid Build Coastguard Worker    build_info = common.BuildInfo(info_dict, use_legacy_id=False)
252*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(
253*9e94795aSAndroid Build Coastguard Worker        'product-brand/product-name/product-device:version-release/'
254*9e94795aSAndroid Build Coastguard Worker        'legacy-build-id.abcde123/version-incremental:build-type/build-tags',
255*9e94795aSAndroid Build Coastguard Worker        build_info.fingerprint)
256*9e94795aSAndroid Build Coastguard Worker
257*9e94795aSAndroid Build Coastguard Worker  def test___getitem__(self):
258*9e94795aSAndroid Build Coastguard Worker    target_info = common.BuildInfo(self.TEST_INFO_DICT, None)
259*9e94795aSAndroid Build Coastguard Worker    self.assertEqual('value1', target_info['property1'])
260*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(4096, target_info['property2'])
261*9e94795aSAndroid Build Coastguard Worker    self.assertEqual('build-foo',
262*9e94795aSAndroid Build Coastguard Worker                     target_info['build.prop'].GetProp('ro.build.foo'))
263*9e94795aSAndroid Build Coastguard Worker
264*9e94795aSAndroid Build Coastguard Worker  def test___getitem__with_oem_props(self):
265*9e94795aSAndroid Build Coastguard Worker    target_info = common.BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
266*9e94795aSAndroid Build Coastguard Worker                                   self.TEST_OEM_DICTS)
267*9e94795aSAndroid Build Coastguard Worker    self.assertEqual('value1', target_info['property1'])
268*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(4096, target_info['property2'])
269*9e94795aSAndroid Build Coastguard Worker    self.assertIsNone(target_info['build.prop'].GetProp('ro.build.foo'))
270*9e94795aSAndroid Build Coastguard Worker
271*9e94795aSAndroid Build Coastguard Worker  def test___setitem__(self):
272*9e94795aSAndroid Build Coastguard Worker    target_info = common.BuildInfo(copy.deepcopy(self.TEST_INFO_DICT), None)
273*9e94795aSAndroid Build Coastguard Worker    self.assertEqual('value1', target_info['property1'])
274*9e94795aSAndroid Build Coastguard Worker    target_info['property1'] = 'value2'
275*9e94795aSAndroid Build Coastguard Worker    self.assertEqual('value2', target_info['property1'])
276*9e94795aSAndroid Build Coastguard Worker
277*9e94795aSAndroid Build Coastguard Worker    self.assertEqual('build-foo',
278*9e94795aSAndroid Build Coastguard Worker                     target_info['build.prop'].GetProp('ro.build.foo'))
279*9e94795aSAndroid Build Coastguard Worker    target_info['build.prop'].build_props['ro.build.foo'] = 'build-bar'
280*9e94795aSAndroid Build Coastguard Worker    self.assertEqual('build-bar',
281*9e94795aSAndroid Build Coastguard Worker                     target_info['build.prop'].GetProp('ro.build.foo'))
282*9e94795aSAndroid Build Coastguard Worker
283*9e94795aSAndroid Build Coastguard Worker  def test_get(self):
284*9e94795aSAndroid Build Coastguard Worker    target_info = common.BuildInfo(self.TEST_INFO_DICT, None)
285*9e94795aSAndroid Build Coastguard Worker    self.assertEqual('value1', target_info.get('property1'))
286*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(4096, target_info.get('property2'))
287*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(4096, target_info.get('property2', 1024))
288*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(1024, target_info.get('property-nonexistent', 1024))
289*9e94795aSAndroid Build Coastguard Worker    self.assertEqual('build-foo',
290*9e94795aSAndroid Build Coastguard Worker                     target_info.get('build.prop').GetProp('ro.build.foo'))
291*9e94795aSAndroid Build Coastguard Worker
292*9e94795aSAndroid Build Coastguard Worker  def test_get_with_oem_props(self):
293*9e94795aSAndroid Build Coastguard Worker    target_info = common.BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
294*9e94795aSAndroid Build Coastguard Worker                                   self.TEST_OEM_DICTS)
295*9e94795aSAndroid Build Coastguard Worker    self.assertEqual('value1', target_info.get('property1'))
296*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(4096, target_info.get('property2'))
297*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(4096, target_info.get('property2', 1024))
298*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(1024, target_info.get('property-nonexistent', 1024))
299*9e94795aSAndroid Build Coastguard Worker    self.assertIsNone(target_info.get('build.prop').GetProp('ro.build.foo'))
300*9e94795aSAndroid Build Coastguard Worker
301*9e94795aSAndroid Build Coastguard Worker  def test_items(self):
302*9e94795aSAndroid Build Coastguard Worker    target_info = common.BuildInfo(self.TEST_INFO_DICT, None)
303*9e94795aSAndroid Build Coastguard Worker    items = target_info.items()
304*9e94795aSAndroid Build Coastguard Worker    self.assertIn(('property1', 'value1'), items)
305*9e94795aSAndroid Build Coastguard Worker    self.assertIn(('property2', 4096), items)
306*9e94795aSAndroid Build Coastguard Worker
307*9e94795aSAndroid Build Coastguard Worker  def test_GetBuildProp(self):
308*9e94795aSAndroid Build Coastguard Worker    target_info = common.BuildInfo(self.TEST_INFO_DICT, None)
309*9e94795aSAndroid Build Coastguard Worker    self.assertEqual('build-foo', target_info.GetBuildProp('ro.build.foo'))
310*9e94795aSAndroid Build Coastguard Worker    self.assertRaises(common.ExternalError, target_info.GetBuildProp,
311*9e94795aSAndroid Build Coastguard Worker                      'ro.build.nonexistent')
312*9e94795aSAndroid Build Coastguard Worker
313*9e94795aSAndroid Build Coastguard Worker  def test_GetBuildProp_with_oem_props(self):
314*9e94795aSAndroid Build Coastguard Worker    target_info = common.BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
315*9e94795aSAndroid Build Coastguard Worker                                   self.TEST_OEM_DICTS)
316*9e94795aSAndroid Build Coastguard Worker    self.assertEqual('build-bar', target_info.GetBuildProp('ro.build.bar'))
317*9e94795aSAndroid Build Coastguard Worker    self.assertRaises(common.ExternalError, target_info.GetBuildProp,
318*9e94795aSAndroid Build Coastguard Worker                      'ro.build.nonexistent')
319*9e94795aSAndroid Build Coastguard Worker
320*9e94795aSAndroid Build Coastguard Worker  def test_GetPartitionFingerprint(self):
321*9e94795aSAndroid Build Coastguard Worker    target_info = common.BuildInfo(self.TEST_INFO_DICT, None)
322*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(
323*9e94795aSAndroid Build Coastguard Worker        target_info.GetPartitionFingerprint('vendor'),
324*9e94795aSAndroid Build Coastguard Worker        'vendor-product-brand/vendor-product-name/vendor-product-device'
325*9e94795aSAndroid Build Coastguard Worker        ':vendor-version-release/vendor-build-id/vendor-version-incremental'
326*9e94795aSAndroid Build Coastguard Worker        ':vendor-build-type/vendor-build-tags')
327*9e94795aSAndroid Build Coastguard Worker
328*9e94795aSAndroid Build Coastguard Worker  def test_GetPartitionFingerprint_system_other_uses_system(self):
329*9e94795aSAndroid Build Coastguard Worker    target_info = common.BuildInfo(self.TEST_INFO_DICT, None)
330*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(
331*9e94795aSAndroid Build Coastguard Worker        target_info.GetPartitionFingerprint('system_other'),
332*9e94795aSAndroid Build Coastguard Worker        target_info.GetPartitionFingerprint('system'))
333*9e94795aSAndroid Build Coastguard Worker
334*9e94795aSAndroid Build Coastguard Worker  def test_GetPartitionFingerprint_uses_fingerprint_prop_if_available(self):
335*9e94795aSAndroid Build Coastguard Worker    info_dict = copy.deepcopy(self.TEST_INFO_DICT)
336*9e94795aSAndroid Build Coastguard Worker    info_dict['vendor.build.prop'].build_props[
337*9e94795aSAndroid Build Coastguard Worker        'ro.vendor.build.fingerprint'] = 'vendor:fingerprint'
338*9e94795aSAndroid Build Coastguard Worker    target_info = common.BuildInfo(info_dict, None)
339*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(
340*9e94795aSAndroid Build Coastguard Worker        target_info.GetPartitionFingerprint('vendor'),
341*9e94795aSAndroid Build Coastguard Worker        'vendor:fingerprint')
342*9e94795aSAndroid Build Coastguard Worker
343*9e94795aSAndroid Build Coastguard Worker  def test_WriteMountOemScript(self):
344*9e94795aSAndroid Build Coastguard Worker    target_info = common.BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
345*9e94795aSAndroid Build Coastguard Worker                                   self.TEST_OEM_DICTS)
346*9e94795aSAndroid Build Coastguard Worker    script_writer = test_utils.MockScriptWriter()
347*9e94795aSAndroid Build Coastguard Worker    target_info.WriteMountOemScript(script_writer)
348*9e94795aSAndroid Build Coastguard Worker    self.assertEqual([('Mount', '/oem', None)], script_writer.lines)
349*9e94795aSAndroid Build Coastguard Worker
350*9e94795aSAndroid Build Coastguard Worker  def test_WriteDeviceAssertions(self):
351*9e94795aSAndroid Build Coastguard Worker    target_info = common.BuildInfo(self.TEST_INFO_DICT, None)
352*9e94795aSAndroid Build Coastguard Worker    script_writer = test_utils.MockScriptWriter()
353*9e94795aSAndroid Build Coastguard Worker    target_info.WriteDeviceAssertions(script_writer, False)
354*9e94795aSAndroid Build Coastguard Worker    self.assertEqual([('AssertDevice', 'product-device')], script_writer.lines)
355*9e94795aSAndroid Build Coastguard Worker
356*9e94795aSAndroid Build Coastguard Worker  def test_WriteDeviceAssertions_with_oem_props(self):
357*9e94795aSAndroid Build Coastguard Worker    target_info = common.BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
358*9e94795aSAndroid Build Coastguard Worker                                   self.TEST_OEM_DICTS)
359*9e94795aSAndroid Build Coastguard Worker    script_writer = test_utils.MockScriptWriter()
360*9e94795aSAndroid Build Coastguard Worker    target_info.WriteDeviceAssertions(script_writer, False)
361*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(
362*9e94795aSAndroid Build Coastguard Worker        [
363*9e94795aSAndroid Build Coastguard Worker            ('AssertOemProperty', 'ro.product.device',
364*9e94795aSAndroid Build Coastguard Worker             ['device1', 'device2', 'device3'], False),
365*9e94795aSAndroid Build Coastguard Worker            ('AssertOemProperty', 'ro.product.brand',
366*9e94795aSAndroid Build Coastguard Worker             ['brand1', 'brand2', 'brand3'], False),
367*9e94795aSAndroid Build Coastguard Worker        ],
368*9e94795aSAndroid Build Coastguard Worker        script_writer.lines)
369*9e94795aSAndroid Build Coastguard Worker
370*9e94795aSAndroid Build Coastguard Worker  def test_ResolveRoProductProperty_FromVendor(self):
371*9e94795aSAndroid Build Coastguard Worker    info_dict = copy.deepcopy(self.TEST_INFO_DICT_PROPERTY_SOURCE_ORDER)
372*9e94795aSAndroid Build Coastguard Worker    info = common.BuildInfo(info_dict, None)
373*9e94795aSAndroid Build Coastguard Worker    self.assertEqual('vendor-product-device',
374*9e94795aSAndroid Build Coastguard Worker                     info.GetBuildProp('ro.product.device'))
375*9e94795aSAndroid Build Coastguard Worker
376*9e94795aSAndroid Build Coastguard Worker  def test_ResolveRoProductProperty_FromSystem(self):
377*9e94795aSAndroid Build Coastguard Worker    info_dict = copy.deepcopy(self.TEST_INFO_DICT_PROPERTY_SOURCE_ORDER)
378*9e94795aSAndroid Build Coastguard Worker    del info_dict['vendor.build.prop'].build_props['ro.product.vendor.device']
379*9e94795aSAndroid Build Coastguard Worker    info = common.BuildInfo(info_dict, None)
380*9e94795aSAndroid Build Coastguard Worker    self.assertEqual('system-product-device',
381*9e94795aSAndroid Build Coastguard Worker                     info.GetBuildProp('ro.product.device'))
382*9e94795aSAndroid Build Coastguard Worker
383*9e94795aSAndroid Build Coastguard Worker  def test_ResolveRoProductProperty_InvalidPropertySearchOrder(self):
384*9e94795aSAndroid Build Coastguard Worker    info_dict = copy.deepcopy(self.TEST_INFO_DICT_PROPERTY_SOURCE_ORDER)
385*9e94795aSAndroid Build Coastguard Worker    info_dict['build.prop'].build_props[
386*9e94795aSAndroid Build Coastguard Worker        'ro.product.property_source_order'] = 'bad-source'
387*9e94795aSAndroid Build Coastguard Worker    with self.assertRaisesRegexp(common.ExternalError,
388*9e94795aSAndroid Build Coastguard Worker                                 'Invalid ro.product.property_source_order'):
389*9e94795aSAndroid Build Coastguard Worker      info = common.BuildInfo(info_dict, None)
390*9e94795aSAndroid Build Coastguard Worker      info.GetBuildProp('ro.product.device')
391*9e94795aSAndroid Build Coastguard Worker
392*9e94795aSAndroid Build Coastguard Worker  def test_ResolveRoProductProperty_Android10PropertySearchOrder(self):
393*9e94795aSAndroid Build Coastguard Worker    info_dict = copy.deepcopy(
394*9e94795aSAndroid Build Coastguard Worker        self.TEST_INFO_DICT_PROPERTY_SOURCE_ORDER_ANDROID_10)
395*9e94795aSAndroid Build Coastguard Worker    info = common.BuildInfo(info_dict, None)
396*9e94795aSAndroid Build Coastguard Worker    self.assertEqual('vendor-product-device',
397*9e94795aSAndroid Build Coastguard Worker                     info.GetBuildProp('ro.product.device'))
398*9e94795aSAndroid Build Coastguard Worker
399*9e94795aSAndroid Build Coastguard Worker  def test_ResolveRoProductProperty_Android9PropertySearchOrder(self):
400*9e94795aSAndroid Build Coastguard Worker    info_dict = copy.deepcopy(
401*9e94795aSAndroid Build Coastguard Worker        self.TEST_INFO_DICT_PROPERTY_SOURCE_ORDER_ANDROID_9)
402*9e94795aSAndroid Build Coastguard Worker    info = common.BuildInfo(info_dict, None)
403*9e94795aSAndroid Build Coastguard Worker    self.assertEqual('product-device',
404*9e94795aSAndroid Build Coastguard Worker                     info.GetBuildProp('ro.product.device'))
405*9e94795aSAndroid Build Coastguard Worker
406*9e94795aSAndroid Build Coastguard Worker
407*9e94795aSAndroid Build Coastguard Workerclass CommonZipTest(test_utils.ReleaseToolsTestCase):
408*9e94795aSAndroid Build Coastguard Worker
409*9e94795aSAndroid Build Coastguard Worker  def _verify(self, zip_file, zip_file_name, arcname, expected_hash,
410*9e94795aSAndroid Build Coastguard Worker              test_file_name=None, expected_stat=None, expected_mode=0o644,
411*9e94795aSAndroid Build Coastguard Worker              expected_compress_type=zipfile.ZIP_STORED):
412*9e94795aSAndroid Build Coastguard Worker    # Verify the stat if present.
413*9e94795aSAndroid Build Coastguard Worker    if test_file_name is not None:
414*9e94795aSAndroid Build Coastguard Worker      new_stat = os.stat(test_file_name)
415*9e94795aSAndroid Build Coastguard Worker      self.assertEqual(int(expected_stat.st_mode), int(new_stat.st_mode))
416*9e94795aSAndroid Build Coastguard Worker      self.assertEqual(int(expected_stat.st_mtime), int(new_stat.st_mtime))
417*9e94795aSAndroid Build Coastguard Worker
418*9e94795aSAndroid Build Coastguard Worker    # Reopen the zip file to verify.
419*9e94795aSAndroid Build Coastguard Worker    zip_file = zipfile.ZipFile(zip_file_name, "r", allowZip64=True)
420*9e94795aSAndroid Build Coastguard Worker
421*9e94795aSAndroid Build Coastguard Worker    # Verify the timestamp.
422*9e94795aSAndroid Build Coastguard Worker    info = zip_file.getinfo(arcname)
423*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(info.date_time, (2009, 1, 1, 0, 0, 0))
424*9e94795aSAndroid Build Coastguard Worker
425*9e94795aSAndroid Build Coastguard Worker    # Verify the file mode.
426*9e94795aSAndroid Build Coastguard Worker    mode = (info.external_attr >> 16) & 0o777
427*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(mode, expected_mode)
428*9e94795aSAndroid Build Coastguard Worker
429*9e94795aSAndroid Build Coastguard Worker    # Verify the compress type.
430*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(info.compress_type, expected_compress_type)
431*9e94795aSAndroid Build Coastguard Worker
432*9e94795aSAndroid Build Coastguard Worker    # Verify the zip contents.
433*9e94795aSAndroid Build Coastguard Worker    entry = zip_file.open(arcname)
434*9e94795aSAndroid Build Coastguard Worker    sha1_hash = sha1()
435*9e94795aSAndroid Build Coastguard Worker    for chunk in iter(lambda: entry.read(4 * MiB), b''):
436*9e94795aSAndroid Build Coastguard Worker      sha1_hash.update(chunk)
437*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(expected_hash, sha1_hash.hexdigest())
438*9e94795aSAndroid Build Coastguard Worker    self.assertIsNone(zip_file.testzip())
439*9e94795aSAndroid Build Coastguard Worker
440*9e94795aSAndroid Build Coastguard Worker  def _test_ZipWrite(self, contents, extra_zipwrite_args=None):
441*9e94795aSAndroid Build Coastguard Worker    with tempfile.NamedTemporaryFile() as test_file:
442*9e94795aSAndroid Build Coastguard Worker      test_file_name = test_file.name
443*9e94795aSAndroid Build Coastguard Worker      for data in contents:
444*9e94795aSAndroid Build Coastguard Worker        test_file.write(bytes(data))
445*9e94795aSAndroid Build Coastguard Worker      return self._test_ZipWriteFile(test_file_name, extra_zipwrite_args)
446*9e94795aSAndroid Build Coastguard Worker
447*9e94795aSAndroid Build Coastguard Worker  def _test_ZipWriteFile(self, test_file_name, extra_zipwrite_args=None):
448*9e94795aSAndroid Build Coastguard Worker    extra_zipwrite_args = dict(extra_zipwrite_args or {})
449*9e94795aSAndroid Build Coastguard Worker
450*9e94795aSAndroid Build Coastguard Worker    test_file = tempfile.NamedTemporaryFile(delete=False)
451*9e94795aSAndroid Build Coastguard Worker    test_file_name = test_file.name
452*9e94795aSAndroid Build Coastguard Worker
453*9e94795aSAndroid Build Coastguard Worker    zip_file = tempfile.NamedTemporaryFile(delete=False)
454*9e94795aSAndroid Build Coastguard Worker    zip_file_name = zip_file.name
455*9e94795aSAndroid Build Coastguard Worker
456*9e94795aSAndroid Build Coastguard Worker    # File names within an archive strip the leading slash.
457*9e94795aSAndroid Build Coastguard Worker    arcname = extra_zipwrite_args.get("arcname", test_file_name)
458*9e94795aSAndroid Build Coastguard Worker    if arcname[0] == "/":
459*9e94795aSAndroid Build Coastguard Worker      arcname = arcname[1:]
460*9e94795aSAndroid Build Coastguard Worker    sha1_hash = hash_file(test_file_name)
461*9e94795aSAndroid Build Coastguard Worker
462*9e94795aSAndroid Build Coastguard Worker    zip_file.close()
463*9e94795aSAndroid Build Coastguard Worker    zip_file = zipfile.ZipFile(zip_file_name, "w", allowZip64=True)
464*9e94795aSAndroid Build Coastguard Worker
465*9e94795aSAndroid Build Coastguard Worker    try:
466*9e94795aSAndroid Build Coastguard Worker      expected_mode = extra_zipwrite_args.get("perms", 0o644)
467*9e94795aSAndroid Build Coastguard Worker      expected_compress_type = extra_zipwrite_args.get("compress_type",
468*9e94795aSAndroid Build Coastguard Worker                                                       zipfile.ZIP_STORED)
469*9e94795aSAndroid Build Coastguard Worker
470*9e94795aSAndroid Build Coastguard Worker      # Arbitrary timestamp, just to make sure common.ZipWrite() restores
471*9e94795aSAndroid Build Coastguard Worker      # the timestamp after writing.
472*9e94795aSAndroid Build Coastguard Worker      os.utime(test_file_name, (1234567, 1234567))
473*9e94795aSAndroid Build Coastguard Worker      expected_stat = os.stat(test_file_name)
474*9e94795aSAndroid Build Coastguard Worker      common.ZipWrite(zip_file, test_file_name, **extra_zipwrite_args)
475*9e94795aSAndroid Build Coastguard Worker      common.ZipClose(zip_file)
476*9e94795aSAndroid Build Coastguard Worker
477*9e94795aSAndroid Build Coastguard Worker      self._verify(zip_file, zip_file_name, arcname, sha1_hash.hexdigest(),
478*9e94795aSAndroid Build Coastguard Worker                   test_file_name, expected_stat, expected_mode,
479*9e94795aSAndroid Build Coastguard Worker                   expected_compress_type)
480*9e94795aSAndroid Build Coastguard Worker    finally:
481*9e94795aSAndroid Build Coastguard Worker      os.remove(zip_file_name)
482*9e94795aSAndroid Build Coastguard Worker
483*9e94795aSAndroid Build Coastguard Worker  def _test_ZipWriteStr(self, zinfo_or_arcname, contents, extra_args=None):
484*9e94795aSAndroid Build Coastguard Worker    extra_args = dict(extra_args or {})
485*9e94795aSAndroid Build Coastguard Worker
486*9e94795aSAndroid Build Coastguard Worker    zip_file = tempfile.NamedTemporaryFile(delete=False)
487*9e94795aSAndroid Build Coastguard Worker    zip_file_name = zip_file.name
488*9e94795aSAndroid Build Coastguard Worker    zip_file.close()
489*9e94795aSAndroid Build Coastguard Worker
490*9e94795aSAndroid Build Coastguard Worker    zip_file = zipfile.ZipFile(zip_file_name, "w", allowZip64=True)
491*9e94795aSAndroid Build Coastguard Worker
492*9e94795aSAndroid Build Coastguard Worker    try:
493*9e94795aSAndroid Build Coastguard Worker      expected_compress_type = extra_args.get("compress_type",
494*9e94795aSAndroid Build Coastguard Worker                                              zipfile.ZIP_STORED)
495*9e94795aSAndroid Build Coastguard Worker      if not isinstance(zinfo_or_arcname, zipfile.ZipInfo):
496*9e94795aSAndroid Build Coastguard Worker        arcname = zinfo_or_arcname
497*9e94795aSAndroid Build Coastguard Worker        expected_mode = extra_args.get("perms", 0o644)
498*9e94795aSAndroid Build Coastguard Worker      else:
499*9e94795aSAndroid Build Coastguard Worker        arcname = zinfo_or_arcname.filename
500*9e94795aSAndroid Build Coastguard Worker        if zinfo_or_arcname.external_attr:
501*9e94795aSAndroid Build Coastguard Worker          zinfo_perms = zinfo_or_arcname.external_attr >> 16
502*9e94795aSAndroid Build Coastguard Worker        else:
503*9e94795aSAndroid Build Coastguard Worker          zinfo_perms = 0o600
504*9e94795aSAndroid Build Coastguard Worker        expected_mode = extra_args.get("perms", zinfo_perms)
505*9e94795aSAndroid Build Coastguard Worker
506*9e94795aSAndroid Build Coastguard Worker      common.ZipWriteStr(zip_file, zinfo_or_arcname, contents, **extra_args)
507*9e94795aSAndroid Build Coastguard Worker      common.ZipClose(zip_file)
508*9e94795aSAndroid Build Coastguard Worker
509*9e94795aSAndroid Build Coastguard Worker      self._verify(zip_file, zip_file_name, arcname, sha1(contents).hexdigest(),
510*9e94795aSAndroid Build Coastguard Worker                   expected_mode=expected_mode,
511*9e94795aSAndroid Build Coastguard Worker                   expected_compress_type=expected_compress_type)
512*9e94795aSAndroid Build Coastguard Worker    finally:
513*9e94795aSAndroid Build Coastguard Worker      os.remove(zip_file_name)
514*9e94795aSAndroid Build Coastguard Worker
515*9e94795aSAndroid Build Coastguard Worker  def _test_ZipWriteStr_large_file(self, large_file: BinaryIO, small, extra_args=None):
516*9e94795aSAndroid Build Coastguard Worker    extra_args = dict(extra_args or {})
517*9e94795aSAndroid Build Coastguard Worker
518*9e94795aSAndroid Build Coastguard Worker    zip_file = tempfile.NamedTemporaryFile(delete=False)
519*9e94795aSAndroid Build Coastguard Worker    zip_file_name = zip_file.name
520*9e94795aSAndroid Build Coastguard Worker
521*9e94795aSAndroid Build Coastguard Worker    test_file_name = large_file.name
522*9e94795aSAndroid Build Coastguard Worker
523*9e94795aSAndroid Build Coastguard Worker    arcname_large = test_file_name
524*9e94795aSAndroid Build Coastguard Worker    arcname_small = "bar"
525*9e94795aSAndroid Build Coastguard Worker
526*9e94795aSAndroid Build Coastguard Worker    # File names within an archive strip the leading slash.
527*9e94795aSAndroid Build Coastguard Worker    if arcname_large[0] == "/":
528*9e94795aSAndroid Build Coastguard Worker      arcname_large = arcname_large[1:]
529*9e94795aSAndroid Build Coastguard Worker
530*9e94795aSAndroid Build Coastguard Worker    zip_file.close()
531*9e94795aSAndroid Build Coastguard Worker    zip_file = zipfile.ZipFile(zip_file_name, "w", allowZip64=True)
532*9e94795aSAndroid Build Coastguard Worker
533*9e94795aSAndroid Build Coastguard Worker    try:
534*9e94795aSAndroid Build Coastguard Worker      sha1_hash = hash_file(test_file_name)
535*9e94795aSAndroid Build Coastguard Worker
536*9e94795aSAndroid Build Coastguard Worker      # Arbitrary timestamp, just to make sure common.ZipWrite() restores
537*9e94795aSAndroid Build Coastguard Worker      # the timestamp after writing.
538*9e94795aSAndroid Build Coastguard Worker      os.utime(test_file_name, (1234567, 1234567))
539*9e94795aSAndroid Build Coastguard Worker      expected_stat = os.stat(test_file_name)
540*9e94795aSAndroid Build Coastguard Worker      expected_mode = 0o644
541*9e94795aSAndroid Build Coastguard Worker      expected_compress_type = extra_args.get("compress_type",
542*9e94795aSAndroid Build Coastguard Worker                                              zipfile.ZIP_STORED)
543*9e94795aSAndroid Build Coastguard Worker
544*9e94795aSAndroid Build Coastguard Worker      common.ZipWrite(zip_file, test_file_name, **extra_args)
545*9e94795aSAndroid Build Coastguard Worker      common.ZipWriteStr(zip_file, arcname_small, small, **extra_args)
546*9e94795aSAndroid Build Coastguard Worker      common.ZipClose(zip_file)
547*9e94795aSAndroid Build Coastguard Worker
548*9e94795aSAndroid Build Coastguard Worker      # Verify the contents written by ZipWrite().
549*9e94795aSAndroid Build Coastguard Worker      self._verify(zip_file, zip_file_name, arcname_large,
550*9e94795aSAndroid Build Coastguard Worker                   sha1_hash.hexdigest(), test_file_name, expected_stat,
551*9e94795aSAndroid Build Coastguard Worker                   expected_mode, expected_compress_type)
552*9e94795aSAndroid Build Coastguard Worker
553*9e94795aSAndroid Build Coastguard Worker      # Verify the contents written by ZipWriteStr().
554*9e94795aSAndroid Build Coastguard Worker      self._verify(zip_file, zip_file_name, arcname_small,
555*9e94795aSAndroid Build Coastguard Worker                   sha1(small).hexdigest(),
556*9e94795aSAndroid Build Coastguard Worker                   expected_compress_type=expected_compress_type)
557*9e94795aSAndroid Build Coastguard Worker    finally:
558*9e94795aSAndroid Build Coastguard Worker      os.remove(zip_file_name)
559*9e94795aSAndroid Build Coastguard Worker
560*9e94795aSAndroid Build Coastguard Worker  def _test_reset_ZIP64_LIMIT(self, func, *args):
561*9e94795aSAndroid Build Coastguard Worker    default_limit = (1 << 31) - 1
562*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(default_limit, zipfile.ZIP64_LIMIT)
563*9e94795aSAndroid Build Coastguard Worker    func(*args)
564*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(default_limit, zipfile.ZIP64_LIMIT)
565*9e94795aSAndroid Build Coastguard Worker
566*9e94795aSAndroid Build Coastguard Worker  def test_ZipWrite(self):
567*9e94795aSAndroid Build Coastguard Worker    file_contents = os.urandom(1024)
568*9e94795aSAndroid Build Coastguard Worker    self._test_ZipWrite(file_contents)
569*9e94795aSAndroid Build Coastguard Worker
570*9e94795aSAndroid Build Coastguard Worker  def test_ZipWrite_with_opts(self):
571*9e94795aSAndroid Build Coastguard Worker    file_contents = os.urandom(1024)
572*9e94795aSAndroid Build Coastguard Worker    self._test_ZipWrite(file_contents, {
573*9e94795aSAndroid Build Coastguard Worker        "arcname": "foobar",
574*9e94795aSAndroid Build Coastguard Worker        "perms": 0o777,
575*9e94795aSAndroid Build Coastguard Worker        "compress_type": zipfile.ZIP_DEFLATED,
576*9e94795aSAndroid Build Coastguard Worker    })
577*9e94795aSAndroid Build Coastguard Worker    self._test_ZipWrite(file_contents, {
578*9e94795aSAndroid Build Coastguard Worker        "arcname": "foobar",
579*9e94795aSAndroid Build Coastguard Worker        "perms": 0o700,
580*9e94795aSAndroid Build Coastguard Worker        "compress_type": zipfile.ZIP_STORED,
581*9e94795aSAndroid Build Coastguard Worker    })
582*9e94795aSAndroid Build Coastguard Worker
583*9e94795aSAndroid Build Coastguard Worker  def test_ZipWrite_large_file(self):
584*9e94795aSAndroid Build Coastguard Worker    with get_2gb_file() as tmpfile:
585*9e94795aSAndroid Build Coastguard Worker      self._test_ZipWriteFile(tmpfile.name, {
586*9e94795aSAndroid Build Coastguard Worker          "compress_type": zipfile.ZIP_DEFLATED,
587*9e94795aSAndroid Build Coastguard Worker      })
588*9e94795aSAndroid Build Coastguard Worker
589*9e94795aSAndroid Build Coastguard Worker  def test_ZipWrite_resets_ZIP64_LIMIT(self):
590*9e94795aSAndroid Build Coastguard Worker    self._test_reset_ZIP64_LIMIT(self._test_ZipWrite, "")
591*9e94795aSAndroid Build Coastguard Worker
592*9e94795aSAndroid Build Coastguard Worker  def test_ZipWriteStr(self):
593*9e94795aSAndroid Build Coastguard Worker    random_string = os.urandom(1024)
594*9e94795aSAndroid Build Coastguard Worker    # Passing arcname
595*9e94795aSAndroid Build Coastguard Worker    self._test_ZipWriteStr("foo", random_string)
596*9e94795aSAndroid Build Coastguard Worker
597*9e94795aSAndroid Build Coastguard Worker    # Passing zinfo
598*9e94795aSAndroid Build Coastguard Worker    zinfo = zipfile.ZipInfo(filename="foo")
599*9e94795aSAndroid Build Coastguard Worker    self._test_ZipWriteStr(zinfo, random_string)
600*9e94795aSAndroid Build Coastguard Worker
601*9e94795aSAndroid Build Coastguard Worker    # Timestamp in the zinfo should be overwritten.
602*9e94795aSAndroid Build Coastguard Worker    zinfo.date_time = (2015, 3, 1, 15, 30, 0)
603*9e94795aSAndroid Build Coastguard Worker    self._test_ZipWriteStr(zinfo, random_string)
604*9e94795aSAndroid Build Coastguard Worker
605*9e94795aSAndroid Build Coastguard Worker  def test_ZipWriteStr_with_opts(self):
606*9e94795aSAndroid Build Coastguard Worker    random_string = os.urandom(1024)
607*9e94795aSAndroid Build Coastguard Worker    # Passing arcname
608*9e94795aSAndroid Build Coastguard Worker    self._test_ZipWriteStr("foo", random_string, {
609*9e94795aSAndroid Build Coastguard Worker        "perms": 0o700,
610*9e94795aSAndroid Build Coastguard Worker        "compress_type": zipfile.ZIP_DEFLATED,
611*9e94795aSAndroid Build Coastguard Worker    })
612*9e94795aSAndroid Build Coastguard Worker    self._test_ZipWriteStr("bar", random_string, {
613*9e94795aSAndroid Build Coastguard Worker        "compress_type": zipfile.ZIP_STORED,
614*9e94795aSAndroid Build Coastguard Worker    })
615*9e94795aSAndroid Build Coastguard Worker
616*9e94795aSAndroid Build Coastguard Worker    # Passing zinfo
617*9e94795aSAndroid Build Coastguard Worker    zinfo = zipfile.ZipInfo(filename="foo")
618*9e94795aSAndroid Build Coastguard Worker    self._test_ZipWriteStr(zinfo, random_string, {
619*9e94795aSAndroid Build Coastguard Worker        "compress_type": zipfile.ZIP_DEFLATED,
620*9e94795aSAndroid Build Coastguard Worker    })
621*9e94795aSAndroid Build Coastguard Worker    self._test_ZipWriteStr(zinfo, random_string, {
622*9e94795aSAndroid Build Coastguard Worker        "perms": 0o600,
623*9e94795aSAndroid Build Coastguard Worker        "compress_type": zipfile.ZIP_STORED,
624*9e94795aSAndroid Build Coastguard Worker    })
625*9e94795aSAndroid Build Coastguard Worker    self._test_ZipWriteStr(zinfo, random_string, {
626*9e94795aSAndroid Build Coastguard Worker        "perms": 0o000,
627*9e94795aSAndroid Build Coastguard Worker        "compress_type": zipfile.ZIP_STORED,
628*9e94795aSAndroid Build Coastguard Worker    })
629*9e94795aSAndroid Build Coastguard Worker
630*9e94795aSAndroid Build Coastguard Worker  def test_ZipWriteStr_large_file(self):
631*9e94795aSAndroid Build Coastguard Worker    # zipfile.writestr() doesn't work when the str size is over 2GiB even with
632*9e94795aSAndroid Build Coastguard Worker    # the workaround. We will only test the case of writing a string into a
633*9e94795aSAndroid Build Coastguard Worker    # large archive.
634*9e94795aSAndroid Build Coastguard Worker    short_string = os.urandom(1024)
635*9e94795aSAndroid Build Coastguard Worker    with get_2gb_file() as large_file:
636*9e94795aSAndroid Build Coastguard Worker      self._test_ZipWriteStr_large_file(large_file, short_string, {
637*9e94795aSAndroid Build Coastguard Worker          "compress_type": zipfile.ZIP_DEFLATED,
638*9e94795aSAndroid Build Coastguard Worker      })
639*9e94795aSAndroid Build Coastguard Worker
640*9e94795aSAndroid Build Coastguard Worker  def test_ZipWriteStr_resets_ZIP64_LIMIT(self):
641*9e94795aSAndroid Build Coastguard Worker    self._test_reset_ZIP64_LIMIT(self._test_ZipWriteStr, 'foo', b'')
642*9e94795aSAndroid Build Coastguard Worker    zinfo = zipfile.ZipInfo(filename="foo")
643*9e94795aSAndroid Build Coastguard Worker    self._test_reset_ZIP64_LIMIT(self._test_ZipWriteStr, zinfo, b'')
644*9e94795aSAndroid Build Coastguard Worker
645*9e94795aSAndroid Build Coastguard Worker  def test_bug21309935(self):
646*9e94795aSAndroid Build Coastguard Worker    zip_file = tempfile.NamedTemporaryFile(delete=False)
647*9e94795aSAndroid Build Coastguard Worker    zip_file_name = zip_file.name
648*9e94795aSAndroid Build Coastguard Worker    zip_file.close()
649*9e94795aSAndroid Build Coastguard Worker
650*9e94795aSAndroid Build Coastguard Worker    try:
651*9e94795aSAndroid Build Coastguard Worker      random_string = os.urandom(1024)
652*9e94795aSAndroid Build Coastguard Worker      zip_file = zipfile.ZipFile(zip_file_name, "w", allowZip64=True)
653*9e94795aSAndroid Build Coastguard Worker      # Default perms should be 0o644 when passing the filename.
654*9e94795aSAndroid Build Coastguard Worker      common.ZipWriteStr(zip_file, "foo", random_string)
655*9e94795aSAndroid Build Coastguard Worker      # Honor the specified perms.
656*9e94795aSAndroid Build Coastguard Worker      common.ZipWriteStr(zip_file, "bar", random_string, perms=0o755)
657*9e94795aSAndroid Build Coastguard Worker      # The perms in zinfo should be untouched.
658*9e94795aSAndroid Build Coastguard Worker      zinfo = zipfile.ZipInfo(filename="baz")
659*9e94795aSAndroid Build Coastguard Worker      zinfo.external_attr = 0o740 << 16
660*9e94795aSAndroid Build Coastguard Worker      common.ZipWriteStr(zip_file, zinfo, random_string)
661*9e94795aSAndroid Build Coastguard Worker      # Explicitly specified perms has the priority.
662*9e94795aSAndroid Build Coastguard Worker      zinfo = zipfile.ZipInfo(filename="qux")
663*9e94795aSAndroid Build Coastguard Worker      zinfo.external_attr = 0o700 << 16
664*9e94795aSAndroid Build Coastguard Worker      common.ZipWriteStr(zip_file, zinfo, random_string, perms=0o400)
665*9e94795aSAndroid Build Coastguard Worker      common.ZipClose(zip_file)
666*9e94795aSAndroid Build Coastguard Worker
667*9e94795aSAndroid Build Coastguard Worker      self._verify(zip_file, zip_file_name, "foo",
668*9e94795aSAndroid Build Coastguard Worker                   sha1(random_string).hexdigest(),
669*9e94795aSAndroid Build Coastguard Worker                   expected_mode=0o644)
670*9e94795aSAndroid Build Coastguard Worker      self._verify(zip_file, zip_file_name, "bar",
671*9e94795aSAndroid Build Coastguard Worker                   sha1(random_string).hexdigest(),
672*9e94795aSAndroid Build Coastguard Worker                   expected_mode=0o755)
673*9e94795aSAndroid Build Coastguard Worker      self._verify(zip_file, zip_file_name, "baz",
674*9e94795aSAndroid Build Coastguard Worker                   sha1(random_string).hexdigest(),
675*9e94795aSAndroid Build Coastguard Worker                   expected_mode=0o740)
676*9e94795aSAndroid Build Coastguard Worker      self._verify(zip_file, zip_file_name, "qux",
677*9e94795aSAndroid Build Coastguard Worker                   sha1(random_string).hexdigest(),
678*9e94795aSAndroid Build Coastguard Worker                   expected_mode=0o400)
679*9e94795aSAndroid Build Coastguard Worker    finally:
680*9e94795aSAndroid Build Coastguard Worker      os.remove(zip_file_name)
681*9e94795aSAndroid Build Coastguard Worker
682*9e94795aSAndroid Build Coastguard Worker  @test_utils.SkipIfExternalToolsUnavailable()
683*9e94795aSAndroid Build Coastguard Worker  def test_ZipDelete(self):
684*9e94795aSAndroid Build Coastguard Worker    zip_file = tempfile.NamedTemporaryFile(delete=False, suffix='.zip')
685*9e94795aSAndroid Build Coastguard Worker    output_zip = zipfile.ZipFile(zip_file.name, 'w',
686*9e94795aSAndroid Build Coastguard Worker                                 compression=zipfile.ZIP_DEFLATED)
687*9e94795aSAndroid Build Coastguard Worker    with tempfile.NamedTemporaryFile() as entry_file:
688*9e94795aSAndroid Build Coastguard Worker      entry_file.write(os.urandom(1024))
689*9e94795aSAndroid Build Coastguard Worker      common.ZipWrite(output_zip, entry_file.name, arcname='Test1')
690*9e94795aSAndroid Build Coastguard Worker      common.ZipWrite(output_zip, entry_file.name, arcname='Test2')
691*9e94795aSAndroid Build Coastguard Worker      common.ZipWrite(output_zip, entry_file.name, arcname='Test3')
692*9e94795aSAndroid Build Coastguard Worker      common.ZipClose(output_zip)
693*9e94795aSAndroid Build Coastguard Worker    zip_file.close()
694*9e94795aSAndroid Build Coastguard Worker
695*9e94795aSAndroid Build Coastguard Worker    try:
696*9e94795aSAndroid Build Coastguard Worker      common.ZipDelete(zip_file.name, 'Test2')
697*9e94795aSAndroid Build Coastguard Worker      with zipfile.ZipFile(zip_file.name, 'r', allowZip64=True) as check_zip:
698*9e94795aSAndroid Build Coastguard Worker        entries = check_zip.namelist()
699*9e94795aSAndroid Build Coastguard Worker        self.assertTrue('Test1' in entries)
700*9e94795aSAndroid Build Coastguard Worker        self.assertFalse('Test2' in entries)
701*9e94795aSAndroid Build Coastguard Worker        self.assertTrue('Test3' in entries)
702*9e94795aSAndroid Build Coastguard Worker
703*9e94795aSAndroid Build Coastguard Worker      self.assertRaises(
704*9e94795aSAndroid Build Coastguard Worker          common.ExternalError, common.ZipDelete, zip_file.name, 'Test2')
705*9e94795aSAndroid Build Coastguard Worker      with zipfile.ZipFile(zip_file.name, 'r', allowZip64=True) as check_zip:
706*9e94795aSAndroid Build Coastguard Worker        entries = check_zip.namelist()
707*9e94795aSAndroid Build Coastguard Worker        self.assertTrue('Test1' in entries)
708*9e94795aSAndroid Build Coastguard Worker        self.assertFalse('Test2' in entries)
709*9e94795aSAndroid Build Coastguard Worker        self.assertTrue('Test3' in entries)
710*9e94795aSAndroid Build Coastguard Worker
711*9e94795aSAndroid Build Coastguard Worker      common.ZipDelete(zip_file.name, ['Test3'])
712*9e94795aSAndroid Build Coastguard Worker      with zipfile.ZipFile(zip_file.name, 'r', allowZip64=True) as check_zip:
713*9e94795aSAndroid Build Coastguard Worker        entries = check_zip.namelist()
714*9e94795aSAndroid Build Coastguard Worker        self.assertTrue('Test1' in entries)
715*9e94795aSAndroid Build Coastguard Worker        self.assertFalse('Test2' in entries)
716*9e94795aSAndroid Build Coastguard Worker        self.assertFalse('Test3' in entries)
717*9e94795aSAndroid Build Coastguard Worker
718*9e94795aSAndroid Build Coastguard Worker      common.ZipDelete(zip_file.name, ['Test1', 'Test2'])
719*9e94795aSAndroid Build Coastguard Worker      with zipfile.ZipFile(zip_file.name, 'r', allowZip64=True) as check_zip:
720*9e94795aSAndroid Build Coastguard Worker        entries = check_zip.namelist()
721*9e94795aSAndroid Build Coastguard Worker        self.assertFalse('Test1' in entries)
722*9e94795aSAndroid Build Coastguard Worker        self.assertFalse('Test2' in entries)
723*9e94795aSAndroid Build Coastguard Worker        self.assertFalse('Test3' in entries)
724*9e94795aSAndroid Build Coastguard Worker    finally:
725*9e94795aSAndroid Build Coastguard Worker      os.remove(zip_file.name)
726*9e94795aSAndroid Build Coastguard Worker
727*9e94795aSAndroid Build Coastguard Worker  @staticmethod
728*9e94795aSAndroid Build Coastguard Worker  def _test_UnzipTemp_createZipFile():
729*9e94795aSAndroid Build Coastguard Worker    zip_file = common.MakeTempFile(suffix='.zip')
730*9e94795aSAndroid Build Coastguard Worker    output_zip = zipfile.ZipFile(
731*9e94795aSAndroid Build Coastguard Worker        zip_file, 'w', compression=zipfile.ZIP_DEFLATED)
732*9e94795aSAndroid Build Coastguard Worker    contents = os.urandom(1024)
733*9e94795aSAndroid Build Coastguard Worker    with tempfile.NamedTemporaryFile() as entry_file:
734*9e94795aSAndroid Build Coastguard Worker      entry_file.write(contents)
735*9e94795aSAndroid Build Coastguard Worker      common.ZipWrite(output_zip, entry_file.name, arcname='Test1')
736*9e94795aSAndroid Build Coastguard Worker      common.ZipWrite(output_zip, entry_file.name, arcname='Test2')
737*9e94795aSAndroid Build Coastguard Worker      common.ZipWrite(output_zip, entry_file.name, arcname='Foo3')
738*9e94795aSAndroid Build Coastguard Worker      common.ZipWrite(output_zip, entry_file.name, arcname='Bar4')
739*9e94795aSAndroid Build Coastguard Worker      common.ZipWrite(output_zip, entry_file.name, arcname='Dir5/Baz5')
740*9e94795aSAndroid Build Coastguard Worker      common.ZipClose(output_zip)
741*9e94795aSAndroid Build Coastguard Worker    common.ZipClose(output_zip)
742*9e94795aSAndroid Build Coastguard Worker    return zip_file
743*9e94795aSAndroid Build Coastguard Worker
744*9e94795aSAndroid Build Coastguard Worker  @test_utils.SkipIfExternalToolsUnavailable()
745*9e94795aSAndroid Build Coastguard Worker  def test_UnzipTemp(self):
746*9e94795aSAndroid Build Coastguard Worker    zip_file = self._test_UnzipTemp_createZipFile()
747*9e94795aSAndroid Build Coastguard Worker    unzipped_dir = common.UnzipTemp(zip_file)
748*9e94795aSAndroid Build Coastguard Worker    self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Test1')))
749*9e94795aSAndroid Build Coastguard Worker    self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Test2')))
750*9e94795aSAndroid Build Coastguard Worker    self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Foo3')))
751*9e94795aSAndroid Build Coastguard Worker    self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Bar4')))
752*9e94795aSAndroid Build Coastguard Worker    self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Dir5/Baz5')))
753*9e94795aSAndroid Build Coastguard Worker
754*9e94795aSAndroid Build Coastguard Worker  @test_utils.SkipIfExternalToolsUnavailable()
755*9e94795aSAndroid Build Coastguard Worker  def test_UnzipTemp_withPatterns(self):
756*9e94795aSAndroid Build Coastguard Worker    zip_file = self._test_UnzipTemp_createZipFile()
757*9e94795aSAndroid Build Coastguard Worker
758*9e94795aSAndroid Build Coastguard Worker    unzipped_dir = common.UnzipTemp(zip_file, ['Test1'])
759*9e94795aSAndroid Build Coastguard Worker    self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Test1')))
760*9e94795aSAndroid Build Coastguard Worker    self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Test2')))
761*9e94795aSAndroid Build Coastguard Worker    self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Foo3')))
762*9e94795aSAndroid Build Coastguard Worker    self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Bar4')))
763*9e94795aSAndroid Build Coastguard Worker    self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Dir5/Baz5')))
764*9e94795aSAndroid Build Coastguard Worker
765*9e94795aSAndroid Build Coastguard Worker    unzipped_dir = common.UnzipTemp(zip_file, ['Test1', 'Foo3'])
766*9e94795aSAndroid Build Coastguard Worker    self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Test1')))
767*9e94795aSAndroid Build Coastguard Worker    self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Test2')))
768*9e94795aSAndroid Build Coastguard Worker    self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Foo3')))
769*9e94795aSAndroid Build Coastguard Worker    self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Bar4')))
770*9e94795aSAndroid Build Coastguard Worker    self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Dir5/Baz5')))
771*9e94795aSAndroid Build Coastguard Worker
772*9e94795aSAndroid Build Coastguard Worker    unzipped_dir = common.UnzipTemp(zip_file, ['Test*', 'Foo3*'])
773*9e94795aSAndroid Build Coastguard Worker    self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Test1')))
774*9e94795aSAndroid Build Coastguard Worker    self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Test2')))
775*9e94795aSAndroid Build Coastguard Worker    self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Foo3')))
776*9e94795aSAndroid Build Coastguard Worker    self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Bar4')))
777*9e94795aSAndroid Build Coastguard Worker    self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Dir5/Baz5')))
778*9e94795aSAndroid Build Coastguard Worker
779*9e94795aSAndroid Build Coastguard Worker    unzipped_dir = common.UnzipTemp(zip_file, ['*Test1', '*Baz*'])
780*9e94795aSAndroid Build Coastguard Worker    self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Test1')))
781*9e94795aSAndroid Build Coastguard Worker    self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Test2')))
782*9e94795aSAndroid Build Coastguard Worker    self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Foo3')))
783*9e94795aSAndroid Build Coastguard Worker    self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Bar4')))
784*9e94795aSAndroid Build Coastguard Worker    self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Dir5/Baz5')))
785*9e94795aSAndroid Build Coastguard Worker
786*9e94795aSAndroid Build Coastguard Worker  def test_UnzipTemp_withEmptyPatterns(self):
787*9e94795aSAndroid Build Coastguard Worker    zip_file = self._test_UnzipTemp_createZipFile()
788*9e94795aSAndroid Build Coastguard Worker    unzipped_dir = common.UnzipTemp(zip_file, [])
789*9e94795aSAndroid Build Coastguard Worker    self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Test1')))
790*9e94795aSAndroid Build Coastguard Worker    self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Test2')))
791*9e94795aSAndroid Build Coastguard Worker    self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Foo3')))
792*9e94795aSAndroid Build Coastguard Worker    self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Bar4')))
793*9e94795aSAndroid Build Coastguard Worker    self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Dir5/Baz5')))
794*9e94795aSAndroid Build Coastguard Worker
795*9e94795aSAndroid Build Coastguard Worker  @test_utils.SkipIfExternalToolsUnavailable()
796*9e94795aSAndroid Build Coastguard Worker  def test_UnzipTemp_withPartiallyMatchingPatterns(self):
797*9e94795aSAndroid Build Coastguard Worker    zip_file = self._test_UnzipTemp_createZipFile()
798*9e94795aSAndroid Build Coastguard Worker    unzipped_dir = common.UnzipTemp(zip_file, ['Test*', 'Nonexistent*'])
799*9e94795aSAndroid Build Coastguard Worker    self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Test1')))
800*9e94795aSAndroid Build Coastguard Worker    self.assertTrue(os.path.exists(os.path.join(unzipped_dir, 'Test2')))
801*9e94795aSAndroid Build Coastguard Worker    self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Foo3')))
802*9e94795aSAndroid Build Coastguard Worker    self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Bar4')))
803*9e94795aSAndroid Build Coastguard Worker    self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Dir5/Baz5')))
804*9e94795aSAndroid Build Coastguard Worker
805*9e94795aSAndroid Build Coastguard Worker  def test_UnzipTemp_withNoMatchingPatterns(self):
806*9e94795aSAndroid Build Coastguard Worker    zip_file = self._test_UnzipTemp_createZipFile()
807*9e94795aSAndroid Build Coastguard Worker    unzipped_dir = common.UnzipTemp(zip_file, ['Foo4', 'Nonexistent*'])
808*9e94795aSAndroid Build Coastguard Worker    self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Test1')))
809*9e94795aSAndroid Build Coastguard Worker    self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Test2')))
810*9e94795aSAndroid Build Coastguard Worker    self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Foo3')))
811*9e94795aSAndroid Build Coastguard Worker    self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Bar4')))
812*9e94795aSAndroid Build Coastguard Worker    self.assertFalse(os.path.exists(os.path.join(unzipped_dir, 'Dir5/Baz5')))
813*9e94795aSAndroid Build Coastguard Worker
814*9e94795aSAndroid Build Coastguard Worker
815*9e94795aSAndroid Build Coastguard Workerclass CommonApkUtilsTest(test_utils.ReleaseToolsTestCase):
816*9e94795aSAndroid Build Coastguard Worker  """Tests the APK utils related functions."""
817*9e94795aSAndroid Build Coastguard Worker
818*9e94795aSAndroid Build Coastguard Worker  APKCERTS_TXT1 = (
819*9e94795aSAndroid Build Coastguard Worker      'name="RecoveryLocalizer.apk" certificate="certs/devkey.x509.pem"'
820*9e94795aSAndroid Build Coastguard Worker      ' private_key="certs/devkey.pk8"\n'
821*9e94795aSAndroid Build Coastguard Worker      'name="Settings.apk"'
822*9e94795aSAndroid Build Coastguard Worker      ' certificate="build/make/target/product/security/platform.x509.pem"'
823*9e94795aSAndroid Build Coastguard Worker      ' private_key="build/make/target/product/security/platform.pk8"\n'
824*9e94795aSAndroid Build Coastguard Worker      'name="TV.apk" certificate="PRESIGNED" private_key=""\n'
825*9e94795aSAndroid Build Coastguard Worker  )
826*9e94795aSAndroid Build Coastguard Worker
827*9e94795aSAndroid Build Coastguard Worker  APKCERTS_CERTMAP1 = {
828*9e94795aSAndroid Build Coastguard Worker      'RecoveryLocalizer.apk': 'certs/devkey',
829*9e94795aSAndroid Build Coastguard Worker      'Settings.apk': 'build/make/target/product/security/platform',
830*9e94795aSAndroid Build Coastguard Worker      'TV.apk': 'PRESIGNED',
831*9e94795aSAndroid Build Coastguard Worker  }
832*9e94795aSAndroid Build Coastguard Worker
833*9e94795aSAndroid Build Coastguard Worker  APKCERTS_TXT2 = (
834*9e94795aSAndroid Build Coastguard Worker      'name="Compressed1.apk" certificate="certs/compressed1.x509.pem"'
835*9e94795aSAndroid Build Coastguard Worker      ' private_key="certs/compressed1.pk8" compressed="gz"\n'
836*9e94795aSAndroid Build Coastguard Worker      'name="Compressed2a.apk" certificate="certs/compressed2.x509.pem"'
837*9e94795aSAndroid Build Coastguard Worker      ' private_key="certs/compressed2.pk8" compressed="gz"\n'
838*9e94795aSAndroid Build Coastguard Worker      'name="Compressed2b.apk" certificate="certs/compressed2.x509.pem"'
839*9e94795aSAndroid Build Coastguard Worker      ' private_key="certs/compressed2.pk8" compressed="gz"\n'
840*9e94795aSAndroid Build Coastguard Worker      'name="Compressed3.apk" certificate="certs/compressed3.x509.pem"'
841*9e94795aSAndroid Build Coastguard Worker      ' private_key="certs/compressed3.pk8" compressed="gz"\n'
842*9e94795aSAndroid Build Coastguard Worker  )
843*9e94795aSAndroid Build Coastguard Worker
844*9e94795aSAndroid Build Coastguard Worker  APKCERTS_CERTMAP2 = {
845*9e94795aSAndroid Build Coastguard Worker      'Compressed1.apk': 'certs/compressed1',
846*9e94795aSAndroid Build Coastguard Worker      'Compressed2a.apk': 'certs/compressed2',
847*9e94795aSAndroid Build Coastguard Worker      'Compressed2b.apk': 'certs/compressed2',
848*9e94795aSAndroid Build Coastguard Worker      'Compressed3.apk': 'certs/compressed3',
849*9e94795aSAndroid Build Coastguard Worker  }
850*9e94795aSAndroid Build Coastguard Worker
851*9e94795aSAndroid Build Coastguard Worker  APKCERTS_TXT3 = (
852*9e94795aSAndroid Build Coastguard Worker      'name="Compressed4.apk" certificate="certs/compressed4.x509.pem"'
853*9e94795aSAndroid Build Coastguard Worker      ' private_key="certs/compressed4.pk8" compressed="xz"\n'
854*9e94795aSAndroid Build Coastguard Worker  )
855*9e94795aSAndroid Build Coastguard Worker
856*9e94795aSAndroid Build Coastguard Worker  APKCERTS_CERTMAP3 = {
857*9e94795aSAndroid Build Coastguard Worker      'Compressed4.apk': 'certs/compressed4',
858*9e94795aSAndroid Build Coastguard Worker  }
859*9e94795aSAndroid Build Coastguard Worker
860*9e94795aSAndroid Build Coastguard Worker  # Test parsing with no optional fields, both optional fields, and only the
861*9e94795aSAndroid Build Coastguard Worker  # partition optional field.
862*9e94795aSAndroid Build Coastguard Worker  APKCERTS_TXT4 = (
863*9e94795aSAndroid Build Coastguard Worker      'name="RecoveryLocalizer.apk" certificate="certs/devkey.x509.pem"'
864*9e94795aSAndroid Build Coastguard Worker      ' private_key="certs/devkey.pk8"\n'
865*9e94795aSAndroid Build Coastguard Worker      'name="Settings.apk"'
866*9e94795aSAndroid Build Coastguard Worker      ' certificate="build/make/target/product/security/platform.x509.pem"'
867*9e94795aSAndroid Build Coastguard Worker      ' private_key="build/make/target/product/security/platform.pk8"'
868*9e94795aSAndroid Build Coastguard Worker      ' compressed="gz" partition="system"\n'
869*9e94795aSAndroid Build Coastguard Worker      'name="TV.apk" certificate="PRESIGNED" private_key=""'
870*9e94795aSAndroid Build Coastguard Worker      ' partition="product"\n'
871*9e94795aSAndroid Build Coastguard Worker  )
872*9e94795aSAndroid Build Coastguard Worker
873*9e94795aSAndroid Build Coastguard Worker  APKCERTS_CERTMAP4 = {
874*9e94795aSAndroid Build Coastguard Worker      'RecoveryLocalizer.apk': 'certs/devkey',
875*9e94795aSAndroid Build Coastguard Worker      'Settings.apk': 'build/make/target/product/security/platform',
876*9e94795aSAndroid Build Coastguard Worker      'TV.apk': 'PRESIGNED',
877*9e94795aSAndroid Build Coastguard Worker  }
878*9e94795aSAndroid Build Coastguard Worker
879*9e94795aSAndroid Build Coastguard Worker  def setUp(self):
880*9e94795aSAndroid Build Coastguard Worker    self.testdata_dir = test_utils.get_testdata_dir()
881*9e94795aSAndroid Build Coastguard Worker
882*9e94795aSAndroid Build Coastguard Worker  @staticmethod
883*9e94795aSAndroid Build Coastguard Worker  def _write_apkcerts_txt(apkcerts_txt, additional=None):
884*9e94795aSAndroid Build Coastguard Worker    if additional is None:
885*9e94795aSAndroid Build Coastguard Worker      additional = []
886*9e94795aSAndroid Build Coastguard Worker    target_files = common.MakeTempFile(suffix='.zip')
887*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(target_files, 'w', allowZip64=True) as target_files_zip:
888*9e94795aSAndroid Build Coastguard Worker      target_files_zip.writestr('META/apkcerts.txt', apkcerts_txt)
889*9e94795aSAndroid Build Coastguard Worker      for entry in additional:
890*9e94795aSAndroid Build Coastguard Worker        target_files_zip.writestr(entry, '')
891*9e94795aSAndroid Build Coastguard Worker    return target_files
892*9e94795aSAndroid Build Coastguard Worker
893*9e94795aSAndroid Build Coastguard Worker  def test_ReadApkCerts_NoncompressedApks(self):
894*9e94795aSAndroid Build Coastguard Worker    target_files = self._write_apkcerts_txt(self.APKCERTS_TXT1)
895*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(target_files, 'r', allowZip64=True) as input_zip:
896*9e94795aSAndroid Build Coastguard Worker      certmap, ext = common.ReadApkCerts(input_zip)
897*9e94795aSAndroid Build Coastguard Worker
898*9e94795aSAndroid Build Coastguard Worker    self.assertDictEqual(self.APKCERTS_CERTMAP1, certmap)
899*9e94795aSAndroid Build Coastguard Worker    self.assertIsNone(ext)
900*9e94795aSAndroid Build Coastguard Worker
901*9e94795aSAndroid Build Coastguard Worker  def test_ReadApkCerts_CompressedApks(self):
902*9e94795aSAndroid Build Coastguard Worker    # We have "installed" Compressed1.apk.gz only. Note that Compressed3.apk is
903*9e94795aSAndroid Build Coastguard Worker    # not stored in '.gz' format, so it shouldn't be considered as installed.
904*9e94795aSAndroid Build Coastguard Worker    target_files = self._write_apkcerts_txt(
905*9e94795aSAndroid Build Coastguard Worker        self.APKCERTS_TXT2,
906*9e94795aSAndroid Build Coastguard Worker        ['Compressed1.apk.gz', 'Compressed3.apk'])
907*9e94795aSAndroid Build Coastguard Worker
908*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(target_files, 'r', allowZip64=True) as input_zip:
909*9e94795aSAndroid Build Coastguard Worker      certmap, ext = common.ReadApkCerts(input_zip)
910*9e94795aSAndroid Build Coastguard Worker
911*9e94795aSAndroid Build Coastguard Worker    self.assertDictEqual(self.APKCERTS_CERTMAP2, certmap)
912*9e94795aSAndroid Build Coastguard Worker    self.assertEqual('.gz', ext)
913*9e94795aSAndroid Build Coastguard Worker
914*9e94795aSAndroid Build Coastguard Worker    # Alternative case with '.xz'.
915*9e94795aSAndroid Build Coastguard Worker    target_files = self._write_apkcerts_txt(
916*9e94795aSAndroid Build Coastguard Worker        self.APKCERTS_TXT3, ['Compressed4.apk.xz'])
917*9e94795aSAndroid Build Coastguard Worker
918*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(target_files, 'r', allowZip64=True) as input_zip:
919*9e94795aSAndroid Build Coastguard Worker      certmap, ext = common.ReadApkCerts(input_zip)
920*9e94795aSAndroid Build Coastguard Worker
921*9e94795aSAndroid Build Coastguard Worker    self.assertDictEqual(self.APKCERTS_CERTMAP3, certmap)
922*9e94795aSAndroid Build Coastguard Worker    self.assertEqual('.xz', ext)
923*9e94795aSAndroid Build Coastguard Worker
924*9e94795aSAndroid Build Coastguard Worker  def test_ReadApkCerts_CompressedAndNoncompressedApks(self):
925*9e94795aSAndroid Build Coastguard Worker    target_files = self._write_apkcerts_txt(
926*9e94795aSAndroid Build Coastguard Worker        self.APKCERTS_TXT1 + self.APKCERTS_TXT2,
927*9e94795aSAndroid Build Coastguard Worker        ['Compressed1.apk.gz', 'Compressed3.apk'])
928*9e94795aSAndroid Build Coastguard Worker
929*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(target_files, 'r', allowZip64=True) as input_zip:
930*9e94795aSAndroid Build Coastguard Worker      certmap, ext = common.ReadApkCerts(input_zip)
931*9e94795aSAndroid Build Coastguard Worker
932*9e94795aSAndroid Build Coastguard Worker    certmap_merged = self.APKCERTS_CERTMAP1.copy()
933*9e94795aSAndroid Build Coastguard Worker    certmap_merged.update(self.APKCERTS_CERTMAP2)
934*9e94795aSAndroid Build Coastguard Worker    self.assertDictEqual(certmap_merged, certmap)
935*9e94795aSAndroid Build Coastguard Worker    self.assertEqual('.gz', ext)
936*9e94795aSAndroid Build Coastguard Worker
937*9e94795aSAndroid Build Coastguard Worker  def test_ReadApkCerts_MultipleCompressionMethods(self):
938*9e94795aSAndroid Build Coastguard Worker    target_files = self._write_apkcerts_txt(
939*9e94795aSAndroid Build Coastguard Worker        self.APKCERTS_TXT2 + self.APKCERTS_TXT3,
940*9e94795aSAndroid Build Coastguard Worker        ['Compressed1.apk.gz', 'Compressed4.apk.xz'])
941*9e94795aSAndroid Build Coastguard Worker
942*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(target_files, 'r', allowZip64=True) as input_zip:
943*9e94795aSAndroid Build Coastguard Worker      self.assertRaises(ValueError, common.ReadApkCerts, input_zip)
944*9e94795aSAndroid Build Coastguard Worker
945*9e94795aSAndroid Build Coastguard Worker  def test_ReadApkCerts_MismatchingKeys(self):
946*9e94795aSAndroid Build Coastguard Worker    malformed_apkcerts_txt = (
947*9e94795aSAndroid Build Coastguard Worker        'name="App1.apk" certificate="certs/cert1.x509.pem"'
948*9e94795aSAndroid Build Coastguard Worker        ' private_key="certs/cert2.pk8"\n'
949*9e94795aSAndroid Build Coastguard Worker    )
950*9e94795aSAndroid Build Coastguard Worker    target_files = self._write_apkcerts_txt(malformed_apkcerts_txt)
951*9e94795aSAndroid Build Coastguard Worker
952*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(target_files, 'r', allowZip64=True) as input_zip:
953*9e94795aSAndroid Build Coastguard Worker      self.assertRaises(ValueError, common.ReadApkCerts, input_zip)
954*9e94795aSAndroid Build Coastguard Worker
955*9e94795aSAndroid Build Coastguard Worker  def test_ReadApkCerts_WithWithoutOptionalFields(self):
956*9e94795aSAndroid Build Coastguard Worker    target_files = self._write_apkcerts_txt(self.APKCERTS_TXT4)
957*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(target_files, 'r', allowZip64=True) as input_zip:
958*9e94795aSAndroid Build Coastguard Worker      certmap, ext = common.ReadApkCerts(input_zip)
959*9e94795aSAndroid Build Coastguard Worker
960*9e94795aSAndroid Build Coastguard Worker    self.assertDictEqual(self.APKCERTS_CERTMAP4, certmap)
961*9e94795aSAndroid Build Coastguard Worker    self.assertIsNone(ext)
962*9e94795aSAndroid Build Coastguard Worker
963*9e94795aSAndroid Build Coastguard Worker  def test_ExtractPublicKey(self):
964*9e94795aSAndroid Build Coastguard Worker    cert = os.path.join(self.testdata_dir, 'testkey.x509.pem')
965*9e94795aSAndroid Build Coastguard Worker    pubkey = os.path.join(self.testdata_dir, 'testkey.pubkey.pem')
966*9e94795aSAndroid Build Coastguard Worker    with open(pubkey) as pubkey_fp:
967*9e94795aSAndroid Build Coastguard Worker      self.assertEqual(pubkey_fp.read(), common.ExtractPublicKey(cert))
968*9e94795aSAndroid Build Coastguard Worker
969*9e94795aSAndroid Build Coastguard Worker  def test_ExtractPublicKey_invalidInput(self):
970*9e94795aSAndroid Build Coastguard Worker    wrong_input = os.path.join(self.testdata_dir, 'testkey.pk8')
971*9e94795aSAndroid Build Coastguard Worker    self.assertRaises(AssertionError, common.ExtractPublicKey, wrong_input)
972*9e94795aSAndroid Build Coastguard Worker
973*9e94795aSAndroid Build Coastguard Worker  @test_utils.SkipIfExternalToolsUnavailable()
974*9e94795aSAndroid Build Coastguard Worker  def test_ExtractAvbPublicKey(self):
975*9e94795aSAndroid Build Coastguard Worker    privkey = os.path.join(self.testdata_dir, 'testkey.key')
976*9e94795aSAndroid Build Coastguard Worker    pubkey = os.path.join(self.testdata_dir, 'testkey.pubkey.pem')
977*9e94795aSAndroid Build Coastguard Worker    extracted_from_privkey = common.ExtractAvbPublicKey('avbtool', privkey)
978*9e94795aSAndroid Build Coastguard Worker    extracted_from_pubkey = common.ExtractAvbPublicKey('avbtool', pubkey)
979*9e94795aSAndroid Build Coastguard Worker    with open(extracted_from_privkey, 'rb') as privkey_fp, \
980*9e94795aSAndroid Build Coastguard Worker            open(extracted_from_pubkey, 'rb') as pubkey_fp:
981*9e94795aSAndroid Build Coastguard Worker      self.assertEqual(privkey_fp.read(), pubkey_fp.read())
982*9e94795aSAndroid Build Coastguard Worker
983*9e94795aSAndroid Build Coastguard Worker  def test_ParseCertificate(self):
984*9e94795aSAndroid Build Coastguard Worker    cert = os.path.join(self.testdata_dir, 'testkey.x509.pem')
985*9e94795aSAndroid Build Coastguard Worker
986*9e94795aSAndroid Build Coastguard Worker    cmd = ['openssl', 'x509', '-in', cert, '-outform', 'DER']
987*9e94795aSAndroid Build Coastguard Worker    proc = common.Run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
988*9e94795aSAndroid Build Coastguard Worker                      universal_newlines=False)
989*9e94795aSAndroid Build Coastguard Worker    expected, _ = proc.communicate()
990*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(0, proc.returncode)
991*9e94795aSAndroid Build Coastguard Worker
992*9e94795aSAndroid Build Coastguard Worker    with open(cert) as cert_fp:
993*9e94795aSAndroid Build Coastguard Worker      actual = common.ParseCertificate(cert_fp.read())
994*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(expected, actual)
995*9e94795aSAndroid Build Coastguard Worker
996*9e94795aSAndroid Build Coastguard Worker  @test_utils.SkipIfExternalToolsUnavailable()
997*9e94795aSAndroid Build Coastguard Worker  def test_GetMinSdkVersion(self):
998*9e94795aSAndroid Build Coastguard Worker    test_app = os.path.join(self.testdata_dir, 'TestApp.apk')
999*9e94795aSAndroid Build Coastguard Worker    self.assertEqual('24', common.GetMinSdkVersion(test_app))
1000*9e94795aSAndroid Build Coastguard Worker
1001*9e94795aSAndroid Build Coastguard Worker  @test_utils.SkipIfExternalToolsUnavailable()
1002*9e94795aSAndroid Build Coastguard Worker  def test_GetMinSdkVersion_invalidInput(self):
1003*9e94795aSAndroid Build Coastguard Worker    self.assertRaises(
1004*9e94795aSAndroid Build Coastguard Worker        common.ExternalError, common.GetMinSdkVersion, 'does-not-exist.apk')
1005*9e94795aSAndroid Build Coastguard Worker
1006*9e94795aSAndroid Build Coastguard Worker  @test_utils.SkipIfExternalToolsUnavailable()
1007*9e94795aSAndroid Build Coastguard Worker  def test_GetMinSdkVersionInt(self):
1008*9e94795aSAndroid Build Coastguard Worker    test_app = os.path.join(self.testdata_dir, 'TestApp.apk')
1009*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(24, common.GetMinSdkVersionInt(test_app, {}))
1010*9e94795aSAndroid Build Coastguard Worker
1011*9e94795aSAndroid Build Coastguard Worker  @test_utils.SkipIfExternalToolsUnavailable()
1012*9e94795aSAndroid Build Coastguard Worker  def test_GetMinSdkVersionInt_invalidInput(self):
1013*9e94795aSAndroid Build Coastguard Worker    self.assertRaises(
1014*9e94795aSAndroid Build Coastguard Worker        common.ExternalError, common.GetMinSdkVersionInt, 'does-not-exist.apk',
1015*9e94795aSAndroid Build Coastguard Worker        {})
1016*9e94795aSAndroid Build Coastguard Worker
1017*9e94795aSAndroid Build Coastguard Worker
1018*9e94795aSAndroid Build Coastguard Workerclass CommonUtilsTest(test_utils.ReleaseToolsTestCase):
1019*9e94795aSAndroid Build Coastguard Worker
1020*9e94795aSAndroid Build Coastguard Worker  def setUp(self):
1021*9e94795aSAndroid Build Coastguard Worker    self.testdata_dir = test_utils.get_testdata_dir()
1022*9e94795aSAndroid Build Coastguard Worker
1023*9e94795aSAndroid Build Coastguard Worker  @test_utils.SkipIfExternalToolsUnavailable()
1024*9e94795aSAndroid Build Coastguard Worker  def test_GetSparseImage_emptyBlockMapFile(self):
1025*9e94795aSAndroid Build Coastguard Worker    target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
1026*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(target_files, 'w', allowZip64=True) as target_files_zip:
1027*9e94795aSAndroid Build Coastguard Worker      target_files_zip.write(
1028*9e94795aSAndroid Build Coastguard Worker          test_utils.construct_sparse_image([
1029*9e94795aSAndroid Build Coastguard Worker              (0xCAC1, 6),
1030*9e94795aSAndroid Build Coastguard Worker              (0xCAC3, 3),
1031*9e94795aSAndroid Build Coastguard Worker              (0xCAC1, 4)]),
1032*9e94795aSAndroid Build Coastguard Worker          arcname='IMAGES/system.img')
1033*9e94795aSAndroid Build Coastguard Worker      target_files_zip.writestr('IMAGES/system.map', '')
1034*9e94795aSAndroid Build Coastguard Worker      target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 8))
1035*9e94795aSAndroid Build Coastguard Worker      target_files_zip.writestr('SYSTEM/file2', os.urandom(4096 * 3))
1036*9e94795aSAndroid Build Coastguard Worker
1037*9e94795aSAndroid Build Coastguard Worker    tempdir = common.UnzipTemp(target_files)
1038*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(target_files, 'r', allowZip64=True) as input_zip:
1039*9e94795aSAndroid Build Coastguard Worker      sparse_image = common.GetSparseImage('system', tempdir, input_zip, False)
1040*9e94795aSAndroid Build Coastguard Worker
1041*9e94795aSAndroid Build Coastguard Worker    self.assertDictEqual(
1042*9e94795aSAndroid Build Coastguard Worker        {
1043*9e94795aSAndroid Build Coastguard Worker            '__COPY': RangeSet("0"),
1044*9e94795aSAndroid Build Coastguard Worker            '__NONZERO-0': RangeSet("1-5 9-12"),
1045*9e94795aSAndroid Build Coastguard Worker        },
1046*9e94795aSAndroid Build Coastguard Worker        sparse_image.file_map)
1047*9e94795aSAndroid Build Coastguard Worker
1048*9e94795aSAndroid Build Coastguard Worker  def test_PartitionMapFromTargetFiles(self):
1049*9e94795aSAndroid Build Coastguard Worker    target_files_dir = common.MakeTempDir()
1050*9e94795aSAndroid Build Coastguard Worker    os.makedirs(os.path.join(target_files_dir, 'SYSTEM'))
1051*9e94795aSAndroid Build Coastguard Worker    os.makedirs(os.path.join(target_files_dir, 'SYSTEM', 'vendor'))
1052*9e94795aSAndroid Build Coastguard Worker    os.makedirs(os.path.join(target_files_dir, 'PRODUCT'))
1053*9e94795aSAndroid Build Coastguard Worker    os.makedirs(os.path.join(target_files_dir, 'SYSTEM', 'product'))
1054*9e94795aSAndroid Build Coastguard Worker    os.makedirs(os.path.join(target_files_dir, 'SYSTEM', 'vendor', 'odm'))
1055*9e94795aSAndroid Build Coastguard Worker    os.makedirs(os.path.join(target_files_dir, 'VENDOR_DLKM'))
1056*9e94795aSAndroid Build Coastguard Worker    partition_map = common.PartitionMapFromTargetFiles(target_files_dir)
1057*9e94795aSAndroid Build Coastguard Worker    self.assertDictEqual(
1058*9e94795aSAndroid Build Coastguard Worker        partition_map,
1059*9e94795aSAndroid Build Coastguard Worker        {
1060*9e94795aSAndroid Build Coastguard Worker            'system': 'SYSTEM',
1061*9e94795aSAndroid Build Coastguard Worker            'vendor': 'SYSTEM/vendor',
1062*9e94795aSAndroid Build Coastguard Worker            # Prefer PRODUCT over SYSTEM/product
1063*9e94795aSAndroid Build Coastguard Worker            'product': 'PRODUCT',
1064*9e94795aSAndroid Build Coastguard Worker            'odm': 'SYSTEM/vendor/odm',
1065*9e94795aSAndroid Build Coastguard Worker            'vendor_dlkm': 'VENDOR_DLKM',
1066*9e94795aSAndroid Build Coastguard Worker            # No system_ext or odm_dlkm
1067*9e94795aSAndroid Build Coastguard Worker        })
1068*9e94795aSAndroid Build Coastguard Worker
1069*9e94795aSAndroid Build Coastguard Worker  def test_SharedUidPartitionViolations(self):
1070*9e94795aSAndroid Build Coastguard Worker    uid_dict = {
1071*9e94795aSAndroid Build Coastguard Worker        'android.uid.phone': {
1072*9e94795aSAndroid Build Coastguard Worker            'system': ['system_phone.apk'],
1073*9e94795aSAndroid Build Coastguard Worker            'system_ext': ['system_ext_phone.apk'],
1074*9e94795aSAndroid Build Coastguard Worker        },
1075*9e94795aSAndroid Build Coastguard Worker        'android.uid.wifi': {
1076*9e94795aSAndroid Build Coastguard Worker            'vendor': ['vendor_wifi.apk'],
1077*9e94795aSAndroid Build Coastguard Worker            'odm': ['odm_wifi.apk'],
1078*9e94795aSAndroid Build Coastguard Worker        },
1079*9e94795aSAndroid Build Coastguard Worker    }
1080*9e94795aSAndroid Build Coastguard Worker    errors = common.SharedUidPartitionViolations(
1081*9e94795aSAndroid Build Coastguard Worker        uid_dict, [('system', 'system_ext'), ('vendor', 'odm')])
1082*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(errors, [])
1083*9e94795aSAndroid Build Coastguard Worker
1084*9e94795aSAndroid Build Coastguard Worker  def test_SharedUidPartitionViolations_Violation(self):
1085*9e94795aSAndroid Build Coastguard Worker    uid_dict = {
1086*9e94795aSAndroid Build Coastguard Worker        'android.uid.phone': {
1087*9e94795aSAndroid Build Coastguard Worker            'system': ['system_phone.apk'],
1088*9e94795aSAndroid Build Coastguard Worker            'vendor': ['vendor_phone.apk'],
1089*9e94795aSAndroid Build Coastguard Worker        },
1090*9e94795aSAndroid Build Coastguard Worker    }
1091*9e94795aSAndroid Build Coastguard Worker    errors = common.SharedUidPartitionViolations(
1092*9e94795aSAndroid Build Coastguard Worker        uid_dict, [('system', 'system_ext'), ('vendor', 'odm')])
1093*9e94795aSAndroid Build Coastguard Worker    self.assertIn(
1094*9e94795aSAndroid Build Coastguard Worker        ('APK sharedUserId "android.uid.phone" found across partition groups '
1095*9e94795aSAndroid Build Coastguard Worker         'in partitions "system,vendor"'), errors)
1096*9e94795aSAndroid Build Coastguard Worker
1097*9e94795aSAndroid Build Coastguard Worker  def test_GetSparseImage_missingImageFile(self):
1098*9e94795aSAndroid Build Coastguard Worker    self.assertRaises(
1099*9e94795aSAndroid Build Coastguard Worker        AssertionError, common.GetSparseImage, 'system2', self.testdata_dir,
1100*9e94795aSAndroid Build Coastguard Worker        None, False)
1101*9e94795aSAndroid Build Coastguard Worker    self.assertRaises(
1102*9e94795aSAndroid Build Coastguard Worker        AssertionError, common.GetSparseImage, 'unknown', self.testdata_dir,
1103*9e94795aSAndroid Build Coastguard Worker        None, False)
1104*9e94795aSAndroid Build Coastguard Worker
1105*9e94795aSAndroid Build Coastguard Worker  @test_utils.SkipIfExternalToolsUnavailable()
1106*9e94795aSAndroid Build Coastguard Worker  def test_GetSparseImage_missingBlockMapFile(self):
1107*9e94795aSAndroid Build Coastguard Worker    target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
1108*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(target_files, 'w', allowZip64=True) as target_files_zip:
1109*9e94795aSAndroid Build Coastguard Worker      target_files_zip.write(
1110*9e94795aSAndroid Build Coastguard Worker          test_utils.construct_sparse_image([
1111*9e94795aSAndroid Build Coastguard Worker              (0xCAC1, 6),
1112*9e94795aSAndroid Build Coastguard Worker              (0xCAC3, 3),
1113*9e94795aSAndroid Build Coastguard Worker              (0xCAC1, 4)]),
1114*9e94795aSAndroid Build Coastguard Worker          arcname='IMAGES/system.img')
1115*9e94795aSAndroid Build Coastguard Worker      target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 8))
1116*9e94795aSAndroid Build Coastguard Worker      target_files_zip.writestr('SYSTEM/file2', os.urandom(4096 * 3))
1117*9e94795aSAndroid Build Coastguard Worker
1118*9e94795aSAndroid Build Coastguard Worker    tempdir = common.UnzipTemp(target_files)
1119*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(target_files, 'r', allowZip64=True) as input_zip:
1120*9e94795aSAndroid Build Coastguard Worker      self.assertRaises(
1121*9e94795aSAndroid Build Coastguard Worker          AssertionError, common.GetSparseImage, 'system', tempdir, input_zip,
1122*9e94795aSAndroid Build Coastguard Worker          False)
1123*9e94795aSAndroid Build Coastguard Worker
1124*9e94795aSAndroid Build Coastguard Worker  @test_utils.SkipIfExternalToolsUnavailable()
1125*9e94795aSAndroid Build Coastguard Worker  def test_GetSparseImage_sharedBlocks_notAllowed(self):
1126*9e94795aSAndroid Build Coastguard Worker    """Tests the case of having overlapping blocks but disallowed."""
1127*9e94795aSAndroid Build Coastguard Worker    target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
1128*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(target_files, 'w', allowZip64=True) as target_files_zip:
1129*9e94795aSAndroid Build Coastguard Worker      target_files_zip.write(
1130*9e94795aSAndroid Build Coastguard Worker          test_utils.construct_sparse_image([(0xCAC2, 16)]),
1131*9e94795aSAndroid Build Coastguard Worker          arcname='IMAGES/system.img')
1132*9e94795aSAndroid Build Coastguard Worker      # Block 10 is shared between two files.
1133*9e94795aSAndroid Build Coastguard Worker      target_files_zip.writestr(
1134*9e94795aSAndroid Build Coastguard Worker          'IMAGES/system.map',
1135*9e94795aSAndroid Build Coastguard Worker          '\n'.join([
1136*9e94795aSAndroid Build Coastguard Worker              '/system/file1 1-5 9-10',
1137*9e94795aSAndroid Build Coastguard Worker              '/system/file2 10-12']))
1138*9e94795aSAndroid Build Coastguard Worker      target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 7))
1139*9e94795aSAndroid Build Coastguard Worker      target_files_zip.writestr('SYSTEM/file2', os.urandom(4096 * 3))
1140*9e94795aSAndroid Build Coastguard Worker
1141*9e94795aSAndroid Build Coastguard Worker    tempdir = common.UnzipTemp(target_files)
1142*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(target_files, 'r', allowZip64=True) as input_zip:
1143*9e94795aSAndroid Build Coastguard Worker      self.assertRaises(
1144*9e94795aSAndroid Build Coastguard Worker          AssertionError, common.GetSparseImage, 'system', tempdir, input_zip,
1145*9e94795aSAndroid Build Coastguard Worker          False)
1146*9e94795aSAndroid Build Coastguard Worker
1147*9e94795aSAndroid Build Coastguard Worker  @test_utils.SkipIfExternalToolsUnavailable()
1148*9e94795aSAndroid Build Coastguard Worker  def test_GetSparseImage_sharedBlocks_allowed(self):
1149*9e94795aSAndroid Build Coastguard Worker    """Tests the case for target using BOARD_EXT4_SHARE_DUP_BLOCKS := true."""
1150*9e94795aSAndroid Build Coastguard Worker    target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
1151*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(target_files, 'w', allowZip64=True) as target_files_zip:
1152*9e94795aSAndroid Build Coastguard Worker      # Construct an image with a care_map of "0-5 9-12".
1153*9e94795aSAndroid Build Coastguard Worker      target_files_zip.write(
1154*9e94795aSAndroid Build Coastguard Worker          test_utils.construct_sparse_image([(0xCAC2, 16)]),
1155*9e94795aSAndroid Build Coastguard Worker          arcname='IMAGES/system.img')
1156*9e94795aSAndroid Build Coastguard Worker      # Block 10 is shared between two files.
1157*9e94795aSAndroid Build Coastguard Worker      target_files_zip.writestr(
1158*9e94795aSAndroid Build Coastguard Worker          'IMAGES/system.map',
1159*9e94795aSAndroid Build Coastguard Worker          '\n'.join([
1160*9e94795aSAndroid Build Coastguard Worker              '/system/file1 1-5 9-10',
1161*9e94795aSAndroid Build Coastguard Worker              '/system/file2 10-12']))
1162*9e94795aSAndroid Build Coastguard Worker      target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 7))
1163*9e94795aSAndroid Build Coastguard Worker      target_files_zip.writestr('SYSTEM/file2', os.urandom(4096 * 3))
1164*9e94795aSAndroid Build Coastguard Worker
1165*9e94795aSAndroid Build Coastguard Worker    tempdir = common.UnzipTemp(target_files)
1166*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(target_files, 'r', allowZip64=True) as input_zip:
1167*9e94795aSAndroid Build Coastguard Worker      sparse_image = common.GetSparseImage('system', tempdir, input_zip, True)
1168*9e94795aSAndroid Build Coastguard Worker
1169*9e94795aSAndroid Build Coastguard Worker    self.assertDictEqual(
1170*9e94795aSAndroid Build Coastguard Worker        {
1171*9e94795aSAndroid Build Coastguard Worker            '__COPY': RangeSet("0"),
1172*9e94795aSAndroid Build Coastguard Worker            '__NONZERO-0': RangeSet("6-8 13-15"),
1173*9e94795aSAndroid Build Coastguard Worker            '/system/file1': RangeSet("1-5 9-10"),
1174*9e94795aSAndroid Build Coastguard Worker            '/system/file2': RangeSet("11-12"),
1175*9e94795aSAndroid Build Coastguard Worker        },
1176*9e94795aSAndroid Build Coastguard Worker        sparse_image.file_map)
1177*9e94795aSAndroid Build Coastguard Worker
1178*9e94795aSAndroid Build Coastguard Worker    # '/system/file2' should be marked with 'uses_shared_blocks', but not with
1179*9e94795aSAndroid Build Coastguard Worker    # 'incomplete'.
1180*9e94795aSAndroid Build Coastguard Worker    self.assertTrue(
1181*9e94795aSAndroid Build Coastguard Worker        sparse_image.file_map['/system/file2'].extra['uses_shared_blocks'])
1182*9e94795aSAndroid Build Coastguard Worker    self.assertNotIn(
1183*9e94795aSAndroid Build Coastguard Worker        'incomplete', sparse_image.file_map['/system/file2'].extra)
1184*9e94795aSAndroid Build Coastguard Worker
1185*9e94795aSAndroid Build Coastguard Worker    # '/system/file1' will only contain one field -- a copy of the input text.
1186*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(1, len(sparse_image.file_map['/system/file1'].extra))
1187*9e94795aSAndroid Build Coastguard Worker
1188*9e94795aSAndroid Build Coastguard Worker    # Meta entries should not have any extra tag.
1189*9e94795aSAndroid Build Coastguard Worker    self.assertFalse(sparse_image.file_map['__COPY'].extra)
1190*9e94795aSAndroid Build Coastguard Worker    self.assertFalse(sparse_image.file_map['__NONZERO-0'].extra)
1191*9e94795aSAndroid Build Coastguard Worker
1192*9e94795aSAndroid Build Coastguard Worker  @test_utils.SkipIfExternalToolsUnavailable()
1193*9e94795aSAndroid Build Coastguard Worker  def test_GetSparseImage_incompleteRanges(self):
1194*9e94795aSAndroid Build Coastguard Worker    """Tests the case of ext4 images with holes."""
1195*9e94795aSAndroid Build Coastguard Worker    target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
1196*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(target_files, 'w', allowZip64=True) as target_files_zip:
1197*9e94795aSAndroid Build Coastguard Worker      target_files_zip.write(
1198*9e94795aSAndroid Build Coastguard Worker          test_utils.construct_sparse_image([(0xCAC2, 16)]),
1199*9e94795aSAndroid Build Coastguard Worker          arcname='IMAGES/system.img')
1200*9e94795aSAndroid Build Coastguard Worker      target_files_zip.writestr(
1201*9e94795aSAndroid Build Coastguard Worker          'IMAGES/system.map',
1202*9e94795aSAndroid Build Coastguard Worker          '\n'.join([
1203*9e94795aSAndroid Build Coastguard Worker              '/system/file1 1-5 9-10',
1204*9e94795aSAndroid Build Coastguard Worker              '/system/file2 11-12']))
1205*9e94795aSAndroid Build Coastguard Worker      target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 7))
1206*9e94795aSAndroid Build Coastguard Worker      # '/system/file2' has less blocks listed (2) than actual (3).
1207*9e94795aSAndroid Build Coastguard Worker      target_files_zip.writestr('SYSTEM/file2', os.urandom(4096 * 3))
1208*9e94795aSAndroid Build Coastguard Worker
1209*9e94795aSAndroid Build Coastguard Worker    tempdir = common.UnzipTemp(target_files)
1210*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(target_files, 'r', allowZip64=True) as input_zip:
1211*9e94795aSAndroid Build Coastguard Worker      sparse_image = common.GetSparseImage('system', tempdir, input_zip, False)
1212*9e94795aSAndroid Build Coastguard Worker
1213*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(
1214*9e94795aSAndroid Build Coastguard Worker        '1-5 9-10',
1215*9e94795aSAndroid Build Coastguard Worker        sparse_image.file_map['/system/file1'].extra['text_str'])
1216*9e94795aSAndroid Build Coastguard Worker    self.assertTrue(sparse_image.file_map['/system/file2'].extra['incomplete'])
1217*9e94795aSAndroid Build Coastguard Worker
1218*9e94795aSAndroid Build Coastguard Worker  @test_utils.SkipIfExternalToolsUnavailable()
1219*9e94795aSAndroid Build Coastguard Worker  def test_GetSparseImage_systemRootImage_filenameWithExtraLeadingSlash(self):
1220*9e94795aSAndroid Build Coastguard Worker    target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
1221*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(target_files, 'w', allowZip64=True) as target_files_zip:
1222*9e94795aSAndroid Build Coastguard Worker      target_files_zip.write(
1223*9e94795aSAndroid Build Coastguard Worker          test_utils.construct_sparse_image([(0xCAC2, 16)]),
1224*9e94795aSAndroid Build Coastguard Worker          arcname='IMAGES/system.img')
1225*9e94795aSAndroid Build Coastguard Worker      target_files_zip.writestr(
1226*9e94795aSAndroid Build Coastguard Worker          'IMAGES/system.map',
1227*9e94795aSAndroid Build Coastguard Worker          '\n'.join([
1228*9e94795aSAndroid Build Coastguard Worker              '//system/file1 1-5 9-10',
1229*9e94795aSAndroid Build Coastguard Worker              '//system/file2 11-12',
1230*9e94795aSAndroid Build Coastguard Worker              '/system/app/file3 13-15']))
1231*9e94795aSAndroid Build Coastguard Worker      target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 7))
1232*9e94795aSAndroid Build Coastguard Worker      # '/system/file2' has less blocks listed (2) than actual (3).
1233*9e94795aSAndroid Build Coastguard Worker      target_files_zip.writestr('SYSTEM/file2', os.urandom(4096 * 3))
1234*9e94795aSAndroid Build Coastguard Worker      # '/system/app/file3' has less blocks listed (3) than actual (4).
1235*9e94795aSAndroid Build Coastguard Worker      target_files_zip.writestr('SYSTEM/app/file3', os.urandom(4096 * 4))
1236*9e94795aSAndroid Build Coastguard Worker
1237*9e94795aSAndroid Build Coastguard Worker    tempdir = common.UnzipTemp(target_files)
1238*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(target_files, 'r', allowZip64=True) as input_zip:
1239*9e94795aSAndroid Build Coastguard Worker      sparse_image = common.GetSparseImage('system', tempdir, input_zip, False)
1240*9e94795aSAndroid Build Coastguard Worker
1241*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(
1242*9e94795aSAndroid Build Coastguard Worker        '1-5 9-10',
1243*9e94795aSAndroid Build Coastguard Worker        sparse_image.file_map['//system/file1'].extra['text_str'])
1244*9e94795aSAndroid Build Coastguard Worker    self.assertTrue(
1245*9e94795aSAndroid Build Coastguard Worker        sparse_image.file_map['//system/file2'].extra['incomplete'])
1246*9e94795aSAndroid Build Coastguard Worker    self.assertTrue(
1247*9e94795aSAndroid Build Coastguard Worker        sparse_image.file_map['/system/app/file3'].extra['incomplete'])
1248*9e94795aSAndroid Build Coastguard Worker
1249*9e94795aSAndroid Build Coastguard Worker  @test_utils.SkipIfExternalToolsUnavailable()
1250*9e94795aSAndroid Build Coastguard Worker  def test_GetSparseImage_systemRootImage_nonSystemFiles(self):
1251*9e94795aSAndroid Build Coastguard Worker    target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
1252*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(target_files, 'w', allowZip64=True) as target_files_zip:
1253*9e94795aSAndroid Build Coastguard Worker      target_files_zip.write(
1254*9e94795aSAndroid Build Coastguard Worker          test_utils.construct_sparse_image([(0xCAC2, 16)]),
1255*9e94795aSAndroid Build Coastguard Worker          arcname='IMAGES/system.img')
1256*9e94795aSAndroid Build Coastguard Worker      target_files_zip.writestr(
1257*9e94795aSAndroid Build Coastguard Worker          'IMAGES/system.map',
1258*9e94795aSAndroid Build Coastguard Worker          '\n'.join([
1259*9e94795aSAndroid Build Coastguard Worker              '//system/file1 1-5 9-10',
1260*9e94795aSAndroid Build Coastguard Worker              '//init.rc 13-15']))
1261*9e94795aSAndroid Build Coastguard Worker      target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 7))
1262*9e94795aSAndroid Build Coastguard Worker      # '/init.rc' has less blocks listed (3) than actual (4).
1263*9e94795aSAndroid Build Coastguard Worker      target_files_zip.writestr('ROOT/init.rc', os.urandom(4096 * 4))
1264*9e94795aSAndroid Build Coastguard Worker
1265*9e94795aSAndroid Build Coastguard Worker    tempdir = common.UnzipTemp(target_files)
1266*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(target_files, 'r', allowZip64=True) as input_zip:
1267*9e94795aSAndroid Build Coastguard Worker      sparse_image = common.GetSparseImage('system', tempdir, input_zip, False)
1268*9e94795aSAndroid Build Coastguard Worker
1269*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(
1270*9e94795aSAndroid Build Coastguard Worker        '1-5 9-10',
1271*9e94795aSAndroid Build Coastguard Worker        sparse_image.file_map['//system/file1'].extra['text_str'])
1272*9e94795aSAndroid Build Coastguard Worker    self.assertTrue(sparse_image.file_map['//init.rc'].extra['incomplete'])
1273*9e94795aSAndroid Build Coastguard Worker
1274*9e94795aSAndroid Build Coastguard Worker  @test_utils.SkipIfExternalToolsUnavailable()
1275*9e94795aSAndroid Build Coastguard Worker  def test_GetSparseImage_fileNotFound(self):
1276*9e94795aSAndroid Build Coastguard Worker    target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
1277*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(target_files, 'w', allowZip64=True) as target_files_zip:
1278*9e94795aSAndroid Build Coastguard Worker      target_files_zip.write(
1279*9e94795aSAndroid Build Coastguard Worker          test_utils.construct_sparse_image([(0xCAC2, 16)]),
1280*9e94795aSAndroid Build Coastguard Worker          arcname='IMAGES/system.img')
1281*9e94795aSAndroid Build Coastguard Worker      target_files_zip.writestr(
1282*9e94795aSAndroid Build Coastguard Worker          'IMAGES/system.map',
1283*9e94795aSAndroid Build Coastguard Worker          '\n'.join([
1284*9e94795aSAndroid Build Coastguard Worker              '//system/file1 1-5 9-10',
1285*9e94795aSAndroid Build Coastguard Worker              '//system/file2 11-12']))
1286*9e94795aSAndroid Build Coastguard Worker      target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 7))
1287*9e94795aSAndroid Build Coastguard Worker
1288*9e94795aSAndroid Build Coastguard Worker    tempdir = common.UnzipTemp(target_files)
1289*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(target_files, 'r', allowZip64=True) as input_zip:
1290*9e94795aSAndroid Build Coastguard Worker      self.assertRaises(
1291*9e94795aSAndroid Build Coastguard Worker          AssertionError, common.GetSparseImage, 'system', tempdir, input_zip,
1292*9e94795aSAndroid Build Coastguard Worker          False)
1293*9e94795aSAndroid Build Coastguard Worker
1294*9e94795aSAndroid Build Coastguard Worker  @test_utils.SkipIfExternalToolsUnavailable()
1295*9e94795aSAndroid Build Coastguard Worker  def test_GetAvbChainedPartitionArg(self):
1296*9e94795aSAndroid Build Coastguard Worker    pubkey = os.path.join(self.testdata_dir, 'testkey.pubkey.pem')
1297*9e94795aSAndroid Build Coastguard Worker    info_dict = {
1298*9e94795aSAndroid Build Coastguard Worker        'avb_avbtool': 'avbtool',
1299*9e94795aSAndroid Build Coastguard Worker        'avb_system_key_path': pubkey,
1300*9e94795aSAndroid Build Coastguard Worker        'avb_system_rollback_index_location': 2,
1301*9e94795aSAndroid Build Coastguard Worker    }
1302*9e94795aSAndroid Build Coastguard Worker    chained_partition_args = common.GetAvbChainedPartitionArg(
1303*9e94795aSAndroid Build Coastguard Worker        'system', info_dict)
1304*9e94795aSAndroid Build Coastguard Worker    self.assertEqual('system', chained_partition_args.partition)
1305*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(2, chained_partition_args.rollback_index_location)
1306*9e94795aSAndroid Build Coastguard Worker    self.assertTrue(os.path.exists(chained_partition_args.pubkey_path))
1307*9e94795aSAndroid Build Coastguard Worker
1308*9e94795aSAndroid Build Coastguard Worker  @test_utils.SkipIfExternalToolsUnavailable()
1309*9e94795aSAndroid Build Coastguard Worker  def test_GetAvbChainedPartitionArg_withPrivateKey(self):
1310*9e94795aSAndroid Build Coastguard Worker    key = os.path.join(self.testdata_dir, 'testkey.key')
1311*9e94795aSAndroid Build Coastguard Worker    info_dict = {
1312*9e94795aSAndroid Build Coastguard Worker        'avb_avbtool': 'avbtool',
1313*9e94795aSAndroid Build Coastguard Worker        'avb_product_key_path': key,
1314*9e94795aSAndroid Build Coastguard Worker        'avb_product_rollback_index_location': 2,
1315*9e94795aSAndroid Build Coastguard Worker    }
1316*9e94795aSAndroid Build Coastguard Worker    chained_partition_args = common.GetAvbChainedPartitionArg(
1317*9e94795aSAndroid Build Coastguard Worker        'product', info_dict)
1318*9e94795aSAndroid Build Coastguard Worker    self.assertEqual('product', chained_partition_args.partition)
1319*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(2, chained_partition_args.rollback_index_location)
1320*9e94795aSAndroid Build Coastguard Worker    self.assertTrue(os.path.exists(chained_partition_args.pubkey_path))
1321*9e94795aSAndroid Build Coastguard Worker
1322*9e94795aSAndroid Build Coastguard Worker  @test_utils.SkipIfExternalToolsUnavailable()
1323*9e94795aSAndroid Build Coastguard Worker  def test_GetAvbChainedPartitionArg_withSpecifiedKey(self):
1324*9e94795aSAndroid Build Coastguard Worker    info_dict = {
1325*9e94795aSAndroid Build Coastguard Worker        'avb_avbtool': 'avbtool',
1326*9e94795aSAndroid Build Coastguard Worker        'avb_system_key_path': 'does-not-exist',
1327*9e94795aSAndroid Build Coastguard Worker        'avb_system_rollback_index_location': 2,
1328*9e94795aSAndroid Build Coastguard Worker    }
1329*9e94795aSAndroid Build Coastguard Worker    pubkey = os.path.join(self.testdata_dir, 'testkey.pubkey.pem')
1330*9e94795aSAndroid Build Coastguard Worker    chained_partition_args = common.GetAvbChainedPartitionArg(
1331*9e94795aSAndroid Build Coastguard Worker        'system', info_dict, pubkey)
1332*9e94795aSAndroid Build Coastguard Worker    self.assertEqual('system', chained_partition_args.partition)
1333*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(2, chained_partition_args.rollback_index_location)
1334*9e94795aSAndroid Build Coastguard Worker    self.assertTrue(os.path.exists(chained_partition_args.pubkey_path))
1335*9e94795aSAndroid Build Coastguard Worker
1336*9e94795aSAndroid Build Coastguard Worker  @test_utils.SkipIfExternalToolsUnavailable()
1337*9e94795aSAndroid Build Coastguard Worker  def test_GetAvbChainedPartitionArg_invalidKey(self):
1338*9e94795aSAndroid Build Coastguard Worker    pubkey = os.path.join(self.testdata_dir, 'testkey_with_passwd.x509.pem')
1339*9e94795aSAndroid Build Coastguard Worker    info_dict = {
1340*9e94795aSAndroid Build Coastguard Worker        'avb_avbtool': 'avbtool',
1341*9e94795aSAndroid Build Coastguard Worker        'avb_system_key_path': pubkey,
1342*9e94795aSAndroid Build Coastguard Worker        'avb_system_rollback_index_location': 2,
1343*9e94795aSAndroid Build Coastguard Worker    }
1344*9e94795aSAndroid Build Coastguard Worker    self.assertRaises(
1345*9e94795aSAndroid Build Coastguard Worker        common.ExternalError, common.GetAvbChainedPartitionArg, 'system',
1346*9e94795aSAndroid Build Coastguard Worker        info_dict)
1347*9e94795aSAndroid Build Coastguard Worker
1348*9e94795aSAndroid Build Coastguard Worker  INFO_DICT_DEFAULT = {
1349*9e94795aSAndroid Build Coastguard Worker      'recovery_api_version': 3,
1350*9e94795aSAndroid Build Coastguard Worker      'fstab_version': 2,
1351*9e94795aSAndroid Build Coastguard Worker      'no_recovery': 'true',
1352*9e94795aSAndroid Build Coastguard Worker      'recovery_as_boot': 'true',
1353*9e94795aSAndroid Build Coastguard Worker  }
1354*9e94795aSAndroid Build Coastguard Worker
1355*9e94795aSAndroid Build Coastguard Worker  def test_LoadListFromFile(self):
1356*9e94795aSAndroid Build Coastguard Worker    file_path = os.path.join(self.testdata_dir,
1357*9e94795aSAndroid Build Coastguard Worker                             'merge_config_framework_item_list')
1358*9e94795aSAndroid Build Coastguard Worker    contents = common.LoadListFromFile(file_path)
1359*9e94795aSAndroid Build Coastguard Worker    expected_contents = [
1360*9e94795aSAndroid Build Coastguard Worker        'META/apkcerts.txt',
1361*9e94795aSAndroid Build Coastguard Worker        'META/filesystem_config.txt',
1362*9e94795aSAndroid Build Coastguard Worker        'META/root_filesystem_config.txt',
1363*9e94795aSAndroid Build Coastguard Worker        'META/system_manifest.xml',
1364*9e94795aSAndroid Build Coastguard Worker        'META/system_matrix.xml',
1365*9e94795aSAndroid Build Coastguard Worker        'META/update_engine_config.txt',
1366*9e94795aSAndroid Build Coastguard Worker        'PRODUCT/*',
1367*9e94795aSAndroid Build Coastguard Worker        'ROOT/*',
1368*9e94795aSAndroid Build Coastguard Worker        'SYSTEM/*',
1369*9e94795aSAndroid Build Coastguard Worker    ]
1370*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(sorted(contents), sorted(expected_contents))
1371*9e94795aSAndroid Build Coastguard Worker
1372*9e94795aSAndroid Build Coastguard Worker  @staticmethod
1373*9e94795aSAndroid Build Coastguard Worker  def _test_LoadInfoDict_createTargetFiles(info_dict, fstab_path):
1374*9e94795aSAndroid Build Coastguard Worker    target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
1375*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(target_files, 'w', allowZip64=True) as target_files_zip:
1376*9e94795aSAndroid Build Coastguard Worker      info_values = ''.join(
1377*9e94795aSAndroid Build Coastguard Worker          ['{}={}\n'.format(k, v) for k, v in sorted(info_dict.items())])
1378*9e94795aSAndroid Build Coastguard Worker      common.ZipWriteStr(target_files_zip, 'META/misc_info.txt', info_values)
1379*9e94795aSAndroid Build Coastguard Worker      common.ZipWriteStr(target_files_zip, fstab_path,
1380*9e94795aSAndroid Build Coastguard Worker                         "/dev/block/system /system ext4 ro,barrier=1 defaults")
1381*9e94795aSAndroid Build Coastguard Worker      common.ZipWriteStr(
1382*9e94795aSAndroid Build Coastguard Worker          target_files_zip, 'META/file_contexts', 'file-contexts')
1383*9e94795aSAndroid Build Coastguard Worker    return target_files
1384*9e94795aSAndroid Build Coastguard Worker
1385*9e94795aSAndroid Build Coastguard Worker  def test_LoadInfoDict(self):
1386*9e94795aSAndroid Build Coastguard Worker    target_files = self._test_LoadInfoDict_createTargetFiles(
1387*9e94795aSAndroid Build Coastguard Worker        self.INFO_DICT_DEFAULT,
1388*9e94795aSAndroid Build Coastguard Worker        'BOOT/RAMDISK/system/etc/recovery.fstab')
1389*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(target_files, 'r', allowZip64=True) as target_files_zip:
1390*9e94795aSAndroid Build Coastguard Worker      loaded_dict = common.LoadInfoDict(target_files_zip)
1391*9e94795aSAndroid Build Coastguard Worker      self.assertEqual(3, loaded_dict['recovery_api_version'])
1392*9e94795aSAndroid Build Coastguard Worker      self.assertEqual(2, loaded_dict['fstab_version'])
1393*9e94795aSAndroid Build Coastguard Worker      self.assertIn('/system', loaded_dict['fstab'])
1394*9e94795aSAndroid Build Coastguard Worker
1395*9e94795aSAndroid Build Coastguard Worker  def test_LoadInfoDict_legacyRecoveryFstabPath(self):
1396*9e94795aSAndroid Build Coastguard Worker    target_files = self._test_LoadInfoDict_createTargetFiles(
1397*9e94795aSAndroid Build Coastguard Worker        self.INFO_DICT_DEFAULT,
1398*9e94795aSAndroid Build Coastguard Worker        'BOOT/RAMDISK/etc/recovery.fstab')
1399*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(target_files, 'r', allowZip64=True) as target_files_zip:
1400*9e94795aSAndroid Build Coastguard Worker      loaded_dict = common.LoadInfoDict(target_files_zip)
1401*9e94795aSAndroid Build Coastguard Worker      self.assertEqual(3, loaded_dict['recovery_api_version'])
1402*9e94795aSAndroid Build Coastguard Worker      self.assertEqual(2, loaded_dict['fstab_version'])
1403*9e94795aSAndroid Build Coastguard Worker      self.assertIn('/system', loaded_dict['fstab'])
1404*9e94795aSAndroid Build Coastguard Worker
1405*9e94795aSAndroid Build Coastguard Worker  @test_utils.SkipIfExternalToolsUnavailable()
1406*9e94795aSAndroid Build Coastguard Worker  def test_LoadInfoDict_dirInput(self):
1407*9e94795aSAndroid Build Coastguard Worker    target_files = self._test_LoadInfoDict_createTargetFiles(
1408*9e94795aSAndroid Build Coastguard Worker        self.INFO_DICT_DEFAULT,
1409*9e94795aSAndroid Build Coastguard Worker        'BOOT/RAMDISK/system/etc/recovery.fstab')
1410*9e94795aSAndroid Build Coastguard Worker    unzipped = common.UnzipTemp(target_files)
1411*9e94795aSAndroid Build Coastguard Worker    loaded_dict = common.LoadInfoDict(unzipped)
1412*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(3, loaded_dict['recovery_api_version'])
1413*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(2, loaded_dict['fstab_version'])
1414*9e94795aSAndroid Build Coastguard Worker    self.assertIn('/system', loaded_dict['fstab'])
1415*9e94795aSAndroid Build Coastguard Worker
1416*9e94795aSAndroid Build Coastguard Worker  @test_utils.SkipIfExternalToolsUnavailable()
1417*9e94795aSAndroid Build Coastguard Worker  def test_LoadInfoDict_dirInput_legacyRecoveryFstabPath(self):
1418*9e94795aSAndroid Build Coastguard Worker    target_files = self._test_LoadInfoDict_createTargetFiles(
1419*9e94795aSAndroid Build Coastguard Worker        self.INFO_DICT_DEFAULT,
1420*9e94795aSAndroid Build Coastguard Worker        'BOOT/RAMDISK/system/etc/recovery.fstab')
1421*9e94795aSAndroid Build Coastguard Worker    unzipped = common.UnzipTemp(target_files)
1422*9e94795aSAndroid Build Coastguard Worker    loaded_dict = common.LoadInfoDict(unzipped)
1423*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(3, loaded_dict['recovery_api_version'])
1424*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(2, loaded_dict['fstab_version'])
1425*9e94795aSAndroid Build Coastguard Worker    self.assertIn('/system', loaded_dict['fstab'])
1426*9e94795aSAndroid Build Coastguard Worker
1427*9e94795aSAndroid Build Coastguard Worker  def test_LoadInfoDict_recoveryAsBootFalse(self):
1428*9e94795aSAndroid Build Coastguard Worker    info_dict = copy.copy(self.INFO_DICT_DEFAULT)
1429*9e94795aSAndroid Build Coastguard Worker    del info_dict['no_recovery']
1430*9e94795aSAndroid Build Coastguard Worker    del info_dict['recovery_as_boot']
1431*9e94795aSAndroid Build Coastguard Worker    target_files = self._test_LoadInfoDict_createTargetFiles(
1432*9e94795aSAndroid Build Coastguard Worker        info_dict,
1433*9e94795aSAndroid Build Coastguard Worker        'RECOVERY/RAMDISK/system/etc/recovery.fstab')
1434*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(target_files, 'r', allowZip64=True) as target_files_zip:
1435*9e94795aSAndroid Build Coastguard Worker      loaded_dict = common.LoadInfoDict(target_files_zip)
1436*9e94795aSAndroid Build Coastguard Worker      self.assertEqual(3, loaded_dict['recovery_api_version'])
1437*9e94795aSAndroid Build Coastguard Worker      self.assertEqual(2, loaded_dict['fstab_version'])
1438*9e94795aSAndroid Build Coastguard Worker      self.assertNotIn('/', loaded_dict['fstab'])
1439*9e94795aSAndroid Build Coastguard Worker      self.assertIn('/system', loaded_dict['fstab'])
1440*9e94795aSAndroid Build Coastguard Worker
1441*9e94795aSAndroid Build Coastguard Worker  def test_LoadInfoDict_noRecoveryTrue(self):
1442*9e94795aSAndroid Build Coastguard Worker    # Device doesn't have a recovery partition at all.
1443*9e94795aSAndroid Build Coastguard Worker    info_dict = copy.copy(self.INFO_DICT_DEFAULT)
1444*9e94795aSAndroid Build Coastguard Worker    del info_dict['recovery_as_boot']
1445*9e94795aSAndroid Build Coastguard Worker    target_files = self._test_LoadInfoDict_createTargetFiles(
1446*9e94795aSAndroid Build Coastguard Worker        info_dict,
1447*9e94795aSAndroid Build Coastguard Worker        'RECOVERY/RAMDISK/system/etc/recovery.fstab')
1448*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(target_files, 'r', allowZip64=True) as target_files_zip:
1449*9e94795aSAndroid Build Coastguard Worker      loaded_dict = common.LoadInfoDict(target_files_zip)
1450*9e94795aSAndroid Build Coastguard Worker      self.assertEqual(3, loaded_dict['recovery_api_version'])
1451*9e94795aSAndroid Build Coastguard Worker      self.assertEqual(2, loaded_dict['fstab_version'])
1452*9e94795aSAndroid Build Coastguard Worker      self.assertIsNone(loaded_dict['fstab'])
1453*9e94795aSAndroid Build Coastguard Worker
1454*9e94795aSAndroid Build Coastguard Worker  @test_utils.SkipIfExternalToolsUnavailable()
1455*9e94795aSAndroid Build Coastguard Worker  def test_LoadInfoDict_missingMetaMiscInfoTxt(self):
1456*9e94795aSAndroid Build Coastguard Worker    target_files = self._test_LoadInfoDict_createTargetFiles(
1457*9e94795aSAndroid Build Coastguard Worker        self.INFO_DICT_DEFAULT,
1458*9e94795aSAndroid Build Coastguard Worker        'BOOT/RAMDISK/system/etc/recovery.fstab')
1459*9e94795aSAndroid Build Coastguard Worker    common.ZipDelete(target_files, 'META/misc_info.txt')
1460*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(target_files, 'r', allowZip64=True) as target_files_zip:
1461*9e94795aSAndroid Build Coastguard Worker      self.assertRaises(ValueError, common.LoadInfoDict, target_files_zip)
1462*9e94795aSAndroid Build Coastguard Worker
1463*9e94795aSAndroid Build Coastguard Worker  @test_utils.SkipIfExternalToolsUnavailable()
1464*9e94795aSAndroid Build Coastguard Worker  def test_LoadInfoDict_repacking(self):
1465*9e94795aSAndroid Build Coastguard Worker    target_files = self._test_LoadInfoDict_createTargetFiles(
1466*9e94795aSAndroid Build Coastguard Worker        self.INFO_DICT_DEFAULT,
1467*9e94795aSAndroid Build Coastguard Worker        'BOOT/RAMDISK/system/etc/recovery.fstab')
1468*9e94795aSAndroid Build Coastguard Worker    unzipped = common.UnzipTemp(target_files)
1469*9e94795aSAndroid Build Coastguard Worker    loaded_dict = common.LoadInfoDict(unzipped, True)
1470*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(3, loaded_dict['recovery_api_version'])
1471*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(2, loaded_dict['fstab_version'])
1472*9e94795aSAndroid Build Coastguard Worker    self.assertIn('/system', loaded_dict['fstab'])
1473*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(
1474*9e94795aSAndroid Build Coastguard Worker        os.path.join(unzipped, 'ROOT'), loaded_dict['root_dir'])
1475*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(
1476*9e94795aSAndroid Build Coastguard Worker        os.path.join(unzipped, 'META', 'root_filesystem_config.txt'),
1477*9e94795aSAndroid Build Coastguard Worker        loaded_dict['root_fs_config'])
1478*9e94795aSAndroid Build Coastguard Worker
1479*9e94795aSAndroid Build Coastguard Worker  def test_LoadInfoDict_repackingWithZipFileInput(self):
1480*9e94795aSAndroid Build Coastguard Worker    target_files = self._test_LoadInfoDict_createTargetFiles(
1481*9e94795aSAndroid Build Coastguard Worker        self.INFO_DICT_DEFAULT,
1482*9e94795aSAndroid Build Coastguard Worker        'BOOT/RAMDISK/system/etc/recovery.fstab')
1483*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(target_files, 'r', allowZip64=True) as target_files_zip:
1484*9e94795aSAndroid Build Coastguard Worker      self.assertRaises(
1485*9e94795aSAndroid Build Coastguard Worker          AssertionError, common.LoadInfoDict, target_files_zip, True)
1486*9e94795aSAndroid Build Coastguard Worker
1487*9e94795aSAndroid Build Coastguard Worker  def test_MergeDynamicPartitionInfoDicts_ReturnsMergedDict(self):
1488*9e94795aSAndroid Build Coastguard Worker    framework_dict = {
1489*9e94795aSAndroid Build Coastguard Worker        'use_dynamic_partitions': 'true',
1490*9e94795aSAndroid Build Coastguard Worker        'super_partition_groups': 'group_a',
1491*9e94795aSAndroid Build Coastguard Worker        'dynamic_partition_list': 'system',
1492*9e94795aSAndroid Build Coastguard Worker        'super_group_a_partition_list': 'system',
1493*9e94795aSAndroid Build Coastguard Worker    }
1494*9e94795aSAndroid Build Coastguard Worker    vendor_dict = {
1495*9e94795aSAndroid Build Coastguard Worker        'use_dynamic_partitions': 'true',
1496*9e94795aSAndroid Build Coastguard Worker        'super_partition_groups': 'group_a group_b',
1497*9e94795aSAndroid Build Coastguard Worker        'dynamic_partition_list': 'vendor product',
1498*9e94795aSAndroid Build Coastguard Worker        'super_block_devices': 'super',
1499*9e94795aSAndroid Build Coastguard Worker        'super_super_device_size': '3000',
1500*9e94795aSAndroid Build Coastguard Worker        'super_group_a_partition_list': 'vendor',
1501*9e94795aSAndroid Build Coastguard Worker        'super_group_a_group_size': '1000',
1502*9e94795aSAndroid Build Coastguard Worker        'super_group_b_partition_list': 'product',
1503*9e94795aSAndroid Build Coastguard Worker        'super_group_b_group_size': '2000',
1504*9e94795aSAndroid Build Coastguard Worker    }
1505*9e94795aSAndroid Build Coastguard Worker    merged_dict = common.MergeDynamicPartitionInfoDicts(
1506*9e94795aSAndroid Build Coastguard Worker        framework_dict=framework_dict,
1507*9e94795aSAndroid Build Coastguard Worker        vendor_dict=vendor_dict)
1508*9e94795aSAndroid Build Coastguard Worker    expected_merged_dict = {
1509*9e94795aSAndroid Build Coastguard Worker        'use_dynamic_partitions': 'true',
1510*9e94795aSAndroid Build Coastguard Worker        'super_partition_groups': 'group_a group_b',
1511*9e94795aSAndroid Build Coastguard Worker        'dynamic_partition_list': 'product system vendor',
1512*9e94795aSAndroid Build Coastguard Worker        'super_block_devices': 'super',
1513*9e94795aSAndroid Build Coastguard Worker        'super_super_device_size': '3000',
1514*9e94795aSAndroid Build Coastguard Worker        'super_group_a_partition_list': 'system vendor',
1515*9e94795aSAndroid Build Coastguard Worker        'super_group_a_group_size': '1000',
1516*9e94795aSAndroid Build Coastguard Worker        'super_group_b_partition_list': 'product',
1517*9e94795aSAndroid Build Coastguard Worker        'super_group_b_group_size': '2000',
1518*9e94795aSAndroid Build Coastguard Worker        'vabc_cow_version': '2',
1519*9e94795aSAndroid Build Coastguard Worker    }
1520*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(merged_dict, expected_merged_dict)
1521*9e94795aSAndroid Build Coastguard Worker
1522*9e94795aSAndroid Build Coastguard Worker  def test_MergeDynamicPartitionInfoDicts_IgnoringFrameworkGroupSize(self):
1523*9e94795aSAndroid Build Coastguard Worker    framework_dict = {
1524*9e94795aSAndroid Build Coastguard Worker        'use_dynamic_partitions': 'true',
1525*9e94795aSAndroid Build Coastguard Worker        'super_partition_groups': 'group_a',
1526*9e94795aSAndroid Build Coastguard Worker        'dynamic_partition_list': 'system',
1527*9e94795aSAndroid Build Coastguard Worker        'super_group_a_partition_list': 'system',
1528*9e94795aSAndroid Build Coastguard Worker        'super_group_a_group_size': '5000',
1529*9e94795aSAndroid Build Coastguard Worker        'vabc_cow_version': '3',
1530*9e94795aSAndroid Build Coastguard Worker    }
1531*9e94795aSAndroid Build Coastguard Worker    vendor_dict = {
1532*9e94795aSAndroid Build Coastguard Worker        'use_dynamic_partitions': 'true',
1533*9e94795aSAndroid Build Coastguard Worker        'super_partition_groups': 'group_a group_b',
1534*9e94795aSAndroid Build Coastguard Worker        'dynamic_partition_list': 'vendor product',
1535*9e94795aSAndroid Build Coastguard Worker        'super_group_a_partition_list': 'vendor',
1536*9e94795aSAndroid Build Coastguard Worker        'super_group_a_group_size': '1000',
1537*9e94795aSAndroid Build Coastguard Worker        'super_group_b_partition_list': 'product',
1538*9e94795aSAndroid Build Coastguard Worker        'super_group_b_group_size': '2000',
1539*9e94795aSAndroid Build Coastguard Worker    }
1540*9e94795aSAndroid Build Coastguard Worker    merged_dict = common.MergeDynamicPartitionInfoDicts(
1541*9e94795aSAndroid Build Coastguard Worker        framework_dict=framework_dict,
1542*9e94795aSAndroid Build Coastguard Worker        vendor_dict=vendor_dict)
1543*9e94795aSAndroid Build Coastguard Worker    expected_merged_dict = {
1544*9e94795aSAndroid Build Coastguard Worker        'use_dynamic_partitions': 'true',
1545*9e94795aSAndroid Build Coastguard Worker        'super_partition_groups': 'group_a group_b',
1546*9e94795aSAndroid Build Coastguard Worker        'dynamic_partition_list': 'product system vendor',
1547*9e94795aSAndroid Build Coastguard Worker        'super_group_a_partition_list': 'system vendor',
1548*9e94795aSAndroid Build Coastguard Worker        'super_group_a_group_size': '1000',
1549*9e94795aSAndroid Build Coastguard Worker        'super_group_b_partition_list': 'product',
1550*9e94795aSAndroid Build Coastguard Worker        'super_group_b_group_size': '2000',
1551*9e94795aSAndroid Build Coastguard Worker        'vabc_cow_version': '2',
1552*9e94795aSAndroid Build Coastguard Worker    }
1553*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(merged_dict, expected_merged_dict)
1554*9e94795aSAndroid Build Coastguard Worker
1555*9e94795aSAndroid Build Coastguard Worker  def test_GetAvbPartitionArg(self):
1556*9e94795aSAndroid Build Coastguard Worker    info_dict = {}
1557*9e94795aSAndroid Build Coastguard Worker    cmd = common.GetAvbPartitionArg('system', '/path/to/system.img', info_dict)
1558*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(
1559*9e94795aSAndroid Build Coastguard Worker        [common.AVB_ARG_NAME_INCLUDE_DESC_FROM_IMG, '/path/to/system.img'],
1560*9e94795aSAndroid Build Coastguard Worker        cmd)
1561*9e94795aSAndroid Build Coastguard Worker
1562*9e94795aSAndroid Build Coastguard Worker  @test_utils.SkipIfExternalToolsUnavailable()
1563*9e94795aSAndroid Build Coastguard Worker  def test_AppendVBMetaArgsForPartition_vendorAsChainedPartition(self):
1564*9e94795aSAndroid Build Coastguard Worker    testdata_dir = test_utils.get_testdata_dir()
1565*9e94795aSAndroid Build Coastguard Worker    pubkey = os.path.join(testdata_dir, 'testkey.pubkey.pem')
1566*9e94795aSAndroid Build Coastguard Worker    info_dict = {
1567*9e94795aSAndroid Build Coastguard Worker        'avb_avbtool': 'avbtool',
1568*9e94795aSAndroid Build Coastguard Worker        'avb_vendor_key_path': pubkey,
1569*9e94795aSAndroid Build Coastguard Worker        'avb_vendor_rollback_index_location': 5,
1570*9e94795aSAndroid Build Coastguard Worker    }
1571*9e94795aSAndroid Build Coastguard Worker    cmd = common.GetAvbPartitionArg('vendor', '/path/to/vendor.img', info_dict)
1572*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(2, len(cmd))
1573*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(common.AVB_ARG_NAME_CHAIN_PARTITION, cmd[0])
1574*9e94795aSAndroid Build Coastguard Worker    chained_partition_args = cmd[1]
1575*9e94795aSAndroid Build Coastguard Worker    self.assertEqual('vendor', chained_partition_args.partition)
1576*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(5, chained_partition_args.rollback_index_location)
1577*9e94795aSAndroid Build Coastguard Worker    self.assertTrue(os.path.exists(chained_partition_args.pubkey_path))
1578*9e94795aSAndroid Build Coastguard Worker
1579*9e94795aSAndroid Build Coastguard Worker  @test_utils.SkipIfExternalToolsUnavailable()
1580*9e94795aSAndroid Build Coastguard Worker  def test_AppendVBMetaArgsForPartition_recoveryAsChainedPartition_nonAb(self):
1581*9e94795aSAndroid Build Coastguard Worker    testdata_dir = test_utils.get_testdata_dir()
1582*9e94795aSAndroid Build Coastguard Worker    pubkey = os.path.join(testdata_dir, 'testkey.pubkey.pem')
1583*9e94795aSAndroid Build Coastguard Worker    info_dict = {
1584*9e94795aSAndroid Build Coastguard Worker        'avb_avbtool': 'avbtool',
1585*9e94795aSAndroid Build Coastguard Worker        'avb_recovery_key_path': pubkey,
1586*9e94795aSAndroid Build Coastguard Worker        'avb_recovery_rollback_index_location': 3,
1587*9e94795aSAndroid Build Coastguard Worker    }
1588*9e94795aSAndroid Build Coastguard Worker    cmd = common.GetAvbPartitionArg(
1589*9e94795aSAndroid Build Coastguard Worker        'recovery', '/path/to/recovery.img', info_dict)
1590*9e94795aSAndroid Build Coastguard Worker    self.assertFalse(cmd)
1591*9e94795aSAndroid Build Coastguard Worker
1592*9e94795aSAndroid Build Coastguard Worker  @test_utils.SkipIfExternalToolsUnavailable()
1593*9e94795aSAndroid Build Coastguard Worker  def test_AppendVBMetaArgsForPartition_recoveryAsChainedPartition_ab(self):
1594*9e94795aSAndroid Build Coastguard Worker    testdata_dir = test_utils.get_testdata_dir()
1595*9e94795aSAndroid Build Coastguard Worker    pubkey = os.path.join(testdata_dir, 'testkey.pubkey.pem')
1596*9e94795aSAndroid Build Coastguard Worker    info_dict = {
1597*9e94795aSAndroid Build Coastguard Worker        'ab_update': 'true',
1598*9e94795aSAndroid Build Coastguard Worker        'avb_avbtool': 'avbtool',
1599*9e94795aSAndroid Build Coastguard Worker        'avb_recovery_key_path': pubkey,
1600*9e94795aSAndroid Build Coastguard Worker        'avb_recovery_rollback_index_location': 3,
1601*9e94795aSAndroid Build Coastguard Worker    }
1602*9e94795aSAndroid Build Coastguard Worker    cmd = common.GetAvbPartitionArg(
1603*9e94795aSAndroid Build Coastguard Worker        'recovery', '/path/to/recovery.img', info_dict)
1604*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(2, len(cmd))
1605*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(common.AVB_ARG_NAME_CHAIN_PARTITION, cmd[0])
1606*9e94795aSAndroid Build Coastguard Worker    chained_partition_args = cmd[1]
1607*9e94795aSAndroid Build Coastguard Worker    self.assertEqual('recovery', chained_partition_args.partition)
1608*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(3, chained_partition_args.rollback_index_location)
1609*9e94795aSAndroid Build Coastguard Worker    self.assertTrue(os.path.exists(chained_partition_args.pubkey_path))
1610*9e94795aSAndroid Build Coastguard Worker
1611*9e94795aSAndroid Build Coastguard Worker
1612*9e94795aSAndroid Build Coastguard Workerclass InstallRecoveryScriptFormatTest(test_utils.ReleaseToolsTestCase):
1613*9e94795aSAndroid Build Coastguard Worker  """Checks the format of install-recovery.sh.
1614*9e94795aSAndroid Build Coastguard Worker
1615*9e94795aSAndroid Build Coastguard Worker  Its format should match between common.py and validate_target_files.py.
1616*9e94795aSAndroid Build Coastguard Worker  """
1617*9e94795aSAndroid Build Coastguard Worker
1618*9e94795aSAndroid Build Coastguard Worker  def setUp(self):
1619*9e94795aSAndroid Build Coastguard Worker    self._tempdir = common.MakeTempDir()
1620*9e94795aSAndroid Build Coastguard Worker    # Create a fake dict that contains the fstab info for boot&recovery.
1621*9e94795aSAndroid Build Coastguard Worker    self._info = {"fstab": {}}
1622*9e94795aSAndroid Build Coastguard Worker    fake_fstab = [
1623*9e94795aSAndroid Build Coastguard Worker        "/dev/soc.0/by-name/boot /boot emmc defaults defaults",
1624*9e94795aSAndroid Build Coastguard Worker        "/dev/soc.0/by-name/recovery /recovery emmc defaults defaults"]
1625*9e94795aSAndroid Build Coastguard Worker    self._info["fstab"] = common.LoadRecoveryFSTab("\n".join, 2, fake_fstab)
1626*9e94795aSAndroid Build Coastguard Worker    # Construct the gzipped recovery.img and boot.img
1627*9e94795aSAndroid Build Coastguard Worker    self.recovery_data = bytearray([
1628*9e94795aSAndroid Build Coastguard Worker        0x1f, 0x8b, 0x08, 0x00, 0x81, 0x11, 0x02, 0x5a, 0x00, 0x03, 0x2b, 0x4a,
1629*9e94795aSAndroid Build Coastguard Worker        0x4d, 0xce, 0x2f, 0x4b, 0x2d, 0xaa, 0x04, 0x00, 0xc9, 0x93, 0x43, 0xf3,
1630*9e94795aSAndroid Build Coastguard Worker        0x08, 0x00, 0x00, 0x00
1631*9e94795aSAndroid Build Coastguard Worker    ])
1632*9e94795aSAndroid Build Coastguard Worker    # echo -n "boot" | gzip -f | hd
1633*9e94795aSAndroid Build Coastguard Worker    self.boot_data = bytearray([
1634*9e94795aSAndroid Build Coastguard Worker        0x1f, 0x8b, 0x08, 0x00, 0x8c, 0x12, 0x02, 0x5a, 0x00, 0x03, 0x4b, 0xca,
1635*9e94795aSAndroid Build Coastguard Worker        0xcf, 0x2f, 0x01, 0x00, 0xc4, 0xae, 0xed, 0x46, 0x04, 0x00, 0x00, 0x00
1636*9e94795aSAndroid Build Coastguard Worker    ])
1637*9e94795aSAndroid Build Coastguard Worker
1638*9e94795aSAndroid Build Coastguard Worker  def _out_tmp_sink(self, name, data, prefix="SYSTEM"):
1639*9e94795aSAndroid Build Coastguard Worker    loc = os.path.join(self._tempdir, prefix, name)
1640*9e94795aSAndroid Build Coastguard Worker    if not os.path.exists(os.path.dirname(loc)):
1641*9e94795aSAndroid Build Coastguard Worker      os.makedirs(os.path.dirname(loc))
1642*9e94795aSAndroid Build Coastguard Worker    with open(loc, "wb") as f:
1643*9e94795aSAndroid Build Coastguard Worker      f.write(data)
1644*9e94795aSAndroid Build Coastguard Worker
1645*9e94795aSAndroid Build Coastguard Worker  def test_full_recovery(self):
1646*9e94795aSAndroid Build Coastguard Worker    recovery_image = common.File("recovery.img", self.recovery_data)
1647*9e94795aSAndroid Build Coastguard Worker    boot_image = common.File("boot.img", self.boot_data)
1648*9e94795aSAndroid Build Coastguard Worker    self._info["full_recovery_image"] = "true"
1649*9e94795aSAndroid Build Coastguard Worker
1650*9e94795aSAndroid Build Coastguard Worker    common.MakeRecoveryPatch(self._tempdir, self._out_tmp_sink,
1651*9e94795aSAndroid Build Coastguard Worker                             recovery_image, boot_image, self._info)
1652*9e94795aSAndroid Build Coastguard Worker    validate_target_files.ValidateInstallRecoveryScript(self._tempdir,
1653*9e94795aSAndroid Build Coastguard Worker                                                        self._info)
1654*9e94795aSAndroid Build Coastguard Worker
1655*9e94795aSAndroid Build Coastguard Worker  @test_utils.SkipIfExternalToolsUnavailable()
1656*9e94795aSAndroid Build Coastguard Worker  def test_recovery_from_boot(self):
1657*9e94795aSAndroid Build Coastguard Worker    recovery_image = common.File("recovery.img", self.recovery_data)
1658*9e94795aSAndroid Build Coastguard Worker    self._out_tmp_sink("recovery.img", recovery_image.data, "IMAGES")
1659*9e94795aSAndroid Build Coastguard Worker    boot_image = common.File("boot.img", self.boot_data)
1660*9e94795aSAndroid Build Coastguard Worker    self._out_tmp_sink("boot.img", boot_image.data, "IMAGES")
1661*9e94795aSAndroid Build Coastguard Worker
1662*9e94795aSAndroid Build Coastguard Worker    common.MakeRecoveryPatch(self._tempdir, self._out_tmp_sink,
1663*9e94795aSAndroid Build Coastguard Worker                             recovery_image, boot_image, self._info)
1664*9e94795aSAndroid Build Coastguard Worker    validate_target_files.ValidateInstallRecoveryScript(self._tempdir,
1665*9e94795aSAndroid Build Coastguard Worker                                                        self._info)
1666*9e94795aSAndroid Build Coastguard Worker    # Validate 'recovery-from-boot' with bonus argument.
1667*9e94795aSAndroid Build Coastguard Worker    self._out_tmp_sink("etc/recovery-resource.dat", b"bonus", "SYSTEM")
1668*9e94795aSAndroid Build Coastguard Worker    common.MakeRecoveryPatch(self._tempdir, self._out_tmp_sink,
1669*9e94795aSAndroid Build Coastguard Worker                             recovery_image, boot_image, self._info)
1670*9e94795aSAndroid Build Coastguard Worker    validate_target_files.ValidateInstallRecoveryScript(self._tempdir,
1671*9e94795aSAndroid Build Coastguard Worker                                                        self._info)
1672*9e94795aSAndroid Build Coastguard Worker
1673*9e94795aSAndroid Build Coastguard Worker
1674*9e94795aSAndroid Build Coastguard Workerclass MockBlockDifference(object):
1675*9e94795aSAndroid Build Coastguard Worker
1676*9e94795aSAndroid Build Coastguard Worker  def __init__(self, partition, tgt, src=None):
1677*9e94795aSAndroid Build Coastguard Worker    self.partition = partition
1678*9e94795aSAndroid Build Coastguard Worker    self.tgt = tgt
1679*9e94795aSAndroid Build Coastguard Worker    self.src = src
1680*9e94795aSAndroid Build Coastguard Worker
1681*9e94795aSAndroid Build Coastguard Worker  def WriteScript(self, script, _, progress=None,
1682*9e94795aSAndroid Build Coastguard Worker                  write_verify_script=False):
1683*9e94795aSAndroid Build Coastguard Worker    if progress:
1684*9e94795aSAndroid Build Coastguard Worker      script.AppendExtra("progress({})".format(progress))
1685*9e94795aSAndroid Build Coastguard Worker    script.AppendExtra("patch({});".format(self.partition))
1686*9e94795aSAndroid Build Coastguard Worker    if write_verify_script:
1687*9e94795aSAndroid Build Coastguard Worker      self.WritePostInstallVerifyScript(script)
1688*9e94795aSAndroid Build Coastguard Worker
1689*9e94795aSAndroid Build Coastguard Worker  def WritePostInstallVerifyScript(self, script):
1690*9e94795aSAndroid Build Coastguard Worker    script.AppendExtra("verify({});".format(self.partition))
1691*9e94795aSAndroid Build Coastguard Worker
1692*9e94795aSAndroid Build Coastguard Worker
1693*9e94795aSAndroid Build Coastguard Workerclass FakeSparseImage(object):
1694*9e94795aSAndroid Build Coastguard Worker
1695*9e94795aSAndroid Build Coastguard Worker  def __init__(self, size):
1696*9e94795aSAndroid Build Coastguard Worker    self.blocksize = 4096
1697*9e94795aSAndroid Build Coastguard Worker    self.total_blocks = size // 4096
1698*9e94795aSAndroid Build Coastguard Worker    assert size % 4096 == 0, "{} is not a multiple of 4096".format(size)
1699*9e94795aSAndroid Build Coastguard Worker
1700*9e94795aSAndroid Build Coastguard Worker
1701*9e94795aSAndroid Build Coastguard Workerclass DynamicPartitionsDifferenceTest(test_utils.ReleaseToolsTestCase):
1702*9e94795aSAndroid Build Coastguard Worker
1703*9e94795aSAndroid Build Coastguard Worker  @staticmethod
1704*9e94795aSAndroid Build Coastguard Worker  def get_op_list(output_path):
1705*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(output_path, allowZip64=True) as output_zip:
1706*9e94795aSAndroid Build Coastguard Worker      with output_zip.open('dynamic_partitions_op_list') as op_list:
1707*9e94795aSAndroid Build Coastguard Worker        return [line.decode().strip() for line in op_list.readlines()
1708*9e94795aSAndroid Build Coastguard Worker                if not line.startswith(b'#')]
1709*9e94795aSAndroid Build Coastguard Worker
1710*9e94795aSAndroid Build Coastguard Worker  def setUp(self):
1711*9e94795aSAndroid Build Coastguard Worker    self.script = test_utils.MockScriptWriter()
1712*9e94795aSAndroid Build Coastguard Worker    self.output_path = common.MakeTempFile(suffix='.zip')
1713*9e94795aSAndroid Build Coastguard Worker
1714*9e94795aSAndroid Build Coastguard Worker  def test_full(self):
1715*9e94795aSAndroid Build Coastguard Worker    target_info = common.LoadDictionaryFromLines("""
1716*9e94795aSAndroid Build Coastguard Workerdynamic_partition_list=system vendor
1717*9e94795aSAndroid Build Coastguard Workersuper_partition_groups=group_foo
1718*9e94795aSAndroid Build Coastguard Workersuper_group_foo_group_size={group_size}
1719*9e94795aSAndroid Build Coastguard Workersuper_group_foo_partition_list=system vendor
1720*9e94795aSAndroid Build Coastguard Worker""".format(group_size=4 * GiB).split("\n"))
1721*9e94795aSAndroid Build Coastguard Worker    block_diffs = [MockBlockDifference("system", FakeSparseImage(3 * GiB)),
1722*9e94795aSAndroid Build Coastguard Worker                   MockBlockDifference("vendor", FakeSparseImage(1 * GiB))]
1723*9e94795aSAndroid Build Coastguard Worker
1724*9e94795aSAndroid Build Coastguard Worker    dp_diff = common.DynamicPartitionsDifference(target_info, block_diffs)
1725*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(self.output_path, 'w', allowZip64=True) as output_zip:
1726*9e94795aSAndroid Build Coastguard Worker      dp_diff.WriteScript(self.script, output_zip, write_verify_script=True)
1727*9e94795aSAndroid Build Coastguard Worker
1728*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(str(self.script).strip(), """
1729*9e94795aSAndroid Build Coastguard Workerassert(update_dynamic_partitions(package_extract_file("dynamic_partitions_op_list")));
1730*9e94795aSAndroid Build Coastguard Workerpatch(system);
1731*9e94795aSAndroid Build Coastguard Workerverify(system);
1732*9e94795aSAndroid Build Coastguard Workerunmap_partition("system");
1733*9e94795aSAndroid Build Coastguard Workerpatch(vendor);
1734*9e94795aSAndroid Build Coastguard Workerverify(vendor);
1735*9e94795aSAndroid Build Coastguard Workerunmap_partition("vendor");
1736*9e94795aSAndroid Build Coastguard Worker""".strip())
1737*9e94795aSAndroid Build Coastguard Worker
1738*9e94795aSAndroid Build Coastguard Worker    lines = self.get_op_list(self.output_path)
1739*9e94795aSAndroid Build Coastguard Worker
1740*9e94795aSAndroid Build Coastguard Worker    remove_all_groups = lines.index("remove_all_groups")
1741*9e94795aSAndroid Build Coastguard Worker    add_group = lines.index("add_group group_foo 4294967296")
1742*9e94795aSAndroid Build Coastguard Worker    add_vendor = lines.index("add vendor group_foo")
1743*9e94795aSAndroid Build Coastguard Worker    add_system = lines.index("add system group_foo")
1744*9e94795aSAndroid Build Coastguard Worker    resize_vendor = lines.index("resize vendor 1073741824")
1745*9e94795aSAndroid Build Coastguard Worker    resize_system = lines.index("resize system 3221225472")
1746*9e94795aSAndroid Build Coastguard Worker
1747*9e94795aSAndroid Build Coastguard Worker    self.assertLess(remove_all_groups, add_group,
1748*9e94795aSAndroid Build Coastguard Worker                    "Should add groups after removing all groups")
1749*9e94795aSAndroid Build Coastguard Worker    self.assertLess(add_group, min(add_vendor, add_system),
1750*9e94795aSAndroid Build Coastguard Worker                    "Should add partitions after adding group")
1751*9e94795aSAndroid Build Coastguard Worker    self.assertLess(add_system, resize_system,
1752*9e94795aSAndroid Build Coastguard Worker                    "Should resize system after adding it")
1753*9e94795aSAndroid Build Coastguard Worker    self.assertLess(add_vendor, resize_vendor,
1754*9e94795aSAndroid Build Coastguard Worker                    "Should resize vendor after adding it")
1755*9e94795aSAndroid Build Coastguard Worker
1756*9e94795aSAndroid Build Coastguard Worker  def test_inc_groups(self):
1757*9e94795aSAndroid Build Coastguard Worker    source_info = common.LoadDictionaryFromLines("""
1758*9e94795aSAndroid Build Coastguard Workersuper_partition_groups=group_foo group_bar group_baz
1759*9e94795aSAndroid Build Coastguard Workersuper_group_foo_group_size={group_foo_size}
1760*9e94795aSAndroid Build Coastguard Workersuper_group_bar_group_size={group_bar_size}
1761*9e94795aSAndroid Build Coastguard Worker""".format(group_foo_size=4 * GiB, group_bar_size=3 * GiB).split("\n"))
1762*9e94795aSAndroid Build Coastguard Worker    target_info = common.LoadDictionaryFromLines("""
1763*9e94795aSAndroid Build Coastguard Workersuper_partition_groups=group_foo group_baz group_qux
1764*9e94795aSAndroid Build Coastguard Workersuper_group_foo_group_size={group_foo_size}
1765*9e94795aSAndroid Build Coastguard Workersuper_group_baz_group_size={group_baz_size}
1766*9e94795aSAndroid Build Coastguard Workersuper_group_qux_group_size={group_qux_size}
1767*9e94795aSAndroid Build Coastguard Worker""".format(group_foo_size=3 * GiB, group_baz_size=4 * GiB,
1768*9e94795aSAndroid Build Coastguard Worker           group_qux_size=1 * GiB).split("\n"))
1769*9e94795aSAndroid Build Coastguard Worker
1770*9e94795aSAndroid Build Coastguard Worker    dp_diff = common.DynamicPartitionsDifference(target_info,
1771*9e94795aSAndroid Build Coastguard Worker                                                 block_diffs=[],
1772*9e94795aSAndroid Build Coastguard Worker                                                 source_info_dict=source_info)
1773*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(self.output_path, 'w', allowZip64=True) as output_zip:
1774*9e94795aSAndroid Build Coastguard Worker      dp_diff.WriteScript(self.script, output_zip, write_verify_script=True)
1775*9e94795aSAndroid Build Coastguard Worker
1776*9e94795aSAndroid Build Coastguard Worker    lines = self.get_op_list(self.output_path)
1777*9e94795aSAndroid Build Coastguard Worker
1778*9e94795aSAndroid Build Coastguard Worker    removed = lines.index("remove_group group_bar")
1779*9e94795aSAndroid Build Coastguard Worker    shrunk = lines.index("resize_group group_foo 3221225472")
1780*9e94795aSAndroid Build Coastguard Worker    grown = lines.index("resize_group group_baz 4294967296")
1781*9e94795aSAndroid Build Coastguard Worker    added = lines.index("add_group group_qux 1073741824")
1782*9e94795aSAndroid Build Coastguard Worker
1783*9e94795aSAndroid Build Coastguard Worker    self.assertLess(max(removed, shrunk),
1784*9e94795aSAndroid Build Coastguard Worker                    min(grown, added),
1785*9e94795aSAndroid Build Coastguard Worker                    "ops that remove / shrink partitions must precede ops that "
1786*9e94795aSAndroid Build Coastguard Worker                    "grow / add partitions")
1787*9e94795aSAndroid Build Coastguard Worker
1788*9e94795aSAndroid Build Coastguard Worker  def test_incremental(self):
1789*9e94795aSAndroid Build Coastguard Worker    source_info = common.LoadDictionaryFromLines("""
1790*9e94795aSAndroid Build Coastguard Workerdynamic_partition_list=system vendor product system_ext
1791*9e94795aSAndroid Build Coastguard Workersuper_partition_groups=group_foo
1792*9e94795aSAndroid Build Coastguard Workersuper_group_foo_group_size={group_foo_size}
1793*9e94795aSAndroid Build Coastguard Workersuper_group_foo_partition_list=system vendor product system_ext
1794*9e94795aSAndroid Build Coastguard Worker""".format(group_foo_size=4 * GiB).split("\n"))
1795*9e94795aSAndroid Build Coastguard Worker    target_info = common.LoadDictionaryFromLines("""
1796*9e94795aSAndroid Build Coastguard Workerdynamic_partition_list=system vendor product odm
1797*9e94795aSAndroid Build Coastguard Workersuper_partition_groups=group_foo group_bar
1798*9e94795aSAndroid Build Coastguard Workersuper_group_foo_group_size={group_foo_size}
1799*9e94795aSAndroid Build Coastguard Workersuper_group_foo_partition_list=system vendor odm
1800*9e94795aSAndroid Build Coastguard Workersuper_group_bar_group_size={group_bar_size}
1801*9e94795aSAndroid Build Coastguard Workersuper_group_bar_partition_list=product
1802*9e94795aSAndroid Build Coastguard Worker""".format(group_foo_size=3 * GiB, group_bar_size=1 * GiB).split("\n"))
1803*9e94795aSAndroid Build Coastguard Worker
1804*9e94795aSAndroid Build Coastguard Worker    block_diffs = [MockBlockDifference("system", FakeSparseImage(1536 * MiB),
1805*9e94795aSAndroid Build Coastguard Worker                                       src=FakeSparseImage(1024 * MiB)),
1806*9e94795aSAndroid Build Coastguard Worker                   MockBlockDifference("vendor", FakeSparseImage(512 * MiB),
1807*9e94795aSAndroid Build Coastguard Worker                                       src=FakeSparseImage(1024 * MiB)),
1808*9e94795aSAndroid Build Coastguard Worker                   MockBlockDifference("product", FakeSparseImage(1024 * MiB),
1809*9e94795aSAndroid Build Coastguard Worker                                       src=FakeSparseImage(1024 * MiB)),
1810*9e94795aSAndroid Build Coastguard Worker                   MockBlockDifference("system_ext", None,
1811*9e94795aSAndroid Build Coastguard Worker                                       src=FakeSparseImage(1024 * MiB)),
1812*9e94795aSAndroid Build Coastguard Worker                   MockBlockDifference("odm", FakeSparseImage(1024 * MiB),
1813*9e94795aSAndroid Build Coastguard Worker                                       src=None)]
1814*9e94795aSAndroid Build Coastguard Worker
1815*9e94795aSAndroid Build Coastguard Worker    dp_diff = common.DynamicPartitionsDifference(target_info, block_diffs,
1816*9e94795aSAndroid Build Coastguard Worker                                                 source_info_dict=source_info)
1817*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(self.output_path, 'w', allowZip64=True) as output_zip:
1818*9e94795aSAndroid Build Coastguard Worker      dp_diff.WriteScript(self.script, output_zip, write_verify_script=True)
1819*9e94795aSAndroid Build Coastguard Worker
1820*9e94795aSAndroid Build Coastguard Worker    metadata_idx = self.script.lines.index(
1821*9e94795aSAndroid Build Coastguard Worker        'assert(update_dynamic_partitions(package_extract_file('
1822*9e94795aSAndroid Build Coastguard Worker        '"dynamic_partitions_op_list")));')
1823*9e94795aSAndroid Build Coastguard Worker    self.assertLess(self.script.lines.index('patch(vendor);'), metadata_idx)
1824*9e94795aSAndroid Build Coastguard Worker    self.assertLess(metadata_idx, self.script.lines.index('verify(vendor);'))
1825*9e94795aSAndroid Build Coastguard Worker    for p in ("product", "system", "odm"):
1826*9e94795aSAndroid Build Coastguard Worker      patch_idx = self.script.lines.index("patch({});".format(p))
1827*9e94795aSAndroid Build Coastguard Worker      verify_idx = self.script.lines.index("verify({});".format(p))
1828*9e94795aSAndroid Build Coastguard Worker      self.assertLess(metadata_idx, patch_idx,
1829*9e94795aSAndroid Build Coastguard Worker                      "Should patch {} after updating metadata".format(p))
1830*9e94795aSAndroid Build Coastguard Worker      self.assertLess(patch_idx, verify_idx,
1831*9e94795aSAndroid Build Coastguard Worker                      "Should verify {} after patching".format(p))
1832*9e94795aSAndroid Build Coastguard Worker
1833*9e94795aSAndroid Build Coastguard Worker    self.assertNotIn("patch(system_ext);", self.script.lines)
1834*9e94795aSAndroid Build Coastguard Worker
1835*9e94795aSAndroid Build Coastguard Worker    lines = self.get_op_list(self.output_path)
1836*9e94795aSAndroid Build Coastguard Worker
1837*9e94795aSAndroid Build Coastguard Worker    remove = lines.index("remove system_ext")
1838*9e94795aSAndroid Build Coastguard Worker    move_product_out = lines.index("move product default")
1839*9e94795aSAndroid Build Coastguard Worker    shrink = lines.index("resize vendor 536870912")
1840*9e94795aSAndroid Build Coastguard Worker    shrink_group = lines.index("resize_group group_foo 3221225472")
1841*9e94795aSAndroid Build Coastguard Worker    add_group_bar = lines.index("add_group group_bar 1073741824")
1842*9e94795aSAndroid Build Coastguard Worker    add_odm = lines.index("add odm group_foo")
1843*9e94795aSAndroid Build Coastguard Worker    grow_existing = lines.index("resize system 1610612736")
1844*9e94795aSAndroid Build Coastguard Worker    grow_added = lines.index("resize odm 1073741824")
1845*9e94795aSAndroid Build Coastguard Worker    move_product_in = lines.index("move product group_bar")
1846*9e94795aSAndroid Build Coastguard Worker
1847*9e94795aSAndroid Build Coastguard Worker    max_idx_move_partition_out_foo = max(remove, move_product_out, shrink)
1848*9e94795aSAndroid Build Coastguard Worker    min_idx_move_partition_in_foo = min(add_odm, grow_existing, grow_added)
1849*9e94795aSAndroid Build Coastguard Worker
1850*9e94795aSAndroid Build Coastguard Worker    self.assertLess(max_idx_move_partition_out_foo, shrink_group,
1851*9e94795aSAndroid Build Coastguard Worker                    "Must shrink group after partitions inside group are shrunk"
1852*9e94795aSAndroid Build Coastguard Worker                    " / removed")
1853*9e94795aSAndroid Build Coastguard Worker
1854*9e94795aSAndroid Build Coastguard Worker    self.assertLess(add_group_bar, move_product_in,
1855*9e94795aSAndroid Build Coastguard Worker                    "Must add partitions to group after group is added")
1856*9e94795aSAndroid Build Coastguard Worker
1857*9e94795aSAndroid Build Coastguard Worker    self.assertLess(max_idx_move_partition_out_foo,
1858*9e94795aSAndroid Build Coastguard Worker                    min_idx_move_partition_in_foo,
1859*9e94795aSAndroid Build Coastguard Worker                    "Must shrink partitions / remove partitions from group"
1860*9e94795aSAndroid Build Coastguard Worker                    "before adding / moving partitions into group")
1861*9e94795aSAndroid Build Coastguard Worker
1862*9e94795aSAndroid Build Coastguard Worker  def test_remove_partition(self):
1863*9e94795aSAndroid Build Coastguard Worker    source_info = common.LoadDictionaryFromLines("""
1864*9e94795aSAndroid Build Coastguard Workerblockimgdiff_versions=3,4
1865*9e94795aSAndroid Build Coastguard Workeruse_dynamic_partitions=true
1866*9e94795aSAndroid Build Coastguard Workerdynamic_partition_list=foo
1867*9e94795aSAndroid Build Coastguard Workersuper_partition_groups=group_foo
1868*9e94795aSAndroid Build Coastguard Workersuper_group_foo_group_size={group_foo_size}
1869*9e94795aSAndroid Build Coastguard Workersuper_group_foo_partition_list=foo
1870*9e94795aSAndroid Build Coastguard Worker""".format(group_foo_size=4 * GiB).split("\n"))
1871*9e94795aSAndroid Build Coastguard Worker    target_info = common.LoadDictionaryFromLines("""
1872*9e94795aSAndroid Build Coastguard Workerblockimgdiff_versions=3,4
1873*9e94795aSAndroid Build Coastguard Workeruse_dynamic_partitions=true
1874*9e94795aSAndroid Build Coastguard Workersuper_partition_groups=group_foo
1875*9e94795aSAndroid Build Coastguard Workersuper_group_foo_group_size={group_foo_size}
1876*9e94795aSAndroid Build Coastguard Worker""".format(group_foo_size=4 * GiB).split("\n"))
1877*9e94795aSAndroid Build Coastguard Worker
1878*9e94795aSAndroid Build Coastguard Worker    common.OPTIONS.info_dict = target_info
1879*9e94795aSAndroid Build Coastguard Worker    common.OPTIONS.target_info_dict = target_info
1880*9e94795aSAndroid Build Coastguard Worker    common.OPTIONS.source_info_dict = source_info
1881*9e94795aSAndroid Build Coastguard Worker    common.OPTIONS.cache_size = 4 * 4096
1882*9e94795aSAndroid Build Coastguard Worker
1883*9e94795aSAndroid Build Coastguard Worker    block_diffs = [common.BlockDifference("foo", EmptyImage(),
1884*9e94795aSAndroid Build Coastguard Worker                                          src=DataImage("source", pad=True))]
1885*9e94795aSAndroid Build Coastguard Worker
1886*9e94795aSAndroid Build Coastguard Worker    dp_diff = common.DynamicPartitionsDifference(target_info, block_diffs,
1887*9e94795aSAndroid Build Coastguard Worker                                                 source_info_dict=source_info)
1888*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(self.output_path, 'w', allowZip64=True) as output_zip:
1889*9e94795aSAndroid Build Coastguard Worker      dp_diff.WriteScript(self.script, output_zip, write_verify_script=True)
1890*9e94795aSAndroid Build Coastguard Worker
1891*9e94795aSAndroid Build Coastguard Worker    self.assertNotIn("block_image_update", str(self.script),
1892*9e94795aSAndroid Build Coastguard Worker                     "Removed partition should not be patched.")
1893*9e94795aSAndroid Build Coastguard Worker
1894*9e94795aSAndroid Build Coastguard Worker    lines = self.get_op_list(self.output_path)
1895*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(lines, ["remove foo"])
1896*9e94795aSAndroid Build Coastguard Worker
1897*9e94795aSAndroid Build Coastguard Worker
1898*9e94795aSAndroid Build Coastguard Workerclass PartitionBuildPropsTest(test_utils.ReleaseToolsTestCase):
1899*9e94795aSAndroid Build Coastguard Worker  def setUp(self):
1900*9e94795aSAndroid Build Coastguard Worker    self.odm_build_prop = [
1901*9e94795aSAndroid Build Coastguard Worker        'ro.odm.build.date.utc=1578430045',
1902*9e94795aSAndroid Build Coastguard Worker        'ro.odm.build.fingerprint='
1903*9e94795aSAndroid Build Coastguard Worker        'google/coral/coral:10/RP1A.200325.001/6337676:user/dev-keys',
1904*9e94795aSAndroid Build Coastguard Worker        'ro.product.odm.device=coral',
1905*9e94795aSAndroid Build Coastguard Worker        'import /odm/etc/build_${ro.boot.product.device_name}.prop',
1906*9e94795aSAndroid Build Coastguard Worker    ]
1907*9e94795aSAndroid Build Coastguard Worker
1908*9e94795aSAndroid Build Coastguard Worker  @staticmethod
1909*9e94795aSAndroid Build Coastguard Worker  def _BuildZipFile(entries):
1910*9e94795aSAndroid Build Coastguard Worker    input_file = common.MakeTempFile(prefix='target_files-', suffix='.zip')
1911*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(input_file, 'w', allowZip64=True) as input_zip:
1912*9e94795aSAndroid Build Coastguard Worker      for name, content in entries.items():
1913*9e94795aSAndroid Build Coastguard Worker        input_zip.writestr(name, content)
1914*9e94795aSAndroid Build Coastguard Worker
1915*9e94795aSAndroid Build Coastguard Worker    return input_file
1916*9e94795aSAndroid Build Coastguard Worker
1917*9e94795aSAndroid Build Coastguard Worker  def test_parseBuildProps_noImportStatement(self):
1918*9e94795aSAndroid Build Coastguard Worker    build_prop = [
1919*9e94795aSAndroid Build Coastguard Worker        'ro.odm.build.date.utc=1578430045',
1920*9e94795aSAndroid Build Coastguard Worker        'ro.odm.build.fingerprint='
1921*9e94795aSAndroid Build Coastguard Worker        'google/coral/coral:10/RP1A.200325.001/6337676:user/dev-keys',
1922*9e94795aSAndroid Build Coastguard Worker        'ro.product.odm.device=coral',
1923*9e94795aSAndroid Build Coastguard Worker    ]
1924*9e94795aSAndroid Build Coastguard Worker    input_file = self._BuildZipFile({
1925*9e94795aSAndroid Build Coastguard Worker        'ODM/etc/build.prop': '\n'.join(build_prop),
1926*9e94795aSAndroid Build Coastguard Worker    })
1927*9e94795aSAndroid Build Coastguard Worker
1928*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(input_file, 'r', allowZip64=True) as input_zip:
1929*9e94795aSAndroid Build Coastguard Worker      placeholder_values = {
1930*9e94795aSAndroid Build Coastguard Worker          'ro.boot.product.device_name': ['std', 'pro']
1931*9e94795aSAndroid Build Coastguard Worker      }
1932*9e94795aSAndroid Build Coastguard Worker      partition_props = common.PartitionBuildProps.FromInputFile(
1933*9e94795aSAndroid Build Coastguard Worker          input_zip, 'odm', placeholder_values)
1934*9e94795aSAndroid Build Coastguard Worker
1935*9e94795aSAndroid Build Coastguard Worker    self.assertEqual({
1936*9e94795aSAndroid Build Coastguard Worker        'ro.odm.build.date.utc': '1578430045',
1937*9e94795aSAndroid Build Coastguard Worker        'ro.odm.build.fingerprint':
1938*9e94795aSAndroid Build Coastguard Worker        'google/coral/coral:10/RP1A.200325.001/6337676:user/dev-keys',
1939*9e94795aSAndroid Build Coastguard Worker        'ro.product.odm.device': 'coral',
1940*9e94795aSAndroid Build Coastguard Worker    }, partition_props.build_props)
1941*9e94795aSAndroid Build Coastguard Worker
1942*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(set(), partition_props.prop_overrides)
1943*9e94795aSAndroid Build Coastguard Worker
1944*9e94795aSAndroid Build Coastguard Worker  def test_parseBuildProps_singleImportStatement(self):
1945*9e94795aSAndroid Build Coastguard Worker    build_std_prop = [
1946*9e94795aSAndroid Build Coastguard Worker        'ro.product.odm.device=coral',
1947*9e94795aSAndroid Build Coastguard Worker        'ro.product.odm.name=product1',
1948*9e94795aSAndroid Build Coastguard Worker    ]
1949*9e94795aSAndroid Build Coastguard Worker    build_pro_prop = [
1950*9e94795aSAndroid Build Coastguard Worker        'ro.product.odm.device=coralpro',
1951*9e94795aSAndroid Build Coastguard Worker        'ro.product.odm.name=product2',
1952*9e94795aSAndroid Build Coastguard Worker    ]
1953*9e94795aSAndroid Build Coastguard Worker
1954*9e94795aSAndroid Build Coastguard Worker    input_file = self._BuildZipFile({
1955*9e94795aSAndroid Build Coastguard Worker        'ODM/etc/build.prop': '\n'.join(self.odm_build_prop),
1956*9e94795aSAndroid Build Coastguard Worker        'ODM/etc/build_std.prop': '\n'.join(build_std_prop),
1957*9e94795aSAndroid Build Coastguard Worker        'ODM/etc/build_pro.prop': '\n'.join(build_pro_prop),
1958*9e94795aSAndroid Build Coastguard Worker    })
1959*9e94795aSAndroid Build Coastguard Worker
1960*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(input_file, 'r', allowZip64=True) as input_zip:
1961*9e94795aSAndroid Build Coastguard Worker      placeholder_values = {
1962*9e94795aSAndroid Build Coastguard Worker          'ro.boot.product.device_name': 'std'
1963*9e94795aSAndroid Build Coastguard Worker      }
1964*9e94795aSAndroid Build Coastguard Worker      partition_props = common.PartitionBuildProps.FromInputFile(
1965*9e94795aSAndroid Build Coastguard Worker          input_zip, 'odm', placeholder_values)
1966*9e94795aSAndroid Build Coastguard Worker
1967*9e94795aSAndroid Build Coastguard Worker    self.assertEqual({
1968*9e94795aSAndroid Build Coastguard Worker        'ro.odm.build.date.utc': '1578430045',
1969*9e94795aSAndroid Build Coastguard Worker        'ro.odm.build.fingerprint':
1970*9e94795aSAndroid Build Coastguard Worker        'google/coral/coral:10/RP1A.200325.001/6337676:user/dev-keys',
1971*9e94795aSAndroid Build Coastguard Worker        'ro.product.odm.device': 'coral',
1972*9e94795aSAndroid Build Coastguard Worker        'ro.product.odm.name': 'product1',
1973*9e94795aSAndroid Build Coastguard Worker    }, partition_props.build_props)
1974*9e94795aSAndroid Build Coastguard Worker
1975*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(input_file, 'r', allowZip64=True) as input_zip:
1976*9e94795aSAndroid Build Coastguard Worker      placeholder_values = {
1977*9e94795aSAndroid Build Coastguard Worker          'ro.boot.product.device_name': 'pro'
1978*9e94795aSAndroid Build Coastguard Worker      }
1979*9e94795aSAndroid Build Coastguard Worker      partition_props = common.PartitionBuildProps.FromInputFile(
1980*9e94795aSAndroid Build Coastguard Worker          input_zip, 'odm', placeholder_values)
1981*9e94795aSAndroid Build Coastguard Worker
1982*9e94795aSAndroid Build Coastguard Worker    self.assertEqual({
1983*9e94795aSAndroid Build Coastguard Worker        'ro.odm.build.date.utc': '1578430045',
1984*9e94795aSAndroid Build Coastguard Worker        'ro.odm.build.fingerprint':
1985*9e94795aSAndroid Build Coastguard Worker        'google/coral/coral:10/RP1A.200325.001/6337676:user/dev-keys',
1986*9e94795aSAndroid Build Coastguard Worker        'ro.product.odm.device': 'coralpro',
1987*9e94795aSAndroid Build Coastguard Worker        'ro.product.odm.name': 'product2',
1988*9e94795aSAndroid Build Coastguard Worker    }, partition_props.build_props)
1989*9e94795aSAndroid Build Coastguard Worker
1990*9e94795aSAndroid Build Coastguard Worker  def test_parseBuildProps_noPlaceHolders(self):
1991*9e94795aSAndroid Build Coastguard Worker    build_prop = copy.copy(self.odm_build_prop)
1992*9e94795aSAndroid Build Coastguard Worker    input_file = self._BuildZipFile({
1993*9e94795aSAndroid Build Coastguard Worker        'ODM/etc/build.prop': '\n'.join(build_prop),
1994*9e94795aSAndroid Build Coastguard Worker    })
1995*9e94795aSAndroid Build Coastguard Worker
1996*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(input_file, 'r', allowZip64=True) as input_zip:
1997*9e94795aSAndroid Build Coastguard Worker      partition_props = common.PartitionBuildProps.FromInputFile(
1998*9e94795aSAndroid Build Coastguard Worker          input_zip, 'odm')
1999*9e94795aSAndroid Build Coastguard Worker
2000*9e94795aSAndroid Build Coastguard Worker    self.assertEqual({
2001*9e94795aSAndroid Build Coastguard Worker        'ro.odm.build.date.utc': '1578430045',
2002*9e94795aSAndroid Build Coastguard Worker        'ro.odm.build.fingerprint':
2003*9e94795aSAndroid Build Coastguard Worker        'google/coral/coral:10/RP1A.200325.001/6337676:user/dev-keys',
2004*9e94795aSAndroid Build Coastguard Worker        'ro.product.odm.device': 'coral',
2005*9e94795aSAndroid Build Coastguard Worker    }, partition_props.build_props)
2006*9e94795aSAndroid Build Coastguard Worker
2007*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(set(), partition_props.prop_overrides)
2008*9e94795aSAndroid Build Coastguard Worker
2009*9e94795aSAndroid Build Coastguard Worker  def test_parseBuildProps_multipleImportStatements(self):
2010*9e94795aSAndroid Build Coastguard Worker    build_prop = copy.deepcopy(self.odm_build_prop)
2011*9e94795aSAndroid Build Coastguard Worker    build_prop.append(
2012*9e94795aSAndroid Build Coastguard Worker        'import /odm/etc/build_${ro.boot.product.product_name}.prop')
2013*9e94795aSAndroid Build Coastguard Worker
2014*9e94795aSAndroid Build Coastguard Worker    build_std_prop = [
2015*9e94795aSAndroid Build Coastguard Worker        'ro.product.odm.device=coral',
2016*9e94795aSAndroid Build Coastguard Worker    ]
2017*9e94795aSAndroid Build Coastguard Worker    build_pro_prop = [
2018*9e94795aSAndroid Build Coastguard Worker        'ro.product.odm.device=coralpro',
2019*9e94795aSAndroid Build Coastguard Worker    ]
2020*9e94795aSAndroid Build Coastguard Worker
2021*9e94795aSAndroid Build Coastguard Worker    product1_prop = [
2022*9e94795aSAndroid Build Coastguard Worker        'ro.product.odm.name=product1',
2023*9e94795aSAndroid Build Coastguard Worker        'ro.product.not_care=not_care',
2024*9e94795aSAndroid Build Coastguard Worker    ]
2025*9e94795aSAndroid Build Coastguard Worker
2026*9e94795aSAndroid Build Coastguard Worker    product2_prop = [
2027*9e94795aSAndroid Build Coastguard Worker        'ro.product.odm.name=product2',
2028*9e94795aSAndroid Build Coastguard Worker        'ro.product.not_care=not_care',
2029*9e94795aSAndroid Build Coastguard Worker    ]
2030*9e94795aSAndroid Build Coastguard Worker
2031*9e94795aSAndroid Build Coastguard Worker    input_file = self._BuildZipFile({
2032*9e94795aSAndroid Build Coastguard Worker        'ODM/etc/build.prop': '\n'.join(build_prop),
2033*9e94795aSAndroid Build Coastguard Worker        'ODM/etc/build_std.prop': '\n'.join(build_std_prop),
2034*9e94795aSAndroid Build Coastguard Worker        'ODM/etc/build_pro.prop': '\n'.join(build_pro_prop),
2035*9e94795aSAndroid Build Coastguard Worker        'ODM/etc/build_product1.prop': '\n'.join(product1_prop),
2036*9e94795aSAndroid Build Coastguard Worker        'ODM/etc/build_product2.prop': '\n'.join(product2_prop),
2037*9e94795aSAndroid Build Coastguard Worker    })
2038*9e94795aSAndroid Build Coastguard Worker
2039*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(input_file, 'r', allowZip64=True) as input_zip:
2040*9e94795aSAndroid Build Coastguard Worker      placeholder_values = {
2041*9e94795aSAndroid Build Coastguard Worker          'ro.boot.product.device_name': 'std',
2042*9e94795aSAndroid Build Coastguard Worker          'ro.boot.product.product_name': 'product1',
2043*9e94795aSAndroid Build Coastguard Worker          'ro.boot.product.not_care': 'not_care',
2044*9e94795aSAndroid Build Coastguard Worker      }
2045*9e94795aSAndroid Build Coastguard Worker      partition_props = common.PartitionBuildProps.FromInputFile(
2046*9e94795aSAndroid Build Coastguard Worker          input_zip, 'odm', placeholder_values)
2047*9e94795aSAndroid Build Coastguard Worker
2048*9e94795aSAndroid Build Coastguard Worker    self.assertEqual({
2049*9e94795aSAndroid Build Coastguard Worker        'ro.odm.build.date.utc': '1578430045',
2050*9e94795aSAndroid Build Coastguard Worker        'ro.odm.build.fingerprint':
2051*9e94795aSAndroid Build Coastguard Worker        'google/coral/coral:10/RP1A.200325.001/6337676:user/dev-keys',
2052*9e94795aSAndroid Build Coastguard Worker        'ro.product.odm.device': 'coral',
2053*9e94795aSAndroid Build Coastguard Worker        'ro.product.odm.name': 'product1'
2054*9e94795aSAndroid Build Coastguard Worker    }, partition_props.build_props)
2055*9e94795aSAndroid Build Coastguard Worker
2056*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(input_file, 'r', allowZip64=True) as input_zip:
2057*9e94795aSAndroid Build Coastguard Worker      placeholder_values = {
2058*9e94795aSAndroid Build Coastguard Worker          'ro.boot.product.device_name': 'pro',
2059*9e94795aSAndroid Build Coastguard Worker          'ro.boot.product.product_name': 'product2',
2060*9e94795aSAndroid Build Coastguard Worker          'ro.boot.product.not_care': 'not_care',
2061*9e94795aSAndroid Build Coastguard Worker      }
2062*9e94795aSAndroid Build Coastguard Worker      partition_props = common.PartitionBuildProps.FromInputFile(
2063*9e94795aSAndroid Build Coastguard Worker          input_zip, 'odm', placeholder_values)
2064*9e94795aSAndroid Build Coastguard Worker
2065*9e94795aSAndroid Build Coastguard Worker    self.assertEqual({
2066*9e94795aSAndroid Build Coastguard Worker        'ro.odm.build.date.utc': '1578430045',
2067*9e94795aSAndroid Build Coastguard Worker        'ro.odm.build.fingerprint':
2068*9e94795aSAndroid Build Coastguard Worker        'google/coral/coral:10/RP1A.200325.001/6337676:user/dev-keys',
2069*9e94795aSAndroid Build Coastguard Worker        'ro.product.odm.device': 'coralpro',
2070*9e94795aSAndroid Build Coastguard Worker        'ro.product.odm.name': 'product2'
2071*9e94795aSAndroid Build Coastguard Worker    }, partition_props.build_props)
2072*9e94795aSAndroid Build Coastguard Worker
2073*9e94795aSAndroid Build Coastguard Worker  def test_parseBuildProps_defineAfterOverride(self):
2074*9e94795aSAndroid Build Coastguard Worker    build_prop = copy.deepcopy(self.odm_build_prop)
2075*9e94795aSAndroid Build Coastguard Worker    build_prop.append('ro.product.odm.device=coral')
2076*9e94795aSAndroid Build Coastguard Worker
2077*9e94795aSAndroid Build Coastguard Worker    build_std_prop = [
2078*9e94795aSAndroid Build Coastguard Worker        'ro.product.odm.device=coral',
2079*9e94795aSAndroid Build Coastguard Worker    ]
2080*9e94795aSAndroid Build Coastguard Worker    build_pro_prop = [
2081*9e94795aSAndroid Build Coastguard Worker        'ro.product.odm.device=coralpro',
2082*9e94795aSAndroid Build Coastguard Worker    ]
2083*9e94795aSAndroid Build Coastguard Worker
2084*9e94795aSAndroid Build Coastguard Worker    input_file = self._BuildZipFile({
2085*9e94795aSAndroid Build Coastguard Worker        'ODM/etc/build.prop': '\n'.join(build_prop),
2086*9e94795aSAndroid Build Coastguard Worker        'ODM/etc/build_std.prop': '\n'.join(build_std_prop),
2087*9e94795aSAndroid Build Coastguard Worker        'ODM/etc/build_pro.prop': '\n'.join(build_pro_prop),
2088*9e94795aSAndroid Build Coastguard Worker    })
2089*9e94795aSAndroid Build Coastguard Worker
2090*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(input_file, 'r', allowZip64=True) as input_zip:
2091*9e94795aSAndroid Build Coastguard Worker      placeholder_values = {
2092*9e94795aSAndroid Build Coastguard Worker          'ro.boot.product.device_name': 'std',
2093*9e94795aSAndroid Build Coastguard Worker      }
2094*9e94795aSAndroid Build Coastguard Worker
2095*9e94795aSAndroid Build Coastguard Worker      self.assertRaises(ValueError, common.PartitionBuildProps.FromInputFile,
2096*9e94795aSAndroid Build Coastguard Worker                        input_zip, 'odm', placeholder_values)
2097*9e94795aSAndroid Build Coastguard Worker
2098*9e94795aSAndroid Build Coastguard Worker  def test_parseBuildProps_duplicateOverride(self):
2099*9e94795aSAndroid Build Coastguard Worker    build_prop = copy.deepcopy(self.odm_build_prop)
2100*9e94795aSAndroid Build Coastguard Worker    build_prop.append(
2101*9e94795aSAndroid Build Coastguard Worker        'import /odm/etc/build_${ro.boot.product.product_name}.prop')
2102*9e94795aSAndroid Build Coastguard Worker
2103*9e94795aSAndroid Build Coastguard Worker    build_std_prop = [
2104*9e94795aSAndroid Build Coastguard Worker        'ro.product.odm.device=coral',
2105*9e94795aSAndroid Build Coastguard Worker        'ro.product.odm.name=product1',
2106*9e94795aSAndroid Build Coastguard Worker    ]
2107*9e94795aSAndroid Build Coastguard Worker    build_pro_prop = [
2108*9e94795aSAndroid Build Coastguard Worker        'ro.product.odm.device=coralpro',
2109*9e94795aSAndroid Build Coastguard Worker    ]
2110*9e94795aSAndroid Build Coastguard Worker
2111*9e94795aSAndroid Build Coastguard Worker    product1_prop = [
2112*9e94795aSAndroid Build Coastguard Worker        'ro.product.odm.name=product1',
2113*9e94795aSAndroid Build Coastguard Worker    ]
2114*9e94795aSAndroid Build Coastguard Worker
2115*9e94795aSAndroid Build Coastguard Worker    product2_prop = [
2116*9e94795aSAndroid Build Coastguard Worker        'ro.product.odm.name=product2',
2117*9e94795aSAndroid Build Coastguard Worker    ]
2118*9e94795aSAndroid Build Coastguard Worker
2119*9e94795aSAndroid Build Coastguard Worker    input_file = self._BuildZipFile({
2120*9e94795aSAndroid Build Coastguard Worker        'ODM/etc/build.prop': '\n'.join(build_prop),
2121*9e94795aSAndroid Build Coastguard Worker        'ODM/etc/build_std.prop': '\n'.join(build_std_prop),
2122*9e94795aSAndroid Build Coastguard Worker        'ODM/etc/build_pro.prop': '\n'.join(build_pro_prop),
2123*9e94795aSAndroid Build Coastguard Worker        'ODM/etc/build_product1.prop': '\n'.join(product1_prop),
2124*9e94795aSAndroid Build Coastguard Worker        'ODM/etc/build_product2.prop': '\n'.join(product2_prop),
2125*9e94795aSAndroid Build Coastguard Worker    })
2126*9e94795aSAndroid Build Coastguard Worker
2127*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(input_file, 'r', allowZip64=True) as input_zip:
2128*9e94795aSAndroid Build Coastguard Worker      placeholder_values = {
2129*9e94795aSAndroid Build Coastguard Worker          'ro.boot.product.device_name': 'std',
2130*9e94795aSAndroid Build Coastguard Worker          'ro.boot.product.product_name': 'product1',
2131*9e94795aSAndroid Build Coastguard Worker      }
2132*9e94795aSAndroid Build Coastguard Worker      self.assertRaises(ValueError, common.PartitionBuildProps.FromInputFile,
2133*9e94795aSAndroid Build Coastguard Worker                        input_zip, 'odm', placeholder_values)
2134*9e94795aSAndroid Build Coastguard Worker
2135*9e94795aSAndroid Build Coastguard Worker  def test_partitionBuildProps_fromInputFile_deepcopy(self):
2136*9e94795aSAndroid Build Coastguard Worker    build_prop = [
2137*9e94795aSAndroid Build Coastguard Worker        'ro.odm.build.date.utc=1578430045',
2138*9e94795aSAndroid Build Coastguard Worker        'ro.odm.build.fingerprint='
2139*9e94795aSAndroid Build Coastguard Worker        'google/coral/coral:10/RP1A.200325.001/6337676:user/dev-keys',
2140*9e94795aSAndroid Build Coastguard Worker        'ro.product.odm.device=coral',
2141*9e94795aSAndroid Build Coastguard Worker    ]
2142*9e94795aSAndroid Build Coastguard Worker    input_file = self._BuildZipFile({
2143*9e94795aSAndroid Build Coastguard Worker        'ODM/etc/build.prop': '\n'.join(build_prop),
2144*9e94795aSAndroid Build Coastguard Worker    })
2145*9e94795aSAndroid Build Coastguard Worker
2146*9e94795aSAndroid Build Coastguard Worker    with zipfile.ZipFile(input_file, 'r', allowZip64=True) as input_zip:
2147*9e94795aSAndroid Build Coastguard Worker      placeholder_values = {
2148*9e94795aSAndroid Build Coastguard Worker          'ro.boot.product.device_name': ['std', 'pro']
2149*9e94795aSAndroid Build Coastguard Worker      }
2150*9e94795aSAndroid Build Coastguard Worker      partition_props = common.PartitionBuildProps.FromInputFile(
2151*9e94795aSAndroid Build Coastguard Worker          input_zip, 'odm', placeholder_values)
2152*9e94795aSAndroid Build Coastguard Worker
2153*9e94795aSAndroid Build Coastguard Worker    copied_props = copy.deepcopy(partition_props)
2154*9e94795aSAndroid Build Coastguard Worker    self.assertEqual({
2155*9e94795aSAndroid Build Coastguard Worker        'ro.odm.build.date.utc': '1578430045',
2156*9e94795aSAndroid Build Coastguard Worker        'ro.odm.build.fingerprint':
2157*9e94795aSAndroid Build Coastguard Worker        'google/coral/coral:10/RP1A.200325.001/6337676:user/dev-keys',
2158*9e94795aSAndroid Build Coastguard Worker        'ro.product.odm.device': 'coral',
2159*9e94795aSAndroid Build Coastguard Worker    }, copied_props.build_props)
2160