blob: fa12d1f61c063e26a504f650b151849ae6008b3c [file] [log] [blame]
herbertxue34776bb2018-07-03 21:57:48 +08001#!/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 acloud.setup.gcp_setup_runner."""
17
18import unittest
19import os
20import mock
chojoyce7479ce32019-10-29 12:05:44 +080021import six
chojoyce8cec5002019-11-04 18:15:09 +080022from six import b
herbertxue34776bb2018-07-03 21:57:48 +080023
chojoyce13cb0c52019-07-01 17:24:52 +080024# pylint: disable=no-name-in-module,import-error,no-member
25from acloud import errors
26from acloud.internal.lib import utils
herbertxue34776bb2018-07-03 21:57:48 +080027from acloud.internal.proto import user_config_pb2
28from acloud.public import config
29from acloud.setup import gcp_setup_runner
30
chojoyce8cec5002019-11-04 18:15:09 +080031_GCP_USER_CONFIG = b("""
herbertxue34776bb2018-07-03 21:57:48 +080032[compute]
33region = new_region
34zone = new_zone
35[core]
36account = new@google.com
37disable_usage_reporting = False
38project = new_project
chojoyce8cec5002019-11-04 18:15:09 +080039""")
herbertxue34776bb2018-07-03 21:57:48 +080040
41
42def _CreateCfgFile():
43 """A helper method that creates a mock configuration object."""
44 default_cfg = """
45project: "fake_project"
46zone: "fake_zone"
47storage_bucket_name: "fake_bucket"
48client_id: "fake_client_id"
49client_secret: "fake_client_secret"
50"""
51 return default_cfg
52
53
54# pylint: disable=protected-access
55class AcloudGCPSetupTest(unittest.TestCase):
56 """Test GCP Setup steps."""
57
58 def setUp(self):
59 """Create config and gcp_env_runner."""
60 self.cfg_path = "acloud_unittest.config"
61 file_write = open(self.cfg_path, 'w')
62 file_write.write(_CreateCfgFile().strip())
63 file_write.close()
64 self.gcp_env_runner = gcp_setup_runner.GcpTaskRunner(self.cfg_path)
65 self.gcloud_runner = gcp_setup_runner.GoogleSDKBins("")
66
67 def tearDown(self):
68 """Remove temp file."""
69 if os.path.isfile(self.cfg_path):
70 os.remove(self.cfg_path)
71
72 def testUpdateConfigFile(self):
73 """Test update config file."""
74 # Test update project field.
75 gcp_setup_runner.UpdateConfigFile(self.cfg_path, "project",
76 "test_project")
77 cfg = config.AcloudConfigManager.LoadConfigFromProtocolBuffer(
78 open(self.cfg_path, "r"), user_config_pb2.UserConfig)
79 self.assertEqual(cfg.project, "test_project")
80 self.assertEqual(cfg.ssh_private_key_path, "")
chojoyce13cb0c52019-07-01 17:24:52 +080081 # Test add ssh key path in config.
herbertxue34776bb2018-07-03 21:57:48 +080082 gcp_setup_runner.UpdateConfigFile(self.cfg_path,
83 "ssh_private_key_path", "test_path")
84 cfg = config.AcloudConfigManager.LoadConfigFromProtocolBuffer(
85 open(self.cfg_path, "r"), user_config_pb2.UserConfig)
86 self.assertEqual(cfg.project, "test_project")
87 self.assertEqual(cfg.ssh_private_key_path, "test_path")
chojoyce13cb0c52019-07-01 17:24:52 +080088 # Test config is not a file
89 with mock.patch("os.path.isfile") as chkfile:
90 chkfile.return_value = False
91 gcp_setup_runner.UpdateConfigFile(self.cfg_path, "project",
92 "test_project")
93 cfg = config.AcloudConfigManager.LoadConfigFromProtocolBuffer(
94 open(self.cfg_path, "r"), user_config_pb2.UserConfig)
95 self.assertEqual(cfg.project, "test_project")
herbertxue34776bb2018-07-03 21:57:48 +080096
herbertxue34776bb2018-07-03 21:57:48 +080097 @mock.patch("os.path.dirname", return_value="")
herbertxueef7a9e62020-03-30 19:23:29 +080098 @mock.patch.object(utils, "CheckOutput")
herbertxue34776bb2018-07-03 21:57:48 +080099 def testSeupProjectZone(self, mock_runner, mock_path):
100 """Test setup project and zone."""
101 gcloud_runner = gcp_setup_runner.GoogleSDKBins(mock_path)
102 self.gcp_env_runner.project = "fake_project"
103 self.gcp_env_runner.zone = "fake_zone"
104 mock_runner.side_effect = [0, _GCP_USER_CONFIG]
105 self.gcp_env_runner._UpdateProject(gcloud_runner)
106 self.assertEqual(self.gcp_env_runner.project, "new_project")
107 self.assertEqual(self.gcp_env_runner.zone, "new_zone")
108
chojoyce7479ce32019-10-29 12:05:44 +0800109 @mock.patch.object(six.moves, "input")
herbertxue34776bb2018-07-03 21:57:48 +0800110 def testSetupClientIDSecret(self, mock_id):
111 """Test setup client ID and client secret."""
112 self.gcp_env_runner.client_id = "fake_client_id"
113 self.gcp_env_runner.client_secret = "fake_client_secret"
114 mock_id.side_effect = ["new_id", "new_secret"]
115 self.gcp_env_runner._SetupClientIDSecret()
116 self.assertEqual(self.gcp_env_runner.client_id, "new_id")
117 self.assertEqual(self.gcp_env_runner.client_secret, "new_secret")
118
chojoyce13cb0c52019-07-01 17:24:52 +0800119 @mock.patch.object(gcp_setup_runner, "UpdateConfigFile")
120 @mock.patch.object(utils, "CreateSshKeyPairIfNotExist")
121 def testSetupSSHKeys(self, mock_check, mock_update):
122 """Test setup the pair of the ssh key for acloud.config."""
123 # Test ssh key has already setup
124 gcp_setup_runner.SetupSSHKeys(self.cfg_path,
125 "fake_private_key_path",
126 "fake_public_key_path")
127 self.assertEqual(mock_update.call_count, 0)
128 # Test if private_key_path is empty string
129 with mock.patch('os.path.expanduser') as ssh_path:
130 ssh_path.return_value = ""
131 gcp_setup_runner.SetupSSHKeys(self.cfg_path,
132 "fake_private_key_path",
133 "fake_public_key_path")
134 mock_check.assert_called_once_with(
135 gcp_setup_runner._DEFAULT_SSH_PRIVATE_KEY,
136 gcp_setup_runner._DEFAULT_SSH_PUBLIC_KEY)
137
138 mock_update.assert_has_calls([
139 mock.call(self.cfg_path, "ssh_private_key_path",
140 gcp_setup_runner._DEFAULT_SSH_PRIVATE_KEY),
141 mock.call(self.cfg_path, "ssh_public_key_path",
142 gcp_setup_runner._DEFAULT_SSH_PUBLIC_KEY)])
143
144 @mock.patch.object(gcp_setup_runner.GcpTaskRunner, "_CreateStableHostImage")
145 @mock.patch.object(gcp_setup_runner.GcpTaskRunner, "_EnableGcloudServices")
146 @mock.patch.object(gcp_setup_runner.GcpTaskRunner, "_SetupProject")
147 @mock.patch.object(gcp_setup_runner, "GoogleSDKBins")
148 def testSetupGcloudInfo(self, mock_sdk, mock_set, mock_run, mock_create):
149 """test setup gcloud info"""
150 with mock.patch("google_sdk.GoogleSDK"):
151 self.gcp_env_runner._SetupGcloudInfo()
152 mock_sdk.assert_called_once()
153 mock_set.assert_called_once()
154 mock_run.assert_called_once()
155 mock_create.assert_called_once()
156
157 @mock.patch.object(gcp_setup_runner, "UpdateConfigFile")
158 def testCreateStableHostImage(self, mock_update):
159 """test create stable hostimage."""
160 # Test no need to create stable hose image name.
161 self.gcp_env_runner.stable_host_image_name = "fake_host_image_name"
162 self.gcp_env_runner._CreateStableHostImage()
163 self.assertEqual(mock_update.call_count, 0)
164 # Test need to reset stable hose image name.
165 self.gcp_env_runner.stable_host_image_name = ""
166 self.gcp_env_runner._CreateStableHostImage()
167 self.assertEqual(mock_update.call_count, 1)
168
herbertxueed577e82019-08-26 18:19:09 +0800169 @mock.patch.object(gcp_setup_runner.GcpTaskRunner, "_CheckBillingEnable")
chojoyce13cb0c52019-07-01 17:24:52 +0800170 @mock.patch.object(gcp_setup_runner.GcpTaskRunner, "_NeedProjectSetup")
chojoyce13cb0c52019-07-01 17:24:52 +0800171 @mock.patch.object(gcp_setup_runner.GcpTaskRunner, "_SetupClientIDSecret")
172 @mock.patch.object(gcp_setup_runner.GcpTaskRunner, "_UpdateProject")
173 def testSetupProjectNoChange(self, mock_setproj, mock_setid,
herbertxuea6a953a2019-06-25 18:29:00 +0800174 mock_chkproj, mock_check_billing):
chojoyce13cb0c52019-07-01 17:24:52 +0800175 """test setup project and project not be changed."""
176 # Test project didn't change, and no need to setup client id/secret
177 mock_chkproj.return_value = False
178 self.gcp_env_runner.client_id = "test_client_id"
179 self.gcp_env_runner._SetupProject(self.gcloud_runner)
180 self.assertEqual(mock_setproj.call_count, 0)
181 self.assertEqual(mock_setid.call_count, 0)
herbertxueed577e82019-08-26 18:19:09 +0800182 mock_check_billing.assert_called_once()
chojoyce13cb0c52019-07-01 17:24:52 +0800183 # Test project didn't change, but client_id is empty
184 self.gcp_env_runner.client_id = ""
185 self.gcp_env_runner._SetupProject(self.gcloud_runner)
186 self.assertEqual(mock_setproj.call_count, 0)
187 mock_setid.assert_called_once()
herbertxueed577e82019-08-26 18:19:09 +0800188 self.assertEqual(mock_check_billing.call_count, 2)
chojoyce13cb0c52019-07-01 17:24:52 +0800189
herbertxueed577e82019-08-26 18:19:09 +0800190 @mock.patch.object(gcp_setup_runner.GcpTaskRunner, "_CheckBillingEnable")
chojoyce13cb0c52019-07-01 17:24:52 +0800191 @mock.patch.object(gcp_setup_runner.GcpTaskRunner, "_NeedProjectSetup")
chojoyce13cb0c52019-07-01 17:24:52 +0800192 @mock.patch.object(gcp_setup_runner.GcpTaskRunner, "_SetupClientIDSecret")
193 @mock.patch.object(gcp_setup_runner.GcpTaskRunner, "_UpdateProject")
194 def testSetupProjectChanged(self, mock_setproj, mock_setid,
herbertxuea6a953a2019-06-25 18:29:00 +0800195 mock_chkproj, mock_check_billing):
chojoyce13cb0c52019-07-01 17:24:52 +0800196 """test setup project when project changed."""
197 mock_chkproj.return_value = True
198 mock_setproj.return_value = True
199 self.gcp_env_runner._SetupProject(self.gcloud_runner)
200 mock_setproj.assert_called_once()
201 mock_setid.assert_called_once()
herbertxueed577e82019-08-26 18:19:09 +0800202 mock_check_billing.assert_called_once()
chojoyce13cb0c52019-07-01 17:24:52 +0800203
204 @mock.patch.object(utils, "GetUserAnswerYes")
205 def testNeedProjectSetup(self, mock_ans):
206 """test need project setup."""
207 # Test need project setup.
208 self.gcp_env_runner.project = ""
209 self.gcp_env_runner.zone = ""
210 self.assertTrue(self.gcp_env_runner._NeedProjectSetup())
211 # Test no need project setup and get user's answer.
212 self.gcp_env_runner.project = "test_project"
213 self.gcp_env_runner.zone = "test_zone"
214 self.gcp_env_runner._NeedProjectSetup()
215 mock_ans.assert_called_once()
216
217 def testNeedClientIDSetup(self):
218 """test need client_id setup."""
219 # Test project changed.
220 self.assertTrue(self.gcp_env_runner._NeedClientIDSetup(True))
221 # Test project is not changed but client_id or client_secret is empty.
222 self.gcp_env_runner.client_id = ""
223 self.gcp_env_runner.client_secret = ""
224 self.assertTrue(self.gcp_env_runner._NeedClientIDSetup(False))
225 # Test no need client_id setup.
226 self.gcp_env_runner.client_id = "test_client_id"
227 self.gcp_env_runner.client_secret = "test_client_secret"
228 self.assertFalse(self.gcp_env_runner._NeedClientIDSetup(False))
229
herbertxueef7a9e62020-03-30 19:23:29 +0800230 @mock.patch.object(utils, "CheckOutput")
chojoyce13cb0c52019-07-01 17:24:52 +0800231 def testEnableGcloudServices(self, mock_run):
232 """test enable Gcloud services."""
herbertxue2160dd92019-10-07 17:34:37 +0800233 mock_run.return_value = ""
chojoyce13cb0c52019-07-01 17:24:52 +0800234 self.gcp_env_runner._EnableGcloudServices(self.gcloud_runner)
235 mock_run.assert_has_calls([
236 mock.call(["gcloud", "services", "enable",
herbertxueb69bc3f2020-02-04 15:28:47 +0800237 gcp_setup_runner._ANDROID_BUILD_SERVICE],
238 env=self.gcloud_runner._env, stderr=-2),
chojoyce13cb0c52019-07-01 17:24:52 +0800239 mock.call(["gcloud", "services", "enable",
herbertxueb69bc3f2020-02-04 15:28:47 +0800240 gcp_setup_runner._COMPUTE_ENGINE_SERVICE],
241 env=self.gcloud_runner._env, stderr=-2)])
herbertxue2160dd92019-10-07 17:34:37 +0800242
herbertxueef7a9e62020-03-30 19:23:29 +0800243 @mock.patch.object(utils, "CheckOutput")
herbertxue2160dd92019-10-07 17:34:37 +0800244 def testGoogleAPIService(self, mock_run):
245 """Test GoogleAPIService"""
246 api_service = gcp_setup_runner.GoogleAPIService("service_name",
247 "error_message")
248 api_service.EnableService(self.gcloud_runner)
249 mock_run.assert_has_calls([
herbertxueb69bc3f2020-02-04 15:28:47 +0800250 mock.call(["gcloud", "services", "enable", "service_name"],
251 env=self.gcloud_runner._env, stderr=-2)])
herbertxue2160dd92019-10-07 17:34:37 +0800252
herbertxueef7a9e62020-03-30 19:23:29 +0800253 @mock.patch.object(utils, "CheckOutput")
herbertxue2160dd92019-10-07 17:34:37 +0800254 def testCheckBillingEnable(self, mock_run):
255 """Test CheckBillingEnable"""
256 # Test billing account in gcp project already enabled.
257 mock_run.return_value = "billingEnabled: true"
258 self.gcp_env_runner._CheckBillingEnable(self.gcloud_runner)
259 mock_run.assert_has_calls([
herbertxueb69bc3f2020-02-04 15:28:47 +0800260 mock.call(
261 [
262 "gcloud", "alpha", "billing", "projects", "describe",
263 self.gcp_env_runner.project
264 ],
265 env=self.gcloud_runner._env)
266 ])
herbertxue2160dd92019-10-07 17:34:37 +0800267
268 # Test billing account in gcp project was not enabled.
269 mock_run.return_value = "billingEnabled: false"
270 with self.assertRaises(errors.NoBillingError):
271 self.gcp_env_runner._CheckBillingEnable(self.gcloud_runner)
herbertxue34776bb2018-07-03 21:57:48 +0800272
273
274if __name__ == "__main__":
275 unittest.main()