Creating remote instance with compressed local image.

- Previously when running "acloud create --local-image" but
  there is no image in $ANDROID_PRODUCT_OUT, an instruction
  "m dist" will be given but the build time is rather lengthy.
  This CL instruct users to "make" which shrinks the build time.
- Assist users to create a remote instance from a local built image.
- Refactor the logic of verifying gce local images into avd_spec.

Bug: 119424219
Bug: 126005308

Test: atest acloud_test &&
      m clean && m acloud && acloud-dev create --local-image
      # will see "make" instruction.
      make && acloud-dev create --local-image
      # will run successfully.

Change-Id: I98884879b7aeb480053c960fb9151d0044aeee91
diff --git a/create/avd_spec_test.py b/create/avd_spec_test.py
index 5d5681b..48b8038 100644
--- a/create/avd_spec_test.py
+++ b/create/avd_spec_test.py
@@ -13,21 +13,27 @@
 # limitations under the License.
 """Tests for avd_spec."""
 
+import glob
+import os
 import unittest
 import mock
 
+
 from acloud import errors
 from acloud.create import avd_spec
 from acloud.create import create_common
 from acloud.internal import constants
+from acloud.internal.lib import driver_test_lib
+from acloud.internal.lib import utils
 
 
 # pylint: disable=invalid-name,protected-access
-class AvdSpecTest(unittest.TestCase):
+class AvdSpecTest(driver_test_lib.BaseDriverTest):
     """Test avd_spec methods."""
 
     def setUp(self):
         """Initialize new avd_spec.AVDSpec."""
+        super(AvdSpecTest, self).setUp()
         self.args = mock.MagicMock()
         self.args.local_image = ""
         self.args.config_file = ""
@@ -35,36 +41,69 @@
         self.AvdSpec = avd_spec.AVDSpec(self.args)
 
     # pylint: disable=protected-access
-    @mock.patch.object(create_common, "VerifyLocalImageArtifactsExist")
-    def testProcessLocalImageArgs(self, mock_image):
+    def testProcessLocalImageArgs(self):
         """Test process args.local_image."""
-        # Specified local_image with an arg
-        mock_image.return_value = "cf_x86_phone-img-eng.user.zip"
-        self.args.local_image = "test_path"
+        self.Patch(create_common, "ZipCFImageFiles",
+                   return_value="/path/cf_x86_phone-img-eng.user.zip")
+        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"
+
+        # 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
         self.AvdSpec._ProcessLocalImageArgs(self.args)
-        self.assertEqual(self.AvdSpec._local_image_dir, "test_path")
+        self.assertEqual(self.AvdSpec._local_image_artifact,
+                         expected_image_artifact)
 
-        # Specified local_image with no arg
+        # Specified --local-image to a dir contains images
+        self.Patch(utils, "GetBuildEnvironmentVariable",
+                   return_value="test_environ")
+        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
+        self.AvdSpec._ProcessLocalImageArgs(self.args)
+        self.assertEqual(self.AvdSpec._local_image_dir, expected_image_dir)
+
+        # Specified local_image without arg
         self.args.local_image = None
-        with mock.patch.dict("os.environ", {"ANDROID_PRODUCT_OUT": "test_environ"}):
-            self.AvdSpec._ProcessLocalImageArgs(self.args)
-            self.assertEqual(self.AvdSpec._local_image_dir, "test_environ")
+        self.Patch(utils, "GetBuildEnvironmentVariable",
+                   return_value="test_environ")
+        self.AvdSpec._ProcessLocalImageArgs(self.args)
+        self.assertEqual(self.AvdSpec._local_image_dir, "test_environ")
+        self.assertEqual(self.AvdSpec.local_image_artifact, expected_image_artifact)
 
-    @mock.patch.object(create_common, "VerifyLocalImageArtifactsExist")
-    def testProcessImageArgs(self, mock_image):
+    def testProcessImageArgs(self):
         """Test process image source."""
+        self.Patch(glob, "glob", return_value=["fake.img"])
         # No specified local_image, image source is from remote
         self.args.local_image = ""
         self.AvdSpec._ProcessImageArgs(self.args)
         self.assertEqual(self.AvdSpec._image_source, constants.IMAGE_SRC_REMOTE)
         self.assertEqual(self.AvdSpec._local_image_dir, None)
 
-        # Specified local_image with an arg, image source is from local
-        mock_image.return_value = "cf_x86_phone-img-eng.user.zip"
-        self.args.local_image = "test_path"
+        # Specified local_image with an arg for cf type
+        self.Patch(os.path, "isfile", return_value=True)
+        self.args.local_image = "/test_path/cf_x86_phone-img-eng.user.zip"
+        self.AvdSpec._avd_type = constants.TYPE_CF
+        self.AvdSpec._instance_type = constants.INSTANCE_TYPE_REMOTE
         self.AvdSpec._ProcessImageArgs(self.args)
         self.assertEqual(self.AvdSpec._image_source, constants.IMAGE_SRC_LOCAL)
-        self.assertEqual(self.AvdSpec._local_image_dir, "test_path")
+        self.assertEqual(self.AvdSpec._local_image_artifact,
+                         "/test_path/cf_x86_phone-img-eng.user.zip")
+
+        # Specified local_image with an arg for gce type
+        self.Patch(os.path, "isfile", return_value=False)
+        self.Patch(os.path, "exists", return_value=True)
+        self.args.local_image = "/test_path_to_dir/"
+        self.AvdSpec._avd_type = constants.TYPE_GCE
+        self.AvdSpec._ProcessImageArgs(self.args)
+        self.assertEqual(self.AvdSpec._image_source, constants.IMAGE_SRC_LOCAL)
+        self.assertEqual(self.AvdSpec._local_image_artifact,
+                         "/test_path_to_dir/avd-system.tar.gz")
 
     @mock.patch.object(avd_spec.AVDSpec, "_GetGitRemote")
     @mock.patch("subprocess.check_output")
@@ -144,23 +183,20 @@
         result_dict = self.AvdSpec._ParseHWPropertyStr(args_str)
         self.assertTrue(expected_dict == result_dict)
 
-    def testGetFlavorFromLocalImage(self):
+    def testGetFlavorFromBuildTargetString(self):
         """Test _GetFlavorFromLocalImage."""
         img_path = "/fack_path/cf_x86_tv-img-eng.user.zip"
-        self.assertEqual(self.AvdSpec._GetFlavorFromLocalImage(img_path), "tv")
+        self.assertEqual(self.AvdSpec._GetFlavorFromString(img_path),
+                         "tv")
+
+        build_target_str = "aosp_cf_x86_auto"
+        self.assertEqual(self.AvdSpec._GetFlavorFromString(
+            build_target_str), "auto")
 
         # Flavor is not supported.
         img_path = "/fack_path/cf_x86_error-img-eng.user.zip"
-        self.assertEqual(self.AvdSpec._GetFlavorFromLocalImage(img_path), None)
-
-    def testGetFlavorFromTarget(self):
-        """Test _GetFlavorFromTarget."""
-        target_name = "cf_x86_auto-userdebug"
-        self.assertEqual(self.AvdSpec._GetFlavorFromTarget(target_name), "auto")
-
-        # Target is not supported.
-        target_name = "cf_x86_error-userdebug"
-        self.assertEqual(self.AvdSpec._GetFlavorFromTarget(target_name), None)
+        self.assertEqual(self.AvdSpec._GetFlavorFromString(img_path),
+                         None)
 
     # pylint: disable=protected-access
     def testProcessRemoteBuildArgs(self):
@@ -212,6 +248,39 @@
         expected_result = " Manifest branch:"
         self.assertEqual(avd_spec.EscapeAnsi(test_string), expected_result)
 
+    def testGetGceLocalImagePath(self):
+        """Test get gce local image path."""
+        self.Patch(os.path, "isfile", return_value=True)
+        # Verify when specify --local-image ~/XXX.tar.gz.
+        fake_image_path = "~/gce_local_image_dir/gce_image.tar.gz"
+        self.Patch(os.path, "exists", return_value=True)
+        self.assertEqual(self.AvdSpec._GetGceLocalImagePath(fake_image_path),
+                         "~/gce_local_image_dir/gce_image.tar.gz")
+
+        # Verify when specify --local-image ~/XXX.img.
+        fake_image_path = "~/gce_local_image_dir/gce_image.img"
+        self.assertEqual(self.AvdSpec._GetGceLocalImagePath(fake_image_path),
+                         "~/gce_local_image_dir/gce_image.img")
+
+        # Verify if exist argument --local-image as a directory.
+        self.Patch(os.path, "isfile", return_value=False)
+        self.Patch(os.path, "exists", return_value=True)
+        fake_image_path = "~/gce_local_image_dir/"
+        # Default to find */avd-system.tar.gz if exist then return the path.
+        self.assertEqual(self.AvdSpec._GetGceLocalImagePath(fake_image_path),
+                         "~/gce_local_image_dir/avd-system.tar.gz")
+
+        # Otherwise choose raw file */android_system_disk_syslinux.img if
+        # exist then return the path.
+        self.Patch(os.path, "exists", side_effect=[False, True])
+        self.assertEqual(self.AvdSpec._GetGceLocalImagePath(fake_image_path),
+                         "~/gce_local_image_dir/android_system_disk_syslinux.img")
+
+        # Both _GCE_LOCAL_IMAGE_CANDIDATE could not be found then raise error.
+        self.Patch(os.path, "exists", side_effect=[False, False])
+        self.assertRaises(errors.BootImgDoesNotExist,
+                          self.AvdSpec._GetGceLocalImagePath, fake_image_path)
+
 
 if __name__ == "__main__":
     unittest.main()