Merge "Support to get WebRTC server port for remote instance."
diff --git a/.coveragerc b/.coveragerc
index 42077e0..db9bf37 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -16,6 +16,9 @@
     # TODO: Remove the bottom 2 when the files are deleted.
     *public/__main__.py
     *setup.py
+    # gce is not support now.
+    *create/gce_local_image_remote_instance.py
+    *create/gce_remote_image_remote_instance.py
 
 [report]
 # Regexes for lines to exclude from consideration
diff --git a/create/avd_spec.py b/create/avd_spec.py
index 203b136..40766a3 100644
--- a/create/avd_spec.py
+++ b/create/avd_spec.py
@@ -111,6 +111,7 @@
         self._extra_files = None
         self._avd_type = None
         self._flavor = None
+        self._force_sync = None
         self._image_source = None
         self._instance_type = None
         self._launch_args = None
@@ -322,6 +323,7 @@
         self._avd_type = args.avd_type
         self._extra_files = create_common.ParseExtraFilesArgs(args.extra_files)
         self._flavor = args.flavor or constants.FLAVOR_PHONE
+        self._force_sync = args.force_sync
         if args.remote_host:
             self._instance_type = constants.INSTANCE_TYPE_HOST
         else:
@@ -1024,3 +1026,8 @@
     def mkcert(self):
         """Return mkcert."""
         return self._mkcert
+
+    @property
+    def force_sync(self):
+        """Return force_sync."""
+        return self._force_sync
diff --git a/create/create_args.py b/create/create_args.py
index c581a70..ffbe0bb 100644
--- a/create/create_args.py
+++ b/create/create_args.py
@@ -125,6 +125,13 @@
         required=False,
         help="Skip the pre-run check.")
     parser.add_argument(
+        "--force-sync",
+        action="store_true",
+        dest="force_sync",
+        required=False,
+        help="Force to sync image files from Android Build servers even if "
+             "they are already existed for local instance mode.")
+    parser.add_argument(
         "--boot-timeout",
         dest="boot_timeout_secs",
         type=int,
diff --git a/create/local_image_remote_host_test.py b/create/local_image_remote_host_test.py
new file mode 100644
index 0000000..15af6db
--- /dev/null
+++ b/create/local_image_remote_host_test.py
@@ -0,0 +1,65 @@
+# Copyright 2021 - The Android Open Source Project
+#
+# 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.
+"""Tests for LocalImageRemoteHost."""
+
+import unittest
+
+from unittest import mock
+
+from acloud.create import avd_spec
+from acloud.create import create
+from acloud.create import create_common
+from acloud.create import local_image_remote_host
+from acloud.internal import constants
+from acloud.internal.lib import driver_test_lib
+from acloud.internal.lib import utils
+from acloud.public.actions import common_operations
+from acloud.public.actions import remote_instance_cf_device_factory
+
+class LocalImageRemoteHostTest(driver_test_lib.BaseDriverTest):
+    """Test LocalImageRemoteHost method."""
+
+    def setUp(self):
+        """Initialize new LocalImageRemoteHost."""
+        super().setUp()
+        self.local_image_remote_host = local_image_remote_host.LocalImageRemoteHost()
+
+    # pylint: disable=no-member
+    def testRun(self):
+        """Test Create AVD of cuttlefish local image remote host."""
+        args = mock.MagicMock()
+        args.skip_pre_run_check = True
+        spec = mock.MagicMock()
+        spec.avd_type = constants.TYPE_CF
+        spec.instance_type = constants.INSTANCE_TYPE_HOST
+        spec.image_source = constants.IMAGE_SRC_LOCAL
+        spec.connect_vnc = False
+        self.Patch(avd_spec, "AVDSpec", return_value=spec)
+        self.Patch(remote_instance_cf_device_factory,
+                   "RemoteInstanceDeviceFactory")
+        self.Patch(create_common, "GetCvdHostPackage")
+        self.Patch(common_operations, "CreateDevices")
+        create.Run(args)
+        remote_instance_cf_device_factory.RemoteInstanceDeviceFactory.assert_called_once()
+        common_operations.CreateDevices.assert_called_once()
+
+        spec.connect_vnc = True
+        self.Patch(avd_spec, "AVDSpec", return_value=spec)
+        self.Patch(utils, "LaunchVNCFromReport")
+        create.Run(args)
+        utils.LaunchVNCFromReport.assert_called_once()
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/create/remote_image_local_instance.py b/create/remote_image_local_instance.py
index fcb0f5c..8d989a8 100644
--- a/create/remote_image_local_instance.py
+++ b/create/remote_image_local_instance.py
@@ -79,7 +79,7 @@
 
     logger.debug("Extract path: %s", extract_path)
 
-    if os.path.exists(extract_path):
+    if avd_spec.force_sync and os.path.exists(extract_path):
         shutil.rmtree(extract_path)
     if not os.path.exists(extract_path):
         os.makedirs(extract_path)
diff --git a/create/remote_image_local_instance_test.py b/create/remote_image_local_instance_test.py
index 5697f4e..8eda639 100644
--- a/create/remote_image_local_instance_test.py
+++ b/create/remote_image_local_instance_test.py
@@ -16,6 +16,7 @@
 import unittest
 from collections import namedtuple
 import os
+import shutil
 import subprocess
 
 from unittest import mock
@@ -69,18 +70,20 @@
         self.assertEqual(paths.image_dir, "/unit/test")
         self.assertEqual(paths.host_bins, "/unit/test")
 
-    def testDownloadAndProcessImageFiles(self):
+    @mock.patch.object(shutil, "rmtree")
+    def testDownloadAndProcessImageFiles(self, mock_rmtree):
         """Test process remote cuttlefish image."""
         avd_spec = mock.MagicMock()
         avd_spec.cfg = mock.MagicMock()
         avd_spec.cfg.creds_cache_file = "cache.file"
         avd_spec.remote_image = self._fake_remote_image
         avd_spec.image_download_dir = "/tmp"
-        self.Patch(os.path, "exists", return_value=False)
+        avd_spec.force_sync = True
+        self.Patch(os.path, "exists", side_effect=[True, False])
         self.Patch(os, "makedirs")
         self.Patch(subprocess, "check_call")
         remote_image_local_instance.DownloadAndProcessImageFiles(avd_spec)
-
+        self.assertEqual(mock_rmtree.call_count, 1)
         self.assertEqual(self.build_client.GetFetchBuildArgs.call_count, 1)
         self.assertEqual(self.build_client.GetFetchCertArg.call_count, 1)
 
diff --git a/create/remote_image_remote_host_test.py b/create/remote_image_remote_host_test.py
index e69de29..1f665e7 100644
--- a/create/remote_image_remote_host_test.py
+++ b/create/remote_image_remote_host_test.py
@@ -0,0 +1,63 @@
+# Copyright 2021 - The Android Open Source Project
+#
+# 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.
+"""Tests for RemoteImageRemoteHost."""
+
+import unittest
+
+from unittest import mock
+
+from acloud.create import avd_spec
+from acloud.create import create
+from acloud.create import remote_image_remote_host
+from acloud.internal import constants
+from acloud.internal.lib import driver_test_lib
+from acloud.internal.lib import utils
+from acloud.public.actions import common_operations
+from acloud.public.actions import remote_instance_cf_device_factory
+
+class RemoteImageRemoteHostTest(driver_test_lib.BaseDriverTest):
+    """Test RemoteImageRemoteHost method."""
+
+    def setUp(self):
+        """Initialize new RemoteImageRemoteHost."""
+        super().setUp()
+        self.remote_image_remote_host = remote_image_remote_host.RemoteImageRemoteHost()
+
+    # pylint: disable=no-member
+    def testRun(self):
+        """Test Create AVD of cuttlefish remote image remote Host."""
+        args = mock.MagicMock()
+        args.skip_pre_run_check = True
+        spec = mock.MagicMock()
+        spec.avd_type = constants.TYPE_CF
+        spec.instance_type = constants.INSTANCE_TYPE_HOST
+        spec.image_source = constants.IMAGE_SRC_REMOTE
+        spec.connect_vnc = False
+        self.Patch(avd_spec, "AVDSpec", return_value=spec)
+        self.Patch(remote_instance_cf_device_factory,
+                   "RemoteInstanceDeviceFactory")
+        self.Patch(common_operations, "CreateDevices")
+        create.Run(args)
+        remote_instance_cf_device_factory.RemoteInstanceDeviceFactory.assert_called_once()
+        common_operations.CreateDevices.assert_called_once()
+
+        spec.connect_vnc = True
+        self.Patch(avd_spec, "AVDSpec", return_value=spec)
+        self.Patch(utils, "LaunchVNCFromReport")
+        create.Run(args)
+        utils.LaunchVNCFromReport.assert_called_once()
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/internal/lib/utils.py b/internal/lib/utils.py
index c7a4610..cf7c2d9 100755
--- a/internal/lib/utils.py
+++ b/internal/lib/utils.py
@@ -74,7 +74,8 @@
 _PORT_1443 = 1443
 PortMapping = collections.namedtuple("PortMapping", ["local", "target"])
 WEBRTC_PORTS_MAPPING = [PortMapping(15550, 15550),
-                        PortMapping(15551, 15551)]
+                        PortMapping(15551, 15551),
+                        PortMapping(15552, 15552)]
 # Use mkcert to generate a localhost certificates for webrtc
 _MKCERT_LOCAL_CERT_CMD = ("%(local_ca_dir)s/mkcert "
                           "-key-file %(local_ca_dir)s/server.key "
diff --git a/internal/lib/utils_test.py b/internal/lib/utils_test.py
index 9eb624f..9b26ab1 100644
--- a/internal/lib/utils_test.py
+++ b/internal/lib/utils_test.py
@@ -441,6 +441,7 @@
         mock_establish_ssh_tunnel = self.Patch(utils, "EstablishSshTunnel")
         fake_port_mapping = [utils.PortMapping(15550, 15550),
                              utils.PortMapping(15551, 15551),
+                             utils.PortMapping(15552, 15552),
                              utils.PortMapping(12345, 8443)]
 
         utils.EstablishWebRTCSshTunnel(