1*33f37583SAndroid Build Coastguard Worker#!/usr/bin/env python 2*33f37583SAndroid Build Coastguard Worker# 3*33f37583SAndroid Build Coastguard Worker# Copyright (C) 2020 The Android Open Source Project 4*33f37583SAndroid Build Coastguard Worker# 5*33f37583SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 6*33f37583SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 7*33f37583SAndroid Build Coastguard Worker# You may obtain a copy of the License at 8*33f37583SAndroid Build Coastguard Worker# 9*33f37583SAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 10*33f37583SAndroid Build Coastguard Worker# 11*33f37583SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 12*33f37583SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 13*33f37583SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*33f37583SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 15*33f37583SAndroid Build Coastguard Worker# limitations under the License. 16*33f37583SAndroid Build Coastguard Worker# 17*33f37583SAndroid Build Coastguard Worker"""Unit tests for apex_compression_tool.""" 18*33f37583SAndroid Build Coastguard Workerimport hashlib 19*33f37583SAndroid Build Coastguard Workerimport logging 20*33f37583SAndroid Build Coastguard Workerimport os 21*33f37583SAndroid Build Coastguard Workerimport shutil 22*33f37583SAndroid Build Coastguard Workerimport stat 23*33f37583SAndroid Build Coastguard Workerimport subprocess 24*33f37583SAndroid Build Coastguard Workerimport tempfile 25*33f37583SAndroid Build Coastguard Workerimport unittest 26*33f37583SAndroid Build Coastguard Workerfrom importlib import resources 27*33f37583SAndroid Build Coastguard Workerfrom zipfile import ZipFile, ZIP_STORED, ZIP_DEFLATED 28*33f37583SAndroid Build Coastguard Worker 29*33f37583SAndroid Build Coastguard Workerimport apex_manifest_pb2 30*33f37583SAndroid Build Coastguard Worker 31*33f37583SAndroid Build Coastguard Workerlogger = logging.getLogger(__name__) 32*33f37583SAndroid Build Coastguard Worker 33*33f37583SAndroid Build Coastguard WorkerTEST_APEX = 'com.android.example.apex' 34*33f37583SAndroid Build Coastguard Worker 35*33f37583SAndroid Build Coastguard Worker# In order to debug test failures, set DEBUG_TEST to True and run the test from 36*33f37583SAndroid Build Coastguard Worker# local workstation bypassing atest, e.g.: 37*33f37583SAndroid Build Coastguard Worker# $ m apex_compression_tool_test && \ 38*33f37583SAndroid Build Coastguard Worker# out/host/linux-x86/nativetest64/apex_compression_tool_test/\ 39*33f37583SAndroid Build Coastguard Worker# apex_compression_tool_test 40*33f37583SAndroid Build Coastguard Worker# 41*33f37583SAndroid Build Coastguard Worker# the test will print out the command used, and the temporary files used by the 42*33f37583SAndroid Build Coastguard Worker# test. 43*33f37583SAndroid Build Coastguard WorkerDEBUG_TEST = False 44*33f37583SAndroid Build Coastguard Worker 45*33f37583SAndroid Build Coastguard Worker 46*33f37583SAndroid Build Coastguard Workerdef run(args, verbose=None, **kwargs): 47*33f37583SAndroid Build Coastguard Worker """Creates and returns a subprocess.Popen object. 48*33f37583SAndroid Build Coastguard Worker 49*33f37583SAndroid Build Coastguard Worker Args: 50*33f37583SAndroid Build Coastguard Worker args: The command represented as a list of strings. 51*33f37583SAndroid Build Coastguard Worker verbose: Whether the commands should be shown. Default to the global 52*33f37583SAndroid Build Coastguard Worker verbosity if unspecified. 53*33f37583SAndroid Build Coastguard Worker kwargs: Any additional args to be passed to subprocess.Popen(), such as env, 54*33f37583SAndroid Build Coastguard Worker stdin, etc. stdout and stderr will default to subprocess.PIPE and 55*33f37583SAndroid Build Coastguard Worker subprocess.STDOUT respectively unless caller specifies any of them. 56*33f37583SAndroid Build Coastguard Worker universal_newlines will default to True, as most of the users in 57*33f37583SAndroid Build Coastguard Worker releasetools expect string output. 58*33f37583SAndroid Build Coastguard Worker 59*33f37583SAndroid Build Coastguard Worker Returns: 60*33f37583SAndroid Build Coastguard Worker A subprocess.Popen object. 61*33f37583SAndroid Build Coastguard Worker """ 62*33f37583SAndroid Build Coastguard Worker if 'stdout' not in kwargs and 'stderr' not in kwargs: 63*33f37583SAndroid Build Coastguard Worker kwargs['stdout'] = subprocess.PIPE 64*33f37583SAndroid Build Coastguard Worker kwargs['stderr'] = subprocess.STDOUT 65*33f37583SAndroid Build Coastguard Worker if 'universal_newlines' not in kwargs: 66*33f37583SAndroid Build Coastguard Worker kwargs['universal_newlines'] = True 67*33f37583SAndroid Build Coastguard Worker if DEBUG_TEST: 68*33f37583SAndroid Build Coastguard Worker print('\nRunning: \n%s\n' % ' '.join(args)) 69*33f37583SAndroid Build Coastguard Worker # Don't log any if caller explicitly says so. 70*33f37583SAndroid Build Coastguard Worker if verbose: 71*33f37583SAndroid Build Coastguard Worker logger.info(' Running: \'%s\'', ' '.join(args)) 72*33f37583SAndroid Build Coastguard Worker return subprocess.Popen(args, **kwargs) 73*33f37583SAndroid Build Coastguard Worker 74*33f37583SAndroid Build Coastguard Worker 75*33f37583SAndroid Build Coastguard Workerdef run_and_check_output(args, verbose=None, **kwargs): 76*33f37583SAndroid Build Coastguard Worker """Runs the given command and returns the output. 77*33f37583SAndroid Build Coastguard Worker 78*33f37583SAndroid Build Coastguard Worker Args: 79*33f37583SAndroid Build Coastguard Worker args: The command represented as a list of strings. 80*33f37583SAndroid Build Coastguard Worker verbose: Whether the commands should be shown. Default to the global 81*33f37583SAndroid Build Coastguard Worker verbosity if unspecified. 82*33f37583SAndroid Build Coastguard Worker kwargs: Any additional args to be passed to subprocess.Popen(), such as env, 83*33f37583SAndroid Build Coastguard Worker stdin, etc. stdout and stderr will default to subprocess.PIPE and 84*33f37583SAndroid Build Coastguard Worker subprocess.STDOUT respectively unless caller specifies any of them. 85*33f37583SAndroid Build Coastguard Worker 86*33f37583SAndroid Build Coastguard Worker Returns: 87*33f37583SAndroid Build Coastguard Worker The output string. 88*33f37583SAndroid Build Coastguard Worker 89*33f37583SAndroid Build Coastguard Worker Raises: 90*33f37583SAndroid Build Coastguard Worker ExternalError: On non-zero exit from the command. 91*33f37583SAndroid Build Coastguard Worker """ 92*33f37583SAndroid Build Coastguard Worker 93*33f37583SAndroid Build Coastguard Worker proc = run(args, verbose=verbose, **kwargs) 94*33f37583SAndroid Build Coastguard Worker output, _ = proc.communicate() 95*33f37583SAndroid Build Coastguard Worker if output is None: 96*33f37583SAndroid Build Coastguard Worker output = '' 97*33f37583SAndroid Build Coastguard Worker # Don't log any if caller explicitly says so. 98*33f37583SAndroid Build Coastguard Worker if verbose: 99*33f37583SAndroid Build Coastguard Worker logger.info('%s', output.rstrip()) 100*33f37583SAndroid Build Coastguard Worker if proc.returncode != 0: 101*33f37583SAndroid Build Coastguard Worker raise RuntimeError( 102*33f37583SAndroid Build Coastguard Worker "Failed to run command '{}' (exit code {}):\n{}".format( 103*33f37583SAndroid Build Coastguard Worker args, proc.returncode, output)) 104*33f37583SAndroid Build Coastguard Worker return output 105*33f37583SAndroid Build Coastguard Worker 106*33f37583SAndroid Build Coastguard Worker 107*33f37583SAndroid Build Coastguard Workerdef get_current_dir(): 108*33f37583SAndroid Build Coastguard Worker """Returns the current dir, relative to the script dir.""" 109*33f37583SAndroid Build Coastguard Worker # The script dir is the one we want, which could be different from pwd. 110*33f37583SAndroid Build Coastguard Worker current_dir = os.path.dirname(os.path.realpath(__file__)) 111*33f37583SAndroid Build Coastguard Worker return current_dir 112*33f37583SAndroid Build Coastguard Worker 113*33f37583SAndroid Build Coastguard Worker 114*33f37583SAndroid Build Coastguard Workerdef get_sha1sum(file_path): 115*33f37583SAndroid Build Coastguard Worker h = hashlib.sha256() 116*33f37583SAndroid Build Coastguard Worker 117*33f37583SAndroid Build Coastguard Worker with open(file_path, 'rb') as file: 118*33f37583SAndroid Build Coastguard Worker while True: 119*33f37583SAndroid Build Coastguard Worker # Reading is buffered, so we can read smaller chunks. 120*33f37583SAndroid Build Coastguard Worker chunk = file.read(h.block_size) 121*33f37583SAndroid Build Coastguard Worker if not chunk: 122*33f37583SAndroid Build Coastguard Worker break 123*33f37583SAndroid Build Coastguard Worker h.update(chunk) 124*33f37583SAndroid Build Coastguard Worker 125*33f37583SAndroid Build Coastguard Worker return h.hexdigest() 126*33f37583SAndroid Build Coastguard Worker 127*33f37583SAndroid Build Coastguard Worker 128*33f37583SAndroid Build Coastguard Workerclass ApexCompressionTest(unittest.TestCase): 129*33f37583SAndroid Build Coastguard Worker def setUp(self): 130*33f37583SAndroid Build Coastguard Worker self._to_cleanup = [] 131*33f37583SAndroid Build Coastguard Worker self._get_host_tools() 132*33f37583SAndroid Build Coastguard Worker 133*33f37583SAndroid Build Coastguard Worker def tearDown(self): 134*33f37583SAndroid Build Coastguard Worker if not DEBUG_TEST: 135*33f37583SAndroid Build Coastguard Worker for i in self._to_cleanup: 136*33f37583SAndroid Build Coastguard Worker if os.path.isdir(i): 137*33f37583SAndroid Build Coastguard Worker shutil.rmtree(i, ignore_errors=True) 138*33f37583SAndroid Build Coastguard Worker else: 139*33f37583SAndroid Build Coastguard Worker os.remove(i) 140*33f37583SAndroid Build Coastguard Worker del self._to_cleanup[:] 141*33f37583SAndroid Build Coastguard Worker else: 142*33f37583SAndroid Build Coastguard Worker print('Cleanup: ' + str(self._to_cleanup)) 143*33f37583SAndroid Build Coastguard Worker 144*33f37583SAndroid Build Coastguard Worker def _get_host_tools(self): 145*33f37583SAndroid Build Coastguard Worker dir_name = tempfile.mkdtemp(prefix=self._testMethodName+"_host_tools_") 146*33f37583SAndroid Build Coastguard Worker self._to_cleanup.append(dir_name) 147*33f37583SAndroid Build Coastguard Worker for tool in ["avbtool", "conv_apex_manifest", "apex_compression_tool", "deapexer", "soong_zip"]: 148*33f37583SAndroid Build Coastguard Worker with ( 149*33f37583SAndroid Build Coastguard Worker resources.files("apex_compression_test").joinpath(tool).open('rb') as tool_resource, 150*33f37583SAndroid Build Coastguard Worker open(os.path.join(dir_name, tool), 'wb') as f 151*33f37583SAndroid Build Coastguard Worker ): 152*33f37583SAndroid Build Coastguard Worker shutil.copyfileobj(tool_resource, f) 153*33f37583SAndroid Build Coastguard Worker os.chmod(os.path.join(dir_name, tool), stat.S_IRUSR | stat.S_IXUSR) 154*33f37583SAndroid Build Coastguard Worker os.environ['APEX_COMPRESSION_TOOL_PATH'] = dir_name 155*33f37583SAndroid Build Coastguard Worker path = dir_name 156*33f37583SAndroid Build Coastguard Worker if "PATH" in os.environ: 157*33f37583SAndroid Build Coastguard Worker path += ":" + os.environ["PATH"] 158*33f37583SAndroid Build Coastguard Worker os.environ["PATH"] = path 159*33f37583SAndroid Build Coastguard Worker 160*33f37583SAndroid Build Coastguard Worker def _get_test_apex(self): 161*33f37583SAndroid Build Coastguard Worker tmpdir = tempfile.mkdtemp() 162*33f37583SAndroid Build Coastguard Worker self._to_cleanup.append(tmpdir) 163*33f37583SAndroid Build Coastguard Worker apexPath = os.path.join(tmpdir, TEST_APEX + '.apex') 164*33f37583SAndroid Build Coastguard Worker with ( 165*33f37583SAndroid Build Coastguard Worker resources.files('apex_compression_test').joinpath(TEST_APEX + '.apex').open('rb') as f, 166*33f37583SAndroid Build Coastguard Worker open(apexPath, 'wb') as f2, 167*33f37583SAndroid Build Coastguard Worker ): 168*33f37583SAndroid Build Coastguard Worker shutil.copyfileobj(f, f2) 169*33f37583SAndroid Build Coastguard Worker 170*33f37583SAndroid Build Coastguard Worker return apexPath 171*33f37583SAndroid Build Coastguard Worker 172*33f37583SAndroid Build Coastguard Worker def _get_container_files(self, apex_file_path): 173*33f37583SAndroid Build Coastguard Worker dir_name = tempfile.mkdtemp( 174*33f37583SAndroid Build Coastguard Worker prefix=self._testMethodName + '_container_files_') 175*33f37583SAndroid Build Coastguard Worker self._to_cleanup.append(dir_name) 176*33f37583SAndroid Build Coastguard Worker with ZipFile(apex_file_path, 'r') as zip_obj: 177*33f37583SAndroid Build Coastguard Worker zip_obj.extractall(path=dir_name) 178*33f37583SAndroid Build Coastguard Worker files = {} 179*33f37583SAndroid Build Coastguard Worker for i in ['apex_manifest.json', 'apex_manifest.pb', 'apex_pubkey', 180*33f37583SAndroid Build Coastguard Worker 'apex_build_info.pb', 'apex_payload.img', 'apex_payload.zip', 181*33f37583SAndroid Build Coastguard Worker 'AndroidManifest.xml', 'original_apex']: 182*33f37583SAndroid Build Coastguard Worker file_path = os.path.join(dir_name, i) 183*33f37583SAndroid Build Coastguard Worker if os.path.exists(file_path): 184*33f37583SAndroid Build Coastguard Worker files[i] = file_path 185*33f37583SAndroid Build Coastguard Worker 186*33f37583SAndroid Build Coastguard Worker image_file = files.get('apex_payload.img', None) 187*33f37583SAndroid Build Coastguard Worker if image_file is None: 188*33f37583SAndroid Build Coastguard Worker image_file = files.get('apex_payload.zip', None) 189*33f37583SAndroid Build Coastguard Worker else: 190*33f37583SAndroid Build Coastguard Worker files['apex_payload'] = image_file 191*33f37583SAndroid Build Coastguard Worker # Also retrieve the root digest of the image 192*33f37583SAndroid Build Coastguard Worker avbtool_cmd = ['avbtool', 193*33f37583SAndroid Build Coastguard Worker 'print_partition_digests', '--image', files['apex_payload']] 194*33f37583SAndroid Build Coastguard Worker # avbtool_cmd output has format "<name>: <value>" 195*33f37583SAndroid Build Coastguard Worker files['digest'] = run_and_check_output( 196*33f37583SAndroid Build Coastguard Worker avbtool_cmd, True).split(': ')[1].strip() 197*33f37583SAndroid Build Coastguard Worker 198*33f37583SAndroid Build Coastguard Worker return files 199*33f37583SAndroid Build Coastguard Worker 200*33f37583SAndroid Build Coastguard Worker def _get_manifest_string(self, manifest_path): 201*33f37583SAndroid Build Coastguard Worker cmd = ['conv_apex_manifest'] 202*33f37583SAndroid Build Coastguard Worker cmd.extend([ 203*33f37583SAndroid Build Coastguard Worker 'print', 204*33f37583SAndroid Build Coastguard Worker manifest_path 205*33f37583SAndroid Build Coastguard Worker ]) 206*33f37583SAndroid Build Coastguard Worker return run_and_check_output(cmd, 'True') 207*33f37583SAndroid Build Coastguard Worker 208*33f37583SAndroid Build Coastguard Worker # Mutates the manifest located at |manifest_path| 209*33f37583SAndroid Build Coastguard Worker def _unset_original_apex_digest(self, manifest_path): 210*33f37583SAndroid Build Coastguard Worker # Open the protobuf 211*33f37583SAndroid Build Coastguard Worker with open(manifest_path, 'rb') as f: 212*33f37583SAndroid Build Coastguard Worker pb = apex_manifest_pb2.ApexManifest() 213*33f37583SAndroid Build Coastguard Worker pb.ParseFromString(f.read()) 214*33f37583SAndroid Build Coastguard Worker pb.ClearField('capexMetadata') 215*33f37583SAndroid Build Coastguard Worker with open(manifest_path, 'wb') as f: 216*33f37583SAndroid Build Coastguard Worker f.write(pb.SerializeToString()) 217*33f37583SAndroid Build Coastguard Worker 218*33f37583SAndroid Build Coastguard Worker def _compress_apex(self, uncompressed_apex_fp): 219*33f37583SAndroid Build Coastguard Worker """Returns file path to compressed APEX""" 220*33f37583SAndroid Build Coastguard Worker fd, compressed_apex_fp = tempfile.mkstemp( 221*33f37583SAndroid Build Coastguard Worker prefix=self._testMethodName + '_compressed_', 222*33f37583SAndroid Build Coastguard Worker suffix='.capex') 223*33f37583SAndroid Build Coastguard Worker os.close(fd) 224*33f37583SAndroid Build Coastguard Worker self._to_cleanup.append(compressed_apex_fp) 225*33f37583SAndroid Build Coastguard Worker run_and_check_output([ 226*33f37583SAndroid Build Coastguard Worker 'apex_compression_tool', 227*33f37583SAndroid Build Coastguard Worker 'compress', 228*33f37583SAndroid Build Coastguard Worker '--input', uncompressed_apex_fp, 229*33f37583SAndroid Build Coastguard Worker '--output', compressed_apex_fp 230*33f37583SAndroid Build Coastguard Worker ]) 231*33f37583SAndroid Build Coastguard Worker return compressed_apex_fp 232*33f37583SAndroid Build Coastguard Worker 233*33f37583SAndroid Build Coastguard Worker def _decompress_apex(self, compressed_apex_fp): 234*33f37583SAndroid Build Coastguard Worker """Returns file path to decompressed APEX""" 235*33f37583SAndroid Build Coastguard Worker decompressed_apex_fp = tempfile. \ 236*33f37583SAndroid Build Coastguard Worker NamedTemporaryFile(prefix=self._testMethodName + '_decompressed_', 237*33f37583SAndroid Build Coastguard Worker suffix='.apex').name 238*33f37583SAndroid Build Coastguard Worker # Use deapexer to decompress 239*33f37583SAndroid Build Coastguard Worker cmd = ['deapexer'] 240*33f37583SAndroid Build Coastguard Worker cmd.extend([ 241*33f37583SAndroid Build Coastguard Worker 'decompress', 242*33f37583SAndroid Build Coastguard Worker '--input', compressed_apex_fp, 243*33f37583SAndroid Build Coastguard Worker '--output', decompressed_apex_fp 244*33f37583SAndroid Build Coastguard Worker ]) 245*33f37583SAndroid Build Coastguard Worker run_and_check_output(cmd, True) 246*33f37583SAndroid Build Coastguard Worker 247*33f37583SAndroid Build Coastguard Worker self.assertTrue(os.path.exists(decompressed_apex_fp), 248*33f37583SAndroid Build Coastguard Worker 'Decompressed APEX does not exist') 249*33f37583SAndroid Build Coastguard Worker self._to_cleanup.append(decompressed_apex_fp) 250*33f37583SAndroid Build Coastguard Worker return decompressed_apex_fp 251*33f37583SAndroid Build Coastguard Worker 252*33f37583SAndroid Build Coastguard Worker def _get_type(self, apex_file_path): 253*33f37583SAndroid Build Coastguard Worker cmd = ['deapexer', 'info', '--print-type', apex_file_path] 254*33f37583SAndroid Build Coastguard Worker return run_and_check_output(cmd, True).strip() 255*33f37583SAndroid Build Coastguard Worker 256*33f37583SAndroid Build Coastguard Worker def test_compression(self): 257*33f37583SAndroid Build Coastguard Worker uncompressed_apex_fp = self._get_test_apex() 258*33f37583SAndroid Build Coastguard Worker # TODO(samiul): try compressing a compressed APEX 259*33f37583SAndroid Build Coastguard Worker compressed_apex_fp = self._compress_apex(uncompressed_apex_fp) 260*33f37583SAndroid Build Coastguard Worker 261*33f37583SAndroid Build Coastguard Worker # Verify output file has been created and is smaller than input file 262*33f37583SAndroid Build Coastguard Worker uncompressed_file_size = os.path.getsize(uncompressed_apex_fp) 263*33f37583SAndroid Build Coastguard Worker compressed_file_size = os.path.getsize(compressed_apex_fp) 264*33f37583SAndroid Build Coastguard Worker self.assertGreater(compressed_file_size, 0, 'Compressed APEX is empty') 265*33f37583SAndroid Build Coastguard Worker self.assertLess(compressed_file_size, uncompressed_file_size, 266*33f37583SAndroid Build Coastguard Worker 'Compressed APEX is not smaller than uncompressed APEX') 267*33f37583SAndroid Build Coastguard Worker 268*33f37583SAndroid Build Coastguard Worker # Verify type of the apex is 'COMPRESSED' 269*33f37583SAndroid Build Coastguard Worker self.assertEqual(self._get_type(compressed_apex_fp), 'COMPRESSED') 270*33f37583SAndroid Build Coastguard Worker 271*33f37583SAndroid Build Coastguard Worker # Verify the contents of the compressed apex files 272*33f37583SAndroid Build Coastguard Worker content_in_compressed_apex = self._get_container_files(compressed_apex_fp) 273*33f37583SAndroid Build Coastguard Worker self.assertIsNotNone(content_in_compressed_apex['original_apex']) 274*33f37583SAndroid Build Coastguard Worker content_in_uncompressed_apex = self._get_container_files( 275*33f37583SAndroid Build Coastguard Worker uncompressed_apex_fp) 276*33f37583SAndroid Build Coastguard Worker self.assertIsNotNone(content_in_uncompressed_apex['apex_payload']) 277*33f37583SAndroid Build Coastguard Worker self.assertIsNotNone(content_in_uncompressed_apex['digest']) 278*33f37583SAndroid Build Coastguard Worker 279*33f37583SAndroid Build Coastguard Worker # Verify that CAPEX manifest contains digest of original_apex 280*33f37583SAndroid Build Coastguard Worker manifest_string = self._get_manifest_string( 281*33f37583SAndroid Build Coastguard Worker content_in_compressed_apex['apex_manifest.pb']) 282*33f37583SAndroid Build Coastguard Worker self.assertIn('originalApexDigest: "' 283*33f37583SAndroid Build Coastguard Worker + content_in_uncompressed_apex['digest'] + '"', manifest_string) 284*33f37583SAndroid Build Coastguard Worker 285*33f37583SAndroid Build Coastguard Worker for i in ['apex_manifest.json', 'apex_manifest.pb', 'apex_pubkey', 286*33f37583SAndroid Build Coastguard Worker 'apex_build_info.pb', 'AndroidManifest.xml']: 287*33f37583SAndroid Build Coastguard Worker if i in content_in_uncompressed_apex: 288*33f37583SAndroid Build Coastguard Worker if i == 'apex_manifest.pb': 289*33f37583SAndroid Build Coastguard Worker # Get rid of originalApexDigest field, which should be the 290*33f37583SAndroid Build Coastguard Worker # only difference 291*33f37583SAndroid Build Coastguard Worker self._unset_original_apex_digest(content_in_compressed_apex[i]) 292*33f37583SAndroid Build Coastguard Worker self.assertEqual(get_sha1sum(content_in_compressed_apex[i]), 293*33f37583SAndroid Build Coastguard Worker get_sha1sum(content_in_uncompressed_apex[i])) 294*33f37583SAndroid Build Coastguard Worker 295*33f37583SAndroid Build Coastguard Worker def test_decompression(self): 296*33f37583SAndroid Build Coastguard Worker # setup: create compressed APEX 297*33f37583SAndroid Build Coastguard Worker uncompressed_apex_fp = self._get_test_apex() 298*33f37583SAndroid Build Coastguard Worker compressed_apex_fp = self._compress_apex(uncompressed_apex_fp) 299*33f37583SAndroid Build Coastguard Worker 300*33f37583SAndroid Build Coastguard Worker # Decompress it 301*33f37583SAndroid Build Coastguard Worker decompressed_apex_fp = self._decompress_apex(compressed_apex_fp) 302*33f37583SAndroid Build Coastguard Worker 303*33f37583SAndroid Build Coastguard Worker # Verify type of the apex is 'UNCOMPRESSED' 304*33f37583SAndroid Build Coastguard Worker self.assertEqual(self._get_type(decompressed_apex_fp), 'UNCOMPRESSED') 305*33f37583SAndroid Build Coastguard Worker 306*33f37583SAndroid Build Coastguard Worker # Verify decompressed APEX is same as uncompressed APEX 307*33f37583SAndroid Build Coastguard Worker self.assertEqual(get_sha1sum(uncompressed_apex_fp), 308*33f37583SAndroid Build Coastguard Worker get_sha1sum(decompressed_apex_fp), 309*33f37583SAndroid Build Coastguard Worker 'Decompressed APEX is not same as uncompressed APEX') 310*33f37583SAndroid Build Coastguard Worker 311*33f37583SAndroid Build Coastguard Worker # Try decompressing uncompressed APEX. It should not work. 312*33f37583SAndroid Build Coastguard Worker with self.assertRaises(RuntimeError) as error: 313*33f37583SAndroid Build Coastguard Worker self._decompress_apex(uncompressed_apex_fp) 314*33f37583SAndroid Build Coastguard Worker 315*33f37583SAndroid Build Coastguard Worker self.assertIn(uncompressed_apex_fp 316*33f37583SAndroid Build Coastguard Worker + ' is not a compressed APEX', str(error.exception)) 317*33f37583SAndroid Build Coastguard Worker 318*33f37583SAndroid Build Coastguard Worker def test_only_original_apex_is_compressed(self): 319*33f37583SAndroid Build Coastguard Worker uncompressed_apex_fp = self._get_test_apex() 320*33f37583SAndroid Build Coastguard Worker compressed_apex_fp = self._compress_apex(uncompressed_apex_fp) 321*33f37583SAndroid Build Coastguard Worker 322*33f37583SAndroid Build Coastguard Worker with ZipFile(compressed_apex_fp, 'r') as zip_obj: 323*33f37583SAndroid Build Coastguard Worker self.assertEqual(zip_obj.getinfo('original_apex').compress_type, 324*33f37583SAndroid Build Coastguard Worker ZIP_DEFLATED) 325*33f37583SAndroid Build Coastguard Worker content_in_uncompressed_apex = self._get_container_files( 326*33f37583SAndroid Build Coastguard Worker uncompressed_apex_fp) 327*33f37583SAndroid Build Coastguard Worker for i in ['apex_manifest.json', 'apex_manifest.pb', 'apex_pubkey', 328*33f37583SAndroid Build Coastguard Worker 'apex_build_info.pb', 'AndroidManifest.xml']: 329*33f37583SAndroid Build Coastguard Worker if i in content_in_uncompressed_apex: 330*33f37583SAndroid Build Coastguard Worker self.assertEqual(zip_obj.getinfo(i).compress_type, ZIP_STORED) 331*33f37583SAndroid Build Coastguard Worker 332*33f37583SAndroid Build Coastguard Workerif __name__ == '__main__': 333*33f37583SAndroid Build Coastguard Worker unittest.main(verbosity=2) 334