| # Lint as: python2, python3 | |
| # 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.""" | |
| from __future__ import absolute_import | |
| from __future__ import division | |
| from __future__ import print_function | |
| import os | |
| import unittest | |
| import zipfile | |
| # Do not edit this line. Copybara replaces it with PY2 migration helper. | |
| import six | |
| if six.PY3: | |
| from unittest import mock | |
| else: | |
| import mock | |
| 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(six.ensure_binary(content, "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 six.ensure_str(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 six.ensure_str(shell_cmdln).startswith("rm"): | |
| file_path = shell_cmdln.split()[2] | |
| self.files.pop(file_path, None) | |
| elif six.ensure_str(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() |