diff options
author | Hsin-Yi Chen <hsinyichen@google.com> | 2021-04-23 09:59:46 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2021-04-23 09:59:46 +0000 |
commit | e4cdc9fb79f7909a08db1cf12e2240d9d1228960 (patch) | |
tree | 1c9e9f5e37345c566f554c08033a5147130f51e8 | |
parent | f215b880d4a61e23eef39f499c7424688f80997a (diff) | |
parent | a53ee5009aab925ea63d916003ba3d766a14bba3 (diff) | |
download | acloud-e4cdc9fb79f7909a08db1cf12e2240d9d1228960.tar.gz |
Merge "Allow --local-system-image to be file" am: a53ee5009a
Original change: https://android-review.googlesource.com/c/platform/tools/acloud/+/1673188
Change-Id: Ibde26be2c57a6741ce9cc3fe0947852d4cfc27da
-rw-r--r-- | create/avd_spec.py | 36 | ||||
-rw-r--r-- | create/avd_spec_test.py | 53 | ||||
-rw-r--r-- | create/create_args.py | 3 | ||||
-rw-r--r-- | create/create_common.py | 21 | ||||
-rw-r--r-- | create/create_common_test.py | 16 | ||||
-rw-r--r-- | create/goldfish_local_image_local_instance.py | 15 | ||||
-rw-r--r-- | create/goldfish_local_image_local_instance_test.py | 84 | ||||
-rw-r--r-- | create/local_image_local_instance.py | 9 | ||||
-rw-r--r-- | create/local_image_local_instance_test.py | 9 |
9 files changed, 186 insertions, 60 deletions
diff --git a/create/avd_spec.py b/create/avd_spec.py index 32661a2e..872c5b08 100644 --- a/create/avd_spec.py +++ b/create/avd_spec.py @@ -113,7 +113,7 @@ class AVDSpec(): self._local_image_dir = None self._local_image_artifact = None self._local_instance_dir = None - self._local_system_image_dir = None + self._local_system_image = None self._local_tool_dirs = None self._image_download_dir = None self._num_of_instances = None @@ -377,8 +377,11 @@ class AVDSpec(): elif self._avd_type == constants.TYPE_FVP: self._ProcessFVPLocalImageArgs() elif self._avd_type == constants.TYPE_GF: - self._local_image_dir = self._ProcessLocalImageDirArgs( + self._local_image_dir = self._GetLocalImagePath( args.local_image) + if not os.path.isdir(self._local_image_dir): + raise errors.GetLocalImageError("%s is not a directory." % + args.local_image) elif self._avd_type == constants.TYPE_GCE: self._local_image_artifact = self._GetGceLocalImagePath( args.local_image) @@ -388,7 +391,7 @@ class AVDSpec(): ) if args.local_system_image is not None: - self._local_system_image_dir = self._ProcessLocalImageDirArgs( + self._local_system_image = self._GetLocalImagePath( args.local_system_image) @staticmethod @@ -427,8 +430,8 @@ class AVDSpec(): ", ".join(_GCE_LOCAL_IMAGE_CANDIDATES)) @staticmethod - def _ProcessLocalImageDirArgs(local_image_arg): - """Get local image directory from argument or environment variable. + def _GetLocalImagePath(local_image_arg): + """Get local image path from argument or environment variable. Args: local_image_arg: The path to the unzipped image package. If the @@ -436,22 +439,21 @@ class AVDSpec(): ANDROID_PRODUCT_OUT in build environment. Returns: - String, the path to the image directory. + String, the path to the image file or directory. Raises: - errors.GetLocalImageError if the directory is not found. + errors.GetLocalImageError if the path does not exist. """ if local_image_arg == constants.FIND_IN_BUILD_ENV: - image_dir = utils.GetBuildEnvironmentVariable( + image_path = utils.GetBuildEnvironmentVariable( constants.ENV_ANDROID_PRODUCT_OUT) else: - image_dir = local_image_arg + image_path = local_image_arg - if not os.path.isdir(image_dir): - raise errors.GetLocalImageError( - "%s is not a directory." % image_dir) - - return image_dir + if not os.path.exists(image_path): + raise errors.GetLocalImageError("%s does not exist." % + local_image_arg) + return image_path def _ProcessCFLocalImageArgs(self, local_image_arg, flavor_arg): """Get local built image path for cuttlefish-type AVD. @@ -730,9 +732,9 @@ class AVDSpec(): return self._local_instance_dir @property - def local_system_image_dir(self): - """Return local system image dir.""" - return self._local_system_image_dir + def local_system_image(self): + """Return local system image path.""" + return self._local_system_image @property def local_tool_dirs(self): diff --git a/create/avd_spec_test.py b/create/avd_spec_test.py index ee5e3a42..f337aab0 100644 --- a/create/avd_spec_test.py +++ b/create/avd_spec_test.py @@ -55,9 +55,15 @@ class AvdSpecTest(driver_test_lib.BaseDriverTest): self.Patch(glob, "glob", return_value=["fake.img"]) expected_image_artifact = "/path/cf_x86_phone-img-eng.user.zip" expected_image_dir = "/path-to-image-dir" + self.Patch(os.path, "exists", + side_effect=lambda path: path in (expected_image_artifact, + expected_image_dir)) + self.Patch(os.path, "isdir", + side_effect=lambda path: path == expected_image_dir) + self.Patch(os.path, "isfile", + side_effect=lambda path: path == expected_image_artifact) # Specified --local-image to a local zipped image file - self.Patch(os.path, "isfile", return_value=True) self.args.local_image = "/path/cf_x86_phone-img-eng.user.zip" self.AvdSpec._avd_type = constants.TYPE_CF self.AvdSpec._instance_type = constants.INSTANCE_TYPE_REMOTE @@ -68,7 +74,6 @@ class AvdSpecTest(driver_test_lib.BaseDriverTest): # Specified --local-image to a dir contains images self.Patch(utils, "GetBuildEnvironmentVariable", return_value="test_cf_x86") - self.Patch(os.path, "isfile", return_value=False) self.args.local_image = "/path-to-image-dir" self.AvdSpec._avd_type = constants.TYPE_CF self.AvdSpec._instance_type = constants.INSTANCE_TYPE_REMOTE @@ -86,28 +91,47 @@ class AvdSpecTest(driver_test_lib.BaseDriverTest): # Specified --avd-type=goldfish --local-image with a dir self.Patch(utils, "GetBuildEnvironmentVariable", return_value="test_environ") - self.Patch(os.path, "isdir", return_value=True) self.args.local_image = "/path-to-image-dir" self.AvdSpec._avd_type = constants.TYPE_GF self.AvdSpec._instance_type = constants.INSTANCE_TYPE_LOCAL self.AvdSpec._ProcessLocalImageArgs(self.args) self.assertEqual(self.AvdSpec._local_image_dir, expected_image_dir) + def testProcessLocalSystemImageArgs(self): + """Test process args.local_system_image.""" + expected_image_dir = "/path-to-image-dir" + expected_image_file = "/path-to-image-file" + self.Patch(os.path, "exists", + side_effect=lambda path: path in (expected_image_file, + expected_image_dir)) + self.Patch(os.path, "isdir", + side_effect=lambda path: path == expected_image_dir) + self.Patch(os.path, "isfile", + side_effect=lambda path: path == expected_image_file) + # Specified --local-image and --local-system-image with dirs self.args.local_image = expected_image_dir self.args.local_system_image = expected_image_dir self.AvdSpec._avd_type = constants.TYPE_CF self.AvdSpec._instance_type = constants.INSTANCE_TYPE_LOCAL - with mock.patch("os.path.isfile", return_value=False), \ - mock.patch("os.path.isdir", - side_effect=lambda path: path == expected_image_dir), \ - mock.patch("acloud.create.avd_spec.utils." + with mock.patch("acloud.create.avd_spec.utils." "GetBuildEnvironmentVariable", return_value="cf_x86_phone"): self.AvdSpec._ProcessLocalImageArgs(self.args) - self.assertEqual(self.AvdSpec._local_image_dir, expected_image_dir) - self.assertEqual(self.AvdSpec._local_system_image_dir, - expected_image_dir) + self.assertEqual(self.AvdSpec.local_image_dir, expected_image_dir) + self.assertEqual(self.AvdSpec.local_system_image, expected_image_dir) + + # Specified --local-image with dir and --local-system-image with file + self.args.local_image = expected_image_dir + self.args.local_system_image = expected_image_file + self.AvdSpec._avd_type = constants.TYPE_CF + self.AvdSpec._instance_type = constants.INSTANCE_TYPE_LOCAL + with mock.patch("acloud.create.avd_spec.utils." + "GetBuildEnvironmentVariable", + return_value="cf_x86_phone"): + self.AvdSpec._ProcessLocalImageArgs(self.args) + self.assertEqual(self.AvdSpec.local_image_dir, expected_image_dir) + self.assertEqual(self.AvdSpec.local_system_image, expected_image_file) # Specified --avd-type=goldfish, --local_image, and # --local-system-image without args @@ -115,15 +139,12 @@ class AvdSpecTest(driver_test_lib.BaseDriverTest): self.args.local_system_image = constants.FIND_IN_BUILD_ENV self.AvdSpec._avd_type = constants.TYPE_GF self.AvdSpec._instance_type = constants.INSTANCE_TYPE_LOCAL - with mock.patch("os.path.isdir", - side_effect=lambda path: path == expected_image_dir), \ - mock.patch("acloud.create.avd_spec.utils." + with mock.patch("acloud.create.avd_spec.utils." "GetBuildEnvironmentVariable", return_value=expected_image_dir): self.AvdSpec._ProcessLocalImageArgs(self.args) - self.assertEqual(self.AvdSpec._local_image_dir, expected_image_dir) - self.assertEqual(self.AvdSpec._local_system_image_dir, - expected_image_dir) + self.assertEqual(self.AvdSpec.local_image_dir, expected_image_dir) + self.assertEqual(self.AvdSpec.local_system_image, expected_image_dir) def testProcessImageArgs(self): """Test process image source.""" diff --git a/create/create_args.py b/create/create_args.py index 70c2df49..c85dc51d 100644 --- a/create/create_args.py +++ b/create/create_args.py @@ -395,7 +395,8 @@ def GetCreateArgParser(subparser): required=False, help="Use the locally built system images for the AVD. Look for the " "images in $ANDROID_PRODUCT_OUT if no args value is provided. " - "e.g., --local-system-image or --local-system-image /path/to/dir") + "e.g., --local-system-image, --local-system-image /path/to/dir, or " + "--local-system-image /path/to/img") create_parser.add_argument( "--local-tool", type=str, diff --git a/create/create_common.py b/create/create_common.py index e18e58bd..c0ec23cb 100644 --- a/create/create_common.py +++ b/create/create_common.py @@ -96,6 +96,27 @@ def GetCvdHostPackage(): '\n'.join(dirs_to_check)) +def FindLocalImage(path, default_name): + """Find an image file in the given path. + + Args: + path: The path to the file or the parent directory. + default_name: The file to look for if the path is a directory. + + Returns: + The absolute path to the image file. + + Raises: + errors.GetLocalImageError if this method cannot find the image. + """ + path = os.path.abspath(path) + if os.path.isdir(path): + path = os.path.join(path, default_name) + if os.path.isfile(path): + return path + raise errors.GetLocalImageError("%s is not a file." % path) + + def DownloadRemoteArtifact(cfg, build_target, build_id, artifact, extract_path, decompress=False): """Download remote artifact. diff --git a/create/create_common_test.py b/create/create_common_test.py index 0c8de70a..40e21335 100644 --- a/create/create_common_test.py +++ b/create/create_common_test.py @@ -96,6 +96,22 @@ class CreateCommonTest(driver_test_lib.BaseDriverTest): create_common.GetCvdHostPackage(), "/fake_dir2/cvd-host_package.tar.gz") + @mock.patch("acloud.create.create_common.os.path.isfile", + side_effect=lambda path: path == "/dir/name") + @mock.patch("acloud.create.create_common.os.path.isdir", + side_effect=lambda path: path == "/dir") + def testFindLocalImage(self, _mock_isdir, _mock_isfile): + """Test FindLocalImage.""" + self.assertEqual( + "/dir/name", + create_common.FindLocalImage("/test/../dir/name", "not_exist")) + + self.assertEqual("/dir/name", + create_common.FindLocalImage("/dir/", "name")) + + with self.assertRaises(errors.GetLocalImageError): + create_common.FindLocalImage("/dir", "not_exist") + @mock.patch.object(utils, "Decompress") def testDownloadRemoteArtifact(self, mock_decompress): """Test Download cuttlefish package.""" diff --git a/create/goldfish_local_image_local_instance.py b/create/goldfish_local_image_local_instance.py index 19afa3f8..5db67a26 100644 --- a/create/goldfish_local_image_local_instance.py +++ b/create/goldfish_local_image_local_instance.py @@ -215,14 +215,14 @@ class GoldfishLocalImageLocalInstance(base_avd_create.BaseAVDCreate): return result_report @staticmethod - def _MixImages(output_dir, image_dir, system_image_dir, ota): + def _MixImages(output_dir, image_dir, system_image_path, ota): """Mix emulator images and a system image into a disk image. Args: output_dir: The path to the output directory. image_dir: The input directory that provides images except system.img. - system_image_dir: The input directory that provides system.img. + system_image_path: The path to the system image. ota: An instance of ota_tools.OtaTools. Returns: @@ -230,7 +230,6 @@ class GoldfishLocalImageLocalInstance(base_avd_create.BaseAVDCreate): """ # Create the super image. mixed_super_image_path = os.path.join(output_dir, "mixed_super.img") - system_image_path = os.path.join(system_image_dir, _SYSTEM_IMAGE_NAME) ota.BuildSuperImage( mixed_super_image_path, os.path.join(image_dir, _MISC_INFO_FILE_NAME), @@ -333,7 +332,7 @@ class GoldfishLocalImageLocalInstance(base_avd_create.BaseAVDCreate): os.path.isfile(os.path.join(image_dir, _SYSTEM_IMAGE_NAME))): return image_dir - raise errors.GetLocalImageError("No system image in %s." % image_dir) + raise errors.GetLocalImageError("No device image in %s." % image_dir) @staticmethod def _IsEmulatorRunning(adb): @@ -446,7 +445,7 @@ class GoldfishLocalImageLocalInstance(base_avd_create.BaseAVDCreate): if not avd_spec.autoconnect: args.append("-no-window") - if avd_spec.local_system_image_dir: + if avd_spec.local_system_image: mixed_image_dir = os.path.join(instance_dir, "mixed_images") if os.path.exists(mixed_image_dir): shutil.rmtree(mixed_image_dir) @@ -454,12 +453,14 @@ class GoldfishLocalImageLocalInstance(base_avd_create.BaseAVDCreate): image_dir = self._FindImageDir(avd_spec.local_image_dir) + system_image_path = create_common.FindLocalImage( + avd_spec.local_system_image, _SYSTEM_IMAGE_NAME) + ota_tools_dir = ota_tools.FindOtaTools(avd_spec.local_tool_dirs) ota_tools_dir = os.path.abspath(ota_tools_dir) mixed_image = self._MixImages( - mixed_image_dir, image_dir, - os.path.abspath(avd_spec.local_system_image_dir), + mixed_image_dir, image_dir, system_image_path, ota_tools.OtaTools(ota_tools_dir)) # TODO(b/142228085): Use -system instead of modifying image_dir. diff --git a/create/goldfish_local_image_local_instance_test.py b/create/goldfish_local_image_local_instance_test.py index eee62f1f..900197bf 100644 --- a/create/goldfish_local_image_local_instance_test.py +++ b/create/goldfish_local_image_local_instance_test.py @@ -145,7 +145,7 @@ class GoldfishLocalImageLocalInstance(unittest.TestCase): local_instance_id=1, local_instance_dir=None, local_image_dir=self._image_dir, - local_system_image_dir=None, + local_system_image=None, local_tool_dirs=[]) # Test deleting an existing instance. @@ -199,7 +199,7 @@ class GoldfishLocalImageLocalInstance(unittest.TestCase): local_instance_id=2, local_instance_dir=instance_dir, local_image_dir=self._image_dir, - local_system_image_dir=None, + local_system_image=None, local_tool_dirs=[self._tool_dir]) with mock.patch.dict("acloud.create." @@ -250,7 +250,7 @@ class GoldfishLocalImageLocalInstance(unittest.TestCase): local_instance_id=2, local_instance_dir=None, local_image_dir=self._image_dir, - local_system_image_dir=None, + local_system_image=None, local_tool_dirs=[self._tool_dir]) with mock.patch.dict("acloud.create." @@ -284,7 +284,7 @@ class GoldfishLocalImageLocalInstance(unittest.TestCase): local_instance_id=0, local_instance_dir=None, local_image_dir=self._image_dir, - local_system_image_dir=None, + local_system_image=None, local_tool_dirs=[self._tool_dir]) with mock.patch.dict("acloud.create." @@ -307,6 +307,75 @@ class GoldfishLocalImageLocalInstance(unittest.TestCase): @mock.patch("acloud.create.goldfish_local_image_local_instance.ota_tools") def testCreateAVDWithMixedImages(self, mock_ota_tools, mock_popen, mock_utils, mock_instance): + """Test _CreateAVD with mixed images and SDK repository files.""" + mock_ota_tools.FindOtaTools.return_value = self._tool_dir + mock_ota_tools_object = mock.Mock() + mock_ota_tools.OtaTools.return_value = mock_ota_tools_object + mock_ota_tools_object.MkCombinedImg.side_effect = ( + lambda out_path, _conf, _get_img: self._CreateEmptyFile(out_path)) + + self._SetUpMocks(mock_popen, mock_utils, mock_instance) + + self._CreateEmptyFile(os.path.join(self._image_dir, "x86", + "system.img")) + self._CreateEmptyFile(os.path.join(self._image_dir, "x86", "system", + "build.prop")) + + mock_avd_spec = mock.Mock(flavor="phone", + boot_timeout_secs=None, + gpu="auto", + autoconnect=False, + local_instance_id=3, + local_instance_dir=None, + local_image_dir=self._image_dir, + local_system_image=os.path.join( + self._image_dir, "x86", "system.img"), + local_tool_dirs=[self._tool_dir]) + + with mock.patch.dict("acloud.create." + "goldfish_local_image_local_instance.os.environ", + dict(), clear=True): + report = self._goldfish._CreateAVD(mock_avd_spec, no_prompts=True) + + self.assertEqual(report.data.get("devices"), + self._EXPECTED_DEVICES_IN_REPORT) + + mock_instance.assert_called_once_with(3, avd_flavor="phone") + + self.assertTrue(os.path.isdir(self._instance_dir)) + + mock_ota_tools.FindOtaTools.assert_called_once() + mock_ota_tools.OtaTools.assert_called_with(self._tool_dir) + + mock_ota_tools_object.BuildSuperImage.assert_called_once() + self.assertEqual(mock_ota_tools_object.BuildSuperImage.call_args[0][1], + os.path.join(self._image_dir, "x86", "misc_info.txt")) + + mock_ota_tools_object.MakeDisabledVbmetaImage.assert_called_once() + + mock_ota_tools_object.MkCombinedImg.assert_called_once() + self.assertEqual( + mock_ota_tools_object.MkCombinedImg.call_args[0][1], + os.path.join(self._image_dir, "x86", "system-qemu-config.txt")) + + mock_utils.SetExecutable.assert_called_with(self._emulator_path) + mock_popen.assert_called_once() + self.assertEqual( + mock_popen.call_args[0][0], + self._GetExpectedEmulatorArgs( + "-gpu", "auto", "-no-window", "-qemu", "-append", + "androidboot.verifiedbootstate=orange")) + self._mock_proc.poll.assert_called() + + # pylint: disable=protected-access + @mock.patch("acloud.create.goldfish_local_image_local_instance.instance." + "LocalGoldfishInstance") + @mock.patch("acloud.create.goldfish_local_image_local_instance.utils") + @mock.patch("acloud.create.goldfish_local_image_local_instance." + "subprocess.Popen") + @mock.patch("acloud.create.goldfish_local_image_local_instance.ota_tools") + def testCreateAVDWithMixedImageDirs(self, mock_ota_tools, mock_popen, + mock_utils, mock_instance): """Test _CreateAVD with mixed images in build environment.""" mock_ota_tools.FindOtaTools.return_value = self._tool_dir mock_ota_tools_object = mock.Mock() @@ -318,15 +387,14 @@ class GoldfishLocalImageLocalInstance(unittest.TestCase): self._CreateEmptyFile(os.path.join(self._image_dir, "system-qemu.img")) + self._CreateEmptyFile(os.path.join(self._image_dir, + "system.img")) self._CreateEmptyFile(os.path.join(self._image_dir, "system", "build.prop")) mock_environ = {"ANDROID_EMULATOR_PREBUILTS": os.path.join(self._tool_dir, "emulator")} - mock_utils.GetBuildEnvironmentVariable.side_effect = ( - lambda key: mock_environ[key]) - mock_avd_spec = mock.Mock(flavor="phone", boot_timeout_secs=None, gpu="auto", @@ -334,7 +402,7 @@ class GoldfishLocalImageLocalInstance(unittest.TestCase): local_instance_id=3, local_instance_dir=None, local_image_dir=self._image_dir, - local_system_image_dir="/unit/test", + local_system_image=self._image_dir, local_tool_dirs=[]) with mock.patch.dict("acloud.create." diff --git a/create/local_image_local_instance.py b/create/local_image_local_instance.py index 96a3c729..f3787cfa 100644 --- a/create/local_image_local_instance.py +++ b/create/local_image_local_instance.py @@ -366,18 +366,15 @@ class LocalImageLocalInstance(base_avd_create.BaseAVDCreate): image_dir = os.path.abspath(avd_spec.local_image_dir) host_bins_path = self._FindCvdHostBinaries(avd_spec.local_tool_dirs) - if not avd_spec.local_system_image_dir: + if not avd_spec.local_system_image: return ArtifactPaths(image_dir, host_bins_path, None, None, None) misc_info_path = self._FindMiscInfo(image_dir) image_dir = self._FindImageDir(image_dir) ota_tools_dir = os.path.abspath( ota_tools.FindOtaTools(avd_spec.local_tool_dirs)) - system_image_path = os.path.abspath( - os.path.join(avd_spec.local_system_image_dir, _SYSTEM_IMAGE_NAME)) - if not os.path.isfile(system_image_path): - raise errors.GetLocalImageError( - "Cannot find %s." % system_image_path) + system_image_path = create_common.FindLocalImage( + avd_spec.local_system_image, _SYSTEM_IMAGE_NAME) return ArtifactPaths(image_dir, host_bins_path, misc_info=misc_info_path, diff --git a/create/local_image_local_instance_test.py b/create/local_image_local_instance_test.py index 7aeb556c..9e6af0e7 100644 --- a/create/local_image_local_instance_test.py +++ b/create/local_image_local_instance_test.py @@ -257,7 +257,7 @@ EOF""" mock_avd_spec = mock.Mock( local_image_dir=image_dir, - local_system_image_dir=None, + local_system_image=None, local_tool_dirs=[cvd_dir]) paths = self.local_image_local_instance.GetImageArtifactsPath( @@ -283,7 +283,7 @@ EOF""" mock_avd_spec = mock.Mock( local_image_dir=image_dir, - local_system_image_dir=system_image_dir, + local_system_image=system_image_dir, local_tool_dirs=[]) with mock.patch.dict("acloud.create.local_image_local_instance." @@ -307,8 +307,7 @@ EOF""" with tempfile.TemporaryDirectory() as temp_dir: image_dir = os.path.join(temp_dir, "image") cvd_dir = os.path.join(temp_dir, "cvd-host_package") - system_image_dir = os.path.join(temp_dir, "system_image") - system_image_path = os.path.join(system_image_dir, "system.img") + system_image_path = os.path.join(temp_dir, "system", "test.img") misc_info_path = os.path.join(image_dir, "META", "misc_info.txt") self._CreateEmptyFile(os.path.join(image_dir, "IMAGES", "boot.img")) @@ -318,7 +317,7 @@ EOF""" mock_avd_spec = mock.Mock( local_image_dir=image_dir, - local_system_image_dir=system_image_dir, + local_system_image=system_image_path, local_tool_dirs=[ota_tools_dir, cvd_dir]) paths = self.local_image_local_instance.GetImageArtifactsPath( |