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 creds_cache_file="credential", 50 service_account_json_private_key_path="/mock/key") 51 return mock.Mock(spec=[], 52 remote_image={ 53 "branch": "aosp-android12-gsi", 54 "build_id": "100000", 55 "build_target": "aosp_cf_x86_64_phone-trunk_staging-userdebug"}, 56 system_build_info={}, 57 kernel_build_info={}, 58 boot_build_info={}, 59 bootloader_build_info={}, 60 android_efi_loader_build_info={}, 61 ota_build_info={}, 62 host_package_build_info={}, 63 remote_host="192.0.2.100", 64 remote_image_dir=None, 65 host_user="user1", 66 host_ssh_private_key_path=None, 67 report_internal_ip=False, 68 image_source=constants.IMAGE_SRC_REMOTE, 69 local_image_dir=None, 70 ins_timeout_secs=200, 71 boot_timeout_secs=100, 72 gpu="auto", 73 no_pull_log=False, 74 remote_fetch=False, 75 fetch_cvd_wrapper=None, 76 base_instance_num=None, 77 num_avds_per_instance=None, 78 openwrt=True, 79 enable_fetch_local_caching=False, 80 cfg=mock_cfg) 81 82 @mock.patch("acloud.public.actions.remote_host_cf_device_factory.ssh") 83 @mock.patch("acloud.public.actions.remote_host_cf_device_factory." 84 "cvd_utils") 85 @mock.patch("acloud.public.actions.remote_host_cf_device_factory.pull") 86 def testCreateInstanceWithImageDir(self, mock_pull, mock_cvd_utils, 87 mock_ssh): 88 """Test CreateInstance with local image directory.""" 89 mock_avd_spec = self._CreateMockAvdSpec() 90 mock_avd_spec.image_source = constants.IMAGE_SRC_LOCAL 91 mock_avd_spec.local_image_dir = "/mock/target_files" 92 mock_avd_spec.base_instance_num = 2 93 mock_avd_spec.num_avds_per_instance = 3 94 mock_ssh_obj = mock.Mock() 95 mock_ssh.Ssh.return_value = mock_ssh_obj 96 factory = remote_host_cf_device_factory.RemoteHostDeviceFactory( 97 mock_avd_spec, cvd_host_package_artifact="/mock/cvd.tar.gz") 98 99 mock_pull.PullLogs.side_effect = errors.DeviceConnectionError 100 101 log = {"path": "/log.txt"} 102 mock_cvd_utils.GetRemoteHostBaseDir.return_value = "acloud_cf_2" 103 mock_cvd_utils.FormatRemoteHostInstanceName.return_value = "inst" 104 mock_cvd_utils.AreTargetFilesRequired.return_value = True 105 mock_cvd_utils.UploadExtraImages.return_value = [("-extra", "image")] 106 mock_cvd_utils.ExecuteRemoteLaunchCvd.return_value = "failure" 107 mock_cvd_utils.FindRemoteLogs.return_value = [log] 108 109 self.assertEqual("inst", factory.CreateInstance()) 110 # InitRemotehost 111 mock_cvd_utils.CleanUpRemoteCvd.assert_called_once_with( 112 mock_ssh_obj, "acloud_cf_2", raise_error=False) 113 mock_cvd_utils.GetRemoteHostBaseDir.assert_called_with(2) 114 # ProcessRemoteHostArtifacts 115 mock_ssh_obj.Run.assert_called_with("mkdir -p acloud_cf_2") 116 self._mock_build_api.GetFetchBuildArgs.assert_not_called() 117 mock_cvd_utils.UploadArtifacts.assert_called_with( 118 mock_ssh_obj, "acloud_cf_2", "/mock/target_files", 119 "/mock/cvd.tar.gz") 120 mock_cvd_utils.UploadExtraImages.assert_called_with( 121 mock_ssh_obj, "acloud_cf_2", mock_avd_spec, "/mock/target_files") 122 mock_cvd_utils.GetConfigFromRemoteAndroidInfo.assert_called_with( 123 mock_ssh_obj, "acloud_cf_2") 124 # LaunchCvd 125 mock_cvd_utils.GetRemoteLaunchCvdCmd.assert_called_with( 126 "acloud_cf_2", mock_avd_spec, mock.ANY, ["-extra", "image"]) 127 mock_cvd_utils.ExecuteRemoteLaunchCvd.assert_called() 128 # FindLogFiles 129 mock_cvd_utils.FindRemoteLogs.assert_called_with( 130 mock_ssh_obj, "acloud_cf_2", 2, 3) 131 mock_pull.GetAllLogFilePaths.assert_called_once() 132 mock_pull.PullLogs.assert_called_once() 133 factory.GetAdbPorts() 134 mock_cvd_utils.GetAdbPorts.assert_called_with(2, 3) 135 factory.GetVncPorts() 136 mock_cvd_utils.GetVncPorts.assert_called_with(2, 3) 137 self.assertEqual({"inst": "failure"}, factory.GetFailures()) 138 self.assertDictEqual({"inst": [log]}, factory.GetLogs()) 139 140 @mock.patch("acloud.public.actions.remote_host_cf_device_factory.ssh") 141 @mock.patch("acloud.public.actions.remote_host_cf_device_factory." 142 "cvd_utils") 143 @mock.patch("acloud.public.actions.remote_host_cf_device_factory.pull") 144 def testCreateInstanceWithImageZip(self, mock_pull, mock_cvd_utils, 145 mock_ssh): 146 """Test CreateInstance with local image zip.""" 147 mock_avd_spec = self._CreateMockAvdSpec() 148 mock_avd_spec.image_source = constants.IMAGE_SRC_LOCAL 149 mock_ssh_obj = mock.Mock() 150 mock_ssh.Ssh.return_value = mock_ssh_obj 151 factory = remote_host_cf_device_factory.RemoteHostDeviceFactory( 152 mock_avd_spec, local_image_artifact="/mock/img.zip", 153 cvd_host_package_artifact="/mock/cvd.tar.gz") 154 155 mock_cvd_utils.GetRemoteHostBaseDir.return_value = "acloud_cf_1" 156 mock_cvd_utils.FormatRemoteHostInstanceName.return_value = "inst" 157 mock_cvd_utils.AreTargetFilesRequired.return_value = False 158 mock_cvd_utils.ExecuteRemoteLaunchCvd.return_value = "" 159 mock_cvd_utils.FindRemoteLogs.return_value = [] 160 161 self.assertEqual("inst", factory.CreateInstance()) 162 # InitRemotehost 163 mock_cvd_utils.GetRemoteHostBaseDir.assert_called_with(None) 164 mock_cvd_utils.CleanUpRemoteCvd.assert_called_once() 165 # ProcessRemoteHostArtifacts 166 mock_ssh_obj.Run.assert_called_with("mkdir -p acloud_cf_1") 167 self._mock_build_api.GetFetchBuildArgs.assert_not_called() 168 mock_cvd_utils.UploadArtifacts.assert_called_with( 169 mock_ssh_obj, "acloud_cf_1", "/mock/img.zip", "/mock/cvd.tar.gz") 170 mock_cvd_utils.UploadExtraImages.assert_called_with( 171 mock_ssh_obj, "acloud_cf_1", mock_avd_spec, None) 172 # LaunchCvd 173 mock_cvd_utils.ExecuteRemoteLaunchCvd.assert_called() 174 # FindLogFiles 175 mock_cvd_utils.FindRemoteLogs.assert_called_with( 176 mock_ssh_obj, "acloud_cf_1", None, None) 177 mock_pull.GetAllLogFilePaths.assert_not_called() 178 mock_pull.PullLogs.assert_not_called() 179 factory.GetAdbPorts() 180 mock_cvd_utils.GetAdbPorts.assert_called_with(None, None) 181 factory.GetVncPorts() 182 mock_cvd_utils.GetVncPorts.assert_called_with(None, None) 183 self.assertFalse(factory.GetFailures()) 184 self.assertDictEqual({"inst": []}, factory.GetLogs()) 185 186 # pylint: disable=invalid-name 187 @mock.patch("acloud.public.actions.remote_host_cf_device_factory.ssh") 188 @mock.patch("acloud.public.actions.remote_host_cf_device_factory." 189 "cvd_utils") 190 @mock.patch("acloud.public.actions.remote_host_cf_device_factory.pull") 191 def testCreateInstanceWithTargetFilesZip(self, mock_pull, mock_cvd_utils, 192 mock_ssh): 193 """Test CreateInstance with local target_files zip.""" 194 mock_avd_spec = self._CreateMockAvdSpec() 195 mock_avd_spec.image_source = constants.IMAGE_SRC_LOCAL 196 mock_ssh_obj = mock.Mock() 197 mock_ssh.Ssh.return_value = mock_ssh_obj 198 factory = remote_host_cf_device_factory.RemoteHostDeviceFactory( 199 mock_avd_spec, local_image_artifact="/mock/target_files.zip", 200 cvd_host_package_artifact="/mock/cvd.tar.gz") 201 202 mock_cvd_utils.GetRemoteHostBaseDir.return_value = "acloud_cf_1" 203 mock_cvd_utils.FormatRemoteHostInstanceName.return_value = "inst" 204 mock_cvd_utils.AreTargetFilesRequired.return_value = True 205 mock_cvd_utils.ExecuteRemoteLaunchCvd.return_value = "" 206 mock_cvd_utils.FindRemoteLogs.return_value = [] 207 208 self.assertEqual("inst", factory.CreateInstance()) 209 # InitRemotehost 210 mock_cvd_utils.GetRemoteHostBaseDir.assert_called_with(None) 211 mock_cvd_utils.CleanUpRemoteCvd.assert_called_once() 212 # ProcessRemoteHostArtifacts 213 mock_ssh_obj.Run.assert_called_with("mkdir -p acloud_cf_1") 214 mock_cvd_utils.ExtractTargetFilesZip.assert_called_with( 215 "/mock/target_files.zip", mock.ANY) 216 self._mock_build_api.GetFetchBuildArgs.assert_not_called() 217 mock_cvd_utils.UploadExtraImages.assert_called_with( 218 mock_ssh_obj, "acloud_cf_1", mock_avd_spec, mock.ANY) 219 mock_cvd_utils.UploadArtifacts.assert_called_with( 220 mock_ssh_obj, "acloud_cf_1", mock.ANY, "/mock/cvd.tar.gz") 221 self.assertIn("acloud_remote_host", # temp dir prefix 222 mock_cvd_utils.UploadArtifacts.call_args[0][2]) 223 # LaunchCvd 224 mock_cvd_utils.ExecuteRemoteLaunchCvd.assert_called() 225 # FindLogFiles 226 mock_cvd_utils.FindRemoteLogs.assert_called_with( 227 mock_ssh_obj, "acloud_cf_1", None, None) 228 mock_pull.GetAllLogFilePaths.assert_not_called() 229 mock_pull.PullLogs.assert_not_called() 230 factory.GetAdbPorts() 231 mock_cvd_utils.GetAdbPorts.assert_called_with(None, None) 232 factory.GetVncPorts() 233 mock_cvd_utils.GetVncPorts.assert_called_with(None, None) 234 self.assertFalse(factory.GetFailures()) 235 self.assertDictEqual({"inst": []}, factory.GetLogs()) 236 237 @mock.patch("acloud.public.actions.remote_host_cf_device_factory.ssh") 238 @mock.patch("acloud.public.actions.remote_host_cf_device_factory." 239 "cvd_utils") 240 @mock.patch("acloud.public.actions.remote_host_cf_device_factory." 241 "subprocess.check_call") 242 @mock.patch("acloud.public.actions.remote_host_cf_device_factory.glob") 243 @mock.patch("acloud.public.actions.remote_host_cf_device_factory.pull") 244 def testCreateInstanceWithRemoteImages(self, mock_pull, mock_glob, 245 mock_check_call, mock_cvd_utils, 246 mock_ssh): 247 """Test CreateInstance with remote images.""" 248 mock_avd_spec = self._CreateMockAvdSpec() 249 mock_avd_spec.image_source = constants.IMAGE_SRC_REMOTE 250 mock_ssh_obj = mock.Mock() 251 mock_ssh.Ssh.return_value = mock_ssh_obj 252 mock_ssh_obj.GetBaseCmd.return_value = "/mock/ssh" 253 mock_glob.glob.return_value = ["/mock/super.img"] 254 factory = remote_host_cf_device_factory.RemoteHostDeviceFactory( 255 mock_avd_spec) 256 257 mock_cvd_utils.GetRemoteHostBaseDir.return_value = "acloud_cf_1" 258 mock_cvd_utils.FormatRemoteHostInstanceName.return_value = "inst" 259 mock_cvd_utils.AreTargetFilesRequired.return_value = True 260 mock_cvd_utils.GetMixBuildTargetFilename.return_value = "mock.zip" 261 mock_cvd_utils.ExecuteRemoteLaunchCvd.return_value = "" 262 mock_cvd_utils.FindRemoteLogs.return_value = [] 263 264 self._mock_build_api.GetFetchBuildArgs.return_value = ["-test"] 265 266 self.assertEqual("inst", factory.CreateInstance()) 267 # InitRemoteHost 268 mock_cvd_utils.CleanUpRemoteCvd.assert_called_once() 269 # ProcessRemoteHostArtifacts 270 mock_ssh_obj.Run.assert_called_with("mkdir -p acloud_cf_1") 271 self._mock_build_api.DownloadArtifact.assert_called_once_with( 272 "aosp_cf_x86_64_phone-trunk_staging-userdebug", "100000", "mock.zip", mock.ANY) 273 mock_cvd_utils.ExtractTargetFilesZip.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 mock_shutil.copyfile.assert_called_with("/mock/key", mock.ANY) 319 self.assertRegex(mock_ssh.ShellCmdWithRetry.call_args_list[0][0][0], 320 r"^tar -cf - --lzop -S -C \S+ fetch_cvd \| " 321 r"/mock/ssh -- tar -xf - --lzop -S -C acloud_cf_1$") 322 self.assertRegex(mock_ssh.ShellCmdWithRetry.call_args_list[1][0][0], 323 r"^/mock/ssh -- cvd fetch " 324 r"-target_directory=acloud_cf_1 " 325 r"-credential_source=acloud_cf_1/credential_key.json " 326 r"-enable_caching=false " 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 mock_shutil.copyfile.assert_called_with("/mock/key", mock.ANY) 372 self.assertRegex(mock_ssh.ShellCmdWithRetry.call_args_list[0][0][0], 373 r"^tar -cf - --lzop -S -C \S+ fetch_cvd \| " 374 r"/mock/ssh -- tar -xf - --lzop -S -C acloud_cf_1$") 375 self.assertRegex(mock_ssh.ShellCmdWithRetry.call_args_list[1][0][0], 376 r"^/mock/ssh -- " 377 r"GOOGLE_APPLICATION_CREDENTIALS=/fake_key.json " 378 r"CACHE_CONFIG=/home/shared/cache.properties " 379 r"java -jar /home/shared/FetchCvdWrapper.jar " 380 r"-fetch_cvd_path=cvd " 381 r"fetch " 382 r"-target_directory=acloud_cf_1 " 383 r"-credential_source=acloud_cf_1/credential_key.json " 384 r"-enable_caching=false " 385 r"-test$") 386 mock_cvd_utils.ExecuteRemoteLaunchCvd.assert_called() 387 mock_pull.GetAllLogFilePaths.assert_not_called() 388 mock_pull.PullLogs.assert_not_called() 389 self.assertFalse(factory.GetFailures()) 390 self.assertDictEqual({"inst": [log]}, factory.GetLogs()) 391 392 @mock.patch("acloud.public.actions.remote_host_cf_device_factory.ssh") 393 @mock.patch("acloud.public.actions.remote_host_cf_device_factory." 394 "cvd_utils") 395 @mock.patch("acloud.public.actions.remote_host_cf_device_factory." 396 "subprocess.check_call") 397 @mock.patch("acloud.public.actions.remote_host_cf_device_factory.glob") 398 @mock.patch("acloud.public.actions.remote_host_cf_device_factory.pull") 399 def testCreateInstanceWithRemoteImageDir(self, _mock_pull, mock_glob, 400 _mock_check_call, mock_cvd_utils, 401 mock_ssh): 402 """Test CreateInstance with AvdSpec.remote_image_dir.""" 403 mock_avd_spec = self._CreateMockAvdSpec() 404 mock_avd_spec.remote_image_dir = "mock_img_dir" 405 406 mock_ssh_obj = mock.Mock() 407 mock_ssh.Ssh.return_value = mock_ssh_obj 408 # Test initializing the remote image dir. 409 mock_glob.glob.return_value = ["/mock/super.img"] 410 factory = remote_host_cf_device_factory.RemoteHostDeviceFactory( 411 mock_avd_spec) 412 413 mock_cvd_utils.GetRemoteHostBaseDir.return_value = "acloud_cf_1" 414 mock_cvd_utils.FormatRemoteHostInstanceName.return_value = "inst" 415 mock_cvd_utils.LoadRemoteImageArgs.return_value = None 416 mock_cvd_utils.AreTargetFilesRequired.return_value = False 417 mock_cvd_utils.UploadExtraImages.return_value = [ 418 ("arg", "mock_img_dir/1")] 419 mock_cvd_utils.ExecuteRemoteLaunchCvd.return_value = "" 420 mock_cvd_utils.FindRemoteLogs.return_value = [] 421 422 self._mock_build_api.GetFetchBuildArgs.return_value = ["-test"] 423 424 self.assertEqual("inst", factory.CreateInstance()) 425 mock_cvd_utils.PrepareRemoteImageDirLink.assert_called_once_with( 426 mock_ssh_obj, "acloud_cf_1", "mock_img_dir") 427 mock_cvd_utils.LoadRemoteImageArgs.assert_called_once_with( 428 mock_ssh_obj, "mock_img_dir/acloud_image_timestamp.txt", 429 "mock_img_dir/acloud_image_args.txt", mock.ANY) 430 mock_cvd_utils.SaveRemoteImageArgs.assert_called_once_with( 431 mock_ssh_obj, "mock_img_dir/acloud_image_args.txt", 432 [("arg", "mock_img_dir/1")]) 433 mock_ssh_obj.Run.assert_called_with("cp -frT mock_img_dir acloud_cf_1") 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 443 self.assertEqual("inst", factory.CreateInstance()) 444 mock_cvd_utils.SaveRemoteImageArgs.assert_not_called() 445 mock_ssh_obj.Run.assert_called_with("cp -frT mock_img_dir acloud_cf_1") 446 self.assertEqual(["arg", "acloud_cf_1/2"], 447 mock_cvd_utils.GetRemoteLaunchCvdCmd.call_args[0][3]) 448 449 @mock.patch("acloud.public.actions.remote_host_cf_device_factory.ssh") 450 @mock.patch("acloud.public.actions.remote_host_cf_device_factory." 451 "cvd_utils") 452 @mock.patch("acloud.public.actions.remote_host_cf_device_factory." 453 "subprocess.check_call") 454 def testCreateInstanceWithCreateError(self, _mock_check_call, 455 mock_cvd_utils, mock_ssh): 456 """Test CreateInstance with CreateError.""" 457 mock_avd_spec = self._CreateMockAvdSpec() 458 mock_avd_spec.remote_image_dir = "mock_img_dir" 459 460 mock_ssh_obj = mock.Mock() 461 mock_ssh.Ssh.return_value = mock_ssh_obj 462 463 mock_cvd_utils.GetRemoteHostBaseDir.return_value = "acloud_cf_1" 464 mock_cvd_utils.FormatRemoteHostInstanceName.return_value = "inst" 465 mock_cvd_utils.LoadRemoteImageArgs.side_effect = errors.CreateError( 466 "failure") 467 factory = remote_host_cf_device_factory.RemoteHostDeviceFactory( 468 mock_avd_spec) 469 470 self.assertEqual("inst", factory.CreateInstance()) 471 self.assertEqual({"inst": "failure"}, factory.GetFailures()) 472 mock_cvd_utils.ExecuteRemoteLaunchCvd.assert_not_called() 473 474 475if __name__ == "__main__": 476 unittest.main() 477