1# Copyright 2018 - 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"""Tests for avd_spec.""" 15 16import glob 17import os 18import subprocess 19import unittest 20import mock 21 22from acloud import errors 23from acloud.create import avd_spec 24from acloud.internal import constants 25from acloud.internal.lib import android_build_client 26from acloud.internal.lib import auth 27from acloud.internal.lib import driver_test_lib 28from acloud.internal.lib import utils 29from acloud.list import list as list_instances 30 31 32# pylint: disable=invalid-name,protected-access 33class AvdSpecTest(driver_test_lib.BaseDriverTest): 34 """Test avd_spec methods.""" 35 36 def setUp(self): 37 """Initialize new avd_spec.AVDSpec.""" 38 super(AvdSpecTest, self).setUp() 39 self.args = mock.MagicMock() 40 self.args.flavor = "" 41 self.args.local_image = "" 42 self.args.config_file = "" 43 self.args.build_target = "fake_build_target" 44 self.args.adb_port = None 45 self.Patch(list_instances, "ChooseOneRemoteInstance", return_value=mock.MagicMock()) 46 self.Patch(list_instances, "GetInstancesFromInstanceNames", return_value=mock.MagicMock()) 47 self.AvdSpec = avd_spec.AVDSpec(self.args) 48 49 # pylint: disable=protected-access 50 def testProcessLocalImageArgs(self): 51 """Test process args.local_image.""" 52 self.Patch(glob, "glob", return_value=["fake.img"]) 53 expected_image_artifact = "/path/cf_x86_phone-img-eng.user.zip" 54 expected_image_dir = "/path-to-image-dir" 55 56 # Specified --local-image to a local zipped image file 57 self.Patch(os.path, "isfile", return_value=True) 58 self.args.local_image = "/path/cf_x86_phone-img-eng.user.zip" 59 self.AvdSpec._avd_type = constants.TYPE_CF 60 self.AvdSpec._instance_type = constants.INSTANCE_TYPE_REMOTE 61 self.AvdSpec._ProcessLocalImageArgs(self.args) 62 self.assertEqual(self.AvdSpec._local_image_artifact, 63 expected_image_artifact) 64 65 # Specified --local-image to a dir contains images 66 self.Patch(utils, "GetBuildEnvironmentVariable", 67 return_value="test_environ") 68 self.Patch(os.path, "isfile", return_value=False) 69 self.args.local_image = "/path-to-image-dir" 70 self.AvdSpec._avd_type = constants.TYPE_CF 71 self.AvdSpec._instance_type = constants.INSTANCE_TYPE_REMOTE 72 self.AvdSpec._ProcessLocalImageArgs(self.args) 73 self.assertEqual(self.AvdSpec._local_image_dir, expected_image_dir) 74 75 # Specified local_image without arg 76 self.args.local_image = None 77 self.Patch(utils, "GetBuildEnvironmentVariable", 78 return_value="test_environ") 79 self.AvdSpec._ProcessLocalImageArgs(self.args) 80 self.assertEqual(self.AvdSpec._local_image_dir, "test_environ") 81 self.assertEqual(self.AvdSpec.local_image_artifact, expected_image_artifact) 82 83 # Specified --avd-type=goldfish --local-image with a dir 84 self.Patch(utils, "GetBuildEnvironmentVariable", 85 return_value="test_environ") 86 self.Patch(os.path, "isdir", return_value=True) 87 self.args.local_image = "/path-to-image-dir" 88 self.AvdSpec._avd_type = constants.TYPE_GF 89 self.AvdSpec._instance_type = constants.INSTANCE_TYPE_LOCAL 90 self.AvdSpec._ProcessLocalImageArgs(self.args) 91 self.assertEqual(self.AvdSpec._local_image_dir, expected_image_dir) 92 93 # Specified --avd-type=goldfish --local_image without arg 94 self.Patch(utils, "GetBuildEnvironmentVariable", 95 return_value="test_environ") 96 self.Patch(os.path, "isdir", return_value=True) 97 self.args.local_image = None 98 self.AvdSpec._avd_type = constants.TYPE_GF 99 self.AvdSpec._instance_type = constants.INSTANCE_TYPE_LOCAL 100 self.AvdSpec._ProcessLocalImageArgs(self.args) 101 self.assertEqual(self.AvdSpec._local_image_dir, "test_environ") 102 103 def testProcessImageArgs(self): 104 """Test process image source.""" 105 self.Patch(glob, "glob", return_value=["fake.img"]) 106 # No specified local_image, image source is from remote 107 self.args.local_image = "" 108 self.AvdSpec._ProcessImageArgs(self.args) 109 self.assertEqual(self.AvdSpec._image_source, constants.IMAGE_SRC_REMOTE) 110 self.assertEqual(self.AvdSpec._local_image_dir, None) 111 112 # Specified local_image with an arg for cf type 113 self.Patch(os.path, "isfile", return_value=True) 114 self.args.local_image = "/test_path/cf_x86_phone-img-eng.user.zip" 115 self.AvdSpec._avd_type = constants.TYPE_CF 116 self.AvdSpec._instance_type = constants.INSTANCE_TYPE_REMOTE 117 self.AvdSpec._ProcessImageArgs(self.args) 118 self.assertEqual(self.AvdSpec._image_source, constants.IMAGE_SRC_LOCAL) 119 self.assertEqual(self.AvdSpec._local_image_artifact, 120 "/test_path/cf_x86_phone-img-eng.user.zip") 121 122 # Specified local_image with an arg for gce type 123 self.Patch(os.path, "isfile", return_value=False) 124 self.Patch(os.path, "exists", return_value=True) 125 self.args.local_image = "/test_path_to_dir/" 126 self.AvdSpec._avd_type = constants.TYPE_GCE 127 self.AvdSpec._ProcessImageArgs(self.args) 128 self.assertEqual(self.AvdSpec._image_source, constants.IMAGE_SRC_LOCAL) 129 self.assertEqual(self.AvdSpec._local_image_artifact, 130 "/test_path_to_dir/avd-system.tar.gz") 131 132 @mock.patch.object(avd_spec.AVDSpec, "_GetGitRemote") 133 def testGetBranchFromRepo(self, mock_gitremote): 134 """Test get branch name from repo info.""" 135 # Check aosp repo gets proper branch prefix. 136 fake_subprocess = mock.MagicMock() 137 fake_subprocess.stdout = mock.MagicMock() 138 fake_subprocess.stdout.readline = mock.MagicMock(return_value='') 139 fake_subprocess.poll = mock.MagicMock(return_value=0) 140 fake_subprocess.returncode = 0 141 return_value = "Manifest branch: master" 142 fake_subprocess.communicate = mock.MagicMock(return_value=(return_value, '')) 143 self.Patch(subprocess, "Popen", return_value=fake_subprocess) 144 145 mock_gitremote.return_value = "aosp" 146 self.assertEqual(self.AvdSpec._GetBranchFromRepo(), "aosp-master") 147 148 # Check default repo gets default branch prefix. 149 mock_gitremote.return_value = "" 150 return_value = "Manifest branch: master" 151 fake_subprocess.communicate = mock.MagicMock(return_value=(return_value, '')) 152 self.Patch(subprocess, "Popen", return_value=fake_subprocess) 153 self.assertEqual(self.AvdSpec._GetBranchFromRepo(), "git_master") 154 155 # Can't get branch from repo info, set it as default branch. 156 return_value = "Manifest branch:" 157 fake_subprocess.communicate = mock.MagicMock(return_value=(return_value, '')) 158 self.Patch(subprocess, "Popen", return_value=fake_subprocess) 159 self.assertEqual(self.AvdSpec._GetBranchFromRepo(), "aosp-master") 160 161 def testGetBuildBranch(self): 162 """Test GetBuildBranch function""" 163 # Test infer branch from build_id and build_target. 164 build_client = mock.MagicMock() 165 build_id = "fake_build_id" 166 build_target = "fake_build_target" 167 expected_branch = "fake_build_branch" 168 self.Patch(android_build_client, "AndroidBuildClient", 169 return_value=build_client) 170 self.Patch(auth, "CreateCredentials", return_value=mock.MagicMock()) 171 self.Patch(build_client, "GetBranch", return_value=expected_branch) 172 self.assertEqual(self.AvdSpec._GetBuildBranch(build_id, build_target), 173 expected_branch) 174 # Infer branch from "repo info" when build_id and build_target is None. 175 self.Patch(self.AvdSpec, "_GetBranchFromRepo", return_value="repo_branch") 176 build_id = None 177 build_target = None 178 expected_branch = "repo_branch" 179 self.assertEqual(self.AvdSpec._GetBuildBranch(build_id, build_target), 180 expected_branch) 181 182 # pylint: disable=protected-access 183 def testGetBuildTarget(self): 184 """Test get build target name.""" 185 self.AvdSpec._remote_image[constants.BUILD_BRANCH] = "git_branch" 186 self.AvdSpec._flavor = constants.FLAVOR_IOT 187 self.args.avd_type = constants.TYPE_GCE 188 self.assertEqual( 189 self.AvdSpec._GetBuildTarget(self.args), 190 "gce_x86_iot-userdebug") 191 192 self.AvdSpec._remote_image[constants.BUILD_BRANCH] = "aosp-master" 193 self.AvdSpec._flavor = constants.FLAVOR_PHONE 194 self.args.avd_type = constants.TYPE_CF 195 self.assertEqual( 196 self.AvdSpec._GetBuildTarget(self.args), 197 "aosp_cf_x86_phone-userdebug") 198 199 self.AvdSpec._remote_image[constants.BUILD_BRANCH] = "git_branch" 200 self.AvdSpec._flavor = constants.FLAVOR_PHONE 201 self.args.avd_type = constants.TYPE_CF 202 self.assertEqual( 203 self.AvdSpec._GetBuildTarget(self.args), 204 "cf_x86_phone-userdebug") 205 206 # pylint: disable=protected-access 207 def testProcessHWPropertyWithInvalidArgs(self): 208 """Test _ProcessHWPropertyArgs with invalid args.""" 209 # Checking wrong resolution. 210 args = mock.MagicMock() 211 args.hw_property = "cpu:3,resolution:1280" 212 args.reuse_instance_name = None 213 with self.assertRaises(errors.InvalidHWPropertyError): 214 self.AvdSpec._ProcessHWPropertyArgs(args) 215 216 # Checking property should be int. 217 args = mock.MagicMock() 218 args.hw_property = "cpu:3,dpi:fake" 219 with self.assertRaises(errors.InvalidHWPropertyError): 220 self.AvdSpec._ProcessHWPropertyArgs(args) 221 222 # Checking disk property should be with 'g' suffix. 223 args = mock.MagicMock() 224 args.hw_property = "cpu:3,disk:2" 225 with self.assertRaises(errors.InvalidHWPropertyError): 226 self.AvdSpec._ProcessHWPropertyArgs(args) 227 228 # Checking memory property should be with 'g' suffix. 229 args = mock.MagicMock() 230 args.hw_property = "cpu:3,memory:2" 231 with self.assertRaises(errors.InvalidHWPropertyError): 232 self.AvdSpec._ProcessHWPropertyArgs(args) 233 234 # pylint: disable=protected-access 235 def testParseHWPropertyStr(self): 236 """Test _ParseHWPropertyStr.""" 237 expected_dict = {"cpu": "2", "x_res": "1080", "y_res": "1920", 238 "dpi": "240", "memory": "4096", "disk": "4096"} 239 args_str = "cpu:2,resolution:1080x1920,dpi:240,memory:4g,disk:4g" 240 result_dict = self.AvdSpec._ParseHWPropertyStr(args_str) 241 self.assertTrue(expected_dict == result_dict) 242 243 expected_dict = {"cpu": "2", "x_res": "1080", "y_res": "1920", 244 "dpi": "240", "memory": "512", "disk": "4096"} 245 args_str = "cpu:2,resolution:1080x1920,dpi:240,memory:512m,disk:4g" 246 result_dict = self.AvdSpec._ParseHWPropertyStr(args_str) 247 self.assertTrue(expected_dict == result_dict) 248 249 def testGetFlavorFromBuildTargetString(self): 250 """Test _GetFlavorFromLocalImage.""" 251 img_path = "/fack_path/cf_x86_tv-img-eng.user.zip" 252 self.assertEqual(self.AvdSpec._GetFlavorFromString(img_path), 253 "tv") 254 255 build_target_str = "aosp_cf_x86_auto" 256 self.assertEqual(self.AvdSpec._GetFlavorFromString( 257 build_target_str), "auto") 258 259 # Flavor is not supported. 260 img_path = "/fack_path/cf_x86_error-img-eng.user.zip" 261 self.assertEqual(self.AvdSpec._GetFlavorFromString(img_path), 262 None) 263 264 # pylint: disable=protected-access 265 def testProcessRemoteBuildArgs(self): 266 """Test _ProcessRemoteBuildArgs.""" 267 self.args.branch = "git_master" 268 self.args.build_id = "1234" 269 270 # Verify auto-assigned avd_type if build_targe contains "_gce_". 271 self.args.build_target = "aosp_gce_x86_phone-userdebug" 272 self.AvdSpec._ProcessRemoteBuildArgs(self.args) 273 self.assertTrue(self.AvdSpec.avd_type == "gce") 274 275 # Verify auto-assigned avd_type if build_targe contains "gce_". 276 self.args.build_target = "gce_x86_phone-userdebug" 277 self.AvdSpec._ProcessRemoteBuildArgs(self.args) 278 self.assertTrue(self.AvdSpec.avd_type == "gce") 279 280 # Verify auto-assigned avd_type if build_targe contains "_cf_". 281 self.args.build_target = "aosp_cf_x86_phone-userdebug" 282 self.AvdSpec._ProcessRemoteBuildArgs(self.args) 283 self.assertTrue(self.AvdSpec.avd_type == "cuttlefish") 284 285 # Verify auto-assigned avd_type if build_targe contains "cf_". 286 self.args.build_target = "cf_x86_phone-userdebug" 287 self.AvdSpec._ProcessRemoteBuildArgs(self.args) 288 self.assertTrue(self.AvdSpec.avd_type == "cuttlefish") 289 290 # Verify auto-assigned avd_type if build_targe contains "sdk_". 291 self.args.build_target = "sdk_phone_armv7-sdk" 292 self.AvdSpec._ProcessRemoteBuildArgs(self.args) 293 self.assertTrue(self.AvdSpec.avd_type == "goldfish") 294 295 # Verify auto-assigned avd_type if build_targe contains "_sdk_". 296 self.args.build_target = "aosp_sdk_phone_armv7-sdk" 297 self.AvdSpec._ProcessRemoteBuildArgs(self.args) 298 self.assertTrue(self.AvdSpec.avd_type == "goldfish") 299 300 # Verify auto-assigned avd_type if no match, default as cuttlefish. 301 self.args.build_target = "mini_emulator_arm64-userdebug" 302 self.args.avd_type = "cuttlefish" 303 # reset args.avd_type default value as cuttlefish. 304 self.AvdSpec = avd_spec.AVDSpec(self.args) 305 self.AvdSpec._ProcessRemoteBuildArgs(self.args) 306 self.assertTrue(self.AvdSpec.avd_type == "cuttlefish") 307 308 def testEscapeAnsi(self): 309 """Test EscapeAnsi.""" 310 test_string = "\033[1;32;40m Manifest branch:" 311 expected_result = " Manifest branch:" 312 self.assertEqual(avd_spec.EscapeAnsi(test_string), expected_result) 313 314 def testGetGceLocalImagePath(self): 315 """Test get gce local image path.""" 316 self.Patch(os.path, "isfile", return_value=True) 317 # Verify when specify --local-image ~/XXX.tar.gz. 318 fake_image_path = "~/gce_local_image_dir/gce_image.tar.gz" 319 self.Patch(os.path, "exists", return_value=True) 320 self.assertEqual(self.AvdSpec._GetGceLocalImagePath(fake_image_path), 321 "~/gce_local_image_dir/gce_image.tar.gz") 322 323 # Verify when specify --local-image ~/XXX.img. 324 fake_image_path = "~/gce_local_image_dir/gce_image.img" 325 self.assertEqual(self.AvdSpec._GetGceLocalImagePath(fake_image_path), 326 "~/gce_local_image_dir/gce_image.img") 327 328 # Verify if exist argument --local-image as a directory. 329 self.Patch(os.path, "isfile", return_value=False) 330 self.Patch(os.path, "exists", return_value=True) 331 fake_image_path = "~/gce_local_image_dir/" 332 # Default to find */avd-system.tar.gz if exist then return the path. 333 self.assertEqual(self.AvdSpec._GetGceLocalImagePath(fake_image_path), 334 "~/gce_local_image_dir/avd-system.tar.gz") 335 336 # Otherwise choose raw file */android_system_disk_syslinux.img if 337 # exist then return the path. 338 self.Patch(os.path, "exists", side_effect=[False, True]) 339 self.assertEqual(self.AvdSpec._GetGceLocalImagePath(fake_image_path), 340 "~/gce_local_image_dir/android_system_disk_syslinux.img") 341 342 # Both _GCE_LOCAL_IMAGE_CANDIDATE could not be found then raise error. 343 self.Patch(os.path, "exists", side_effect=[False, False]) 344 self.assertRaises(errors.ImgDoesNotExist, 345 self.AvdSpec._GetGceLocalImagePath, fake_image_path) 346 347 def testProcessMiscArgs(self): 348 """Test process misc args.""" 349 self.args.remote_host = None 350 self.args.local_instance = None 351 self.AvdSpec._ProcessMiscArgs(self.args) 352 self.assertEqual(self.AvdSpec._instance_type, constants.INSTANCE_TYPE_REMOTE) 353 354 self.args.remote_host = None 355 self.args.local_instance = True 356 self.AvdSpec._ProcessMiscArgs(self.args) 357 self.assertEqual(self.AvdSpec._instance_type, constants.INSTANCE_TYPE_LOCAL) 358 359 self.args.remote_host = "1.1.1.1" 360 self.args.local_instance = None 361 self.AvdSpec._ProcessMiscArgs(self.args) 362 self.assertEqual(self.AvdSpec._instance_type, constants.INSTANCE_TYPE_HOST) 363 364 self.args.remote_host = "1.1.1.1" 365 self.args.local_instance = True 366 self.AvdSpec._ProcessMiscArgs(self.args) 367 self.assertEqual(self.AvdSpec._instance_type, constants.INSTANCE_TYPE_HOST) 368 369 # Test avd_spec.autoconnect 370 self.args.autoconnect = False 371 self.AvdSpec._ProcessMiscArgs(self.args) 372 self.assertEqual(self.AvdSpec.autoconnect, False) 373 self.assertEqual(self.AvdSpec.connect_adb, False) 374 self.assertEqual(self.AvdSpec.connect_vnc, False) 375 self.assertEqual(self.AvdSpec.connect_webrtc, False) 376 377 self.args.autoconnect = constants.INS_KEY_VNC 378 self.AvdSpec._ProcessMiscArgs(self.args) 379 self.assertEqual(self.AvdSpec.autoconnect, True) 380 self.assertEqual(self.AvdSpec.connect_adb, True) 381 self.assertEqual(self.AvdSpec.connect_vnc, True) 382 self.assertEqual(self.AvdSpec.connect_webrtc, False) 383 384 self.args.autoconnect = constants.INS_KEY_ADB 385 self.AvdSpec._ProcessMiscArgs(self.args) 386 self.assertEqual(self.AvdSpec.autoconnect, True) 387 self.assertEqual(self.AvdSpec.connect_adb, True) 388 self.assertEqual(self.AvdSpec.connect_vnc, False) 389 self.assertEqual(self.AvdSpec.connect_webrtc, False) 390 391 self.args.autoconnect = constants.INS_KEY_WEBRTC 392 self.AvdSpec._ProcessMiscArgs(self.args) 393 self.assertEqual(self.AvdSpec.autoconnect, True) 394 self.assertEqual(self.AvdSpec.connect_adb, True) 395 self.assertEqual(self.AvdSpec.connect_vnc, False) 396 self.assertEqual(self.AvdSpec.connect_webrtc, True) 397 398 399if __name__ == "__main__": 400 unittest.main() 401