1#!/usr/bin/env python 2# 3# Copyright 2018 - The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16"""Tests for LocalImageLocalInstance.""" 17 18import os 19import shutil 20import subprocess 21import unittest 22import mock 23 24from acloud import errors 25from acloud.create import local_image_local_instance 26from acloud.list import instance 27from acloud.list import list as list_instance 28from acloud.internal import constants 29from acloud.internal.lib import driver_test_lib 30from acloud.internal.lib import utils 31 32 33class LocalImageLocalInstanceTest(driver_test_lib.BaseDriverTest): 34 """Test LocalImageLocalInstance method.""" 35 36 LAUNCH_CVD_CMD_WITH_DISK = """sg group1 <<EOF 37sg group2 38launch_cvd -daemon -cpus fake -x_res fake -y_res fake -dpi fake -memory_mb fake -run_adb_connector=true -system_image_dir fake_image_dir -instance_dir fake_cvd_dir -undefok=report_anonymous_usage_stats,enable_sandbox -report_anonymous_usage_stats=y -enable_sandbox=false -blank_data_image_mb fake -data_policy always_create 39EOF""" 40 41 LAUNCH_CVD_CMD_NO_DISK = """sg group1 <<EOF 42sg group2 43launch_cvd -daemon -cpus fake -x_res fake -y_res fake -dpi fake -memory_mb fake -run_adb_connector=true -system_image_dir fake_image_dir -instance_dir fake_cvd_dir -undefok=report_anonymous_usage_stats,enable_sandbox -report_anonymous_usage_stats=y -enable_sandbox=false 44EOF""" 45 46 LAUNCH_CVD_CMD_NO_DISK_WITH_GPU = """sg group1 <<EOF 47sg group2 48launch_cvd -daemon -cpus fake -x_res fake -y_res fake -dpi fake -memory_mb fake -run_adb_connector=true -system_image_dir fake_image_dir -instance_dir fake_cvd_dir -undefok=report_anonymous_usage_stats,enable_sandbox -report_anonymous_usage_stats=y -enable_sandbox=false -gpu_mode=drm_virgl 49EOF""" 50 51 LAUNCH_CVD_CMD_WITH_WEBRTC = """sg group1 <<EOF 52sg group2 53launch_cvd -daemon -cpus fake -x_res fake -y_res fake -dpi fake -memory_mb fake -run_adb_connector=true -system_image_dir fake_image_dir -instance_dir fake_cvd_dir -undefok=report_anonymous_usage_stats,enable_sandbox -report_anonymous_usage_stats=y -enable_sandbox=false -guest_enforce_security=false -vm_manager=crosvm -start_webrtc=true -webrtc_public_ip=127.0.0.1 54EOF""" 55 56 _EXPECTED_DEVICES_IN_REPORT = [ 57 { 58 "instance_name": "local-instance-1", 59 "ip": "127.0.0.1:6520", 60 "adb_port": 6520, 61 "vnc_port": 6444 62 } 63 ] 64 65 _EXPECTED_DEVICES_IN_FAILED_REPORT = [ 66 { 67 "instance_name": "local-instance-1", 68 "ip": "127.0.0.1" 69 } 70 ] 71 72 def setUp(self): 73 """Initialize new LocalImageLocalInstance.""" 74 super(LocalImageLocalInstanceTest, self).setUp() 75 self.local_image_local_instance = local_image_local_instance.LocalImageLocalInstance() 76 77 # pylint: disable=protected-access 78 @mock.patch("acloud.create.local_image_local_instance.utils") 79 @mock.patch.object(local_image_local_instance.LocalImageLocalInstance, 80 "PrepareLaunchCVDCmd") 81 @mock.patch.object(local_image_local_instance.LocalImageLocalInstance, 82 "GetImageArtifactsPath") 83 @mock.patch.object(local_image_local_instance.LocalImageLocalInstance, 84 "CheckLaunchCVD") 85 def testCreateAVD(self, mock_check_launch_cvd, mock_get_image, 86 _mock_prepare, mock_utils): 87 """Test the report returned by _CreateAVD.""" 88 mock_utils.IsSupportedPlatform.return_value = True 89 mock_get_image.return_value = ("/image/path", "/host/bin/path") 90 mock_avd_spec = mock.Mock(connect_adb=False, unlock_screen=False) 91 self.Patch(instance, "GetLocalInstanceName", 92 return_value="local-instance-1") 93 local_ins = mock.MagicMock( 94 adb_port=6520, 95 vnc_port=6444 96 ) 97 local_ins.CvdStatus.return_value = True 98 self.Patch(instance, "LocalInstance", 99 return_value=local_ins) 100 self.Patch(list_instance, "GetActiveCVD", 101 return_value=local_ins) 102 103 # Success 104 report = self.local_image_local_instance._CreateAVD( 105 mock_avd_spec, no_prompts=True) 106 107 self.assertEqual(report.data.get("devices"), 108 self._EXPECTED_DEVICES_IN_REPORT) 109 # Failure 110 mock_check_launch_cvd.side_effect = errors.LaunchCVDFail("timeout") 111 112 report = self.local_image_local_instance._CreateAVD( 113 mock_avd_spec, no_prompts=True) 114 115 self.assertEqual(report.data.get("devices_failing_boot"), 116 self._EXPECTED_DEVICES_IN_FAILED_REPORT) 117 self.assertEqual(report.errors, ["timeout"]) 118 119 # pylint: disable=protected-access 120 @mock.patch("acloud.create.local_image_local_instance.os.path.isfile") 121 def testFindCvdHostBinaries(self, mock_isfile): 122 """Test FindCvdHostBinaries.""" 123 cvd_host_dir = "/unit/test" 124 mock_isfile.return_value = None 125 126 with mock.patch.dict("acloud.internal.lib.ota_tools.os.environ", 127 {"ANDROID_HOST_OUT": cvd_host_dir}, clear=True): 128 with self.assertRaises(errors.GetCvdLocalHostPackageError): 129 self.local_image_local_instance._FindCvdHostBinaries( 130 [cvd_host_dir]) 131 132 mock_isfile.side_effect = ( 133 lambda path: path == "/unit/test/bin/launch_cvd") 134 135 with mock.patch.dict("acloud.internal.lib.ota_tools.os.environ", 136 {"ANDROID_HOST_OUT": cvd_host_dir}, clear=True): 137 path = self.local_image_local_instance._FindCvdHostBinaries([]) 138 self.assertEqual(path, cvd_host_dir) 139 140 with mock.patch.dict("acloud.internal.lib.ota_tools.os.environ", 141 dict(), clear=True): 142 path = self.local_image_local_instance._FindCvdHostBinaries( 143 [cvd_host_dir]) 144 self.assertEqual(path, cvd_host_dir) 145 146 # pylint: disable=protected-access 147 @mock.patch.object(instance, "GetLocalInstanceRuntimeDir") 148 @mock.patch.object(utils, "CheckUserInGroups") 149 def testPrepareLaunchCVDCmd(self, mock_usergroups, mock_cvd_dir): 150 """test PrepareLaunchCVDCmd.""" 151 mock_usergroups.return_value = False 152 mock_cvd_dir.return_value = "fake_cvd_dir" 153 hw_property = {"cpu": "fake", "x_res": "fake", "y_res": "fake", 154 "dpi":"fake", "memory": "fake", "disk": "fake"} 155 constants.LIST_CF_USER_GROUPS = ["group1", "group2"] 156 157 launch_cmd = self.local_image_local_instance.PrepareLaunchCVDCmd( 158 constants.CMD_LAUNCH_CVD, hw_property, True, "fake_image_dir", 159 "fake_cvd_dir", False, None) 160 self.assertEqual(launch_cmd, self.LAUNCH_CVD_CMD_WITH_DISK) 161 162 # "disk" doesn't exist in hw_property. 163 hw_property = {"cpu": "fake", "x_res": "fake", "y_res": "fake", 164 "dpi": "fake", "memory": "fake"} 165 launch_cmd = self.local_image_local_instance.PrepareLaunchCVDCmd( 166 constants.CMD_LAUNCH_CVD, hw_property, True, "fake_image_dir", 167 "fake_cvd_dir", False, None) 168 self.assertEqual(launch_cmd, self.LAUNCH_CVD_CMD_NO_DISK) 169 170 # "gpu" is enabled with "default" 171 launch_cmd = self.local_image_local_instance.PrepareLaunchCVDCmd( 172 constants.CMD_LAUNCH_CVD, hw_property, True, "fake_image_dir", 173 "fake_cvd_dir", False, "default") 174 self.assertEqual(launch_cmd, self.LAUNCH_CVD_CMD_NO_DISK_WITH_GPU) 175 176 launch_cmd = self.local_image_local_instance.PrepareLaunchCVDCmd( 177 constants.CMD_LAUNCH_CVD, hw_property, True, "fake_image_dir", 178 "fake_cvd_dir", True, None) 179 self.assertEqual(launch_cmd, self.LAUNCH_CVD_CMD_WITH_WEBRTC) 180 181 @mock.patch.object(local_image_local_instance.LocalImageLocalInstance, 182 "_LaunchCvd") 183 @mock.patch.object(utils, "GetUserAnswerYes") 184 @mock.patch.object(list_instance, "GetActiveCVD") 185 @mock.patch.object(local_image_local_instance.LocalImageLocalInstance, 186 "IsLocalImageOccupied") 187 def testCheckLaunchCVD(self, mock_image_occupied, mock_cvd_running, 188 mock_get_answer, 189 mock_launch_cvd): 190 """test CheckLaunchCVD.""" 191 launch_cvd_cmd = "fake_launch_cvd" 192 host_bins_path = "fake_host_path" 193 local_instance_id = 3 194 local_image_path = "fake_image_path" 195 196 # Test if image is in use. 197 mock_cvd_running.return_value = False 198 mock_image_occupied.return_value = True 199 with self.assertRaises(SystemExit): 200 self.local_image_local_instance.CheckLaunchCVD(launch_cvd_cmd, 201 host_bins_path, 202 local_instance_id, 203 local_image_path) 204 # Test if launch_cvd is running. 205 mock_image_occupied.return_value = False 206 mock_cvd_running.return_value = True 207 mock_get_answer.return_value = False 208 with self.assertRaises(SystemExit): 209 self.local_image_local_instance.CheckLaunchCVD(launch_cvd_cmd, 210 host_bins_path, 211 local_instance_id, 212 local_image_path) 213 214 # Test if there's no using image and no conflict launch_cvd process. 215 mock_image_occupied.return_value = False 216 mock_cvd_running.return_value = False 217 self.local_image_local_instance.CheckLaunchCVD(launch_cvd_cmd, 218 host_bins_path, 219 local_instance_id, 220 local_image_path) 221 mock_launch_cvd.assert_called_once_with( 222 "fake_launch_cvd", 3, timeout=constants.DEFAULT_CF_BOOT_TIMEOUT) 223 224 # pylint: disable=protected-access 225 @mock.patch.dict("os.environ", clear=True) 226 def testLaunchCVD(self): 227 """test _LaunchCvd should call subprocess.Popen with the specific env""" 228 local_instance_id = 3 229 launch_cvd_cmd = "launch_cvd" 230 cvd_env = {} 231 cvd_env[constants.ENV_CVD_HOME] = "fake_home" 232 cvd_env[constants.ENV_CUTTLEFISH_INSTANCE] = str( 233 local_instance_id) 234 process = mock.MagicMock() 235 process.wait.return_value = True 236 process.returncode = 0 237 self.Patch(subprocess, "Popen", return_value=process) 238 self.Patch(instance, "GetLocalInstanceHomeDir", 239 return_value="fake_home") 240 self.Patch(os, "makedirs") 241 self.Patch(shutil, "rmtree") 242 243 self.local_image_local_instance._LaunchCvd(launch_cvd_cmd, 244 local_instance_id) 245 # pylint: disable=no-member 246 subprocess.Popen.assert_called_once_with(launch_cvd_cmd, 247 shell=True, 248 stderr=subprocess.STDOUT, 249 env=cvd_env) 250 251 252if __name__ == "__main__": 253 unittest.main() 254