1# Copyright 2022 - The Android Open Source Project 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15"""Tests for remote_host_cf_device_factory.""" 16 17import time 18import unittest 19from unittest import mock 20 21from acloud import errors 22from acloud.internal import constants 23from acloud.internal.lib import driver_test_lib 24from acloud.public.actions import remote_host_cf_device_factory 25 26 27class RemoteHostDeviceFactoryTest(driver_test_lib.BaseDriverTest): 28 """Test RemoteHostDeviceFactory.""" 29 30 def setUp(self): 31 """Set up the test.""" 32 super().setUp() 33 self.Patch(remote_host_cf_device_factory.auth, "CreateCredentials") 34 mock_client = mock.Mock() 35 self.Patch(remote_host_cf_device_factory.remote_host_client, 36 "RemoteHostClient", return_value=mock_client) 37 mock_client.RecordTime.side_effect = ( 38 lambda _stage, _start_time: time.time()) 39 self._mock_build_api = mock.Mock() 40 self.Patch(remote_host_cf_device_factory.android_build_client, 41 "AndroidBuildClient", return_value=self._mock_build_api) 42 43 @staticmethod 44 def _CreateMockAvdSpec(): 45 """Create a mock AvdSpec with necessary attributes.""" 46 mock_cfg = mock.Mock(spec=[], 47 ssh_private_key_path="/mock/id_rsa", 48 extra_args_ssh_tunnel="extra args", 49 fetch_cvd_version="123456", 50 creds_cache_file="credential", 51 service_account_json_private_key_path="/mock/key") 52 return mock.Mock(spec=[], 53 remote_image={ 54 "branch": "aosp-android12-gsi", 55 "build_id": "100000", 56 "build_target": "aosp_cf_x86_64_phone-userdebug"}, 57 system_build_info={}, 58 kernel_build_info={}, 59 boot_build_info={}, 60 bootloader_build_info={}, 61 android_efi_loader_build_info={}, 62 ota_build_info={}, 63 host_package_build_info={}, 64 remote_host="192.0.2.100", 65 remote_image_dir=None, 66 host_user="user1", 67 host_ssh_private_key_path=None, 68 report_internal_ip=False, 69 image_source=constants.IMAGE_SRC_REMOTE, 70 local_image_dir=None, 71 ins_timeout_secs=200, 72 boot_timeout_secs=100, 73 gpu="auto", 74 no_pull_log=False, 75 remote_fetch=False, 76 fetch_cvd_wrapper=None, 77 base_instance_num=None, 78 num_avds_per_instance=None, 79 fetch_cvd_version="123456", 80 openwrt=True, 81 cfg=mock_cfg) 82 83 @mock.patch("acloud.public.actions.remote_host_cf_device_factory.ssh") 84 @mock.patch("acloud.public.actions.remote_host_cf_device_factory." 85 "cvd_utils") 86 @mock.patch("acloud.public.actions.remote_host_cf_device_factory.pull") 87 def testCreateInstanceWithImageDir(self, mock_pull, mock_cvd_utils, 88 mock_ssh): 89 """Test CreateInstance with local image directory.""" 90 mock_avd_spec = self._CreateMockAvdSpec() 91 mock_avd_spec.image_source = constants.IMAGE_SRC_LOCAL 92 mock_avd_spec.local_image_dir = "/mock/target_files" 93 mock_avd_spec.base_instance_num = 2 94 mock_avd_spec.num_avds_per_instance = 3 95 mock_ssh_obj = mock.Mock() 96 mock_ssh.Ssh.return_value = mock_ssh_obj 97 factory = remote_host_cf_device_factory.RemoteHostDeviceFactory( 98 mock_avd_spec, cvd_host_package_artifact="/mock/cvd.tar.gz") 99 100 log = {"path": "/log.txt"} 101 mock_cvd_utils.GetRemoteHostBaseDir.return_value = "acloud_cf_2" 102 mock_cvd_utils.FormatRemoteHostInstanceName.return_value = "inst" 103 mock_cvd_utils.AreTargetFilesRequired.return_value = True 104 mock_cvd_utils.UploadExtraImages.return_value = [("-extra", "image")] 105 mock_cvd_utils.ExecuteRemoteLaunchCvd.return_value = "failure" 106 mock_cvd_utils.FindRemoteLogs.return_value = [log] 107 108 self.assertEqual("inst", factory.CreateInstance()) 109 # InitRemotehost 110 mock_cvd_utils.CleanUpRemoteCvd.assert_called_once_with( 111 mock_ssh_obj, "acloud_cf_2", raise_error=False) 112 mock_cvd_utils.GetRemoteHostBaseDir.assert_called_with(2) 113 # ProcessRemoteHostArtifacts 114 mock_ssh_obj.Run.assert_called_with("mkdir -p acloud_cf_2") 115 self._mock_build_api.GetFetchBuildArgs.assert_not_called() 116 mock_cvd_utils.UploadArtifacts.assert_called_with( 117 mock_ssh_obj, "acloud_cf_2", "/mock/target_files", 118 "/mock/cvd.tar.gz") 119 mock_cvd_utils.UploadExtraImages.assert_called_with( 120 mock_ssh_obj, "acloud_cf_2", mock_avd_spec, "/mock/target_files") 121 mock_cvd_utils.GetConfigFromRemoteAndroidInfo.assert_called_with( 122 mock_ssh_obj, "acloud_cf_2") 123 # LaunchCvd 124 mock_cvd_utils.GetRemoteLaunchCvdCmd.assert_called_with( 125 "acloud_cf_2", mock_avd_spec, mock.ANY, ["-extra", "image"]) 126 mock_cvd_utils.ExecuteRemoteLaunchCvd.assert_called() 127 # FindLogFiles 128 mock_cvd_utils.FindRemoteLogs.assert_called_with( 129 mock_ssh_obj, "acloud_cf_2", 2, 3) 130 mock_pull.GetAllLogFilePaths.assert_called_once() 131 mock_pull.PullLogs.assert_called_once() 132 factory.GetAdbPorts() 133 mock_cvd_utils.GetAdbPorts.assert_called_with(2, 3) 134 factory.GetVncPorts() 135 mock_cvd_utils.GetVncPorts.assert_called_with(2, 3) 136 self.assertEqual({"inst": "failure"}, factory.GetFailures()) 137 self.assertDictEqual({"inst": [log]}, factory.GetLogs()) 138 139 @mock.patch("acloud.public.actions.remote_host_cf_device_factory.ssh") 140 @mock.patch("acloud.public.actions.remote_host_cf_device_factory." 141 "cvd_utils") 142 @mock.patch("acloud.public.actions.remote_host_cf_device_factory.pull") 143 def testCreateInstanceWithImageZip(self, mock_pull, mock_cvd_utils, 144 mock_ssh): 145 """Test CreateInstance with local image zip.""" 146 mock_avd_spec = self._CreateMockAvdSpec() 147 mock_avd_spec.image_source = constants.IMAGE_SRC_LOCAL 148 mock_ssh_obj = mock.Mock() 149 mock_ssh.Ssh.return_value = mock_ssh_obj 150 factory = remote_host_cf_device_factory.RemoteHostDeviceFactory( 151 mock_avd_spec, local_image_artifact="/mock/img.zip", 152 cvd_host_package_artifact="/mock/cvd.tar.gz") 153 154 mock_cvd_utils.GetRemoteHostBaseDir.return_value = "acloud_cf_1" 155 mock_cvd_utils.FormatRemoteHostInstanceName.return_value = "inst" 156 mock_cvd_utils.AreTargetFilesRequired.return_value = False 157 mock_cvd_utils.ExecuteRemoteLaunchCvd.return_value = "" 158 mock_cvd_utils.FindRemoteLogs.return_value = [] 159 160 self.assertEqual("inst", factory.CreateInstance()) 161 # InitRemotehost 162 mock_cvd_utils.GetRemoteHostBaseDir.assert_called_with(None) 163 mock_cvd_utils.CleanUpRemoteCvd.assert_called_once() 164 # ProcessRemoteHostArtifacts 165 mock_ssh_obj.Run.assert_called_with("mkdir -p acloud_cf_1") 166 self._mock_build_api.GetFetchBuildArgs.assert_not_called() 167 mock_cvd_utils.UploadArtifacts.assert_called_with( 168 mock_ssh_obj, "acloud_cf_1", "/mock/img.zip", "/mock/cvd.tar.gz") 169 mock_cvd_utils.UploadExtraImages.assert_called_with( 170 mock_ssh_obj, "acloud_cf_1", mock_avd_spec, None) 171 # LaunchCvd 172 mock_cvd_utils.ExecuteRemoteLaunchCvd.assert_called() 173 # FindLogFiles 174 mock_cvd_utils.FindRemoteLogs.assert_called_with( 175 mock_ssh_obj, "acloud_cf_1", None, None) 176 mock_pull.GetAllLogFilePaths.assert_not_called() 177 mock_pull.PullLogs.assert_not_called() 178 factory.GetAdbPorts() 179 mock_cvd_utils.GetAdbPorts.assert_called_with(None, None) 180 factory.GetVncPorts() 181 mock_cvd_utils.GetVncPorts.assert_called_with(None, None) 182 self.assertFalse(factory.GetFailures()) 183 self.assertDictEqual({"inst": []}, factory.GetLogs()) 184 185 # pylint: disable=invalid-name 186 @mock.patch("acloud.public.actions.remote_host_cf_device_factory.ssh") 187 @mock.patch("acloud.public.actions.remote_host_cf_device_factory." 188 "cvd_utils") 189 @mock.patch("acloud.public.actions.remote_host_cf_device_factory.pull") 190 def testCreateInstanceWithTargetFilesZip(self, mock_pull, mock_cvd_utils, 191 mock_ssh): 192 """Test CreateInstance with local target_files zip.""" 193 mock_avd_spec = self._CreateMockAvdSpec() 194 mock_avd_spec.image_source = constants.IMAGE_SRC_LOCAL 195 mock_ssh_obj = mock.Mock() 196 mock_ssh.Ssh.return_value = mock_ssh_obj 197 factory = remote_host_cf_device_factory.RemoteHostDeviceFactory( 198 mock_avd_spec, local_image_artifact="/mock/target_files.zip", 199 cvd_host_package_artifact="/mock/cvd.tar.gz") 200 201 mock_cvd_utils.GetRemoteHostBaseDir.return_value = "acloud_cf_1" 202 mock_cvd_utils.FormatRemoteHostInstanceName.return_value = "inst" 203 mock_cvd_utils.AreTargetFilesRequired.return_value = True 204 mock_cvd_utils.ExecuteRemoteLaunchCvd.return_value = "" 205 mock_cvd_utils.FindRemoteLogs.return_value = [] 206 207 self.assertEqual("inst", factory.CreateInstance()) 208 # InitRemotehost 209 mock_cvd_utils.GetRemoteHostBaseDir.assert_called_with(None) 210 mock_cvd_utils.CleanUpRemoteCvd.assert_called_once() 211 # ProcessRemoteHostArtifacts 212 mock_ssh_obj.Run.assert_called_with("mkdir -p acloud_cf_1") 213 mock_cvd_utils.ExtractTargetFilesZip.assert_called_with( 214 "/mock/target_files.zip", mock.ANY) 215 self._mock_build_api.GetFetchBuildArgs.assert_not_called() 216 mock_cvd_utils.UploadExtraImages.assert_called_with( 217 mock_ssh_obj, "acloud_cf_1", mock_avd_spec, mock.ANY) 218 mock_cvd_utils.UploadArtifacts.assert_called_with( 219 mock_ssh_obj, "acloud_cf_1", mock.ANY, "/mock/cvd.tar.gz") 220 self.assertIn("acloud_remote_host", # temp dir prefix 221 mock_cvd_utils.UploadArtifacts.call_args[0][2]) 222 # LaunchCvd 223 mock_cvd_utils.ExecuteRemoteLaunchCvd.assert_called() 224 # FindLogFiles 225 mock_cvd_utils.FindRemoteLogs.assert_called_with( 226 mock_ssh_obj, "acloud_cf_1", None, None) 227 mock_pull.GetAllLogFilePaths.assert_not_called() 228 mock_pull.PullLogs.assert_not_called() 229 factory.GetAdbPorts() 230 mock_cvd_utils.GetAdbPorts.assert_called_with(None, None) 231 factory.GetVncPorts() 232 mock_cvd_utils.GetVncPorts.assert_called_with(None, None) 233 self.assertFalse(factory.GetFailures()) 234 self.assertDictEqual({"inst": []}, factory.GetLogs()) 235 236 @mock.patch("acloud.public.actions.remote_host_cf_device_factory.ssh") 237 @mock.patch("acloud.public.actions.remote_host_cf_device_factory." 238 "cvd_utils") 239 @mock.patch("acloud.public.actions.remote_host_cf_device_factory." 240 "subprocess.check_call") 241 @mock.patch("acloud.public.actions.remote_host_cf_device_factory.glob") 242 @mock.patch("acloud.public.actions.remote_host_cf_device_factory.pull") 243 def testCreateInstanceWithRemoteImages(self, mock_pull, mock_glob, 244 mock_check_call, mock_cvd_utils, 245 mock_ssh): 246 """Test CreateInstance with remote images.""" 247 mock_avd_spec = self._CreateMockAvdSpec() 248 mock_avd_spec.image_source = constants.IMAGE_SRC_REMOTE 249 mock_ssh_obj = mock.Mock() 250 mock_ssh.Ssh.return_value = mock_ssh_obj 251 mock_ssh_obj.GetBaseCmd.return_value = "/mock/ssh" 252 mock_glob.glob.return_value = ["/mock/super.img"] 253 factory = remote_host_cf_device_factory.RemoteHostDeviceFactory( 254 mock_avd_spec) 255 256 mock_cvd_utils.GetRemoteHostBaseDir.return_value = "acloud_cf_1" 257 mock_cvd_utils.FormatRemoteHostInstanceName.return_value = "inst" 258 mock_cvd_utils.AreTargetFilesRequired.return_value = True 259 mock_cvd_utils.GetMixBuildTargetFilename.return_value = "mock.zip" 260 mock_cvd_utils.ExecuteRemoteLaunchCvd.return_value = "" 261 mock_cvd_utils.FindRemoteLogs.return_value = [] 262 263 self._mock_build_api.GetFetchBuildArgs.return_value = ["-test"] 264 265 self.assertEqual("inst", factory.CreateInstance()) 266 # InitRemoteHost 267 mock_cvd_utils.CleanUpRemoteCvd.assert_called_once() 268 # ProcessRemoteHostArtifacts 269 mock_ssh_obj.Run.assert_called_with("mkdir -p acloud_cf_1") 270 self._mock_build_api.DownloadArtifact.assert_called_once_with( 271 "aosp_cf_x86_64_phone-userdebug", "100000", "mock.zip", mock.ANY) 272 mock_cvd_utils.ExtractTargetFilesZip.assert_called_once() 273 self._mock_build_api.DownloadFetchcvd.assert_called_once() 274 mock_check_call.assert_called_once() 275 mock_ssh.ShellCmdWithRetry.assert_called_once() 276 self.assertRegex(mock_ssh.ShellCmdWithRetry.call_args[0][0], 277 r"^tar -cf - --lzop -S -C \S+ super\.img \| " 278 r"/mock/ssh -- tar -xf - --lzop -S -C acloud_cf_1$") 279 # LaunchCvd 280 mock_cvd_utils.ExecuteRemoteLaunchCvd.assert_called() 281 # FindLogFiles 282 mock_pull.GetAllLogFilePaths.assert_not_called() 283 mock_pull.PullLogs.assert_not_called() 284 self.assertFalse(factory.GetFailures()) 285 self.assertDictEqual({"inst": []}, factory.GetLogs()) 286 287 @mock.patch("acloud.public.actions.remote_host_cf_device_factory.ssh") 288 @mock.patch("acloud.public.actions.remote_host_cf_device_factory." 289 "cvd_utils") 290 @mock.patch("acloud.public.actions.remote_host_cf_device_factory.glob") 291 @mock.patch("acloud.public.actions.remote_host_cf_device_factory.shutil") 292 @mock.patch("acloud.public.actions.remote_host_cf_device_factory.pull") 293 def testCreateInstanceWithRemoteFetch(self, mock_pull, mock_shutil, 294 mock_glob, mock_cvd_utils, mock_ssh): 295 """Test CreateInstance with remotely fetched images.""" 296 mock_avd_spec = self._CreateMockAvdSpec() 297 mock_avd_spec.remote_fetch = True 298 mock_ssh_obj = mock.Mock() 299 mock_ssh.Ssh.return_value = mock_ssh_obj 300 mock_ssh_obj.GetBaseCmd.return_value = "/mock/ssh" 301 mock_glob.glob.return_value = ["/mock/fetch_cvd"] 302 factory = remote_host_cf_device_factory.RemoteHostDeviceFactory( 303 mock_avd_spec) 304 305 log = {"path": "/log.txt"} 306 mock_cvd_utils.GetRemoteHostBaseDir.return_value = "acloud_cf_1" 307 mock_cvd_utils.FormatRemoteHostInstanceName.return_value = "inst" 308 mock_cvd_utils.AreTargetFilesRequired.return_value = False 309 mock_cvd_utils.ExecuteRemoteLaunchCvd.return_value = "" 310 mock_cvd_utils.FindRemoteLogs.return_value = [] 311 mock_cvd_utils.GetRemoteFetcherConfigJson.return_value = log 312 313 self._mock_build_api.GetFetchBuildArgs.return_value = ["-test"] 314 315 self.assertEqual("inst", factory.CreateInstance()) 316 mock_cvd_utils.CleanUpRemoteCvd.assert_called_once() 317 mock_ssh_obj.Run.assert_called_with("mkdir -p acloud_cf_1") 318 self._mock_build_api.DownloadFetchcvd.assert_called_once() 319 mock_shutil.copyfile.assert_called_with("/mock/key", mock.ANY) 320 self.assertRegex(mock_ssh.ShellCmdWithRetry.call_args_list[0][0][0], 321 r"^tar -cf - --lzop -S -C \S+ fetch_cvd \| " 322 r"/mock/ssh -- tar -xf - --lzop -S -C acloud_cf_1$") 323 self.assertRegex(mock_ssh.ShellCmdWithRetry.call_args_list[1][0][0], 324 r"^/mock/ssh -- acloud_cf_1/fetch_cvd " 325 r"-directory=acloud_cf_1 " 326 r"-credential_source=acloud_cf_1/credential_key.json " 327 r"-test$") 328 mock_cvd_utils.ExecuteRemoteLaunchCvd.assert_called() 329 mock_pull.GetAllLogFilePaths.assert_not_called() 330 mock_pull.PullLogs.assert_not_called() 331 self.assertFalse(factory.GetFailures()) 332 self.assertDictEqual({"inst": [log]}, factory.GetLogs()) 333 334 @mock.patch("acloud.public.actions.remote_host_cf_device_factory.ssh") 335 @mock.patch("acloud.public.actions.remote_host_cf_device_factory." 336 "cvd_utils") 337 @mock.patch("acloud.public.actions.remote_host_cf_device_factory.glob") 338 @mock.patch("acloud.public.actions.remote_host_cf_device_factory.shutil") 339 @mock.patch("acloud.public.actions.remote_host_cf_device_factory.pull") 340 def testCreateInstanceWithFetchCvdWrapper(self, mock_pull, mock_shutil, 341 mock_glob, mock_cvd_utils, 342 mock_ssh): 343 """Test CreateInstance with remotely fetched images.""" 344 mock_avd_spec = self._CreateMockAvdSpec() 345 mock_avd_spec.remote_fetch = True 346 mock_avd_spec.fetch_cvd_wrapper = ( 347 r"GOOGLE_APPLICATION_CREDENTIALS=/fake_key.json," 348 r"CACHE_CONFIG=/home/shared/cache.properties," 349 r"java,-jar,/home/shared/FetchCvdWrapper.jar" 350 ) 351 mock_ssh_obj = mock.Mock() 352 mock_ssh.Ssh.return_value = mock_ssh_obj 353 mock_ssh_obj.GetBaseCmd.return_value = "/mock/ssh" 354 mock_glob.glob.return_value = ["/mock/fetch_cvd"] 355 factory = remote_host_cf_device_factory.RemoteHostDeviceFactory( 356 mock_avd_spec) 357 358 log = {"path": "/log.txt"} 359 mock_cvd_utils.GetRemoteHostBaseDir.return_value = "acloud_cf_1" 360 mock_cvd_utils.FormatRemoteHostInstanceName.return_value = "inst" 361 mock_cvd_utils.AreTargetFilesRequired.return_value = False 362 mock_cvd_utils.ExecuteRemoteLaunchCvd.return_value = "" 363 mock_cvd_utils.FindRemoteLogs.return_value = [] 364 mock_cvd_utils.GetRemoteFetcherConfigJson.return_value = log 365 366 self._mock_build_api.GetFetchBuildArgs.return_value = ["-test"] 367 368 self.assertEqual("inst", factory.CreateInstance()) 369 mock_cvd_utils.CleanUpRemoteCvd.assert_called_once() 370 mock_ssh_obj.Run.assert_called_with("mkdir -p acloud_cf_1") 371 self._mock_build_api.DownloadFetchcvd.assert_called_once() 372 mock_shutil.copyfile.assert_called_with("/mock/key", mock.ANY) 373 self.assertRegex(mock_ssh.ShellCmdWithRetry.call_args_list[0][0][0], 374 r"^tar -cf - --lzop -S -C \S+ fetch_cvd \| " 375 r"/mock/ssh -- tar -xf - --lzop -S -C acloud_cf_1$") 376 self.assertRegex(mock_ssh.ShellCmdWithRetry.call_args_list[1][0][0], 377 r"^/mock/ssh -- " 378 r"GOOGLE_APPLICATION_CREDENTIALS=/fake_key.json " 379 r"CACHE_CONFIG=/home/shared/cache.properties " 380 r"java -jar /home/shared/FetchCvdWrapper.jar " 381 r"-directory=acloud_cf_1 " 382 r"-fetch_cvd_path=acloud_cf_1/fetch_cvd " 383 r"-credential_source=acloud_cf_1/credential_key.json " 384 r"-test$") 385 mock_cvd_utils.ExecuteRemoteLaunchCvd.assert_called() 386 mock_pull.GetAllLogFilePaths.assert_not_called() 387 mock_pull.PullLogs.assert_not_called() 388 self.assertFalse(factory.GetFailures()) 389 self.assertDictEqual({"inst": [log]}, factory.GetLogs()) 390 391 @mock.patch("acloud.public.actions.remote_host_cf_device_factory.ssh") 392 @mock.patch("acloud.public.actions.remote_host_cf_device_factory." 393 "cvd_utils") 394 @mock.patch("acloud.public.actions.remote_host_cf_device_factory." 395 "subprocess.check_call") 396 @mock.patch("acloud.public.actions.remote_host_cf_device_factory.glob") 397 @mock.patch("acloud.public.actions.remote_host_cf_device_factory.pull") 398 def testCreateInstanceWithRemoteImageDir(self, _mock_pull, mock_glob, 399 _mock_check_call, mock_cvd_utils, 400 mock_ssh): 401 """Test CreateInstance with AvdSpec.remote_image_dir.""" 402 mock_avd_spec = self._CreateMockAvdSpec() 403 mock_avd_spec.remote_image_dir = "mock_img_dir" 404 405 mock_ssh_obj = mock.Mock() 406 mock_ssh.Ssh.return_value = mock_ssh_obj 407 # Test initializing the remote image dir. 408 mock_glob.glob.return_value = ["/mock/super.img"] 409 factory = remote_host_cf_device_factory.RemoteHostDeviceFactory( 410 mock_avd_spec) 411 412 mock_cvd_utils.GetRemoteHostBaseDir.return_value = "acloud_cf_1" 413 mock_cvd_utils.FormatRemoteHostInstanceName.return_value = "inst" 414 mock_cvd_utils.LoadRemoteImageArgs.return_value = None 415 mock_cvd_utils.AreTargetFilesRequired.return_value = False 416 mock_cvd_utils.UploadExtraImages.return_value = [ 417 ("arg", "mock_img_dir/1")] 418 mock_cvd_utils.ExecuteRemoteLaunchCvd.return_value = "" 419 mock_cvd_utils.FindRemoteLogs.return_value = [] 420 421 self._mock_build_api.GetFetchBuildArgs.return_value = ["-test"] 422 423 self.assertEqual("inst", factory.CreateInstance()) 424 mock_cvd_utils.PrepareRemoteImageDirLink.assert_called_once_with( 425 mock_ssh_obj, "acloud_cf_1", "mock_img_dir") 426 mock_cvd_utils.LoadRemoteImageArgs.assert_called_once_with( 427 mock_ssh_obj, "mock_img_dir/acloud_image_timestamp.txt", 428 "mock_img_dir/acloud_image_args.txt", mock.ANY) 429 mock_cvd_utils.SaveRemoteImageArgs.assert_called_once_with( 430 mock_ssh_obj, "mock_img_dir/acloud_image_args.txt", 431 [("arg", "mock_img_dir/1")]) 432 mock_ssh_obj.Run.assert_called_with("cp -frT mock_img_dir acloud_cf_1") 433 self._mock_build_api.DownloadFetchcvd.assert_called_once() 434 self.assertEqual(["arg", "acloud_cf_1/1"], 435 mock_cvd_utils.GetRemoteLaunchCvdCmd.call_args[0][3]) 436 437 # Test reusing the remote image dir. 438 mock_cvd_utils.LoadRemoteImageArgs.return_value = [ 439 ["arg", "mock_img_dir/2"]] 440 mock_cvd_utils.SaveRemoteImageArgs.reset_mock() 441 mock_ssh_obj.reset_mock() 442 self._mock_build_api.DownloadFetchcvd.reset_mock() 443 444 self.assertEqual("inst", factory.CreateInstance()) 445 mock_cvd_utils.SaveRemoteImageArgs.assert_not_called() 446 mock_ssh_obj.Run.assert_called_with("cp -frT mock_img_dir acloud_cf_1") 447 self._mock_build_api.DownloadFetchcvd.assert_not_called() 448 self.assertEqual(["arg", "acloud_cf_1/2"], 449 mock_cvd_utils.GetRemoteLaunchCvdCmd.call_args[0][3]) 450 451 @mock.patch("acloud.public.actions.remote_host_cf_device_factory.ssh") 452 @mock.patch("acloud.public.actions.remote_host_cf_device_factory." 453 "cvd_utils") 454 @mock.patch("acloud.public.actions.remote_host_cf_device_factory." 455 "subprocess.check_call") 456 def testCreateInstanceWithCreateError(self, _mock_check_call, 457 mock_cvd_utils, mock_ssh): 458 """Test CreateInstance with CreateError.""" 459 mock_avd_spec = self._CreateMockAvdSpec() 460 mock_avd_spec.remote_image_dir = "mock_img_dir" 461 462 mock_ssh_obj = mock.Mock() 463 mock_ssh.Ssh.return_value = mock_ssh_obj 464 465 mock_cvd_utils.GetRemoteHostBaseDir.return_value = "acloud_cf_1" 466 mock_cvd_utils.FormatRemoteHostInstanceName.return_value = "inst" 467 mock_cvd_utils.LoadRemoteImageArgs.side_effect = errors.CreateError( 468 "failure") 469 factory = remote_host_cf_device_factory.RemoteHostDeviceFactory( 470 mock_avd_spec) 471 472 self.assertEqual("inst", factory.CreateInstance()) 473 self.assertEqual({"inst": "failure"}, factory.GetFailures()) 474 mock_cvd_utils.ExecuteRemoteLaunchCvd.assert_not_called() 475 476 477if __name__ == "__main__": 478 unittest.main() 479