blob: 5f14f7e95a66fa23f68692a80667302a525f2027 [file] [log] [blame]
Tri Vo29ac1822016-10-01 17:06:29 -07001#!/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.
Tri Vo29ac1822016-10-01 17:06:29 -070016"""Tests for acloud.internal.lib.gcompute_client."""
Kevin Cheng5c124ec2018-05-16 13:28:51 -070017# pylint: disable=too-many-lines
Tri Vo29ac1822016-10-01 17:06:29 -070018
Kevin Cheng5c124ec2018-05-16 13:28:51 -070019import copy
Tri Vo29ac1822016-10-01 17:06:29 -070020import os
21
Kevin Cheng5c124ec2018-05-16 13:28:51 -070022import unittest
Tri Vo29ac1822016-10-01 17:06:29 -070023import mock
Kevin Cheng5c124ec2018-05-16 13:28:51 -070024
25# pylint: disable=import-error
Kevin Chengda4f07a2018-06-26 10:25:05 -070026import apiclient.http
Tri Vo29ac1822016-10-01 17:06:29 -070027
Sam Chiu7de3b232018-12-06 19:45:52 +080028from acloud import errors
cylanc2f98802019-08-15 17:47:30 +080029from acloud.internal import constants
Tri Vo29ac1822016-10-01 17:06:29 -070030from acloud.internal.lib import driver_test_lib
31from acloud.internal.lib import gcompute_client
32from acloud.internal.lib import utils
Tri Vo29ac1822016-10-01 17:06:29 -070033
herbertxue1512f8a2019-06-27 13:56:23 +080034
Kevin Chengb5963882018-05-09 00:06:27 -070035GS_IMAGE_SOURCE_URI = "https://storage.googleapis.com/fake-bucket/fake.tar.gz"
36GS_IMAGE_SOURCE_DISK = (
37 "https://www.googleapis.com/compute/v1/projects/fake-project/zones/"
38 "us-east1-d/disks/fake-disk")
39PROJECT = "fake-project"
Tri Vo29ac1822016-10-01 17:06:29 -070040
herbertxue1512f8a2019-06-27 13:56:23 +080041
Kevin Cheng5c124ec2018-05-16 13:28:51 -070042# pylint: disable=protected-access, too-many-public-methods
Kevin Cheng070ae5c2018-08-02 16:03:00 -070043class ComputeClientTest(driver_test_lib.BaseDriverTest):
Tri Vo29ac1822016-10-01 17:06:29 -070044 """Test ComputeClient."""
45
Kevin Chengb5963882018-05-09 00:06:27 -070046 PROJECT_OTHER = "fake-project-other"
Tri Vo29ac1822016-10-01 17:06:29 -070047 INSTANCE = "fake-instance"
48 IMAGE = "fake-image"
49 IMAGE_URL = "http://fake-image-url"
Kevin Chengb5963882018-05-09 00:06:27 -070050 IMAGE_OTHER = "fake-image-other"
Tri Vo29ac1822016-10-01 17:06:29 -070051 MACHINE_TYPE = "fake-machine-type"
52 MACHINE_TYPE_URL = "http://fake-machine-type-url"
53 METADATA = ("metadata_key", "metadata_value")
Kevin Chengb5963882018-05-09 00:06:27 -070054 ACCELERATOR_URL = "http://speedy-gpu"
Tri Vo29ac1822016-10-01 17:06:29 -070055 NETWORK = "fake-network"
56 NETWORK_URL = "http://fake-network-url"
Kevin Cheng480e1212018-10-24 00:23:30 -070057 SUBNETWORK_URL = "http://fake-subnetwork-url"
Tri Vo29ac1822016-10-01 17:06:29 -070058 ZONE = "fake-zone"
59 REGION = "fake-region"
60 OPERATION_NAME = "fake-op"
Kevin Chengb5963882018-05-09 00:06:27 -070061 IMAGE_FINGERPRINT = "L_NWHuz7wTY="
62 GPU = "fancy-graphics"
cylan64af2db2019-01-17 15:13:59 +080063 SSHKEY = (
64 "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDBkTOTRze9v2VOqkkf7RG"
65 "jSkg6Z2kb9Q9UHsDGatvend3fmjIw1Tugg0O7nnjlPkskmlgyd4a/j99WOeLL"
66 "CPk6xPyoVjrPUVBU/pAk09ORTC4Zqk6YjlW7LOfzvqmXhmIZfYu6Q4Yt50pZzhl"
67 "lllfu26nYjY7Tg12D019nJi/kqPX5+NKgt0LGXTu8T1r2Gav/q4V7QRWQrB8Eiu"
68 "pxXR7I2YhynqovkEt/OXG4qWgvLEXGsWtSQs0CtCzqEVxz0Y9ECr7er4VdjSQxV"
69 "AaeLAsQsK9ROae8hMBFZ3//8zLVapBwpuffCu+fUoql9qeV9xagZcc9zj8XOUOW"
70 "ApiihqNL1111 test@test1.org")
Kevin Chengc330f6f2019-05-13 09:32:42 -070071 EXTRA_SCOPES = ["scope1"]
Tri Vo29ac1822016-10-01 17:06:29 -070072
73 def setUp(self):
74 """Set up test."""
75 super(ComputeClientTest, self).setUp()
76 self.Patch(gcompute_client.ComputeClient, "InitResourceHandle")
77 fake_cfg = mock.MagicMock()
Kevin Chengb5963882018-05-09 00:06:27 -070078 fake_cfg.project = PROJECT
Kevin Chengc330f6f2019-05-13 09:32:42 -070079 fake_cfg.extra_scopes = self.EXTRA_SCOPES
Kevin Chengb5963882018-05-09 00:06:27 -070080 self.compute_client = gcompute_client.ComputeClient(
81 fake_cfg, mock.MagicMock())
Tri Vo29ac1822016-10-01 17:06:29 -070082 self.compute_client._service = mock.MagicMock()
83
Kevin Cheng5c124ec2018-05-16 13:28:51 -070084 self._disk_args = copy.deepcopy(gcompute_client.BASE_DISK_ARGS)
85 self._disk_args["initializeParams"] = {"diskName": self.INSTANCE,
86 "sourceImage": self.IMAGE_URL}
87
88 # pylint: disable=invalid-name
Tri Vo29ac1822016-10-01 17:06:29 -070089 def _SetupMocksForGetOperationStatus(self, mock_result, operation_scope):
90 """A helper class for setting up mocks for testGetOperationStatus*.
91
Kevin Chengb5963882018-05-09 00:06:27 -070092 Args:
93 mock_result: The result to return by _GetOperationStatus.
94 operation_scope: A value of OperationScope.
Tri Vo29ac1822016-10-01 17:06:29 -070095
Kevin Chengb5963882018-05-09 00:06:27 -070096 Returns:
97 A mock for Resource object.
98 """
Tri Vo29ac1822016-10-01 17:06:29 -070099 resource_mock = mock.MagicMock()
100 mock_api = mock.MagicMock()
101 if operation_scope == gcompute_client.OperationScope.GLOBAL:
102 self.compute_client._service.globalOperations = mock.MagicMock(
103 return_value=resource_mock)
104 elif operation_scope == gcompute_client.OperationScope.ZONE:
105 self.compute_client._service.zoneOperations = mock.MagicMock(
106 return_value=resource_mock)
107 elif operation_scope == gcompute_client.OperationScope.REGION:
108 self.compute_client._service.regionOperations = mock.MagicMock(
109 return_value=resource_mock)
110 resource_mock.get = mock.MagicMock(return_value=mock_api)
111 mock_api.execute = mock.MagicMock(return_value=mock_result)
112 return resource_mock
113
114 def testGetOperationStatusGlobal(self):
115 """Test _GetOperationStatus for global."""
116 resource_mock = self._SetupMocksForGetOperationStatus(
117 {"status": "GOOD"}, gcompute_client.OperationScope.GLOBAL)
118 status = self.compute_client._GetOperationStatus(
119 {"name": self.OPERATION_NAME},
120 gcompute_client.OperationScope.GLOBAL)
121 self.assertEqual(status, "GOOD")
122 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700123 project=PROJECT, operation=self.OPERATION_NAME)
Tri Vo29ac1822016-10-01 17:06:29 -0700124
125 def testGetOperationStatusZone(self):
126 """Test _GetOperationStatus for zone."""
127 resource_mock = self._SetupMocksForGetOperationStatus(
128 {"status": "GOOD"}, gcompute_client.OperationScope.ZONE)
129 status = self.compute_client._GetOperationStatus(
130 {"name": self.OPERATION_NAME}, gcompute_client.OperationScope.ZONE,
131 self.ZONE)
132 self.assertEqual(status, "GOOD")
133 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700134 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -0700135 operation=self.OPERATION_NAME,
136 zone=self.ZONE)
137
138 def testGetOperationStatusRegion(self):
139 """Test _GetOperationStatus for region."""
140 resource_mock = self._SetupMocksForGetOperationStatus(
141 {"status": "GOOD"}, gcompute_client.OperationScope.REGION)
142 self.compute_client._GetOperationStatus(
143 {"name": self.OPERATION_NAME},
144 gcompute_client.OperationScope.REGION, self.REGION)
145 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700146 project=PROJECT, operation=self.OPERATION_NAME, region=self.REGION)
Tri Vo29ac1822016-10-01 17:06:29 -0700147
148 def testGetOperationStatusError(self):
149 """Test _GetOperationStatus failed."""
150 self._SetupMocksForGetOperationStatus(
151 {"error": {"errors": ["error1", "error2"]}},
152 gcompute_client.OperationScope.GLOBAL)
153 self.assertRaisesRegexp(errors.DriverError,
154 "Get operation state failed.*error1.*error2",
155 self.compute_client._GetOperationStatus,
156 {"name": self.OPERATION_NAME},
157 gcompute_client.OperationScope.GLOBAL)
158
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700159 @mock.patch.object(errors, "GceOperationTimeoutError")
160 @mock.patch.object(utils, "PollAndWait")
161 def testWaitOnOperation(self, mock_poll, mock_gce_operation_timeout_error):
Tri Vo29ac1822016-10-01 17:06:29 -0700162 """Test WaitOnOperation."""
163 mock_error = mock.MagicMock()
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700164 mock_gce_operation_timeout_error.return_value = mock_error
Tri Vo29ac1822016-10-01 17:06:29 -0700165 self.compute_client.WaitOnOperation(
166 operation={"name": self.OPERATION_NAME},
167 operation_scope=gcompute_client.OperationScope.REGION,
168 scope_name=self.REGION)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700169 mock_poll.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700170 func=self.compute_client._GetOperationStatus,
171 expected_return="DONE",
172 timeout_exception=mock_error,
173 timeout_secs=self.compute_client.OPERATION_TIMEOUT_SECS,
Kevin Chengb5963882018-05-09 00:06:27 -0700174 sleep_interval_secs=self.compute_client.OPERATION_POLL_INTERVAL_SECS,
Tri Vo29ac1822016-10-01 17:06:29 -0700175 operation={"name": self.OPERATION_NAME},
176 operation_scope=gcompute_client.OperationScope.REGION,
177 scope_name=self.REGION)
178
Kevin Chengb5963882018-05-09 00:06:27 -0700179 def testGetImage(self):
180 """Test GetImage."""
181 resource_mock = mock.MagicMock()
182 mock_api = mock.MagicMock()
183 self.compute_client._service.images = mock.MagicMock(
184 return_value=resource_mock)
185 resource_mock.get = mock.MagicMock(return_value=mock_api)
186 mock_api.execute = mock.MagicMock(return_value={"name": self.IMAGE})
187 result = self.compute_client.GetImage(self.IMAGE)
188 self.assertEqual(result, {"name": self.IMAGE})
189 resource_mock.get.assert_called_with(project=PROJECT, image=self.IMAGE)
190
191 def testGetImageOther(self):
192 """Test GetImage with other project."""
193 resource_mock = mock.MagicMock()
194 mock_api = mock.MagicMock()
195 self.compute_client._service.images = mock.MagicMock(
196 return_value=resource_mock)
197 resource_mock.get = mock.MagicMock(return_value=mock_api)
198 mock_api.execute = mock.MagicMock(return_value={"name": self.IMAGE_OTHER})
199 result = self.compute_client.GetImage(
200 image_name=self.IMAGE_OTHER,
201 image_project=self.PROJECT_OTHER)
202 self.assertEqual(result, {"name": self.IMAGE_OTHER})
203 resource_mock.get.assert_called_with(
204 project=self.PROJECT_OTHER, image=self.IMAGE_OTHER)
205
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700206 def testCreateImageWithSourceURI(self):
207 """Test CreateImage with src uri."""
208 source_uri = GS_IMAGE_SOURCE_URI
209 source_disk = None
210 labels = None
211 expected_body = {"name": self.IMAGE,
212 "rawDisk": {"source": GS_IMAGE_SOURCE_URI}}
213 mock_check = self.Patch(gcompute_client.ComputeClient,
214 "CheckImageExists",
215 return_value=False)
216 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
217 resource_mock = mock.MagicMock()
218 self.compute_client._service.images = mock.MagicMock(
219 return_value=resource_mock)
220 resource_mock.insert = mock.MagicMock()
221 self.compute_client.CreateImage(
222 image_name=self.IMAGE, source_uri=source_uri,
223 source_disk=source_disk, labels=labels)
224 resource_mock.insert.assert_called_with(
225 project=PROJECT, body=expected_body)
226 mock_wait.assert_called_with(
227 operation=mock.ANY,
228 operation_scope=gcompute_client.OperationScope.GLOBAL)
229 mock_check.assert_called_with(self.IMAGE)
230
231 def testCreateImageWithSourceDisk(self):
232 """Test CreateImage with src disk."""
233 source_uri = None
234 source_disk = GS_IMAGE_SOURCE_DISK
235 labels = None
236 expected_body = {"name": self.IMAGE,
237 "sourceDisk": GS_IMAGE_SOURCE_DISK}
238 mock_check = self.Patch(gcompute_client.ComputeClient,
239 "CheckImageExists",
240 return_value=False)
241 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
242 resource_mock = mock.MagicMock()
243 self.compute_client._service.images = mock.MagicMock(
244 return_value=resource_mock)
245 resource_mock.insert = mock.MagicMock()
246 self.compute_client.CreateImage(
247 image_name=self.IMAGE, source_uri=source_uri,
248 source_disk=source_disk, labels=labels)
249 resource_mock.insert.assert_called_with(
250 project=PROJECT, body=expected_body)
251 mock_wait.assert_called_with(
252 operation=mock.ANY,
253 operation_scope=gcompute_client.OperationScope.GLOBAL)
254 mock_check.assert_called_with(self.IMAGE)
255
256 def testCreateImageWithSourceDiskAndLabel(self):
257 """Test CreateImage with src disk and label."""
258 source_uri = None
259 source_disk = GS_IMAGE_SOURCE_DISK
260 labels = {"label1": "xxx"}
261 expected_body = {"name": self.IMAGE,
262 "sourceDisk": GS_IMAGE_SOURCE_DISK,
263 "labels": {"label1": "xxx"}}
herbertxue308f7662018-05-18 03:25:58 +0000264 mock_check = self.Patch(gcompute_client.ComputeClient,
265 "CheckImageExists",
266 return_value=False)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700267 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
Tri Vo29ac1822016-10-01 17:06:29 -0700268 resource_mock = mock.MagicMock()
269 self.compute_client._service.images = mock.MagicMock(
270 return_value=resource_mock)
271 resource_mock.insert = mock.MagicMock()
Tri Vo29ac1822016-10-01 17:06:29 -0700272 self.compute_client.CreateImage(
Kevin Chengb5963882018-05-09 00:06:27 -0700273 image_name=self.IMAGE, source_uri=source_uri,
274 source_disk=source_disk, labels=labels)
Tri Vo29ac1822016-10-01 17:06:29 -0700275 resource_mock.insert.assert_called_with(
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700276 project=PROJECT, body=expected_body)
277 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700278 operation=mock.ANY,
279 operation_scope=gcompute_client.OperationScope.GLOBAL)
herbertxue308f7662018-05-18 03:25:58 +0000280 mock_check.assert_called_with(self.IMAGE)
Tri Vo29ac1822016-10-01 17:06:29 -0700281
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700282 @mock.patch.object(gcompute_client.ComputeClient, "GetImage")
283 def testSetImageLabel(self, mock_get_image):
284 """Test SetImageLabel."""
285 with mock.patch.object(self.compute_client._service, "images",
286 return_value=mock.MagicMock(
287 setLabels=mock.MagicMock())) as _:
288 image = {"name": self.IMAGE,
289 "sourceDisk": GS_IMAGE_SOURCE_DISK,
290 "labelFingerprint": self.IMAGE_FINGERPRINT,
291 "labels": {"a": "aaa", "b": "bbb"}}
292 mock_get_image.return_value = image
293 new_labels = {"a": "xxx", "c": "ccc"}
294 # Test
295 self.compute_client.SetImageLabels(
296 self.IMAGE, new_labels)
297 # Check result
298 expected_labels = {"a": "xxx", "b": "bbb", "c": "ccc"}
299 self.compute_client._service.images().setLabels.assert_called_with(
300 project=PROJECT,
301 resource=self.IMAGE,
302 body={
303 "labels": expected_labels,
304 "labelFingerprint": self.IMAGE_FINGERPRINT
305 })
Kevin Chengb5963882018-05-09 00:06:27 -0700306
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700307 def testCreateImageRaiseDriverErrorWithValidInput(self):
308 """Test CreateImage with valid input."""
309 source_uri = GS_IMAGE_SOURCE_URI
310 source_disk = GS_IMAGE_SOURCE_DISK
herbertxue308f7662018-05-18 03:25:58 +0000311 self.Patch(gcompute_client.ComputeClient, "CheckImageExists", return_value=False)
Kevin Chengb5963882018-05-09 00:06:27 -0700312 self.assertRaises(errors.DriverError, self.compute_client.CreateImage,
313 image_name=self.IMAGE, source_uri=source_uri,
314 source_disk=source_disk)
315
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700316 def testCreateImageRaiseDriverErrorWithInvalidInput(self):
317 """Test CreateImage with valid input."""
318 source_uri = None
319 source_disk = None
320 self.Patch(gcompute_client.ComputeClient, "CheckImageExists", return_value=False)
321 self.assertRaises(errors.DriverError, self.compute_client.CreateImage,
322 image_name=self.IMAGE, source_uri=source_uri,
323 source_disk=source_disk)
Tri Vo29ac1822016-10-01 17:06:29 -0700324
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700325 @mock.patch.object(gcompute_client.ComputeClient, "DeleteImage")
326 @mock.patch.object(gcompute_client.ComputeClient, "CheckImageExists",
herbertxue308f7662018-05-18 03:25:58 +0000327 side_effect=[False, True])
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700328 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation",
329 side_effect=errors.DriverError("Expected fake error"))
330 def testCreateImageFail(self, mock_wait, mock_check, mock_delete):
331 """Test CreateImage fails."""
Tri Vo29ac1822016-10-01 17:06:29 -0700332 resource_mock = mock.MagicMock()
333 self.compute_client._service.images = mock.MagicMock(
334 return_value=resource_mock)
335 resource_mock.insert = mock.MagicMock()
336
337 expected_body = {
338 "name": self.IMAGE,
339 "rawDisk": {
Kevin Chengb5963882018-05-09 00:06:27 -0700340 "source": GS_IMAGE_SOURCE_URI,
Tri Vo29ac1822016-10-01 17:06:29 -0700341 },
342 }
343 self.assertRaisesRegexp(
344 errors.DriverError,
345 "Expected fake error",
346 self.compute_client.CreateImage,
347 image_name=self.IMAGE,
Kevin Chengb5963882018-05-09 00:06:27 -0700348 source_uri=GS_IMAGE_SOURCE_URI)
Tri Vo29ac1822016-10-01 17:06:29 -0700349 resource_mock.insert.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700350 project=PROJECT, body=expected_body)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700351 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700352 operation=mock.ANY,
353 operation_scope=gcompute_client.OperationScope.GLOBAL)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700354 mock_check.assert_called_with(self.IMAGE)
355 mock_delete.assert_called_with(self.IMAGE)
Tri Vo29ac1822016-10-01 17:06:29 -0700356
357 def testCheckImageExistsTrue(self):
358 """Test CheckImageExists return True."""
359 resource_mock = mock.MagicMock()
360 mock_api = mock.MagicMock()
361 self.compute_client._service.images = mock.MagicMock(
362 return_value=resource_mock)
363 resource_mock.get = mock.MagicMock(return_value=mock_api)
364 mock_api.execute = mock.MagicMock(return_value={"name": self.IMAGE})
365 self.assertTrue(self.compute_client.CheckImageExists(self.IMAGE))
366
367 def testCheckImageExistsFalse(self):
368 """Test CheckImageExists return False."""
369 resource_mock = mock.MagicMock()
370 mock_api = mock.MagicMock()
371 self.compute_client._service.images = mock.MagicMock(
372 return_value=resource_mock)
373 resource_mock.get = mock.MagicMock(return_value=mock_api)
374 mock_api.execute = mock.MagicMock(
375 side_effect=errors.ResourceNotFoundError(404, "no image"))
376 self.assertFalse(self.compute_client.CheckImageExists(self.IMAGE))
377
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700378 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
379 def testDeleteImage(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700380 """Test DeleteImage."""
Tri Vo29ac1822016-10-01 17:06:29 -0700381 resource_mock = mock.MagicMock()
382 self.compute_client._service.images = mock.MagicMock(
383 return_value=resource_mock)
384 resource_mock.delete = mock.MagicMock()
385 self.compute_client.DeleteImage(self.IMAGE)
386 resource_mock.delete.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700387 project=PROJECT, image=self.IMAGE)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700388 self.assertTrue(mock_wait.called)
Tri Vo29ac1822016-10-01 17:06:29 -0700389
390 def _SetupBatchHttpRequestMock(self):
391 """Setup BatchHttpRequest mock."""
392 requests = {}
393
394 def _Add(request, callback, request_id):
395 requests[request_id] = (request, callback)
396
397 def _Execute():
398 for rid in requests:
399 _, callback = requests[rid]
400 callback(
401 request_id=rid, response=mock.MagicMock(), exception=None)
Tri Vo29ac1822016-10-01 17:06:29 -0700402 mock_batch = mock.MagicMock()
403 mock_batch.add = _Add
404 mock_batch.execute = _Execute
405 self.Patch(apiclient.http, "BatchHttpRequest", return_value=mock_batch)
406
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700407 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
408 def testDeleteImages(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700409 """Test DeleteImages."""
410 self._SetupBatchHttpRequestMock()
Tri Vo29ac1822016-10-01 17:06:29 -0700411 fake_images = ["fake_image_1", "fake_image_2"]
412 mock_api = mock.MagicMock()
413 resource_mock = mock.MagicMock()
414 self.compute_client._service.images = mock.MagicMock(
415 return_value=resource_mock)
416 resource_mock.delete = mock.MagicMock(return_value=mock_api)
417 # Call the API.
418 deleted, failed, error_msgs = self.compute_client.DeleteImages(
419 fake_images)
420 # Verify
Kevin Chengb5963882018-05-09 00:06:27 -0700421 calls = [
422 mock.call(project=PROJECT, image="fake_image_1"),
423 mock.call(project=PROJECT, image="fake_image_2")
424 ]
Tri Vo29ac1822016-10-01 17:06:29 -0700425 resource_mock.delete.assert_has_calls(calls, any_order=True)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700426 self.assertEqual(mock_wait.call_count, 2)
Tri Vo29ac1822016-10-01 17:06:29 -0700427 self.assertEqual(error_msgs, [])
428 self.assertEqual(failed, [])
429 self.assertEqual(set(deleted), set(fake_images))
430
431 def testListImages(self):
432 """Test ListImages."""
433 fake_token = "fake_next_page_token"
434 image_1 = "image_1"
435 image_2 = "image_2"
436 response_1 = {"items": [image_1], "nextPageToken": fake_token}
437 response_2 = {"items": [image_2]}
438 self.Patch(
439 gcompute_client.ComputeClient,
440 "Execute",
441 side_effect=[response_1, response_2])
442 resource_mock = mock.MagicMock()
443 self.compute_client._service.images = mock.MagicMock(
444 return_value=resource_mock)
445 resource_mock.list = mock.MagicMock()
446 images = self.compute_client.ListImages()
447 calls = [
Kevin Chengb5963882018-05-09 00:06:27 -0700448 mock.call(project=PROJECT, filter=None, pageToken=None),
449 mock.call(project=PROJECT, filter=None, pageToken=fake_token)
Tri Vo29ac1822016-10-01 17:06:29 -0700450 ]
451 resource_mock.list.assert_has_calls(calls)
452 self.assertEqual(images, [image_1, image_2])
453
Kevin Chengb5963882018-05-09 00:06:27 -0700454 def testListImagesFromExternalProject(self):
455 """Test ListImages which accepts different project."""
456 image = "image_1"
457 response = {"items": [image]}
458 self.Patch(gcompute_client.ComputeClient, "Execute", side_effect=[response])
459 resource_mock = mock.MagicMock()
460 self.compute_client._service.images = mock.MagicMock(
461 return_value=resource_mock)
462 resource_mock.list = mock.MagicMock()
463 images = self.compute_client.ListImages(
464 image_project="fake-project-2")
465 calls = [
466 mock.call(project="fake-project-2", filter=None, pageToken=None)]
467 resource_mock.list.assert_has_calls(calls)
468 self.assertEqual(images, [image])
469
Tri Vo29ac1822016-10-01 17:06:29 -0700470 def testGetInstance(self):
471 """Test GetInstance."""
472 resource_mock = mock.MagicMock()
473 mock_api = mock.MagicMock()
474 self.compute_client._service.instances = mock.MagicMock(
475 return_value=resource_mock)
476 resource_mock.get = mock.MagicMock(return_value=mock_api)
477 mock_api.execute = mock.MagicMock(return_value={"name": self.INSTANCE})
478 result = self.compute_client.GetInstance(self.INSTANCE, self.ZONE)
479 self.assertEqual(result, {"name": self.INSTANCE})
480 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700481 project=PROJECT, zone=self.ZONE, instance=self.INSTANCE)
Tri Vo29ac1822016-10-01 17:06:29 -0700482
483 def testListInstances(self):
484 """Test ListInstances."""
485 fake_token = "fake_next_page_token"
486 instance_1 = "instance_1"
487 instance_2 = "instance_2"
488 response_1 = {"items": [instance_1], "nextPageToken": fake_token}
489 response_2 = {"items": [instance_2]}
490 self.Patch(
491 gcompute_client.ComputeClient,
492 "Execute",
493 side_effect=[response_1, response_2])
494 resource_mock = mock.MagicMock()
495 self.compute_client._service.instances = mock.MagicMock(
496 return_value=resource_mock)
497 resource_mock.list = mock.MagicMock()
498 instances = self.compute_client.ListInstances(self.ZONE)
499 calls = [
500 mock.call(
Kevin Chengb5963882018-05-09 00:06:27 -0700501 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -0700502 zone=self.ZONE,
503 filter=None,
504 pageToken=None),
505 mock.call(
Kevin Chengb5963882018-05-09 00:06:27 -0700506 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -0700507 zone=self.ZONE,
508 filter=None,
509 pageToken=fake_token),
510 ]
511 resource_mock.list.assert_has_calls(calls)
512 self.assertEqual(instances, [instance_1, instance_2])
513
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700514 @mock.patch.object(gcompute_client.ComputeClient, "GetImage")
515 @mock.patch.object(gcompute_client.ComputeClient, "GetNetworkUrl")
Kevin Cheng480e1212018-10-24 00:23:30 -0700516 @mock.patch.object(gcompute_client.ComputeClient, "GetSubnetworkUrl")
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700517 @mock.patch.object(gcompute_client.ComputeClient, "GetMachineType")
518 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
cylanc2f98802019-08-15 17:47:30 +0800519 @mock.patch("getpass.getuser", return_value="fake_user")
520 def testCreateInstance(self, _get_user, mock_wait, mock_get_mach_type,
Kevin Cheng480e1212018-10-24 00:23:30 -0700521 mock_get_subnetwork_url, mock_get_network_url,
522 mock_get_image):
Tri Vo29ac1822016-10-01 17:06:29 -0700523 """Test CreateInstance."""
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700524 mock_get_mach_type.return_value = {"selfLink": self.MACHINE_TYPE_URL}
525 mock_get_network_url.return_value = self.NETWORK_URL
Kevin Cheng480e1212018-10-24 00:23:30 -0700526 mock_get_subnetwork_url.return_value = self.SUBNETWORK_URL
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700527 mock_get_image.return_value = {"selfLink": self.IMAGE_URL}
Tri Vo29ac1822016-10-01 17:06:29 -0700528 resource_mock = mock.MagicMock()
529 self.compute_client._service.instances = mock.MagicMock(
530 return_value=resource_mock)
531 resource_mock.insert = mock.MagicMock()
herbertxue308f7662018-05-18 03:25:58 +0000532 self.Patch(
533 self.compute_client,
534 "_GetExtraDiskArgs",
535 return_value=[{"fake_extra_arg": "fake_extra_value"}])
536 extra_disk_name = "gce-x86-userdebug-2345-abcd-data"
537 expected_disk_args = [self._disk_args]
538 expected_disk_args.extend([{"fake_extra_arg": "fake_extra_value"}])
Kevin Chengc330f6f2019-05-13 09:32:42 -0700539 expected_scope = []
540 expected_scope.extend(self.compute_client.DEFAULT_INSTANCE_SCOPE)
541 expected_scope.extend(self.EXTRA_SCOPES)
Tri Vo29ac1822016-10-01 17:06:29 -0700542
543 expected_body = {
544 "machineType": self.MACHINE_TYPE_URL,
545 "name": self.INSTANCE,
546 "networkInterfaces": [
547 {
548 "network": self.NETWORK_URL,
Kevin Cheng480e1212018-10-24 00:23:30 -0700549 "subnetwork": self.SUBNETWORK_URL,
Tri Vo29ac1822016-10-01 17:06:29 -0700550 "accessConfigs": [
551 {"name": "External NAT",
552 "type": "ONE_TO_ONE_NAT"}
553 ],
554 }
555 ],
herbertxue308f7662018-05-18 03:25:58 +0000556 "disks": expected_disk_args,
Tri Vo29ac1822016-10-01 17:06:29 -0700557 "serviceAccounts": [
558 {"email": "default",
Kevin Chengc330f6f2019-05-13 09:32:42 -0700559 "scopes": expected_scope}
Tri Vo29ac1822016-10-01 17:06:29 -0700560 ],
561 "metadata": {
562 "items": [{"key": self.METADATA[0],
563 "value": self.METADATA[1]}],
564 },
cylanc2f98802019-08-15 17:47:30 +0800565 "labels":{constants.LABEL_CREATE_BY: "fake_user"},
Tri Vo29ac1822016-10-01 17:06:29 -0700566 }
567
568 self.compute_client.CreateInstance(
569 instance=self.INSTANCE,
570 image_name=self.IMAGE,
571 machine_type=self.MACHINE_TYPE,
572 metadata={self.METADATA[0]: self.METADATA[1]},
573 network=self.NETWORK,
herbertxue308f7662018-05-18 03:25:58 +0000574 zone=self.ZONE,
Kevin Chengc330f6f2019-05-13 09:32:42 -0700575 extra_disk_name=extra_disk_name,
576 extra_scopes=self.EXTRA_SCOPES)
Tri Vo29ac1822016-10-01 17:06:29 -0700577
578 resource_mock.insert.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700579 project=PROJECT, zone=self.ZONE, body=expected_body)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700580 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700581 mock.ANY,
582 operation_scope=gcompute_client.OperationScope.ZONE,
583 scope_name=self.ZONE)
584
Erwin Jansenf39798d2019-05-14 21:06:44 -0700585
586 @mock.patch.object(gcompute_client.ComputeClient, "GetImage")
587 @mock.patch.object(gcompute_client.ComputeClient, "GetNetworkUrl")
588 @mock.patch.object(gcompute_client.ComputeClient, "GetSubnetworkUrl")
589 @mock.patch.object(gcompute_client.ComputeClient, "GetMachineType")
590 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
cylanc2f98802019-08-15 17:47:30 +0800591 @mock.patch("getpass.getuser", return_value="fake_user")
herbertxue1512f8a2019-06-27 13:56:23 +0800592 def testCreateInstanceWithTags(self,
cylanc2f98802019-08-15 17:47:30 +0800593 _get_user,
herbertxue1512f8a2019-06-27 13:56:23 +0800594 mock_wait,
595 mock_get_mach_type,
596 mock_get_subnetwork_url,
597 mock_get_network_url,
598 mock_get_image):
Erwin Jansenf39798d2019-05-14 21:06:44 -0700599 """Test CreateInstance."""
600 mock_get_mach_type.return_value = {"selfLink": self.MACHINE_TYPE_URL}
601 mock_get_network_url.return_value = self.NETWORK_URL
602 mock_get_subnetwork_url.return_value = self.SUBNETWORK_URL
603 mock_get_image.return_value = {"selfLink": self.IMAGE_URL}
604 resource_mock = mock.MagicMock()
605 self.compute_client._service.instances = mock.MagicMock(
606 return_value=resource_mock)
607 resource_mock.insert = mock.MagicMock()
608 self.Patch(
609 self.compute_client,
610 "_GetExtraDiskArgs",
611 return_value=[{"fake_extra_arg": "fake_extra_value"}])
612 extra_disk_name = "gce-x86-userdebug-2345-abcd-data"
613 expected_disk_args = [self._disk_args]
614 expected_disk_args.extend([{"fake_extra_arg": "fake_extra_value"}])
615 expected_scope = []
616 expected_scope.extend(self.compute_client.DEFAULT_INSTANCE_SCOPE)
617 expected_scope.extend(self.EXTRA_SCOPES)
618
619 expected_body = {
620 "machineType": self.MACHINE_TYPE_URL,
621 "name": self.INSTANCE,
622 "networkInterfaces": [
623 {
624 "network": self.NETWORK_URL,
625 "subnetwork": self.SUBNETWORK_URL,
626 "accessConfigs": [
627 {"name": "External NAT",
628 "type": "ONE_TO_ONE_NAT"}
629 ],
630 }
631 ],
632 'tags': {'items': ['https-server']},
633 "disks": expected_disk_args,
634 "serviceAccounts": [
635 {"email": "default",
636 "scopes": expected_scope}
637 ],
638 "metadata": {
639 "items": [{"key": self.METADATA[0],
640 "value": self.METADATA[1]}],
641 },
cylanc2f98802019-08-15 17:47:30 +0800642 "labels":{'created_by': "fake_user"},
Erwin Jansenf39798d2019-05-14 21:06:44 -0700643 }
644
645 self.compute_client.CreateInstance(
646 instance=self.INSTANCE,
647 image_name=self.IMAGE,
648 machine_type=self.MACHINE_TYPE,
649 metadata={self.METADATA[0]: self.METADATA[1]},
650 network=self.NETWORK,
651 zone=self.ZONE,
652 extra_disk_name=extra_disk_name,
653 tags=["https-server"],
654 extra_scopes=self.EXTRA_SCOPES)
655
656 resource_mock.insert.assert_called_with(
657 project=PROJECT, zone=self.ZONE, body=expected_body)
658 mock_wait.assert_called_with(
659 mock.ANY,
660 operation_scope=gcompute_client.OperationScope.ZONE,
661 scope_name=self.ZONE)
662
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700663 @mock.patch.object(gcompute_client.ComputeClient, "GetAcceleratorUrl")
664 @mock.patch.object(gcompute_client.ComputeClient, "GetImage")
665 @mock.patch.object(gcompute_client.ComputeClient, "GetNetworkUrl")
Kevin Cheng480e1212018-10-24 00:23:30 -0700666 @mock.patch.object(gcompute_client.ComputeClient, "GetSubnetworkUrl")
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700667 @mock.patch.object(gcompute_client.ComputeClient, "GetMachineType")
668 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
cylanc2f98802019-08-15 17:47:30 +0800669 @mock.patch("getpass.getuser", return_value="fake_user")
670 def testCreateInstanceWithGpu(self, _get_user, mock_wait, mock_get_mach,
Kevin Cheng480e1212018-10-24 00:23:30 -0700671 mock_get_subnetwork, mock_get_network,
672 mock_get_image, mock_get_accel):
Kevin Chengb5963882018-05-09 00:06:27 -0700673 """Test CreateInstance with a GPU parameter not set to None."""
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700674 mock_get_mach.return_value = {"selfLink": self.MACHINE_TYPE_URL}
675 mock_get_network.return_value = self.NETWORK_URL
Kevin Cheng480e1212018-10-24 00:23:30 -0700676 mock_get_subnetwork.return_value = self.SUBNETWORK_URL
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700677 mock_get_accel.return_value = self.ACCELERATOR_URL
678 mock_get_image.return_value = {"selfLink": self.IMAGE_URL}
Kevin Chengb5963882018-05-09 00:06:27 -0700679
680 resource_mock = mock.MagicMock()
681 self.compute_client._service.instances = mock.MagicMock(
682 return_value=resource_mock)
683 resource_mock.insert = mock.MagicMock()
684
685 expected_body = {
686 "machineType":
687 self.MACHINE_TYPE_URL,
688 "name":
689 self.INSTANCE,
690 "networkInterfaces": [{
Kevin Cheng480e1212018-10-24 00:23:30 -0700691 "network": self.NETWORK_URL,
692 "subnetwork": self.SUBNETWORK_URL,
Kevin Chengb5963882018-05-09 00:06:27 -0700693 "accessConfigs": [{
694 "name": "External NAT",
695 "type": "ONE_TO_ONE_NAT"
696 }],
697 }],
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700698 "disks": [self._disk_args],
Kevin Chengb5963882018-05-09 00:06:27 -0700699 "serviceAccounts": [{
700 "email": "default",
701 "scopes": self.compute_client.DEFAULT_INSTANCE_SCOPE
702 }],
703 "scheduling": {
704 "onHostMaintenance": "terminate"
705 },
706 "guestAccelerators": [{
707 "acceleratorCount": 1,
708 "acceleratorType": "http://speedy-gpu"
709 }],
710 "metadata": {
711 "items": [{
712 "key": self.METADATA[0],
713 "value": self.METADATA[1]
714 }],
715 },
cylanc2f98802019-08-15 17:47:30 +0800716 "labels":{'created_by': "fake_user"},
Kevin Chengb5963882018-05-09 00:06:27 -0700717 }
718
719 self.compute_client.CreateInstance(
720 instance=self.INSTANCE,
721 image_name=self.IMAGE,
722 machine_type=self.MACHINE_TYPE,
723 metadata={self.METADATA[0]: self.METADATA[1]},
724 network=self.NETWORK,
725 zone=self.ZONE,
Kevin Chengc330f6f2019-05-13 09:32:42 -0700726 gpu=self.GPU,
727 extra_scopes=None)
Kevin Chengb5963882018-05-09 00:06:27 -0700728
729 resource_mock.insert.assert_called_with(
730 project=PROJECT, zone=self.ZONE, body=expected_body)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700731 mock_wait.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700732 mock.ANY, operation_scope=gcompute_client.OperationScope.ZONE,
733 scope_name=self.ZONE)
734
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700735 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
736 def testDeleteInstance(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700737 """Test DeleteInstance."""
Tri Vo29ac1822016-10-01 17:06:29 -0700738 resource_mock = mock.MagicMock()
739 self.compute_client._service.instances = mock.MagicMock(
740 return_value=resource_mock)
741 resource_mock.delete = mock.MagicMock()
742 self.compute_client.DeleteInstance(
743 instance=self.INSTANCE, zone=self.ZONE)
744 resource_mock.delete.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700745 project=PROJECT, zone=self.ZONE, instance=self.INSTANCE)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700746 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700747 mock.ANY,
748 operation_scope=gcompute_client.OperationScope.ZONE,
749 scope_name=self.ZONE)
750
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700751 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
752 def testDeleteInstances(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700753 """Test DeleteInstances."""
754 self._SetupBatchHttpRequestMock()
Tri Vo29ac1822016-10-01 17:06:29 -0700755 fake_instances = ["fake_instance_1", "fake_instance_2"]
756 mock_api = mock.MagicMock()
757 resource_mock = mock.MagicMock()
758 self.compute_client._service.instances = mock.MagicMock(
759 return_value=resource_mock)
760 resource_mock.delete = mock.MagicMock(return_value=mock_api)
761 deleted, failed, error_msgs = self.compute_client.DeleteInstances(
762 fake_instances, self.ZONE)
763 calls = [
764 mock.call(
Kevin Chengb5963882018-05-09 00:06:27 -0700765 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -0700766 instance="fake_instance_1",
Kevin Chengb5963882018-05-09 00:06:27 -0700767 zone=self.ZONE),
768 mock.call(
769 project=PROJECT,
770 instance="fake_instance_2",
771 zone=self.ZONE)
Tri Vo29ac1822016-10-01 17:06:29 -0700772 ]
773 resource_mock.delete.assert_has_calls(calls, any_order=True)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700774 self.assertEqual(mock_wait.call_count, 2)
Tri Vo29ac1822016-10-01 17:06:29 -0700775 self.assertEqual(error_msgs, [])
776 self.assertEqual(failed, [])
777 self.assertEqual(set(deleted), set(fake_instances))
778
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700779 def testCreateDiskWithProject(self):
780 """Test CreateDisk with images using a set project."""
781 source_project = "fake-image-project"
782 expected_project_to_use = "fake-image-project"
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700783 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
Kevin Chengb5963882018-05-09 00:06:27 -0700784 resource_mock = mock.MagicMock()
785 self.compute_client._service.disks = mock.MagicMock(
786 return_value=resource_mock)
787 resource_mock.insert = mock.MagicMock()
788 self.compute_client.CreateDisk(
789 "fake_disk", "fake_image", 10, self.ZONE, source_project=source_project)
790 resource_mock.insert.assert_called_with(
791 project=PROJECT,
792 zone=self.ZONE,
793 sourceImage="projects/%s/global/images/fake_image" %
794 expected_project_to_use,
795 body={
796 "name":
797 "fake_disk",
798 "sizeGb":
799 10,
800 "type":
801 "projects/%s/zones/%s/diskTypes/pd-standard" % (PROJECT,
802 self.ZONE)
803 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700804 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700805
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700806 def testCreateDiskWithNoSourceProject(self):
807 """Test CreateDisk with images with no set project."""
808 source_project = None
809 expected_project_to_use = PROJECT
810 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
811 resource_mock = mock.MagicMock()
812 self.compute_client._service.disks = mock.MagicMock(
813 return_value=resource_mock)
814 resource_mock.insert = mock.MagicMock()
815 self.compute_client.CreateDisk(
816 "fake_disk", "fake_image", 10, self.ZONE, source_project=source_project)
817 resource_mock.insert.assert_called_with(
818 project=PROJECT,
819 zone=self.ZONE,
820 sourceImage="projects/%s/global/images/fake_image" %
821 expected_project_to_use,
822 body={
823 "name":
824 "fake_disk",
825 "sizeGb":
826 10,
827 "type":
828 "projects/%s/zones/%s/diskTypes/pd-standard" % (PROJECT,
829 self.ZONE)
830 })
831 self.assertTrue(mock_wait.called)
832
833 def testCreateDiskWithTypeStandard(self):
834 """Test CreateDisk with images using standard."""
835 disk_type = gcompute_client.PersistentDiskType.STANDARD
836 expected_disk_type_string = "pd-standard"
837 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
838 resource_mock = mock.MagicMock()
839 self.compute_client._service.disks = mock.MagicMock(
840 return_value=resource_mock)
841 resource_mock.insert = mock.MagicMock()
842 self.compute_client.CreateDisk(
843 "fake_disk",
844 "fake_image",
845 10,
846 self.ZONE,
847 source_project="fake-project",
848 disk_type=disk_type)
849 resource_mock.insert.assert_called_with(
850 project=PROJECT,
851 zone=self.ZONE,
852 sourceImage="projects/%s/global/images/fake_image" % "fake-project",
853 body={
854 "name":
855 "fake_disk",
856 "sizeGb":
857 10,
858 "type":
859 "projects/%s/zones/%s/diskTypes/%s" %
860 (PROJECT, self.ZONE, expected_disk_type_string)
861 })
862 self.assertTrue(mock_wait.called)
863
864 def testCreateDiskWithTypeSSD(self):
865 """Test CreateDisk with images using standard."""
866 disk_type = gcompute_client.PersistentDiskType.SSD
867 expected_disk_type_string = "pd-ssd"
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700868 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
Kevin Chengb5963882018-05-09 00:06:27 -0700869 resource_mock = mock.MagicMock()
870 self.compute_client._service.disks = mock.MagicMock(
871 return_value=resource_mock)
872 resource_mock.insert = mock.MagicMock()
873 self.compute_client.CreateDisk(
874 "fake_disk",
875 "fake_image",
876 10,
877 self.ZONE,
878 source_project="fake-project",
879 disk_type=disk_type)
880 resource_mock.insert.assert_called_with(
881 project=PROJECT,
882 zone=self.ZONE,
883 sourceImage="projects/%s/global/images/fake_image" % "fake-project",
884 body={
885 "name":
886 "fake_disk",
887 "sizeGb":
888 10,
889 "type":
890 "projects/%s/zones/%s/diskTypes/%s" %
891 (PROJECT, self.ZONE, expected_disk_type_string)
892 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700893 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700894
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700895 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
896 def testAttachDisk(self, mock_wait):
Kevin Chengb5963882018-05-09 00:06:27 -0700897 """Test AttachDisk."""
Kevin Chengb5963882018-05-09 00:06:27 -0700898 resource_mock = mock.MagicMock()
899 self.compute_client._service.instances = mock.MagicMock(
900 return_value=resource_mock)
901 resource_mock.attachDisk = mock.MagicMock()
902 self.compute_client.AttachDisk(
903 "fake_instance_1", self.ZONE, deviceName="fake_disk",
904 source="fake-selfLink")
905 resource_mock.attachDisk.assert_called_with(
906 project=PROJECT,
907 zone=self.ZONE,
908 instance="fake_instance_1",
909 body={
910 "deviceName": "fake_disk",
911 "source": "fake-selfLink"
912 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700913 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700914
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700915 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
916 def testDetachDisk(self, mock_wait):
Kevin Chengb5963882018-05-09 00:06:27 -0700917 """Test DetachDisk."""
Kevin Chengb5963882018-05-09 00:06:27 -0700918 resource_mock = mock.MagicMock()
919 self.compute_client._service.instances = mock.MagicMock(
920 return_value=resource_mock)
921 resource_mock.detachDisk = mock.MagicMock()
922 self.compute_client.DetachDisk("fake_instance_1", self.ZONE, "fake_disk")
923 resource_mock.detachDisk.assert_called_with(
924 project=PROJECT,
925 zone=self.ZONE,
926 instance="fake_instance_1",
927 deviceName="fake_disk")
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700928 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700929
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700930 @mock.patch.object(gcompute_client.ComputeClient, "GetAcceleratorUrl")
931 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
932 def testAttachAccelerator(self, mock_wait, mock_get_accel):
Kevin Chengb5963882018-05-09 00:06:27 -0700933 """Test AttachAccelerator."""
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700934 mock_get_accel.return_value = self.ACCELERATOR_URL
Kevin Chengb5963882018-05-09 00:06:27 -0700935 resource_mock = mock.MagicMock()
936 self.compute_client._service.instances = mock.MagicMock(
937 return_value=resource_mock)
938 resource_mock.attachAccelerator = mock.MagicMock()
939 self.compute_client.AttachAccelerator("fake_instance_1", self.ZONE, 1,
940 "nvidia-tesla-k80")
941 resource_mock.setMachineResources.assert_called_with(
942 project=PROJECT,
943 zone=self.ZONE,
944 instance="fake_instance_1",
945 body={
946 "guestAccelerators": [{
947 "acceleratorType": self.ACCELERATOR_URL,
948 "acceleratorCount": 1
949 }]
950 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700951 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700952
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700953 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
954 def testBatchExecuteOnInstances(self, mock_wait):
955 """Test BatchExecuteOnInstances."""
Tri Vo29ac1822016-10-01 17:06:29 -0700956 self._SetupBatchHttpRequestMock()
Tri Vo29ac1822016-10-01 17:06:29 -0700957 action = mock.MagicMock(return_value=mock.MagicMock())
958 fake_instances = ["fake_instance_1", "fake_instance_2"]
959 done, failed, error_msgs = self.compute_client._BatchExecuteOnInstances(
960 fake_instances, self.ZONE, action)
961 calls = [mock.call(instance="fake_instance_1"),
962 mock.call(instance="fake_instance_2")]
963 action.assert_has_calls(calls, any_order=True)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700964 self.assertEqual(mock_wait.call_count, 2)
Tri Vo29ac1822016-10-01 17:06:29 -0700965 self.assertEqual(set(done), set(fake_instances))
966 self.assertEqual(error_msgs, [])
967 self.assertEqual(failed, [])
968
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700969 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
970 def testResetInstance(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700971 """Test ResetInstance."""
Tri Vo29ac1822016-10-01 17:06:29 -0700972 resource_mock = mock.MagicMock()
973 self.compute_client._service.instances = mock.MagicMock(
974 return_value=resource_mock)
975 resource_mock.reset = mock.MagicMock()
976 self.compute_client.ResetInstance(
977 instance=self.INSTANCE, zone=self.ZONE)
978 resource_mock.reset.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700979 project=PROJECT, zone=self.ZONE, instance=self.INSTANCE)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700980 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700981 mock.ANY,
982 operation_scope=gcompute_client.OperationScope.ZONE,
983 scope_name=self.ZONE)
984
985 def _CompareMachineSizeTestHelper(self,
986 machine_info_1,
987 machine_info_2,
988 expected_result=None,
989 expected_error_type=None):
990 """Helper class for testing CompareMachineSize.
991
Kevin Chengb5963882018-05-09 00:06:27 -0700992 Args:
993 machine_info_1: A dictionary representing the first machine size.
994 machine_info_2: A dictionary representing the second machine size.
995 expected_result: An integer, 0, 1 or -1, or None if not set.
996 expected_error_type: An exception type, if set will check for exception.
997 """
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700998 mock_get_mach_type = self.Patch(
Tri Vo29ac1822016-10-01 17:06:29 -0700999 gcompute_client.ComputeClient,
1000 "GetMachineType",
1001 side_effect=[machine_info_1, machine_info_2])
1002 if expected_error_type:
1003 self.assertRaises(expected_error_type,
1004 self.compute_client.CompareMachineSize, "name1",
1005 "name2", self.ZONE)
1006 else:
1007 result = self.compute_client.CompareMachineSize("name1", "name2",
1008 self.ZONE)
1009 self.assertEqual(result, expected_result)
1010
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001011 mock_get_mach_type.assert_has_calls(
Tri Vo29ac1822016-10-01 17:06:29 -07001012 [mock.call("name1", self.ZONE), mock.call("name2", self.ZONE)])
1013
1014 def testCompareMachineSizeSmall(self):
1015 """Test CompareMachineSize where the first one is smaller."""
1016 machine_info_1 = {"guestCpus": 10, "memoryMb": 100}
1017 machine_info_2 = {"guestCpus": 10, "memoryMb": 200}
1018 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, -1)
1019
Kevin Cheng4ae42772018-10-02 11:39:48 -07001020 def testCompareMachineSizeSmallSmallerOnSecond(self):
1021 """Test CompareMachineSize where the first one is smaller."""
1022 machine_info_1 = {"guestCpus": 11, "memoryMb": 100}
1023 machine_info_2 = {"guestCpus": 10, "memoryMb": 200}
1024 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, -1)
1025
Tri Vo29ac1822016-10-01 17:06:29 -07001026 def testCompareMachineSizeLarge(self):
1027 """Test CompareMachineSize where the first one is larger."""
Kevin Cheng4ae42772018-10-02 11:39:48 -07001028 machine_info_1 = {"guestCpus": 11, "memoryMb": 200}
1029 machine_info_2 = {"guestCpus": 10, "memoryMb": 100}
1030 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, 1)
1031
1032 def testCompareMachineSizeLargeWithEqualElement(self):
1033 """Test CompareMachineSize where the first one is larger."""
Tri Vo29ac1822016-10-01 17:06:29 -07001034 machine_info_1 = {"guestCpus": 10, "memoryMb": 200}
1035 machine_info_2 = {"guestCpus": 10, "memoryMb": 100}
1036 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, 1)
1037
1038 def testCompareMachineSizeEqual(self):
1039 """Test CompareMachineSize where two machine sizes are equal."""
1040 machine_info = {"guestCpus": 10, "memoryMb": 100}
1041 self._CompareMachineSizeTestHelper(machine_info, machine_info, 0)
1042
1043 def testCompareMachineSizeBadMetric(self):
1044 """Test CompareMachineSize with bad metric."""
Kevin Chengb5963882018-05-09 00:06:27 -07001045 machine_info = {"unknown_metric": 10, "memoryMb": 100}
Tri Vo29ac1822016-10-01 17:06:29 -07001046 self._CompareMachineSizeTestHelper(
1047 machine_info, machine_info, expected_error_type=errors.DriverError)
1048
1049 def testGetMachineType(self):
1050 """Test GetMachineType."""
1051 resource_mock = mock.MagicMock()
1052 mock_api = mock.MagicMock()
1053 self.compute_client._service.machineTypes = mock.MagicMock(
1054 return_value=resource_mock)
1055 resource_mock.get = mock.MagicMock(return_value=mock_api)
1056 mock_api.execute = mock.MagicMock(
1057 return_value={"name": self.MACHINE_TYPE})
1058 result = self.compute_client.GetMachineType(self.MACHINE_TYPE,
1059 self.ZONE)
1060 self.assertEqual(result, {"name": self.MACHINE_TYPE})
1061 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -07001062 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -07001063 zone=self.ZONE,
1064 machineType=self.MACHINE_TYPE)
1065
1066 def _GetSerialPortOutputTestHelper(self, response):
1067 """Helper function for testing GetSerialPortOutput.
1068
Kevin Chengb5963882018-05-09 00:06:27 -07001069 Args:
1070 response: A dictionary representing a fake response.
1071 """
Tri Vo29ac1822016-10-01 17:06:29 -07001072 resource_mock = mock.MagicMock()
1073 mock_api = mock.MagicMock()
1074 self.compute_client._service.instances = mock.MagicMock(
1075 return_value=resource_mock)
1076 resource_mock.getSerialPortOutput = mock.MagicMock(
1077 return_value=mock_api)
1078 mock_api.execute = mock.MagicMock(return_value=response)
1079
1080 if "contents" in response:
1081 result = self.compute_client.GetSerialPortOutput(
1082 instance=self.INSTANCE, zone=self.ZONE)
1083 self.assertEqual(result, "fake contents")
1084 else:
1085 self.assertRaisesRegexp(
1086 errors.DriverError,
1087 "Malformed response.*",
1088 self.compute_client.GetSerialPortOutput,
1089 instance=self.INSTANCE,
1090 zone=self.ZONE)
1091 resource_mock.getSerialPortOutput.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -07001092 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -07001093 zone=self.ZONE,
1094 instance=self.INSTANCE,
1095 port=1)
1096
1097 def testGetSerialPortOutput(self):
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001098 """Test GetSerialPortOutput."""
Tri Vo29ac1822016-10-01 17:06:29 -07001099 response = {"contents": "fake contents"}
1100 self._GetSerialPortOutputTestHelper(response)
1101
1102 def testGetSerialPortOutputFail(self):
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001103 """Test GetSerialPortOutputFail."""
Tri Vo29ac1822016-10-01 17:06:29 -07001104 response = {"malformed": "fake contents"}
1105 self._GetSerialPortOutputTestHelper(response)
1106
1107 def testGetInstanceNamesByIPs(self):
1108 """Test GetInstanceNamesByIPs."""
1109 good_instance = {
1110 "name": "instance_1",
1111 "networkInterfaces": [
1112 {
1113 "accessConfigs": [
1114 {"natIP": "172.22.22.22"},
1115 ],
1116 },
1117 ],
1118 }
1119 bad_instance = {"name": "instance_2"}
1120 self.Patch(
1121 gcompute_client.ComputeClient,
1122 "ListInstances",
1123 return_value=[good_instance, bad_instance])
1124 ip_name_map = self.compute_client.GetInstanceNamesByIPs(
1125 ips=["172.22.22.22", "172.22.22.23"], zone=self.ZONE)
1126 self.assertEqual(ip_name_map, {"172.22.22.22": "instance_1",
1127 "172.22.22.23": None})
1128
cylan64af2db2019-01-17 15:13:59 +08001129 def testRsaNotInMetadata(self):
1130 """Test rsa not in metadata."""
Tri Vo29ac1822016-10-01 17:06:29 -07001131 fake_user = "fake_user"
cylan64af2db2019-01-17 15:13:59 +08001132 fake_ssh_key = "fake_ssh"
1133 metadata = {
1134 "kind": "compute#metadata",
1135 "fingerprint": "a-23icsyx4E=",
1136 "items": [
1137 {
1138 "key": "sshKeys",
1139 "value": "%s:%s" % (fake_user, self.SSHKEY)
1140 }
1141 ]
1142 }
1143 # Test rsa doesn't exist in metadata.
1144 new_entry = "%s:%s" % (fake_user, fake_ssh_key)
1145 self.assertEqual(True, gcompute_client.RsaNotInMetadata(metadata, new_entry))
1146
1147 # Test rsa exists in metadata.
1148 exist_entry = "%s:%s" %(fake_user, self.SSHKEY)
1149 self.assertEqual(False, gcompute_client.RsaNotInMetadata(metadata, exist_entry))
1150
1151 def testGetSshKeyFromMetadata(self):
1152 """Test get ssh key from metadata."""
1153 fake_user = "fake_user"
1154 metadata_key_exist_value_is_empty = {
1155 "kind": "compute#metadata",
1156 "fingerprint": "a-23icsyx4E=",
1157 "items": [
1158 {
1159 "key": "sshKeys",
1160 "value": ""
1161 }
1162 ]
1163 }
1164 metadata_key_exist = {
1165 "kind": "compute#metadata",
1166 "fingerprint": "a-23icsyx4E=",
1167 "items": [
1168 {
1169 "key": "sshKeys",
1170 "value": "%s:%s" % (fake_user, self.SSHKEY)
1171 }
1172 ]
1173 }
1174 metadata_key_not_exist = {
1175 "kind": "compute#metadata",
1176 "fingerprint": "a-23icsyx4E=",
1177 "items": [
1178 {
1179 }
1180 ]
1181 }
1182 expected_key_exist_value_is_empty = {
1183 "key": "sshKeys",
1184 "value": ""
1185 }
1186 expected_key_exist = {
1187 "key": "sshKeys",
1188 "value": "%s:%s" % (fake_user, self.SSHKEY)
1189 }
1190 self.assertEqual(expected_key_exist_value_is_empty,
1191 gcompute_client.GetSshKeyFromMetadata(metadata_key_exist_value_is_empty))
1192 self.assertEqual(expected_key_exist,
1193 gcompute_client.GetSshKeyFromMetadata(metadata_key_exist))
1194 self.assertEqual(None,
1195 gcompute_client.GetSshKeyFromMetadata(metadata_key_not_exist))
1196
1197
1198 def testGetRsaKeyPathExistsFalse(self):
1199 """Test the rsa key path not exists."""
1200 fake_ssh_rsa_path = "/path/to/test_rsa.pub"
1201 self.Patch(os.path, "exists", return_value=False)
1202 self.assertRaisesRegexp(errors.DriverError,
1203 "RSA file %s does not exist." % fake_ssh_rsa_path,
1204 gcompute_client.GetRsaKey,
1205 ssh_rsa_path=fake_ssh_rsa_path)
1206
1207 def testGetRsaKey(self):
1208 """Test get the rsa key."""
1209 fake_ssh_rsa_path = "/path/to/test_rsa.pub"
1210 self.Patch(os.path, "exists", return_value=True)
1211 m = mock.mock_open(read_data=self.SSHKEY)
1212 with mock.patch("__builtin__.open", m):
1213 result = gcompute_client.GetRsaKey(fake_ssh_rsa_path)
1214 self.assertEqual(self.SSHKEY, result)
1215
1216 def testUpdateRsaInMetadata(self):
1217 """Test update rsa in metadata."""
1218 fake_ssh_key = "fake_ssh"
1219 fake_metadata_sshkeys_not_exist = {
1220 "kind": "compute#metadata",
1221 "fingerprint": "a-23icsyx4E=",
1222 "items": [
1223 {
1224 "key": "not_sshKeys",
1225 "value": ""
1226 }
1227 ]
1228 }
1229 new_entry = "new_user:%s" % fake_ssh_key
1230 expected = {
1231 "kind": "compute#metadata",
1232 "fingerprint": "a-23icsyx4E=",
1233 "items": [
1234 {
1235 "key": "not_sshKeys",
1236 "value": ""
1237 },
1238 {
1239 "key": "sshKeys",
1240 "value": new_entry
1241 }
1242 ]
1243 }
1244 self.Patch(os.path, "exists", return_value=True)
1245 self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
1246 resource_mock = mock.MagicMock()
1247 self.compute_client.SetInstanceMetadata = mock.MagicMock(
1248 return_value=resource_mock)
1249 # Test the key item not exists in the metadata.
1250 self.compute_client.UpdateRsaInMetadata(
1251 "fake_zone",
1252 "fake_instance",
1253 fake_metadata_sshkeys_not_exist,
1254 new_entry)
1255 self.compute_client.SetInstanceMetadata.assert_called_with(
1256 "fake_zone",
1257 "fake_instance",
1258 expected)
1259
1260 # Test the key item exists in the metadata.
1261 fake_metadata_ssh_keys_exists = {
1262 "kind": "compute#metadata",
1263 "fingerprint": "a-23icsyx4E=",
1264 "items": [
1265 {
1266 "key": "sshKeys",
1267 "value": "old_user:%s" % self.SSHKEY
1268 }
1269 ]
1270 }
1271 expected_ssh_keys_exists = {
1272 "kind": "compute#metadata",
1273 "fingerprint": "a-23icsyx4E=",
1274 "items": [
1275 {
1276 "key": "sshKeys",
1277 "value": "old_user:%s\n%s" % (self.SSHKEY, new_entry)
1278 }
1279 ]
1280 }
1281
1282 self.compute_client.UpdateRsaInMetadata(
1283 "fake_zone",
1284 "fake_instance",
1285 fake_metadata_ssh_keys_exists,
1286 new_entry)
1287 self.compute_client.SetInstanceMetadata.assert_called_with(
1288 "fake_zone",
1289 "fake_instance",
1290 expected_ssh_keys_exists)
1291
1292 def testAddSshRsaToInstance(self):
1293 """Test add ssh rsa key to instance."""
1294 fake_user = "fake_user"
1295 instance_metadata_key_not_exist = {
1296 "metadata": {
Tri Vo29ac1822016-10-01 17:06:29 -07001297 "kind": "compute#metadata",
1298 "fingerprint": "a-23icsyx4E=",
1299 "items": [
1300 {
1301 "key": "sshKeys",
cylan64af2db2019-01-17 15:13:59 +08001302 "value": ""
1303 }
1304 ]
1305 }
1306 }
1307 instance_metadata_key_exist = {
1308 "metadata": {
1309 "kind": "compute#metadata",
1310 "fingerprint": "a-23icsyx4E=",
1311 "items": [
1312 {
1313 "key": "sshKeys",
1314 "value": "%s:%s" % (fake_user, self.SSHKEY)
Tri Vo29ac1822016-10-01 17:06:29 -07001315 }
1316 ]
1317 }
1318 }
1319 expected = {
1320 "kind": "compute#metadata",
1321 "fingerprint": "a-23icsyx4E=",
1322 "items": [
1323 {
1324 "key": "sshKeys",
cylan64af2db2019-01-17 15:13:59 +08001325 "value": "%s:%s" % (fake_user, self.SSHKEY)
Tri Vo29ac1822016-10-01 17:06:29 -07001326 }
1327 ]
1328 }
1329
1330 self.Patch(os.path, "exists", return_value=True)
cylan64af2db2019-01-17 15:13:59 +08001331 m = mock.mock_open(read_data=self.SSHKEY)
Tri Vo29ac1822016-10-01 17:06:29 -07001332 self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
Tri Vo29ac1822016-10-01 17:06:29 -07001333 resource_mock = mock.MagicMock()
cylan64af2db2019-01-17 15:13:59 +08001334 self.compute_client._service.instances = mock.MagicMock(
Tri Vo29ac1822016-10-01 17:06:29 -07001335 return_value=resource_mock)
cylan64af2db2019-01-17 15:13:59 +08001336 resource_mock.setMetadata = mock.MagicMock()
Tri Vo29ac1822016-10-01 17:06:29 -07001337
cylan64af2db2019-01-17 15:13:59 +08001338 # Test the key not exists in the metadata.
Tri Vo29ac1822016-10-01 17:06:29 -07001339 self.Patch(
cylan64af2db2019-01-17 15:13:59 +08001340 gcompute_client.ComputeClient, "GetInstance",
1341 return_value=instance_metadata_key_not_exist)
Kevin Chengda4f07a2018-06-26 10:25:05 -07001342 with mock.patch("__builtin__.open", m):
cylan64af2db2019-01-17 15:13:59 +08001343 self.compute_client.AddSshRsaInstanceMetadata(
1344 "fake_zone",
1345 fake_user,
1346 "/path/to/test_rsa.pub",
1347 "fake_instance")
1348 resource_mock.setMetadata.assert_called_with(
1349 project=PROJECT,
1350 zone="fake_zone",
1351 instance="fake_instance",
1352 body=expected)
1353
1354 # Test the key already exists in the metadata.
1355 resource_mock.setMetadata.call_count = 0
1356 self.Patch(
1357 gcompute_client.ComputeClient, "GetInstance",
1358 return_value=instance_metadata_key_exist)
1359 with mock.patch("__builtin__.open", m):
1360 self.compute_client.AddSshRsaInstanceMetadata(
1361 "fake_zone",
1362 fake_user,
1363 "/path/to/test_rsa.pub",
1364 "fake_instance")
1365 resource_mock.setMetadata.assert_not_called()
Tri Vo29ac1822016-10-01 17:06:29 -07001366
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001367 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
1368 def testDeleteDisks(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -07001369 """Test DeleteDisks."""
1370 self._SetupBatchHttpRequestMock()
Tri Vo29ac1822016-10-01 17:06:29 -07001371 fake_disks = ["fake_disk_1", "fake_disk_2"]
1372 mock_api = mock.MagicMock()
1373 resource_mock = mock.MagicMock()
1374 self.compute_client._service.disks = mock.MagicMock(
1375 return_value=resource_mock)
1376 resource_mock.delete = mock.MagicMock(return_value=mock_api)
1377 # Call the API.
1378 deleted, failed, error_msgs = self.compute_client.DeleteDisks(
1379 fake_disks, zone=self.ZONE)
1380 # Verify
Kevin Chengb5963882018-05-09 00:06:27 -07001381 calls = [
1382 mock.call(project=PROJECT, disk="fake_disk_1", zone=self.ZONE),
1383 mock.call(project=PROJECT, disk="fake_disk_2", zone=self.ZONE)
1384 ]
Tri Vo29ac1822016-10-01 17:06:29 -07001385 resource_mock.delete.assert_has_calls(calls, any_order=True)
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001386 self.assertEqual(mock_wait.call_count, 2)
Tri Vo29ac1822016-10-01 17:06:29 -07001387 self.assertEqual(error_msgs, [])
1388 self.assertEqual(failed, [])
1389 self.assertEqual(set(deleted), set(fake_disks))
1390
Kevin Chengb5963882018-05-09 00:06:27 -07001391 def testRetryOnFingerPrintError(self):
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001392 """Test RetryOnFingerPrintError."""
Kevin Chengb5963882018-05-09 00:06:27 -07001393 @utils.RetryOnException(gcompute_client._IsFingerPrintError, 10)
1394 def Raise412(sentinel):
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001395 """Raise 412 HTTP exception."""
1396 if not sentinel.hitFingerPrintConflict.called:
1397 sentinel.hitFingerPrintConflict()
1398 raise errors.HttpError(412, "resource labels have changed")
1399 return "Passed"
Kevin Chengb5963882018-05-09 00:06:27 -07001400
1401 sentinel = mock.MagicMock()
1402 result = Raise412(sentinel)
1403 self.assertEqual(1, sentinel.hitFingerPrintConflict.call_count)
1404 self.assertEqual("Passed", result)
1405
Tri Vo29ac1822016-10-01 17:06:29 -07001406
1407if __name__ == "__main__":
1408 unittest.main()