|  | # pylint: disable=g-direct-third-party-import | 
|  | # Copyright 2015 The Bazel Authors. All rights reserved. | 
|  | # | 
|  | # Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | # you may not use this file except in compliance with the License. | 
|  | # You may obtain a copy of the License at | 
|  | # | 
|  | #    http://www.apache.org/licenses/LICENSE-2.0 | 
|  | # | 
|  | # Unless required by applicable law or agreed to in writing, software | 
|  | # distributed under the License is distributed on an "AS IS" BASIS, | 
|  | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | # See the License for the specific language governing permissions and | 
|  | # limitations under the License. | 
|  |  | 
|  | """Unit tests for stubify_incremental_install.""" | 
|  |  | 
|  | import os | 
|  | import unittest | 
|  | from unittest import mock | 
|  | import zipfile | 
|  |  | 
|  | # Do not edit this line. Copybara replaces it with PY2 migration helper. | 
|  |  | 
|  | from tools.android import incremental_install | 
|  |  | 
|  |  | 
|  | class MockAdb(object): | 
|  | """Mocks the Android ADB binary.""" | 
|  |  | 
|  | def __init__(self): | 
|  | # Map of file name -> contents. | 
|  | self.files = {} | 
|  | self.split_apks = set() | 
|  | self._error = None | 
|  | self.package_timestamp = None | 
|  | self._last_package_timestamp = 1 | 
|  | self.shell_cmdlns = [] | 
|  | self.abi = "armeabi-v7a" | 
|  |  | 
|  | def Exec(self, args): | 
|  | if self._error: | 
|  | error_info, arg = self._error  # pylint: disable=unpacking-non-sequence | 
|  | if not arg or arg in args: | 
|  | return self._CreatePopenMock(*error_info) | 
|  |  | 
|  | returncode = 0 | 
|  | stdout = "" | 
|  | stderr = "" | 
|  | cmd = args[1] | 
|  | if cmd == "push": | 
|  | # "/test/adb push local remote" | 
|  | with open(args[2], "rb") as f: | 
|  | content = f.read().decode("utf-8") | 
|  | self.files[args[3]] = content | 
|  | elif cmd == "pull": | 
|  | # "/test/adb pull remote local" | 
|  | remote = args[2] | 
|  | local = args[3] | 
|  | content = self.files.get(remote) | 
|  | if content is not None: | 
|  | with open(local, "wb") as f: | 
|  | f.write(content.encode("utf-8")) | 
|  | else: | 
|  | returncode = 1 | 
|  | stderr = "remote object '%s' does not exist\n" % remote | 
|  | elif cmd == "install": | 
|  | self.package_timestamp = self._last_package_timestamp | 
|  | self._last_package_timestamp += 1 | 
|  | return self._CreatePopenMock(0, "Success", "") | 
|  | elif cmd == "install-multiple": | 
|  | if args[3] == "-p": | 
|  | with open(args[5], "rb") as f: | 
|  | content = f.read().decode("utf-8") | 
|  | self.split_apks.add(content) | 
|  | else: | 
|  | self.package_timestamp = self._last_package_timestamp | 
|  | self._last_package_timestamp += 1 | 
|  | return self._CreatePopenMock(0, "Success", "") | 
|  | elif cmd == "uninstall": | 
|  | self._CreatePopenMock(0, "Success", "") | 
|  | self.split_apks = set() | 
|  | self.package_timestamp = None | 
|  | elif cmd == "shell": | 
|  | # "/test/adb shell ..." | 
|  | # mkdir, rm, am (application manager), or monkey | 
|  | shell_cmdln = args[2] | 
|  | self.shell_cmdlns.append(shell_cmdln) | 
|  | if shell_cmdln.startswith(("mkdir", "am", "monkey", "input")): | 
|  | pass | 
|  | elif shell_cmdln.startswith("dumpsys package "): | 
|  | if self.package_timestamp is not None: | 
|  | timestamp = "firstInstallTime=%s" % self.package_timestamp | 
|  | else: | 
|  | timestamp = "" | 
|  | return self._CreatePopenMock(0, timestamp, "") | 
|  | elif shell_cmdln.startswith("rm"): | 
|  | file_path = shell_cmdln.split()[2] | 
|  | self.files.pop(file_path, None) | 
|  | elif shell_cmdln.startswith("getprop ro.product.cpu.abi"): | 
|  | return self._CreatePopenMock(0, self.abi, "") | 
|  | else: | 
|  | raise Exception("Unknown shell command line: %s" % shell_cmdln) | 
|  | # Return a mock subprocess.Popen object | 
|  | return self._CreatePopenMock(returncode, stdout, stderr) | 
|  |  | 
|  | def _CreatePopenMock(self, returncode, stdout, stderr): | 
|  | return mock.Mock( | 
|  | returncode=returncode, communicate=lambda: (stdout, stderr)) | 
|  |  | 
|  | def SetError(self, returncode, stdout, stderr, for_arg=None): | 
|  | self._error = ((returncode, stdout, stderr), for_arg) | 
|  |  | 
|  | def SetAbi(self, abi): | 
|  | self.abi = abi | 
|  |  | 
|  |  | 
|  | class IncrementalInstallTest(unittest.TestCase): | 
|  | """Unit tests for incremental install.""" | 
|  |  | 
|  | _DEXMANIFEST = "dexmanifest.txt" | 
|  | _ADB_PATH = "/test/adb" | 
|  | _OUTPUT_MARKER = "full_deploy_marker" | 
|  | _APK = "myapp_incremental.apk" | 
|  | _RESOURCE_APK = "incremental.ap_" | 
|  | _STUB_DATAFILE = "stub_application_data.txt" | 
|  | _OLD_APP_PACKGE = "old.app.package" | 
|  | _APP_PACKAGE = "new.app.package" | 
|  | _EXEC_ROOT = "." | 
|  |  | 
|  | def setUp(self): | 
|  | os.chdir(os.environ["TEST_TMPDIR"]) | 
|  |  | 
|  | self._mock_adb = MockAdb() | 
|  |  | 
|  | # Write the stub datafile which contains the package name of the app. | 
|  | with open(self._STUB_DATAFILE, "wb") as f: | 
|  | f.write(("\n".join([self._OLD_APP_PACKGE, self._APP_PACKAGE])) | 
|  | .encode("utf-8")) | 
|  |  | 
|  | # Write the local resource apk file. | 
|  | with open(self._RESOURCE_APK, "wb") as f: | 
|  | f.write(b"resource apk") | 
|  |  | 
|  | # Mock out subprocess.Popen to use our mock adb. | 
|  | self._popen_patch = mock.patch.object(incremental_install, "subprocess") | 
|  | self._popen = self._popen_patch.start().Popen | 
|  | self._popen.side_effect = lambda args, **kwargs: self._mock_adb.Exec(args) | 
|  |  | 
|  | def tearDown(self): | 
|  | self._popen_patch.stop() | 
|  |  | 
|  | def _CreateZip(self, name="zip1", *files): | 
|  | if not files: | 
|  | files = [("zp1", "content1"), ("zp2", "content2")] | 
|  | with zipfile.ZipFile(name, "w") as z: | 
|  | for f, content in files: | 
|  | z.writestr(f, content) | 
|  |  | 
|  | def _CreateLocalManifest(self, *lines): | 
|  | content = "\n".join(lines) | 
|  | with open(self._DEXMANIFEST, "wb") as f: | 
|  | f.write(content.encode("utf-8")) | 
|  | return content | 
|  |  | 
|  | def _CreateRemoteManifest(self, *lines): | 
|  | self._PutDeviceFile("dex/manifest", "\n".join(lines)) | 
|  |  | 
|  | def _GetDeviceAppPath(self, f): | 
|  | return os.path.join( | 
|  | incremental_install.DEVICE_DIRECTORY, self._APP_PACKAGE, f) | 
|  |  | 
|  | def _GetDeviceFile(self, f): | 
|  | return self._mock_adb.files[self._GetDeviceAppPath(f)] | 
|  |  | 
|  | def _PutDeviceFile(self, f, content): | 
|  | self._mock_adb.files[self._GetDeviceAppPath(f)] = content | 
|  |  | 
|  | def _DeleteDeviceFile(self, f): | 
|  | self._mock_adb.files.pop(self._GetDeviceAppPath(f), None) | 
|  |  | 
|  | def _CallIncrementalInstall(self, incremental, native_libs=None, | 
|  | split_main_apk=None, split_apks=None, | 
|  | start_type="no"): | 
|  | if split_main_apk: | 
|  | apk = split_main_apk | 
|  | elif incremental: | 
|  | apk = None | 
|  | else: | 
|  | apk = self._APK | 
|  |  | 
|  | incremental_install.IncrementalInstall( | 
|  | adb_path=self._ADB_PATH, | 
|  | execroot=self._EXEC_ROOT, | 
|  | stub_datafile=self._STUB_DATAFILE, | 
|  | dexmanifest=self._DEXMANIFEST, | 
|  | apk=apk, | 
|  | resource_apk=self._RESOURCE_APK, | 
|  | split_main_apk=split_main_apk, | 
|  | split_apks=split_apks, | 
|  | native_libs=native_libs, | 
|  | output_marker=self._OUTPUT_MARKER, | 
|  | adb_jobs=1, | 
|  | start_type=start_type, | 
|  | user_home_dir="/home/root") | 
|  |  | 
|  | def testUploadToPristineDevice(self): | 
|  | self._CreateZip() | 
|  |  | 
|  | with open("dex1", "wb") as f: | 
|  | f.write(b"content3") | 
|  |  | 
|  | manifest = self._CreateLocalManifest( | 
|  | "zip1 zp1 ip1 0", | 
|  | "zip1 zp2 ip2 0", | 
|  | "dex1 - ip3 0") | 
|  |  | 
|  | self._CallIncrementalInstall(incremental=False) | 
|  |  | 
|  | resources_checksum_path = self._GetDeviceAppPath("resources_checksum") | 
|  | self.assertTrue(resources_checksum_path in self._mock_adb.files) | 
|  | self.assertEqual(manifest, self._GetDeviceFile("dex/manifest")) | 
|  | self.assertEqual("content1", self._GetDeviceFile("dex/ip1")) | 
|  | self.assertEqual("content2", self._GetDeviceFile("dex/ip2")) | 
|  | self.assertEqual("content3", self._GetDeviceFile("dex/ip3")) | 
|  | self.assertEqual("resource apk", self._GetDeviceFile("resources.ap_")) | 
|  |  | 
|  | def testSplitInstallToPristineDevice(self): | 
|  | with open("split1", "wb") as f: | 
|  | f.write(b"split_content1") | 
|  |  | 
|  | with open("main", "wb") as f: | 
|  | f.write(b"main_Content") | 
|  |  | 
|  | self._CallIncrementalInstall( | 
|  | incremental=False, split_main_apk="main", split_apks=["split1"]) | 
|  | self.assertEqual(set(["split_content1"]), self._mock_adb.split_apks) | 
|  |  | 
|  | def testSplitInstallUnchanged(self): | 
|  | with open("split1", "wb") as f: | 
|  | f.write(b"split_content1") | 
|  |  | 
|  | with open("main", "wb") as f: | 
|  | f.write(b"main_Content") | 
|  |  | 
|  | self._CallIncrementalInstall( | 
|  | incremental=False, split_main_apk="main", split_apks=["split1"]) | 
|  | self.assertEqual(set(["split_content1"]), self._mock_adb.split_apks) | 
|  | self._mock_adb.split_apks = set() | 
|  | self._CallIncrementalInstall( | 
|  | incremental=False, split_main_apk="main", split_apks=["split1"]) | 
|  | self.assertEqual(set([]), self._mock_adb.split_apks) | 
|  |  | 
|  | def testSplitInstallChanges(self): | 
|  | with open("split1", "wb") as f: | 
|  | f.write(b"split_content1") | 
|  |  | 
|  | with open("main", "wb") as f: | 
|  | f.write(b"main_Content") | 
|  |  | 
|  | self._CallIncrementalInstall( | 
|  | incremental=False, split_main_apk="main", split_apks=["split1"]) | 
|  | self.assertEqual(set(["split_content1"]), self._mock_adb.split_apks) | 
|  |  | 
|  | with open("split1", "wb") as f: | 
|  | f.write(b"split_content2") | 
|  | self._mock_adb.split_apks = set() | 
|  | self._CallIncrementalInstall( | 
|  | incremental=False, split_main_apk="main", split_apks=["split1"]) | 
|  | self.assertEqual(set(["split_content2"]), self._mock_adb.split_apks) | 
|  |  | 
|  | def testMissingNativeManifestWithIncrementalInstall(self): | 
|  | self._CreateZip() | 
|  | with open("liba.so", "wb") as f: | 
|  | f.write(b"liba_1") | 
|  |  | 
|  | # Upload a library to the device. | 
|  | native_libs = ["armeabi-v7a:liba.so"] | 
|  | self._CallIncrementalInstall(incremental=False, native_libs=native_libs) | 
|  | self.assertEqual("liba_1", self._GetDeviceFile("native/liba.so")) | 
|  |  | 
|  | # Delete the manifest, overwrite the library and check that even an | 
|  | # incremental install straightens things out. | 
|  | self._PutDeviceFile("native/liba.so", "GARBAGE") | 
|  | self._CallIncrementalInstall(incremental=False, native_libs=native_libs) | 
|  | self.assertEqual("liba_1", self._GetDeviceFile("native/liba.so")) | 
|  |  | 
|  | def testNonIncrementalInstallOverwritesNativeLibs(self): | 
|  | self._CreateZip() | 
|  | with open("liba.so", "wb") as f: | 
|  | f.write(b"liba_1") | 
|  |  | 
|  | # Upload a library to the device. | 
|  | native_libs = ["armeabi-v7a:liba.so"] | 
|  | self._CallIncrementalInstall(incremental=False, native_libs=native_libs) | 
|  | self.assertEqual("liba_1", self._GetDeviceFile("native/liba.so")) | 
|  |  | 
|  | # Change a library on the device. Incremental install should not replace the | 
|  | # changed file, because it only checks the manifest. | 
|  | self._PutDeviceFile("native/liba.so", "GARBAGE") | 
|  | self._CallIncrementalInstall(incremental=True, native_libs=native_libs) | 
|  | self.assertEqual("GARBAGE", self._GetDeviceFile("native/liba.so")) | 
|  |  | 
|  | # However, a full install should overwrite it. | 
|  | self._CallIncrementalInstall(incremental=False, native_libs=native_libs) | 
|  | self.assertEqual("liba_1", self._GetDeviceFile("native/liba.so")) | 
|  |  | 
|  | def testNativeAbiCompatibility(self): | 
|  | self._CreateZip() | 
|  | with open("liba.so", "wb") as f: | 
|  | f.write(b"liba") | 
|  |  | 
|  | native_libs = ["armeabi:liba.so"] | 
|  | self._mock_adb.SetAbi("arm64-v8a") | 
|  | self._CallIncrementalInstall(incremental=False, native_libs=native_libs) | 
|  | self.assertEqual("liba", self._GetDeviceFile("native/liba.so")) | 
|  |  | 
|  | def testUploadNativeLibs(self): | 
|  | self._CreateZip() | 
|  | with open("liba.so", "wb") as f: | 
|  | f.write(b"liba_1") | 
|  | with open("libb.so", "wb") as f: | 
|  | f.write(b"libb_1") | 
|  |  | 
|  | native_libs = ["armeabi-v7a:liba.so", "armeabi-v7a:libb.so"] | 
|  | self._CallIncrementalInstall(incremental=False, native_libs=native_libs) | 
|  | self.assertEqual("liba_1", self._GetDeviceFile("native/liba.so")) | 
|  | self.assertEqual("libb_1", self._GetDeviceFile("native/libb.so")) | 
|  |  | 
|  | # Change a library | 
|  | with open("libb.so", "wb") as f: | 
|  | f.write(b"libb_2") | 
|  | self._CallIncrementalInstall(incremental=True, native_libs=native_libs) | 
|  | self.assertEqual("libb_2", self._GetDeviceFile("native/libb.so")) | 
|  |  | 
|  | # Delete a library | 
|  | self._CallIncrementalInstall( | 
|  | incremental=True, native_libs=["armeabi-v7a:liba.so"]) | 
|  | self.assertFalse( | 
|  | self._GetDeviceAppPath("native/libb.so") in self._mock_adb.files) | 
|  |  | 
|  | # Add the deleted library back | 
|  | self._CallIncrementalInstall(incremental=True, native_libs=native_libs) | 
|  | self.assertEqual("libb_2", self._GetDeviceFile("native/libb.so")) | 
|  |  | 
|  | def testUploadWithOneChangedFile(self): | 
|  | # Existing manifest from a previous install. | 
|  | self._CreateRemoteManifest( | 
|  | "zip1 zp1 ip1 0", | 
|  | "zip1 zp2 ip2 1") | 
|  |  | 
|  | # Existing files from a previous install. | 
|  | self._PutDeviceFile("dex/ip1", "old content1") | 
|  | self._PutDeviceFile("dex/ip2", "old content2") | 
|  | self._PutDeviceFile("install_timestamp", "0") | 
|  | self._mock_adb.package_timestamp = "0" | 
|  |  | 
|  | self._CreateZip() | 
|  |  | 
|  | # Updated dex manifest. | 
|  | self._CreateLocalManifest( | 
|  | "zip1 zp1 ip1 0", | 
|  | "zip1 zp2 ip2 2") | 
|  |  | 
|  | self._CallIncrementalInstall(incremental=True) | 
|  |  | 
|  | # This is a bit of a dishonest test: the local content for "ip1" is | 
|  | # "content1" and the remote content for it is "old content1", but | 
|  | # the checksums for that file are the same in the local and remote manifest. | 
|  | # We just want to make sure that only one file was updated, so to | 
|  | # distinguish that we force the local and remote content to be different but | 
|  | # keep the checksum the same. | 
|  | self.assertEqual("old content1", self._GetDeviceFile("dex/ip1")) | 
|  | self.assertEqual("content2", self._GetDeviceFile("dex/ip2")) | 
|  |  | 
|  | def testFullUploadWithOneChangedFile(self): | 
|  |  | 
|  | # Existing manifest from a previous install. | 
|  | self._CreateRemoteManifest( | 
|  | "zip1 zp1 ip1 0", | 
|  | "zip1 zp2 ip2 1") | 
|  |  | 
|  | self._PutDeviceFile("dex/ip1", "old content1") | 
|  | self._PutDeviceFile("dex/ip2", "old content2") | 
|  | self._PutDeviceFile("install_timestamp", "0") | 
|  | self._mock_adb.package_timestamp = "0" | 
|  |  | 
|  | self._CreateZip() | 
|  |  | 
|  | self._CreateLocalManifest( | 
|  | "zip1 zp1 ip1 0", | 
|  | "zip1 zp2 ip2 2") | 
|  |  | 
|  | self._CallIncrementalInstall(incremental=False) | 
|  |  | 
|  | # Even though the checksums for ip1 were the same, the file still got | 
|  | # updated. This is a bit of a dishonest test because the local and remote | 
|  | # content for ip1 were different, but their checksums were the same. | 
|  | self.assertEqual("content1", self._GetDeviceFile("dex/ip1")) | 
|  | self.assertEqual("content2", self._GetDeviceFile("dex/ip2")) | 
|  |  | 
|  | def testUploadWithNewFile(self): | 
|  |  | 
|  | self._CreateRemoteManifest("zip1 zp1 ip1 0") | 
|  | self._PutDeviceFile("dex/ip1", "content1") | 
|  | self._PutDeviceFile("install_timestamp", "0") | 
|  | self._mock_adb.package_timestamp = "0" | 
|  |  | 
|  | self._CreateLocalManifest( | 
|  | "zip1 zp1 ip1 0", | 
|  | "zip1 zp2 ip2 1") | 
|  |  | 
|  | self._CreateZip() | 
|  |  | 
|  | self._CallIncrementalInstall(incremental=True) | 
|  |  | 
|  | self.assertEqual("content1", self._GetDeviceFile("dex/ip1")) | 
|  | self.assertEqual("content2", self._GetDeviceFile("dex/ip2")) | 
|  |  | 
|  | def testDeletesFile(self): | 
|  |  | 
|  | self._CreateRemoteManifest( | 
|  | "zip1 zp1 ip1 0", | 
|  | "zip1 zip2 ip2 1") | 
|  | self._PutDeviceFile("dex/ip1", "content1") | 
|  | self._PutDeviceFile("dex/ip2", "content2") | 
|  | self._PutDeviceFile("install_timestamp", "1") | 
|  | self._mock_adb.package_timestamp = "1" | 
|  |  | 
|  | self._CreateZip("zip1", ("zp1", "content1")) | 
|  | self._CreateLocalManifest("zip1 zp1 ip1 0") | 
|  |  | 
|  | self.assertTrue(self._GetDeviceAppPath("dex/ip2") in self._mock_adb.files) | 
|  | self._CallIncrementalInstall(incremental=True) | 
|  | self.assertFalse(self._GetDeviceAppPath("dex/ip2") in self._mock_adb.files) | 
|  |  | 
|  | def testNothingToUpdate(self): | 
|  | self._CreateRemoteManifest( | 
|  | "zip1 zp1 ip1 0", | 
|  | "zip1 zip2 ip2 1", | 
|  | "dex1 - ip3 0") | 
|  | self._PutDeviceFile("dex/ip1", "content1") | 
|  | self._PutDeviceFile("dex/ip2", "content2") | 
|  | self._PutDeviceFile("dex/ip3", "content3") | 
|  | self._PutDeviceFile("install_timestamp", "0") | 
|  | self._mock_adb.package_timestamp = "0" | 
|  |  | 
|  | self._CreateZip() | 
|  | self._CreateLocalManifest( | 
|  | "zip1 zp1 ip1 0", | 
|  | "zip1 zip2 ip2 1", | 
|  | "dex1 - ip3 0") | 
|  |  | 
|  | self._CallIncrementalInstall(incremental=True) | 
|  | self.assertEqual("content1", self._GetDeviceFile("dex/ip1")) | 
|  | self.assertEqual("content2", self._GetDeviceFile("dex/ip2")) | 
|  | self.assertEqual("content3", self._GetDeviceFile("dex/ip3")) | 
|  |  | 
|  | def testNoResourcesToUpdate(self): | 
|  | self._CreateRemoteManifest("zip1 zp1 ip1 0") | 
|  | self._PutDeviceFile("dex/ip1", "content1") | 
|  | # The local file is actually "resource apk", but the checksum on the device | 
|  | # for the resources file is set to be the same as the checksum for the | 
|  | # local file so that we can confirm that it was not updated. | 
|  | self._PutDeviceFile("resources.ap_", "resources") | 
|  | self._PutDeviceFile("resources_checksum", | 
|  | incremental_install.Checksum(self._RESOURCE_APK)) | 
|  | self._PutDeviceFile("install_timestamp", "0") | 
|  | self._mock_adb.package_timestamp = "0" | 
|  |  | 
|  | self._CreateZip() | 
|  | self._CreateLocalManifest("zip1 zp1 ip1 0") | 
|  |  | 
|  | self._CallIncrementalInstall(incremental=True) | 
|  | self.assertEqual("resources", self._GetDeviceFile("resources.ap_")) | 
|  |  | 
|  | def testUpdateResources(self): | 
|  | self._CreateRemoteManifest("zip1 zp1 ip1 0") | 
|  | self._PutDeviceFile("dex/ip1", "content1") | 
|  | self._PutDeviceFile("resources.ap_", "resources") | 
|  | self._PutDeviceFile("resources_checksum", "checksum") | 
|  | self._PutDeviceFile("install_timestamp", "0") | 
|  | self._mock_adb.package_timestamp = "0" | 
|  |  | 
|  | self._CreateZip() | 
|  | self._CreateLocalManifest("zip1 zp1 ip1 0") | 
|  |  | 
|  | self._CallIncrementalInstall(incremental=True) | 
|  | self.assertEqual("resource apk", self._GetDeviceFile("resources.ap_")) | 
|  |  | 
|  | def testNoDevice(self): | 
|  | self._mock_adb.SetError(1, "", "device not found") | 
|  | try: | 
|  | self._CallIncrementalInstall(incremental=True) | 
|  | self.fail("Should have quit if there is no device") | 
|  | except SystemExit as e: | 
|  | # make sure it's the right SystemExit reason | 
|  | self.assertTrue("Device not found" in str(e)) | 
|  |  | 
|  | def testUnauthorizedDevice(self): | 
|  | self._mock_adb.SetError(1, "", "device unauthorized. Please check the " | 
|  | "confirmation dialog on your device") | 
|  | try: | 
|  | self._CallIncrementalInstall(incremental=True) | 
|  | self.fail("Should have quit if the device is unauthorized.") | 
|  | except SystemExit as e: | 
|  | # make sure it's the right SystemExit reason | 
|  | self.assertTrue("Device unauthorized." in str(e)) | 
|  |  | 
|  | def testInstallFailure(self): | 
|  | self._mock_adb.SetError(0, "Failure", "INSTALL_FAILED", for_arg="install") | 
|  | self._CreateZip() | 
|  | self._CreateLocalManifest("zip1 zp1 ip1 0") | 
|  | try: | 
|  | self._CallIncrementalInstall(incremental=False) | 
|  | self.fail("Should have quit if the install failed.") | 
|  | except SystemExit as e: | 
|  | # make sure it's the right SystemExit reason | 
|  | self.assertTrue("Failure" in str(e)) | 
|  |  | 
|  | def testStartCold(self): | 
|  | # Based on testUploadToPristineDevice | 
|  | self._CreateZip() | 
|  |  | 
|  | with open("dex1", "wb") as f: | 
|  | f.write(b"content3") | 
|  |  | 
|  | self._CreateLocalManifest( | 
|  | "zip1 zp1 ip1 0", | 
|  | "zip1 zp2 ip2 0", | 
|  | "dex1 - ip3 0") | 
|  |  | 
|  | self._CallIncrementalInstall(incremental=False, start_type="cold") | 
|  |  | 
|  | self.assertTrue(("monkey -p %s -c android.intent.category.LAUNCHER 1" % | 
|  | self._APP_PACKAGE) in self._mock_adb.shell_cmdlns) | 
|  |  | 
|  | def testDebugStart(self): | 
|  | self._CreateZip() | 
|  |  | 
|  | with open("dex1", "wb") as f: | 
|  | f.write(b"content3") | 
|  |  | 
|  | self._CreateLocalManifest( | 
|  | "zip1 zp1 ip1 0", | 
|  | "zip1 zp2 ip2 0", | 
|  | "dex1 - ip3 0") | 
|  |  | 
|  | self._CallIncrementalInstall(incremental=False, start_type="debug") | 
|  | enable_debug_cmd = ("am set-debug-app -w --persistent %s" % | 
|  | self._APP_PACKAGE) | 
|  | start_app_cmd = ("monkey -p %s -c android.intent.category.LAUNCHER 1" % | 
|  | self._APP_PACKAGE) | 
|  | self.assertTrue(enable_debug_cmd in self._mock_adb.shell_cmdlns) | 
|  | self.assertTrue(start_app_cmd in self._mock_adb.shell_cmdlns) | 
|  |  | 
|  | def testColdStop(self): | 
|  | self._CreateRemoteManifest( | 
|  | "zip1 zp1 ip1 0", | 
|  | "zip1 zip2 ip2 1", | 
|  | "dex1 - ip3 0") | 
|  | self._PutDeviceFile("dex/ip1", "content1") | 
|  | self._PutDeviceFile("dex/ip2", "content2") | 
|  | self._PutDeviceFile("dex/ip3", "content3") | 
|  | self._PutDeviceFile("install_timestamp", "0") | 
|  | self._mock_adb.package_timestamp = "0" | 
|  |  | 
|  | self._CreateZip() | 
|  | self._CreateLocalManifest( | 
|  | "zip1 zp1 ip1 0", | 
|  | "zip1 zip2 ip2 1", | 
|  | "dex1 - ip3 0") | 
|  | self._CallIncrementalInstall(incremental=True, start_type="cold") | 
|  |  | 
|  | stop_cmd = "am force-stop %s" % self._APP_PACKAGE | 
|  | self.assertTrue(stop_cmd in self._mock_adb.shell_cmdlns) | 
|  |  | 
|  | def testWarmStop(self): | 
|  | self._CreateRemoteManifest( | 
|  | "zip1 zp1 ip1 0", | 
|  | "zip1 zip2 ip2 1", | 
|  | "dex1 - ip3 0") | 
|  | self._PutDeviceFile("dex/ip1", "content1") | 
|  | self._PutDeviceFile("dex/ip2", "content2") | 
|  | self._PutDeviceFile("dex/ip3", "content3") | 
|  | self._PutDeviceFile("install_timestamp", "0") | 
|  | self._mock_adb.package_timestamp = "0" | 
|  |  | 
|  | self._CreateZip() | 
|  | self._CreateLocalManifest( | 
|  | "zip1 zp1 ip1 0", | 
|  | "zip1 zip2 ip2 1", | 
|  | "dex1 - ip3 0") | 
|  | self._CallIncrementalInstall(incremental=True, start_type="warm") | 
|  |  | 
|  | background_cmd = "input keyevent KEYCODE_APP_SWITCH" | 
|  | stop_cmd = "am kill %s" % self._APP_PACKAGE | 
|  | self.assertTrue(background_cmd in self._mock_adb.shell_cmdlns) | 
|  | self.assertTrue(stop_cmd in self._mock_adb.shell_cmdlns) | 
|  |  | 
|  | def testMultipleDevicesError(self): | 
|  | errors = [ | 
|  | "more than one device and emulator", | 
|  | "more than one device", | 
|  | "more than one emulator", | 
|  | ] | 
|  | for error in errors: | 
|  | self._mock_adb.SetError(1, "", error) | 
|  | try: | 
|  | self._CallIncrementalInstall(incremental=True) | 
|  | self.fail("Should have quit if there were multiple devices.") | 
|  | except SystemExit as e: | 
|  | # make sure it's the right SystemExit reason | 
|  | self.assertTrue("Try specifying a device serial" in str(e)) | 
|  |  | 
|  | def testIncrementalInstallOnPristineDevice(self): | 
|  | self._CreateZip() | 
|  | self._CreateLocalManifest( | 
|  | "zip1 zp1 ip1 0", | 
|  | "zip1 zip2 ip2 1", | 
|  | "dex1 - ip3 0") | 
|  |  | 
|  | try: | 
|  | self._CallIncrementalInstall(incremental=True) | 
|  | self.fail("Should have quit for incremental install on pristine device") | 
|  | except SystemExit: | 
|  | pass | 
|  |  | 
|  | def testIncrementalInstallWithWrongInstallTimestamp(self): | 
|  | self._CreateRemoteManifest( | 
|  | "zip1 zp1 ip1 0", | 
|  | "zip1 zip2 ip2 1", | 
|  | "dex1 - ip3 0") | 
|  | self._PutDeviceFile("dex/ip1", "content1") | 
|  | self._PutDeviceFile("dex/ip2", "content2") | 
|  | self._PutDeviceFile("dex/ip3", "content3") | 
|  | self._mock_adb.package_timestamp = "WRONG" | 
|  |  | 
|  | self._CreateZip() | 
|  | self._CreateLocalManifest( | 
|  | "zip1 zp1 ip1 0", | 
|  | "zip1 zip2 ip2 1", | 
|  | "dex1 - ip3 0") | 
|  |  | 
|  | try: | 
|  | self._CallIncrementalInstall(incremental=True) | 
|  | self.fail("Should have quit if install timestamp is wrong") | 
|  | except SystemExit: | 
|  | pass | 
|  |  | 
|  | def testSdkTooOld(self): | 
|  | self._mock_adb.SetError( | 
|  | 0, "INSTALL_FAILED_OLDER_SDK", "", for_arg="install") | 
|  | self._CreateZip() | 
|  | self._CreateLocalManifest("zip1 zp1 ip1 0") | 
|  | try: | 
|  | self._CallIncrementalInstall(incremental=False) | 
|  | self.fail("Should have quit if the SDK is too old.") | 
|  | except SystemExit as e: | 
|  | # make sure it's the right SystemExit reason | 
|  | self.assertTrue("minSdkVersion" in str(e)) | 
|  |  | 
|  |  | 
|  | if __name__ == "__main__": | 
|  | unittest.main() |