1#!/usr/bin/env python 2# 3# Copyright 2016 - 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 17"""Tests for acloud.public.config.""" 18import unittest 19import os 20import tempfile 21 22from unittest import mock 23 24import six 25 26# pylint: disable=no-name-in-module,import-error 27from acloud import errors 28from acloud.internal.proto import internal_config_pb2 29from acloud.internal.proto import user_config_pb2 30from acloud.public import config 31 32 33class AcloudConfigManagerTest(unittest.TestCase): 34 """Test acloud configuration manager.""" 35 36 USER_CONFIG = """ 37service_account_name: "fake@developer.gserviceaccount.com" 38service_account_private_key_path: "/path/to/service/account/key" 39service_account_json_private_key_path: "/path/to/service/account/json_key" 40project: "fake-project" 41zone: "us-central1-f" 42machine_type: "n1-standard-1" 43network: "default" 44ssh_private_key_path: "/path/to/ssh/key" 45storage_bucket_name: "fake_bucket" 46orientation: "portrait" 47resolution: "1200x1200x1200x1200" 48client_id: "fake_client_id" 49client_secret: "fake_client_secret" 50extra_args_ssh_tunnel: "fake_extra_args_ssh_tunnel" 51metadata_variable { 52 key: "metadata_1" 53 value: "metadata_value_1" 54} 55hw_property: "cpu:3,resolution:1080x1920,dpi:480,memory:4g,disk:10g" 56extra_scopes: "scope1" 57extra_scopes: "scope2" 58betty_image: "fake_betty_image" 59""" 60 61 INTERNAL_CONFIG = """ 62min_machine_size: "n1-standard-1" 63disk_image_name: "avd-system.tar.gz" 64disk_image_mime_type: "application/x-tar" 65disk_image_extension: ".tar.gz" 66disk_raw_image_name: "disk.raw" 67disk_raw_image_extension: ".img" 68creds_cache_file: ".fake_oauth2.dat" 69user_agent: "fake_user_agent" 70kernel_build_target: "kernel" 71emulator_build_target: "sdk_tools_linux" 72 73default_usr_cfg { 74 machine_type: "n1-standard-1" 75 network: "default" 76 stable_host_image_name: "fake_stable_host_image_name" 77 stable_host_image_project: "fake_stable_host_image_project" 78 stable_goldfish_host_image_name: "fake_stable_goldfish_host_image_name" 79 stable_goldfish_host_image_project: "fake_stable_goldfish_host_image_project" 80 instance_name_pattern: "fake_instance_name_pattern" 81 stable_cheeps_host_image_name: "fake_stable_cheeps_host_image_name" 82 stable_cheeps_host_image_project: "fake_stable_cheeps_host_image_project" 83 metadata_variable { 84 key: "metadata_1" 85 value: "metadata_value_1" 86 } 87 88 metadata_variable { 89 key: "metadata_2" 90 value: "metadata_value_2" 91 } 92} 93 94device_resolution_map { 95 key: "nexus5" 96 value: "1080x1920x32x480" 97} 98 99device_default_orientation_map { 100 key: "nexus5" 101 value: "portrait" 102} 103 104valid_branch_and_min_build_id { 105 key: "aosp-master" 106 value: 0 107} 108 109common_hw_property_map { 110 key: "phone" 111 value: "cpu:2,resolution:1080x1920,dpi:420,memory:4g,disk:8g" 112} 113 114common_hw_property_map { 115 key: "auto" 116 value: "cpu:4,resolution:1280x800,dpi:160,memory:4g" 117} 118""" 119 120 def setUp(self): 121 self.config_file = mock.MagicMock() 122 # initial config with test config. 123 self.config_file.read.return_value = self.INTERNAL_CONFIG 124 internal_cfg = config.AcloudConfigManager.LoadConfigFromProtocolBuffer( 125 self.config_file, internal_config_pb2.InternalConfig) 126 self.config_file.read.return_value = self.USER_CONFIG 127 usr_cfg = config.AcloudConfigManager.LoadConfigFromProtocolBuffer( 128 self.config_file, user_config_pb2.UserConfig) 129 self.cfg = config.AcloudConfig(usr_cfg, internal_cfg) 130 131 # pylint: disable=no-member 132 def testLoadUserConfig(self): 133 """Test loading user config.""" 134 self.config_file.read.return_value = self.USER_CONFIG 135 cfg = config.AcloudConfigManager.LoadConfigFromProtocolBuffer( 136 self.config_file, user_config_pb2.UserConfig) 137 self.assertEqual(cfg.service_account_name, 138 "fake@developer.gserviceaccount.com") 139 self.assertEqual(cfg.service_account_private_key_path, 140 "/path/to/service/account/key") 141 self.assertEqual(cfg.service_account_json_private_key_path, 142 "/path/to/service/account/json_key") 143 self.assertEqual(cfg.project, "fake-project") 144 self.assertEqual(cfg.zone, "us-central1-f") 145 self.assertEqual(cfg.machine_type, "n1-standard-1") 146 self.assertEqual(cfg.network, "default") 147 self.assertEqual(cfg.ssh_private_key_path, "/path/to/ssh/key") 148 self.assertEqual(cfg.storage_bucket_name, "fake_bucket") 149 self.assertEqual(cfg.orientation, "portrait") 150 self.assertEqual(cfg.resolution, "1200x1200x1200x1200") 151 self.assertEqual(cfg.client_id, "fake_client_id") 152 self.assertEqual(cfg.client_secret, "fake_client_secret") 153 self.assertEqual(cfg.extra_args_ssh_tunnel, "fake_extra_args_ssh_tunnel") 154 self.assertEqual( 155 {key: val for key, val in six.iteritems(cfg.metadata_variable)}, 156 {"metadata_1": "metadata_value_1"}) 157 self.assertEqual(cfg.hw_property, 158 "cpu:3,resolution:1080x1920,dpi:480,memory:4g," 159 "disk:10g") 160 self.assertEqual(cfg.extra_scopes, ["scope1", "scope2"]) 161 self.assertEqual(cfg.betty_image, "fake_betty_image") 162 163 # pylint: disable=protected-access 164 @mock.patch("os.makedirs") 165 @mock.patch("os.path.exists") 166 def testLoadUserConfigLogic(self, mock_file_exist, _mock_makedirs): 167 """Test load user config logic. 168 169 Load user config with some special design. 170 1. User specified user config: 171 If user config didn't exist: Raise exception. 172 2. User didn't specify user config, use default config: 173 If default config didn't exist: Initialize empty data. 174 """ 175 config_specify = config.AcloudConfigManager(self.config_file) 176 self.config_file.read.return_value = self.USER_CONFIG 177 self.assertEqual(config_specify.user_config_path, self.config_file) 178 mock_file_exist.return_value = False 179 with self.assertRaises(errors.ConfigError): 180 config_specify.Load() 181 # Test default config 182 config_unspecify = config.AcloudConfigManager(None) 183 cfg = config_unspecify.Load() 184 self.assertEqual(config_unspecify.user_config_path, 185 config.GetDefaultConfigFile()) 186 self.assertEqual(cfg.project, "") 187 self.assertEqual(cfg.zone, "") 188 189 # Test default user config exist 190 mock_file_exist.return_value = True 191 # Write the config data into a tmp file and have GetDefaultConfigFile 192 # return that. 193 _, temp_cfg_file_path = tempfile.mkstemp() 194 with open(temp_cfg_file_path, "w") as cfg_file: 195 cfg_file.writelines(self.USER_CONFIG) 196 default_patcher = mock.patch.object(config, "GetDefaultConfigFile", 197 return_value=temp_cfg_file_path) 198 default_patcher.start() 199 try: 200 config_exist = config.AcloudConfigManager(None) 201 cfg = config_exist.Load() 202 self.assertEqual(cfg.project, "fake-project") 203 self.assertEqual(cfg.zone, "us-central1-f") 204 self.assertEqual(cfg.client_id, "fake_client_id") 205 self.assertEqual(cfg.client_secret, "fake_client_secret") 206 finally: 207 # Delete tmp file 208 os.remove(temp_cfg_file_path) 209 default_patcher.stop() 210 211 def testLoadInternalConfig(self): 212 """Test loading internal config.""" 213 self.config_file.read.return_value = self.INTERNAL_CONFIG 214 cfg = config.AcloudConfigManager.LoadConfigFromProtocolBuffer( 215 self.config_file, internal_config_pb2.InternalConfig) 216 self.assertEqual(cfg.min_machine_size, "n1-standard-1") 217 self.assertEqual(cfg.disk_image_name, "avd-system.tar.gz") 218 self.assertEqual(cfg.disk_image_mime_type, "application/x-tar") 219 self.assertEqual(cfg.disk_image_extension, ".tar.gz") 220 self.assertEqual(cfg.disk_raw_image_name, "disk.raw") 221 self.assertEqual(cfg.disk_raw_image_extension, ".img") 222 self.assertEqual(cfg.creds_cache_file, ".fake_oauth2.dat") 223 self.assertEqual(cfg.user_agent, "fake_user_agent") 224 self.assertEqual(cfg.default_usr_cfg.machine_type, "n1-standard-1") 225 self.assertEqual(cfg.default_usr_cfg.network, "default") 226 self.assertEqual({ 227 key: val 228 for key, val in six.iteritems(cfg.default_usr_cfg.metadata_variable) 229 }, { 230 "metadata_1": "metadata_value_1", 231 "metadata_2": "metadata_value_2" 232 }) 233 self.assertEqual( 234 {key: val for key, val in six.iteritems(cfg.device_resolution_map)}, 235 {"nexus5": "1080x1920x32x480"}) 236 device_resolution = { 237 key: val 238 for key, val in six.iteritems(cfg.device_default_orientation_map) 239 } 240 self.assertEqual(device_resolution, {"nexus5": "portrait"}) 241 valid_branch_and_min_build_id = { 242 key: val 243 for key, val in six.iteritems(cfg.valid_branch_and_min_build_id) 244 } 245 self.assertEqual(valid_branch_and_min_build_id, {"aosp-master": 0}) 246 self.assertEqual(cfg.default_usr_cfg.stable_host_image_name, 247 "fake_stable_host_image_name") 248 self.assertEqual(cfg.default_usr_cfg.stable_host_image_project, 249 "fake_stable_host_image_project") 250 self.assertEqual(cfg.kernel_build_target, "kernel") 251 252 # Emulator related 253 self.assertEqual(cfg.default_usr_cfg.stable_goldfish_host_image_name, 254 "fake_stable_goldfish_host_image_name") 255 self.assertEqual(cfg.default_usr_cfg.stable_goldfish_host_image_project, 256 "fake_stable_goldfish_host_image_project") 257 self.assertEqual(cfg.emulator_build_target, "sdk_tools_linux") 258 self.assertEqual(cfg.default_usr_cfg.instance_name_pattern, 259 "fake_instance_name_pattern") 260 261 # Cheeps related 262 self.assertEqual(cfg.default_usr_cfg.stable_cheeps_host_image_name, 263 "fake_stable_cheeps_host_image_name") 264 self.assertEqual(cfg.default_usr_cfg.stable_cheeps_host_image_project, 265 "fake_stable_cheeps_host_image_project") 266 267 # hw property 268 self.assertEqual( 269 {key: val for key, val in six.iteritems(cfg.common_hw_property_map)}, 270 {"phone": "cpu:2,resolution:1080x1920,dpi:420,memory:4g,disk:8g", 271 "auto": "cpu:4,resolution:1280x800,dpi:160,memory:4g"}) 272 273 def testLoadConfigFails(self): 274 """Test loading a bad file.""" 275 self.config_file.read.return_value = "malformed text" 276 with self.assertRaises(errors.ConfigError): 277 config.AcloudConfigManager.LoadConfigFromProtocolBuffer( 278 self.config_file, internal_config_pb2.InternalConfig) 279 280 def testOverrideWithArgs(self): 281 """Test OverrideWithArgs.""" 282 # test override zone. 283 self.cfg.zone = "us-central1-f" 284 args = mock.MagicMock() 285 args.which = "create" 286 args.flavor = "phone" 287 args.zone = "us-central1-b" 288 self.cfg.OverrideWithArgs(args) 289 self.assertEqual(self.cfg.zone, "us-central1-b") 290 291 def testGetDefaultHwProperty(self): 292 """Test GetDefaultHwProperty.""" 293 # test with "phone" flavor 294 expected = "cpu:2,resolution:1080x1920,dpi:420,memory:4g,disk:8g" 295 self.assertEqual(expected, self.cfg.GetDefaultHwProperty("phone")) 296 297 # test with "auto" flavor 298 expected = "cpu:4,resolution:1280x800,dpi:160,memory:4g" 299 self.assertEqual(expected, self.cfg.GetDefaultHwProperty("auto")) 300 301 def testGetMissingFields(self): 302 """Test GetMissingFields.""" 303 fields = ["project", "zone", "hw_property"] 304 self.cfg.hw_property = "" 305 expected = ["hw_property"] 306 self.assertEqual(expected, self.cfg.GetMissingFields(fields)) 307 308 309if __name__ == "__main__": 310 unittest.main() 311