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