blob: df84a87b28d7a8ec5fe879d92ca953358e95f2ad [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
Tri Vo29ac1822016-10-01 17:06:29 -070029from acloud.internal.lib import driver_test_lib
30from acloud.internal.lib import gcompute_client
31from acloud.internal.lib import utils
Tri Vo29ac1822016-10-01 17:06:29 -070032
Kevin Chengb5963882018-05-09 00:06:27 -070033GS_IMAGE_SOURCE_URI = "https://storage.googleapis.com/fake-bucket/fake.tar.gz"
34GS_IMAGE_SOURCE_DISK = (
35 "https://www.googleapis.com/compute/v1/projects/fake-project/zones/"
36 "us-east1-d/disks/fake-disk")
37PROJECT = "fake-project"
Tri Vo29ac1822016-10-01 17:06:29 -070038
Kevin Cheng5c124ec2018-05-16 13:28:51 -070039# pylint: disable=protected-access, too-many-public-methods
Kevin Cheng070ae5c2018-08-02 16:03:00 -070040class ComputeClientTest(driver_test_lib.BaseDriverTest):
Tri Vo29ac1822016-10-01 17:06:29 -070041 """Test ComputeClient."""
42
Kevin Chengb5963882018-05-09 00:06:27 -070043 PROJECT_OTHER = "fake-project-other"
Tri Vo29ac1822016-10-01 17:06:29 -070044 INSTANCE = "fake-instance"
45 IMAGE = "fake-image"
46 IMAGE_URL = "http://fake-image-url"
Kevin Chengb5963882018-05-09 00:06:27 -070047 IMAGE_OTHER = "fake-image-other"
Tri Vo29ac1822016-10-01 17:06:29 -070048 MACHINE_TYPE = "fake-machine-type"
49 MACHINE_TYPE_URL = "http://fake-machine-type-url"
50 METADATA = ("metadata_key", "metadata_value")
Kevin Chengb5963882018-05-09 00:06:27 -070051 ACCELERATOR_URL = "http://speedy-gpu"
Tri Vo29ac1822016-10-01 17:06:29 -070052 NETWORK = "fake-network"
53 NETWORK_URL = "http://fake-network-url"
Kevin Cheng480e1212018-10-24 00:23:30 -070054 SUBNETWORK_URL = "http://fake-subnetwork-url"
Tri Vo29ac1822016-10-01 17:06:29 -070055 ZONE = "fake-zone"
56 REGION = "fake-region"
57 OPERATION_NAME = "fake-op"
Kevin Chengb5963882018-05-09 00:06:27 -070058 IMAGE_FINGERPRINT = "L_NWHuz7wTY="
59 GPU = "fancy-graphics"
cylan64af2db2019-01-17 15:13:59 +080060 SSHKEY = (
61 "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDBkTOTRze9v2VOqkkf7RG"
62 "jSkg6Z2kb9Q9UHsDGatvend3fmjIw1Tugg0O7nnjlPkskmlgyd4a/j99WOeLL"
63 "CPk6xPyoVjrPUVBU/pAk09ORTC4Zqk6YjlW7LOfzvqmXhmIZfYu6Q4Yt50pZzhl"
64 "lllfu26nYjY7Tg12D019nJi/kqPX5+NKgt0LGXTu8T1r2Gav/q4V7QRWQrB8Eiu"
65 "pxXR7I2YhynqovkEt/OXG4qWgvLEXGsWtSQs0CtCzqEVxz0Y9ECr7er4VdjSQxV"
66 "AaeLAsQsK9ROae8hMBFZ3//8zLVapBwpuffCu+fUoql9qeV9xagZcc9zj8XOUOW"
67 "ApiihqNL1111 test@test1.org")
Kevin Chengc330f6f2019-05-13 09:32:42 -070068 EXTRA_SCOPES = ["scope1"]
Tri Vo29ac1822016-10-01 17:06:29 -070069
70 def setUp(self):
71 """Set up test."""
72 super(ComputeClientTest, self).setUp()
73 self.Patch(gcompute_client.ComputeClient, "InitResourceHandle")
74 fake_cfg = mock.MagicMock()
Kevin Chengb5963882018-05-09 00:06:27 -070075 fake_cfg.project = PROJECT
Kevin Chengc330f6f2019-05-13 09:32:42 -070076 fake_cfg.extra_scopes = self.EXTRA_SCOPES
Kevin Chengb5963882018-05-09 00:06:27 -070077 self.compute_client = gcompute_client.ComputeClient(
78 fake_cfg, mock.MagicMock())
Tri Vo29ac1822016-10-01 17:06:29 -070079 self.compute_client._service = mock.MagicMock()
80
Kevin Cheng5c124ec2018-05-16 13:28:51 -070081 self._disk_args = copy.deepcopy(gcompute_client.BASE_DISK_ARGS)
82 self._disk_args["initializeParams"] = {"diskName": self.INSTANCE,
83 "sourceImage": self.IMAGE_URL}
84
85 # pylint: disable=invalid-name
Tri Vo29ac1822016-10-01 17:06:29 -070086 def _SetupMocksForGetOperationStatus(self, mock_result, operation_scope):
87 """A helper class for setting up mocks for testGetOperationStatus*.
88
Kevin Chengb5963882018-05-09 00:06:27 -070089 Args:
90 mock_result: The result to return by _GetOperationStatus.
91 operation_scope: A value of OperationScope.
Tri Vo29ac1822016-10-01 17:06:29 -070092
Kevin Chengb5963882018-05-09 00:06:27 -070093 Returns:
94 A mock for Resource object.
95 """
Tri Vo29ac1822016-10-01 17:06:29 -070096 resource_mock = mock.MagicMock()
97 mock_api = mock.MagicMock()
98 if operation_scope == gcompute_client.OperationScope.GLOBAL:
99 self.compute_client._service.globalOperations = mock.MagicMock(
100 return_value=resource_mock)
101 elif operation_scope == gcompute_client.OperationScope.ZONE:
102 self.compute_client._service.zoneOperations = mock.MagicMock(
103 return_value=resource_mock)
104 elif operation_scope == gcompute_client.OperationScope.REGION:
105 self.compute_client._service.regionOperations = mock.MagicMock(
106 return_value=resource_mock)
107 resource_mock.get = mock.MagicMock(return_value=mock_api)
108 mock_api.execute = mock.MagicMock(return_value=mock_result)
109 return resource_mock
110
111 def testGetOperationStatusGlobal(self):
112 """Test _GetOperationStatus for global."""
113 resource_mock = self._SetupMocksForGetOperationStatus(
114 {"status": "GOOD"}, gcompute_client.OperationScope.GLOBAL)
115 status = self.compute_client._GetOperationStatus(
116 {"name": self.OPERATION_NAME},
117 gcompute_client.OperationScope.GLOBAL)
118 self.assertEqual(status, "GOOD")
119 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700120 project=PROJECT, operation=self.OPERATION_NAME)
Tri Vo29ac1822016-10-01 17:06:29 -0700121
122 def testGetOperationStatusZone(self):
123 """Test _GetOperationStatus for zone."""
124 resource_mock = self._SetupMocksForGetOperationStatus(
125 {"status": "GOOD"}, gcompute_client.OperationScope.ZONE)
126 status = self.compute_client._GetOperationStatus(
127 {"name": self.OPERATION_NAME}, gcompute_client.OperationScope.ZONE,
128 self.ZONE)
129 self.assertEqual(status, "GOOD")
130 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700131 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -0700132 operation=self.OPERATION_NAME,
133 zone=self.ZONE)
134
135 def testGetOperationStatusRegion(self):
136 """Test _GetOperationStatus for region."""
137 resource_mock = self._SetupMocksForGetOperationStatus(
138 {"status": "GOOD"}, gcompute_client.OperationScope.REGION)
139 self.compute_client._GetOperationStatus(
140 {"name": self.OPERATION_NAME},
141 gcompute_client.OperationScope.REGION, self.REGION)
142 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700143 project=PROJECT, operation=self.OPERATION_NAME, region=self.REGION)
Tri Vo29ac1822016-10-01 17:06:29 -0700144
145 def testGetOperationStatusError(self):
146 """Test _GetOperationStatus failed."""
147 self._SetupMocksForGetOperationStatus(
148 {"error": {"errors": ["error1", "error2"]}},
149 gcompute_client.OperationScope.GLOBAL)
150 self.assertRaisesRegexp(errors.DriverError,
151 "Get operation state failed.*error1.*error2",
152 self.compute_client._GetOperationStatus,
153 {"name": self.OPERATION_NAME},
154 gcompute_client.OperationScope.GLOBAL)
155
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700156 @mock.patch.object(errors, "GceOperationTimeoutError")
157 @mock.patch.object(utils, "PollAndWait")
158 def testWaitOnOperation(self, mock_poll, mock_gce_operation_timeout_error):
Tri Vo29ac1822016-10-01 17:06:29 -0700159 """Test WaitOnOperation."""
160 mock_error = mock.MagicMock()
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700161 mock_gce_operation_timeout_error.return_value = mock_error
Tri Vo29ac1822016-10-01 17:06:29 -0700162 self.compute_client.WaitOnOperation(
163 operation={"name": self.OPERATION_NAME},
164 operation_scope=gcompute_client.OperationScope.REGION,
165 scope_name=self.REGION)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700166 mock_poll.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700167 func=self.compute_client._GetOperationStatus,
168 expected_return="DONE",
169 timeout_exception=mock_error,
170 timeout_secs=self.compute_client.OPERATION_TIMEOUT_SECS,
Kevin Chengb5963882018-05-09 00:06:27 -0700171 sleep_interval_secs=self.compute_client.OPERATION_POLL_INTERVAL_SECS,
Tri Vo29ac1822016-10-01 17:06:29 -0700172 operation={"name": self.OPERATION_NAME},
173 operation_scope=gcompute_client.OperationScope.REGION,
174 scope_name=self.REGION)
175
Kevin Chengb5963882018-05-09 00:06:27 -0700176 def testGetImage(self):
177 """Test GetImage."""
178 resource_mock = mock.MagicMock()
179 mock_api = mock.MagicMock()
180 self.compute_client._service.images = mock.MagicMock(
181 return_value=resource_mock)
182 resource_mock.get = mock.MagicMock(return_value=mock_api)
183 mock_api.execute = mock.MagicMock(return_value={"name": self.IMAGE})
184 result = self.compute_client.GetImage(self.IMAGE)
185 self.assertEqual(result, {"name": self.IMAGE})
186 resource_mock.get.assert_called_with(project=PROJECT, image=self.IMAGE)
187
188 def testGetImageOther(self):
189 """Test GetImage with other project."""
190 resource_mock = mock.MagicMock()
191 mock_api = mock.MagicMock()
192 self.compute_client._service.images = mock.MagicMock(
193 return_value=resource_mock)
194 resource_mock.get = mock.MagicMock(return_value=mock_api)
195 mock_api.execute = mock.MagicMock(return_value={"name": self.IMAGE_OTHER})
196 result = self.compute_client.GetImage(
197 image_name=self.IMAGE_OTHER,
198 image_project=self.PROJECT_OTHER)
199 self.assertEqual(result, {"name": self.IMAGE_OTHER})
200 resource_mock.get.assert_called_with(
201 project=self.PROJECT_OTHER, image=self.IMAGE_OTHER)
202
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700203 def testCreateImageWithSourceURI(self):
204 """Test CreateImage with src uri."""
205 source_uri = GS_IMAGE_SOURCE_URI
206 source_disk = None
207 labels = None
208 expected_body = {"name": self.IMAGE,
209 "rawDisk": {"source": GS_IMAGE_SOURCE_URI}}
210 mock_check = self.Patch(gcompute_client.ComputeClient,
211 "CheckImageExists",
212 return_value=False)
213 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
214 resource_mock = mock.MagicMock()
215 self.compute_client._service.images = mock.MagicMock(
216 return_value=resource_mock)
217 resource_mock.insert = mock.MagicMock()
218 self.compute_client.CreateImage(
219 image_name=self.IMAGE, source_uri=source_uri,
220 source_disk=source_disk, labels=labels)
221 resource_mock.insert.assert_called_with(
222 project=PROJECT, body=expected_body)
223 mock_wait.assert_called_with(
224 operation=mock.ANY,
225 operation_scope=gcompute_client.OperationScope.GLOBAL)
226 mock_check.assert_called_with(self.IMAGE)
227
228 def testCreateImageWithSourceDisk(self):
229 """Test CreateImage with src disk."""
230 source_uri = None
231 source_disk = GS_IMAGE_SOURCE_DISK
232 labels = None
233 expected_body = {"name": self.IMAGE,
234 "sourceDisk": GS_IMAGE_SOURCE_DISK}
235 mock_check = self.Patch(gcompute_client.ComputeClient,
236 "CheckImageExists",
237 return_value=False)
238 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
239 resource_mock = mock.MagicMock()
240 self.compute_client._service.images = mock.MagicMock(
241 return_value=resource_mock)
242 resource_mock.insert = mock.MagicMock()
243 self.compute_client.CreateImage(
244 image_name=self.IMAGE, source_uri=source_uri,
245 source_disk=source_disk, labels=labels)
246 resource_mock.insert.assert_called_with(
247 project=PROJECT, body=expected_body)
248 mock_wait.assert_called_with(
249 operation=mock.ANY,
250 operation_scope=gcompute_client.OperationScope.GLOBAL)
251 mock_check.assert_called_with(self.IMAGE)
252
253 def testCreateImageWithSourceDiskAndLabel(self):
254 """Test CreateImage with src disk and label."""
255 source_uri = None
256 source_disk = GS_IMAGE_SOURCE_DISK
257 labels = {"label1": "xxx"}
258 expected_body = {"name": self.IMAGE,
259 "sourceDisk": GS_IMAGE_SOURCE_DISK,
260 "labels": {"label1": "xxx"}}
herbertxue308f7662018-05-18 03:25:58 +0000261 mock_check = self.Patch(gcompute_client.ComputeClient,
262 "CheckImageExists",
263 return_value=False)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700264 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
Tri Vo29ac1822016-10-01 17:06:29 -0700265 resource_mock = mock.MagicMock()
266 self.compute_client._service.images = mock.MagicMock(
267 return_value=resource_mock)
268 resource_mock.insert = mock.MagicMock()
Tri Vo29ac1822016-10-01 17:06:29 -0700269 self.compute_client.CreateImage(
Kevin Chengb5963882018-05-09 00:06:27 -0700270 image_name=self.IMAGE, source_uri=source_uri,
271 source_disk=source_disk, labels=labels)
Tri Vo29ac1822016-10-01 17:06:29 -0700272 resource_mock.insert.assert_called_with(
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700273 project=PROJECT, body=expected_body)
274 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700275 operation=mock.ANY,
276 operation_scope=gcompute_client.OperationScope.GLOBAL)
herbertxue308f7662018-05-18 03:25:58 +0000277 mock_check.assert_called_with(self.IMAGE)
Tri Vo29ac1822016-10-01 17:06:29 -0700278
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700279 @mock.patch.object(gcompute_client.ComputeClient, "GetImage")
280 def testSetImageLabel(self, mock_get_image):
281 """Test SetImageLabel."""
282 with mock.patch.object(self.compute_client._service, "images",
283 return_value=mock.MagicMock(
284 setLabels=mock.MagicMock())) as _:
285 image = {"name": self.IMAGE,
286 "sourceDisk": GS_IMAGE_SOURCE_DISK,
287 "labelFingerprint": self.IMAGE_FINGERPRINT,
288 "labels": {"a": "aaa", "b": "bbb"}}
289 mock_get_image.return_value = image
290 new_labels = {"a": "xxx", "c": "ccc"}
291 # Test
292 self.compute_client.SetImageLabels(
293 self.IMAGE, new_labels)
294 # Check result
295 expected_labels = {"a": "xxx", "b": "bbb", "c": "ccc"}
296 self.compute_client._service.images().setLabels.assert_called_with(
297 project=PROJECT,
298 resource=self.IMAGE,
299 body={
300 "labels": expected_labels,
301 "labelFingerprint": self.IMAGE_FINGERPRINT
302 })
Kevin Chengb5963882018-05-09 00:06:27 -0700303
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700304 def testCreateImageRaiseDriverErrorWithValidInput(self):
305 """Test CreateImage with valid input."""
306 source_uri = GS_IMAGE_SOURCE_URI
307 source_disk = GS_IMAGE_SOURCE_DISK
herbertxue308f7662018-05-18 03:25:58 +0000308 self.Patch(gcompute_client.ComputeClient, "CheckImageExists", return_value=False)
Kevin Chengb5963882018-05-09 00:06:27 -0700309 self.assertRaises(errors.DriverError, self.compute_client.CreateImage,
310 image_name=self.IMAGE, source_uri=source_uri,
311 source_disk=source_disk)
312
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700313 def testCreateImageRaiseDriverErrorWithInvalidInput(self):
314 """Test CreateImage with valid input."""
315 source_uri = None
316 source_disk = None
317 self.Patch(gcompute_client.ComputeClient, "CheckImageExists", return_value=False)
318 self.assertRaises(errors.DriverError, self.compute_client.CreateImage,
319 image_name=self.IMAGE, source_uri=source_uri,
320 source_disk=source_disk)
Tri Vo29ac1822016-10-01 17:06:29 -0700321
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700322 @mock.patch.object(gcompute_client.ComputeClient, "DeleteImage")
323 @mock.patch.object(gcompute_client.ComputeClient, "CheckImageExists",
herbertxue308f7662018-05-18 03:25:58 +0000324 side_effect=[False, True])
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700325 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation",
326 side_effect=errors.DriverError("Expected fake error"))
327 def testCreateImageFail(self, mock_wait, mock_check, mock_delete):
328 """Test CreateImage fails."""
Tri Vo29ac1822016-10-01 17:06:29 -0700329 resource_mock = mock.MagicMock()
330 self.compute_client._service.images = mock.MagicMock(
331 return_value=resource_mock)
332 resource_mock.insert = mock.MagicMock()
333
334 expected_body = {
335 "name": self.IMAGE,
336 "rawDisk": {
Kevin Chengb5963882018-05-09 00:06:27 -0700337 "source": GS_IMAGE_SOURCE_URI,
Tri Vo29ac1822016-10-01 17:06:29 -0700338 },
339 }
340 self.assertRaisesRegexp(
341 errors.DriverError,
342 "Expected fake error",
343 self.compute_client.CreateImage,
344 image_name=self.IMAGE,
Kevin Chengb5963882018-05-09 00:06:27 -0700345 source_uri=GS_IMAGE_SOURCE_URI)
Tri Vo29ac1822016-10-01 17:06:29 -0700346 resource_mock.insert.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700347 project=PROJECT, body=expected_body)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700348 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700349 operation=mock.ANY,
350 operation_scope=gcompute_client.OperationScope.GLOBAL)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700351 mock_check.assert_called_with(self.IMAGE)
352 mock_delete.assert_called_with(self.IMAGE)
Tri Vo29ac1822016-10-01 17:06:29 -0700353
354 def testCheckImageExistsTrue(self):
355 """Test CheckImageExists return True."""
356 resource_mock = mock.MagicMock()
357 mock_api = mock.MagicMock()
358 self.compute_client._service.images = mock.MagicMock(
359 return_value=resource_mock)
360 resource_mock.get = mock.MagicMock(return_value=mock_api)
361 mock_api.execute = mock.MagicMock(return_value={"name": self.IMAGE})
362 self.assertTrue(self.compute_client.CheckImageExists(self.IMAGE))
363
364 def testCheckImageExistsFalse(self):
365 """Test CheckImageExists return False."""
366 resource_mock = mock.MagicMock()
367 mock_api = mock.MagicMock()
368 self.compute_client._service.images = mock.MagicMock(
369 return_value=resource_mock)
370 resource_mock.get = mock.MagicMock(return_value=mock_api)
371 mock_api.execute = mock.MagicMock(
372 side_effect=errors.ResourceNotFoundError(404, "no image"))
373 self.assertFalse(self.compute_client.CheckImageExists(self.IMAGE))
374
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700375 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
376 def testDeleteImage(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700377 """Test DeleteImage."""
Tri Vo29ac1822016-10-01 17:06:29 -0700378 resource_mock = mock.MagicMock()
379 self.compute_client._service.images = mock.MagicMock(
380 return_value=resource_mock)
381 resource_mock.delete = mock.MagicMock()
382 self.compute_client.DeleteImage(self.IMAGE)
383 resource_mock.delete.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700384 project=PROJECT, image=self.IMAGE)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700385 self.assertTrue(mock_wait.called)
Tri Vo29ac1822016-10-01 17:06:29 -0700386
387 def _SetupBatchHttpRequestMock(self):
388 """Setup BatchHttpRequest mock."""
389 requests = {}
390
391 def _Add(request, callback, request_id):
392 requests[request_id] = (request, callback)
393
394 def _Execute():
395 for rid in requests:
396 _, callback = requests[rid]
397 callback(
398 request_id=rid, response=mock.MagicMock(), exception=None)
Tri Vo29ac1822016-10-01 17:06:29 -0700399 mock_batch = mock.MagicMock()
400 mock_batch.add = _Add
401 mock_batch.execute = _Execute
402 self.Patch(apiclient.http, "BatchHttpRequest", return_value=mock_batch)
403
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700404 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
405 def testDeleteImages(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700406 """Test DeleteImages."""
407 self._SetupBatchHttpRequestMock()
Tri Vo29ac1822016-10-01 17:06:29 -0700408 fake_images = ["fake_image_1", "fake_image_2"]
409 mock_api = mock.MagicMock()
410 resource_mock = mock.MagicMock()
411 self.compute_client._service.images = mock.MagicMock(
412 return_value=resource_mock)
413 resource_mock.delete = mock.MagicMock(return_value=mock_api)
414 # Call the API.
415 deleted, failed, error_msgs = self.compute_client.DeleteImages(
416 fake_images)
417 # Verify
Kevin Chengb5963882018-05-09 00:06:27 -0700418 calls = [
419 mock.call(project=PROJECT, image="fake_image_1"),
420 mock.call(project=PROJECT, image="fake_image_2")
421 ]
Tri Vo29ac1822016-10-01 17:06:29 -0700422 resource_mock.delete.assert_has_calls(calls, any_order=True)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700423 self.assertEqual(mock_wait.call_count, 2)
Tri Vo29ac1822016-10-01 17:06:29 -0700424 self.assertEqual(error_msgs, [])
425 self.assertEqual(failed, [])
426 self.assertEqual(set(deleted), set(fake_images))
427
428 def testListImages(self):
429 """Test ListImages."""
430 fake_token = "fake_next_page_token"
431 image_1 = "image_1"
432 image_2 = "image_2"
433 response_1 = {"items": [image_1], "nextPageToken": fake_token}
434 response_2 = {"items": [image_2]}
435 self.Patch(
436 gcompute_client.ComputeClient,
437 "Execute",
438 side_effect=[response_1, response_2])
439 resource_mock = mock.MagicMock()
440 self.compute_client._service.images = mock.MagicMock(
441 return_value=resource_mock)
442 resource_mock.list = mock.MagicMock()
443 images = self.compute_client.ListImages()
444 calls = [
Kevin Chengb5963882018-05-09 00:06:27 -0700445 mock.call(project=PROJECT, filter=None, pageToken=None),
446 mock.call(project=PROJECT, filter=None, pageToken=fake_token)
Tri Vo29ac1822016-10-01 17:06:29 -0700447 ]
448 resource_mock.list.assert_has_calls(calls)
449 self.assertEqual(images, [image_1, image_2])
450
Kevin Chengb5963882018-05-09 00:06:27 -0700451 def testListImagesFromExternalProject(self):
452 """Test ListImages which accepts different project."""
453 image = "image_1"
454 response = {"items": [image]}
455 self.Patch(gcompute_client.ComputeClient, "Execute", side_effect=[response])
456 resource_mock = mock.MagicMock()
457 self.compute_client._service.images = mock.MagicMock(
458 return_value=resource_mock)
459 resource_mock.list = mock.MagicMock()
460 images = self.compute_client.ListImages(
461 image_project="fake-project-2")
462 calls = [
463 mock.call(project="fake-project-2", filter=None, pageToken=None)]
464 resource_mock.list.assert_has_calls(calls)
465 self.assertEqual(images, [image])
466
Tri Vo29ac1822016-10-01 17:06:29 -0700467 def testGetInstance(self):
468 """Test GetInstance."""
469 resource_mock = mock.MagicMock()
470 mock_api = mock.MagicMock()
471 self.compute_client._service.instances = mock.MagicMock(
472 return_value=resource_mock)
473 resource_mock.get = mock.MagicMock(return_value=mock_api)
474 mock_api.execute = mock.MagicMock(return_value={"name": self.INSTANCE})
475 result = self.compute_client.GetInstance(self.INSTANCE, self.ZONE)
476 self.assertEqual(result, {"name": self.INSTANCE})
477 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700478 project=PROJECT, zone=self.ZONE, instance=self.INSTANCE)
Tri Vo29ac1822016-10-01 17:06:29 -0700479
480 def testListInstances(self):
481 """Test ListInstances."""
482 fake_token = "fake_next_page_token"
483 instance_1 = "instance_1"
484 instance_2 = "instance_2"
485 response_1 = {"items": [instance_1], "nextPageToken": fake_token}
486 response_2 = {"items": [instance_2]}
487 self.Patch(
488 gcompute_client.ComputeClient,
489 "Execute",
490 side_effect=[response_1, response_2])
491 resource_mock = mock.MagicMock()
492 self.compute_client._service.instances = mock.MagicMock(
493 return_value=resource_mock)
494 resource_mock.list = mock.MagicMock()
495 instances = self.compute_client.ListInstances(self.ZONE)
496 calls = [
497 mock.call(
Kevin Chengb5963882018-05-09 00:06:27 -0700498 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -0700499 zone=self.ZONE,
500 filter=None,
501 pageToken=None),
502 mock.call(
Kevin Chengb5963882018-05-09 00:06:27 -0700503 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -0700504 zone=self.ZONE,
505 filter=None,
506 pageToken=fake_token),
507 ]
508 resource_mock.list.assert_has_calls(calls)
509 self.assertEqual(instances, [instance_1, instance_2])
510
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700511 @mock.patch.object(gcompute_client.ComputeClient, "GetImage")
512 @mock.patch.object(gcompute_client.ComputeClient, "GetNetworkUrl")
Kevin Cheng480e1212018-10-24 00:23:30 -0700513 @mock.patch.object(gcompute_client.ComputeClient, "GetSubnetworkUrl")
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700514 @mock.patch.object(gcompute_client.ComputeClient, "GetMachineType")
515 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
516 def testCreateInstance(self, mock_wait, mock_get_mach_type,
Kevin Cheng480e1212018-10-24 00:23:30 -0700517 mock_get_subnetwork_url, mock_get_network_url,
518 mock_get_image):
Tri Vo29ac1822016-10-01 17:06:29 -0700519 """Test CreateInstance."""
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700520 mock_get_mach_type.return_value = {"selfLink": self.MACHINE_TYPE_URL}
521 mock_get_network_url.return_value = self.NETWORK_URL
Kevin Cheng480e1212018-10-24 00:23:30 -0700522 mock_get_subnetwork_url.return_value = self.SUBNETWORK_URL
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700523 mock_get_image.return_value = {"selfLink": self.IMAGE_URL}
Tri Vo29ac1822016-10-01 17:06:29 -0700524 resource_mock = mock.MagicMock()
525 self.compute_client._service.instances = mock.MagicMock(
526 return_value=resource_mock)
527 resource_mock.insert = mock.MagicMock()
herbertxue308f7662018-05-18 03:25:58 +0000528 self.Patch(
529 self.compute_client,
530 "_GetExtraDiskArgs",
531 return_value=[{"fake_extra_arg": "fake_extra_value"}])
532 extra_disk_name = "gce-x86-userdebug-2345-abcd-data"
533 expected_disk_args = [self._disk_args]
534 expected_disk_args.extend([{"fake_extra_arg": "fake_extra_value"}])
Kevin Chengc330f6f2019-05-13 09:32:42 -0700535 expected_scope = []
536 expected_scope.extend(self.compute_client.DEFAULT_INSTANCE_SCOPE)
537 expected_scope.extend(self.EXTRA_SCOPES)
Tri Vo29ac1822016-10-01 17:06:29 -0700538
539 expected_body = {
540 "machineType": self.MACHINE_TYPE_URL,
541 "name": self.INSTANCE,
542 "networkInterfaces": [
543 {
544 "network": self.NETWORK_URL,
Kevin Cheng480e1212018-10-24 00:23:30 -0700545 "subnetwork": self.SUBNETWORK_URL,
Tri Vo29ac1822016-10-01 17:06:29 -0700546 "accessConfigs": [
547 {"name": "External NAT",
548 "type": "ONE_TO_ONE_NAT"}
549 ],
550 }
551 ],
herbertxue308f7662018-05-18 03:25:58 +0000552 "disks": expected_disk_args,
Tri Vo29ac1822016-10-01 17:06:29 -0700553 "serviceAccounts": [
554 {"email": "default",
Kevin Chengc330f6f2019-05-13 09:32:42 -0700555 "scopes": expected_scope}
Tri Vo29ac1822016-10-01 17:06:29 -0700556 ],
557 "metadata": {
558 "items": [{"key": self.METADATA[0],
559 "value": self.METADATA[1]}],
560 },
561 }
562
563 self.compute_client.CreateInstance(
564 instance=self.INSTANCE,
565 image_name=self.IMAGE,
566 machine_type=self.MACHINE_TYPE,
567 metadata={self.METADATA[0]: self.METADATA[1]},
568 network=self.NETWORK,
herbertxue308f7662018-05-18 03:25:58 +0000569 zone=self.ZONE,
Kevin Chengc330f6f2019-05-13 09:32:42 -0700570 extra_disk_name=extra_disk_name,
571 extra_scopes=self.EXTRA_SCOPES)
Tri Vo29ac1822016-10-01 17:06:29 -0700572
573 resource_mock.insert.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700574 project=PROJECT, zone=self.ZONE, body=expected_body)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700575 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700576 mock.ANY,
577 operation_scope=gcompute_client.OperationScope.ZONE,
578 scope_name=self.ZONE)
579
Erwin Jansenf39798d2019-05-14 21:06:44 -0700580
581 @mock.patch.object(gcompute_client.ComputeClient, "GetImage")
582 @mock.patch.object(gcompute_client.ComputeClient, "GetNetworkUrl")
583 @mock.patch.object(gcompute_client.ComputeClient, "GetSubnetworkUrl")
584 @mock.patch.object(gcompute_client.ComputeClient, "GetMachineType")
585 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
586 def testCreateInstanceWithTags(self, mock_wait, mock_get_mach_type,
587 mock_get_subnetwork_url, mock_get_network_url,
588 mock_get_image):
589 """Test CreateInstance."""
590 mock_get_mach_type.return_value = {"selfLink": self.MACHINE_TYPE_URL}
591 mock_get_network_url.return_value = self.NETWORK_URL
592 mock_get_subnetwork_url.return_value = self.SUBNETWORK_URL
593 mock_get_image.return_value = {"selfLink": self.IMAGE_URL}
594 resource_mock = mock.MagicMock()
595 self.compute_client._service.instances = mock.MagicMock(
596 return_value=resource_mock)
597 resource_mock.insert = mock.MagicMock()
598 self.Patch(
599 self.compute_client,
600 "_GetExtraDiskArgs",
601 return_value=[{"fake_extra_arg": "fake_extra_value"}])
602 extra_disk_name = "gce-x86-userdebug-2345-abcd-data"
603 expected_disk_args = [self._disk_args]
604 expected_disk_args.extend([{"fake_extra_arg": "fake_extra_value"}])
605 expected_scope = []
606 expected_scope.extend(self.compute_client.DEFAULT_INSTANCE_SCOPE)
607 expected_scope.extend(self.EXTRA_SCOPES)
608
609 expected_body = {
610 "machineType": self.MACHINE_TYPE_URL,
611 "name": self.INSTANCE,
612 "networkInterfaces": [
613 {
614 "network": self.NETWORK_URL,
615 "subnetwork": self.SUBNETWORK_URL,
616 "accessConfigs": [
617 {"name": "External NAT",
618 "type": "ONE_TO_ONE_NAT"}
619 ],
620 }
621 ],
622 'tags': {'items': ['https-server']},
623 "disks": expected_disk_args,
624 "serviceAccounts": [
625 {"email": "default",
626 "scopes": expected_scope}
627 ],
628 "metadata": {
629 "items": [{"key": self.METADATA[0],
630 "value": self.METADATA[1]}],
631 },
632 }
633
634 self.compute_client.CreateInstance(
635 instance=self.INSTANCE,
636 image_name=self.IMAGE,
637 machine_type=self.MACHINE_TYPE,
638 metadata={self.METADATA[0]: self.METADATA[1]},
639 network=self.NETWORK,
640 zone=self.ZONE,
641 extra_disk_name=extra_disk_name,
642 tags=["https-server"],
643 extra_scopes=self.EXTRA_SCOPES)
644
645 resource_mock.insert.assert_called_with(
646 project=PROJECT, zone=self.ZONE, body=expected_body)
647 mock_wait.assert_called_with(
648 mock.ANY,
649 operation_scope=gcompute_client.OperationScope.ZONE,
650 scope_name=self.ZONE)
651
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700652 @mock.patch.object(gcompute_client.ComputeClient, "GetAcceleratorUrl")
653 @mock.patch.object(gcompute_client.ComputeClient, "GetImage")
654 @mock.patch.object(gcompute_client.ComputeClient, "GetNetworkUrl")
Kevin Cheng480e1212018-10-24 00:23:30 -0700655 @mock.patch.object(gcompute_client.ComputeClient, "GetSubnetworkUrl")
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700656 @mock.patch.object(gcompute_client.ComputeClient, "GetMachineType")
657 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
658 def testCreateInstanceWithGpu(self, mock_wait, mock_get_mach,
Kevin Cheng480e1212018-10-24 00:23:30 -0700659 mock_get_subnetwork, mock_get_network,
660 mock_get_image, mock_get_accel):
Kevin Chengb5963882018-05-09 00:06:27 -0700661 """Test CreateInstance with a GPU parameter not set to None."""
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700662 mock_get_mach.return_value = {"selfLink": self.MACHINE_TYPE_URL}
663 mock_get_network.return_value = self.NETWORK_URL
Kevin Cheng480e1212018-10-24 00:23:30 -0700664 mock_get_subnetwork.return_value = self.SUBNETWORK_URL
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700665 mock_get_accel.return_value = self.ACCELERATOR_URL
666 mock_get_image.return_value = {"selfLink": self.IMAGE_URL}
Kevin Chengb5963882018-05-09 00:06:27 -0700667
668 resource_mock = mock.MagicMock()
669 self.compute_client._service.instances = mock.MagicMock(
670 return_value=resource_mock)
671 resource_mock.insert = mock.MagicMock()
672
673 expected_body = {
674 "machineType":
675 self.MACHINE_TYPE_URL,
676 "name":
677 self.INSTANCE,
678 "networkInterfaces": [{
Kevin Cheng480e1212018-10-24 00:23:30 -0700679 "network": self.NETWORK_URL,
680 "subnetwork": self.SUBNETWORK_URL,
Kevin Chengb5963882018-05-09 00:06:27 -0700681 "accessConfigs": [{
682 "name": "External NAT",
683 "type": "ONE_TO_ONE_NAT"
684 }],
685 }],
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700686 "disks": [self._disk_args],
Kevin Chengb5963882018-05-09 00:06:27 -0700687 "serviceAccounts": [{
688 "email": "default",
689 "scopes": self.compute_client.DEFAULT_INSTANCE_SCOPE
690 }],
691 "scheduling": {
692 "onHostMaintenance": "terminate"
693 },
694 "guestAccelerators": [{
695 "acceleratorCount": 1,
696 "acceleratorType": "http://speedy-gpu"
697 }],
698 "metadata": {
699 "items": [{
700 "key": self.METADATA[0],
701 "value": self.METADATA[1]
702 }],
703 },
704 }
705
706 self.compute_client.CreateInstance(
707 instance=self.INSTANCE,
708 image_name=self.IMAGE,
709 machine_type=self.MACHINE_TYPE,
710 metadata={self.METADATA[0]: self.METADATA[1]},
711 network=self.NETWORK,
712 zone=self.ZONE,
Kevin Chengc330f6f2019-05-13 09:32:42 -0700713 gpu=self.GPU,
714 extra_scopes=None)
Kevin Chengb5963882018-05-09 00:06:27 -0700715
716 resource_mock.insert.assert_called_with(
717 project=PROJECT, zone=self.ZONE, body=expected_body)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700718 mock_wait.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700719 mock.ANY, operation_scope=gcompute_client.OperationScope.ZONE,
720 scope_name=self.ZONE)
721
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700722 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
723 def testDeleteInstance(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700724 """Test DeleteInstance."""
Tri Vo29ac1822016-10-01 17:06:29 -0700725 resource_mock = mock.MagicMock()
726 self.compute_client._service.instances = mock.MagicMock(
727 return_value=resource_mock)
728 resource_mock.delete = mock.MagicMock()
729 self.compute_client.DeleteInstance(
730 instance=self.INSTANCE, zone=self.ZONE)
731 resource_mock.delete.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700732 project=PROJECT, zone=self.ZONE, instance=self.INSTANCE)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700733 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700734 mock.ANY,
735 operation_scope=gcompute_client.OperationScope.ZONE,
736 scope_name=self.ZONE)
737
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700738 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
739 def testDeleteInstances(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700740 """Test DeleteInstances."""
741 self._SetupBatchHttpRequestMock()
Tri Vo29ac1822016-10-01 17:06:29 -0700742 fake_instances = ["fake_instance_1", "fake_instance_2"]
743 mock_api = mock.MagicMock()
744 resource_mock = mock.MagicMock()
745 self.compute_client._service.instances = mock.MagicMock(
746 return_value=resource_mock)
747 resource_mock.delete = mock.MagicMock(return_value=mock_api)
748 deleted, failed, error_msgs = self.compute_client.DeleteInstances(
749 fake_instances, self.ZONE)
750 calls = [
751 mock.call(
Kevin Chengb5963882018-05-09 00:06:27 -0700752 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -0700753 instance="fake_instance_1",
Kevin Chengb5963882018-05-09 00:06:27 -0700754 zone=self.ZONE),
755 mock.call(
756 project=PROJECT,
757 instance="fake_instance_2",
758 zone=self.ZONE)
Tri Vo29ac1822016-10-01 17:06:29 -0700759 ]
760 resource_mock.delete.assert_has_calls(calls, any_order=True)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700761 self.assertEqual(mock_wait.call_count, 2)
Tri Vo29ac1822016-10-01 17:06:29 -0700762 self.assertEqual(error_msgs, [])
763 self.assertEqual(failed, [])
764 self.assertEqual(set(deleted), set(fake_instances))
765
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700766 def testCreateDiskWithProject(self):
767 """Test CreateDisk with images using a set project."""
768 source_project = "fake-image-project"
769 expected_project_to_use = "fake-image-project"
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700770 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
Kevin Chengb5963882018-05-09 00:06:27 -0700771 resource_mock = mock.MagicMock()
772 self.compute_client._service.disks = mock.MagicMock(
773 return_value=resource_mock)
774 resource_mock.insert = mock.MagicMock()
775 self.compute_client.CreateDisk(
776 "fake_disk", "fake_image", 10, self.ZONE, source_project=source_project)
777 resource_mock.insert.assert_called_with(
778 project=PROJECT,
779 zone=self.ZONE,
780 sourceImage="projects/%s/global/images/fake_image" %
781 expected_project_to_use,
782 body={
783 "name":
784 "fake_disk",
785 "sizeGb":
786 10,
787 "type":
788 "projects/%s/zones/%s/diskTypes/pd-standard" % (PROJECT,
789 self.ZONE)
790 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700791 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700792
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700793 def testCreateDiskWithNoSourceProject(self):
794 """Test CreateDisk with images with no set project."""
795 source_project = None
796 expected_project_to_use = PROJECT
797 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
798 resource_mock = mock.MagicMock()
799 self.compute_client._service.disks = mock.MagicMock(
800 return_value=resource_mock)
801 resource_mock.insert = mock.MagicMock()
802 self.compute_client.CreateDisk(
803 "fake_disk", "fake_image", 10, self.ZONE, source_project=source_project)
804 resource_mock.insert.assert_called_with(
805 project=PROJECT,
806 zone=self.ZONE,
807 sourceImage="projects/%s/global/images/fake_image" %
808 expected_project_to_use,
809 body={
810 "name":
811 "fake_disk",
812 "sizeGb":
813 10,
814 "type":
815 "projects/%s/zones/%s/diskTypes/pd-standard" % (PROJECT,
816 self.ZONE)
817 })
818 self.assertTrue(mock_wait.called)
819
820 def testCreateDiskWithTypeStandard(self):
821 """Test CreateDisk with images using standard."""
822 disk_type = gcompute_client.PersistentDiskType.STANDARD
823 expected_disk_type_string = "pd-standard"
824 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
825 resource_mock = mock.MagicMock()
826 self.compute_client._service.disks = mock.MagicMock(
827 return_value=resource_mock)
828 resource_mock.insert = mock.MagicMock()
829 self.compute_client.CreateDisk(
830 "fake_disk",
831 "fake_image",
832 10,
833 self.ZONE,
834 source_project="fake-project",
835 disk_type=disk_type)
836 resource_mock.insert.assert_called_with(
837 project=PROJECT,
838 zone=self.ZONE,
839 sourceImage="projects/%s/global/images/fake_image" % "fake-project",
840 body={
841 "name":
842 "fake_disk",
843 "sizeGb":
844 10,
845 "type":
846 "projects/%s/zones/%s/diskTypes/%s" %
847 (PROJECT, self.ZONE, expected_disk_type_string)
848 })
849 self.assertTrue(mock_wait.called)
850
851 def testCreateDiskWithTypeSSD(self):
852 """Test CreateDisk with images using standard."""
853 disk_type = gcompute_client.PersistentDiskType.SSD
854 expected_disk_type_string = "pd-ssd"
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700855 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
Kevin Chengb5963882018-05-09 00:06:27 -0700856 resource_mock = mock.MagicMock()
857 self.compute_client._service.disks = mock.MagicMock(
858 return_value=resource_mock)
859 resource_mock.insert = mock.MagicMock()
860 self.compute_client.CreateDisk(
861 "fake_disk",
862 "fake_image",
863 10,
864 self.ZONE,
865 source_project="fake-project",
866 disk_type=disk_type)
867 resource_mock.insert.assert_called_with(
868 project=PROJECT,
869 zone=self.ZONE,
870 sourceImage="projects/%s/global/images/fake_image" % "fake-project",
871 body={
872 "name":
873 "fake_disk",
874 "sizeGb":
875 10,
876 "type":
877 "projects/%s/zones/%s/diskTypes/%s" %
878 (PROJECT, self.ZONE, expected_disk_type_string)
879 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700880 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700881
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700882 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
883 def testAttachDisk(self, mock_wait):
Kevin Chengb5963882018-05-09 00:06:27 -0700884 """Test AttachDisk."""
Kevin Chengb5963882018-05-09 00:06:27 -0700885 resource_mock = mock.MagicMock()
886 self.compute_client._service.instances = mock.MagicMock(
887 return_value=resource_mock)
888 resource_mock.attachDisk = mock.MagicMock()
889 self.compute_client.AttachDisk(
890 "fake_instance_1", self.ZONE, deviceName="fake_disk",
891 source="fake-selfLink")
892 resource_mock.attachDisk.assert_called_with(
893 project=PROJECT,
894 zone=self.ZONE,
895 instance="fake_instance_1",
896 body={
897 "deviceName": "fake_disk",
898 "source": "fake-selfLink"
899 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700900 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700901
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700902 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
903 def testDetachDisk(self, mock_wait):
Kevin Chengb5963882018-05-09 00:06:27 -0700904 """Test DetachDisk."""
Kevin Chengb5963882018-05-09 00:06:27 -0700905 resource_mock = mock.MagicMock()
906 self.compute_client._service.instances = mock.MagicMock(
907 return_value=resource_mock)
908 resource_mock.detachDisk = mock.MagicMock()
909 self.compute_client.DetachDisk("fake_instance_1", self.ZONE, "fake_disk")
910 resource_mock.detachDisk.assert_called_with(
911 project=PROJECT,
912 zone=self.ZONE,
913 instance="fake_instance_1",
914 deviceName="fake_disk")
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700915 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700916
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700917 @mock.patch.object(gcompute_client.ComputeClient, "GetAcceleratorUrl")
918 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
919 def testAttachAccelerator(self, mock_wait, mock_get_accel):
Kevin Chengb5963882018-05-09 00:06:27 -0700920 """Test AttachAccelerator."""
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700921 mock_get_accel.return_value = self.ACCELERATOR_URL
Kevin Chengb5963882018-05-09 00:06:27 -0700922 resource_mock = mock.MagicMock()
923 self.compute_client._service.instances = mock.MagicMock(
924 return_value=resource_mock)
925 resource_mock.attachAccelerator = mock.MagicMock()
926 self.compute_client.AttachAccelerator("fake_instance_1", self.ZONE, 1,
927 "nvidia-tesla-k80")
928 resource_mock.setMachineResources.assert_called_with(
929 project=PROJECT,
930 zone=self.ZONE,
931 instance="fake_instance_1",
932 body={
933 "guestAccelerators": [{
934 "acceleratorType": self.ACCELERATOR_URL,
935 "acceleratorCount": 1
936 }]
937 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700938 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700939
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700940 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
941 def testBatchExecuteOnInstances(self, mock_wait):
942 """Test BatchExecuteOnInstances."""
Tri Vo29ac1822016-10-01 17:06:29 -0700943 self._SetupBatchHttpRequestMock()
Tri Vo29ac1822016-10-01 17:06:29 -0700944 action = mock.MagicMock(return_value=mock.MagicMock())
945 fake_instances = ["fake_instance_1", "fake_instance_2"]
946 done, failed, error_msgs = self.compute_client._BatchExecuteOnInstances(
947 fake_instances, self.ZONE, action)
948 calls = [mock.call(instance="fake_instance_1"),
949 mock.call(instance="fake_instance_2")]
950 action.assert_has_calls(calls, any_order=True)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700951 self.assertEqual(mock_wait.call_count, 2)
Tri Vo29ac1822016-10-01 17:06:29 -0700952 self.assertEqual(set(done), set(fake_instances))
953 self.assertEqual(error_msgs, [])
954 self.assertEqual(failed, [])
955
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700956 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
957 def testResetInstance(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700958 """Test ResetInstance."""
Tri Vo29ac1822016-10-01 17:06:29 -0700959 resource_mock = mock.MagicMock()
960 self.compute_client._service.instances = mock.MagicMock(
961 return_value=resource_mock)
962 resource_mock.reset = mock.MagicMock()
963 self.compute_client.ResetInstance(
964 instance=self.INSTANCE, zone=self.ZONE)
965 resource_mock.reset.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700966 project=PROJECT, zone=self.ZONE, instance=self.INSTANCE)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700967 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700968 mock.ANY,
969 operation_scope=gcompute_client.OperationScope.ZONE,
970 scope_name=self.ZONE)
971
972 def _CompareMachineSizeTestHelper(self,
973 machine_info_1,
974 machine_info_2,
975 expected_result=None,
976 expected_error_type=None):
977 """Helper class for testing CompareMachineSize.
978
Kevin Chengb5963882018-05-09 00:06:27 -0700979 Args:
980 machine_info_1: A dictionary representing the first machine size.
981 machine_info_2: A dictionary representing the second machine size.
982 expected_result: An integer, 0, 1 or -1, or None if not set.
983 expected_error_type: An exception type, if set will check for exception.
984 """
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700985 mock_get_mach_type = self.Patch(
Tri Vo29ac1822016-10-01 17:06:29 -0700986 gcompute_client.ComputeClient,
987 "GetMachineType",
988 side_effect=[machine_info_1, machine_info_2])
989 if expected_error_type:
990 self.assertRaises(expected_error_type,
991 self.compute_client.CompareMachineSize, "name1",
992 "name2", self.ZONE)
993 else:
994 result = self.compute_client.CompareMachineSize("name1", "name2",
995 self.ZONE)
996 self.assertEqual(result, expected_result)
997
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700998 mock_get_mach_type.assert_has_calls(
Tri Vo29ac1822016-10-01 17:06:29 -0700999 [mock.call("name1", self.ZONE), mock.call("name2", self.ZONE)])
1000
1001 def testCompareMachineSizeSmall(self):
1002 """Test CompareMachineSize where the first one is smaller."""
1003 machine_info_1 = {"guestCpus": 10, "memoryMb": 100}
1004 machine_info_2 = {"guestCpus": 10, "memoryMb": 200}
1005 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, -1)
1006
Kevin Cheng4ae42772018-10-02 11:39:48 -07001007 def testCompareMachineSizeSmallSmallerOnSecond(self):
1008 """Test CompareMachineSize where the first one is smaller."""
1009 machine_info_1 = {"guestCpus": 11, "memoryMb": 100}
1010 machine_info_2 = {"guestCpus": 10, "memoryMb": 200}
1011 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, -1)
1012
Tri Vo29ac1822016-10-01 17:06:29 -07001013 def testCompareMachineSizeLarge(self):
1014 """Test CompareMachineSize where the first one is larger."""
Kevin Cheng4ae42772018-10-02 11:39:48 -07001015 machine_info_1 = {"guestCpus": 11, "memoryMb": 200}
1016 machine_info_2 = {"guestCpus": 10, "memoryMb": 100}
1017 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, 1)
1018
1019 def testCompareMachineSizeLargeWithEqualElement(self):
1020 """Test CompareMachineSize where the first one is larger."""
Tri Vo29ac1822016-10-01 17:06:29 -07001021 machine_info_1 = {"guestCpus": 10, "memoryMb": 200}
1022 machine_info_2 = {"guestCpus": 10, "memoryMb": 100}
1023 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, 1)
1024
1025 def testCompareMachineSizeEqual(self):
1026 """Test CompareMachineSize where two machine sizes are equal."""
1027 machine_info = {"guestCpus": 10, "memoryMb": 100}
1028 self._CompareMachineSizeTestHelper(machine_info, machine_info, 0)
1029
1030 def testCompareMachineSizeBadMetric(self):
1031 """Test CompareMachineSize with bad metric."""
Kevin Chengb5963882018-05-09 00:06:27 -07001032 machine_info = {"unknown_metric": 10, "memoryMb": 100}
Tri Vo29ac1822016-10-01 17:06:29 -07001033 self._CompareMachineSizeTestHelper(
1034 machine_info, machine_info, expected_error_type=errors.DriverError)
1035
1036 def testGetMachineType(self):
1037 """Test GetMachineType."""
1038 resource_mock = mock.MagicMock()
1039 mock_api = mock.MagicMock()
1040 self.compute_client._service.machineTypes = mock.MagicMock(
1041 return_value=resource_mock)
1042 resource_mock.get = mock.MagicMock(return_value=mock_api)
1043 mock_api.execute = mock.MagicMock(
1044 return_value={"name": self.MACHINE_TYPE})
1045 result = self.compute_client.GetMachineType(self.MACHINE_TYPE,
1046 self.ZONE)
1047 self.assertEqual(result, {"name": self.MACHINE_TYPE})
1048 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -07001049 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -07001050 zone=self.ZONE,
1051 machineType=self.MACHINE_TYPE)
1052
1053 def _GetSerialPortOutputTestHelper(self, response):
1054 """Helper function for testing GetSerialPortOutput.
1055
Kevin Chengb5963882018-05-09 00:06:27 -07001056 Args:
1057 response: A dictionary representing a fake response.
1058 """
Tri Vo29ac1822016-10-01 17:06:29 -07001059 resource_mock = mock.MagicMock()
1060 mock_api = mock.MagicMock()
1061 self.compute_client._service.instances = mock.MagicMock(
1062 return_value=resource_mock)
1063 resource_mock.getSerialPortOutput = mock.MagicMock(
1064 return_value=mock_api)
1065 mock_api.execute = mock.MagicMock(return_value=response)
1066
1067 if "contents" in response:
1068 result = self.compute_client.GetSerialPortOutput(
1069 instance=self.INSTANCE, zone=self.ZONE)
1070 self.assertEqual(result, "fake contents")
1071 else:
1072 self.assertRaisesRegexp(
1073 errors.DriverError,
1074 "Malformed response.*",
1075 self.compute_client.GetSerialPortOutput,
1076 instance=self.INSTANCE,
1077 zone=self.ZONE)
1078 resource_mock.getSerialPortOutput.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -07001079 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -07001080 zone=self.ZONE,
1081 instance=self.INSTANCE,
1082 port=1)
1083
1084 def testGetSerialPortOutput(self):
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001085 """Test GetSerialPortOutput."""
Tri Vo29ac1822016-10-01 17:06:29 -07001086 response = {"contents": "fake contents"}
1087 self._GetSerialPortOutputTestHelper(response)
1088
1089 def testGetSerialPortOutputFail(self):
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001090 """Test GetSerialPortOutputFail."""
Tri Vo29ac1822016-10-01 17:06:29 -07001091 response = {"malformed": "fake contents"}
1092 self._GetSerialPortOutputTestHelper(response)
1093
1094 def testGetInstanceNamesByIPs(self):
1095 """Test GetInstanceNamesByIPs."""
1096 good_instance = {
1097 "name": "instance_1",
1098 "networkInterfaces": [
1099 {
1100 "accessConfigs": [
1101 {"natIP": "172.22.22.22"},
1102 ],
1103 },
1104 ],
1105 }
1106 bad_instance = {"name": "instance_2"}
1107 self.Patch(
1108 gcompute_client.ComputeClient,
1109 "ListInstances",
1110 return_value=[good_instance, bad_instance])
1111 ip_name_map = self.compute_client.GetInstanceNamesByIPs(
1112 ips=["172.22.22.22", "172.22.22.23"], zone=self.ZONE)
1113 self.assertEqual(ip_name_map, {"172.22.22.22": "instance_1",
1114 "172.22.22.23": None})
1115
cylan64af2db2019-01-17 15:13:59 +08001116 def testRsaNotInMetadata(self):
1117 """Test rsa not in metadata."""
Tri Vo29ac1822016-10-01 17:06:29 -07001118 fake_user = "fake_user"
cylan64af2db2019-01-17 15:13:59 +08001119 fake_ssh_key = "fake_ssh"
1120 metadata = {
1121 "kind": "compute#metadata",
1122 "fingerprint": "a-23icsyx4E=",
1123 "items": [
1124 {
1125 "key": "sshKeys",
1126 "value": "%s:%s" % (fake_user, self.SSHKEY)
1127 }
1128 ]
1129 }
1130 # Test rsa doesn't exist in metadata.
1131 new_entry = "%s:%s" % (fake_user, fake_ssh_key)
1132 self.assertEqual(True, gcompute_client.RsaNotInMetadata(metadata, new_entry))
1133
1134 # Test rsa exists in metadata.
1135 exist_entry = "%s:%s" %(fake_user, self.SSHKEY)
1136 self.assertEqual(False, gcompute_client.RsaNotInMetadata(metadata, exist_entry))
1137
1138 def testGetSshKeyFromMetadata(self):
1139 """Test get ssh key from metadata."""
1140 fake_user = "fake_user"
1141 metadata_key_exist_value_is_empty = {
1142 "kind": "compute#metadata",
1143 "fingerprint": "a-23icsyx4E=",
1144 "items": [
1145 {
1146 "key": "sshKeys",
1147 "value": ""
1148 }
1149 ]
1150 }
1151 metadata_key_exist = {
1152 "kind": "compute#metadata",
1153 "fingerprint": "a-23icsyx4E=",
1154 "items": [
1155 {
1156 "key": "sshKeys",
1157 "value": "%s:%s" % (fake_user, self.SSHKEY)
1158 }
1159 ]
1160 }
1161 metadata_key_not_exist = {
1162 "kind": "compute#metadata",
1163 "fingerprint": "a-23icsyx4E=",
1164 "items": [
1165 {
1166 }
1167 ]
1168 }
1169 expected_key_exist_value_is_empty = {
1170 "key": "sshKeys",
1171 "value": ""
1172 }
1173 expected_key_exist = {
1174 "key": "sshKeys",
1175 "value": "%s:%s" % (fake_user, self.SSHKEY)
1176 }
1177 self.assertEqual(expected_key_exist_value_is_empty,
1178 gcompute_client.GetSshKeyFromMetadata(metadata_key_exist_value_is_empty))
1179 self.assertEqual(expected_key_exist,
1180 gcompute_client.GetSshKeyFromMetadata(metadata_key_exist))
1181 self.assertEqual(None,
1182 gcompute_client.GetSshKeyFromMetadata(metadata_key_not_exist))
1183
1184
1185 def testGetRsaKeyPathExistsFalse(self):
1186 """Test the rsa key path not exists."""
1187 fake_ssh_rsa_path = "/path/to/test_rsa.pub"
1188 self.Patch(os.path, "exists", return_value=False)
1189 self.assertRaisesRegexp(errors.DriverError,
1190 "RSA file %s does not exist." % fake_ssh_rsa_path,
1191 gcompute_client.GetRsaKey,
1192 ssh_rsa_path=fake_ssh_rsa_path)
1193
1194 def testGetRsaKey(self):
1195 """Test get the rsa key."""
1196 fake_ssh_rsa_path = "/path/to/test_rsa.pub"
1197 self.Patch(os.path, "exists", return_value=True)
1198 m = mock.mock_open(read_data=self.SSHKEY)
1199 with mock.patch("__builtin__.open", m):
1200 result = gcompute_client.GetRsaKey(fake_ssh_rsa_path)
1201 self.assertEqual(self.SSHKEY, result)
1202
1203 def testUpdateRsaInMetadata(self):
1204 """Test update rsa in metadata."""
1205 fake_ssh_key = "fake_ssh"
1206 fake_metadata_sshkeys_not_exist = {
1207 "kind": "compute#metadata",
1208 "fingerprint": "a-23icsyx4E=",
1209 "items": [
1210 {
1211 "key": "not_sshKeys",
1212 "value": ""
1213 }
1214 ]
1215 }
1216 new_entry = "new_user:%s" % fake_ssh_key
1217 expected = {
1218 "kind": "compute#metadata",
1219 "fingerprint": "a-23icsyx4E=",
1220 "items": [
1221 {
1222 "key": "not_sshKeys",
1223 "value": ""
1224 },
1225 {
1226 "key": "sshKeys",
1227 "value": new_entry
1228 }
1229 ]
1230 }
1231 self.Patch(os.path, "exists", return_value=True)
1232 self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
1233 resource_mock = mock.MagicMock()
1234 self.compute_client.SetInstanceMetadata = mock.MagicMock(
1235 return_value=resource_mock)
1236 # Test the key item not exists in the metadata.
1237 self.compute_client.UpdateRsaInMetadata(
1238 "fake_zone",
1239 "fake_instance",
1240 fake_metadata_sshkeys_not_exist,
1241 new_entry)
1242 self.compute_client.SetInstanceMetadata.assert_called_with(
1243 "fake_zone",
1244 "fake_instance",
1245 expected)
1246
1247 # Test the key item exists in the metadata.
1248 fake_metadata_ssh_keys_exists = {
1249 "kind": "compute#metadata",
1250 "fingerprint": "a-23icsyx4E=",
1251 "items": [
1252 {
1253 "key": "sshKeys",
1254 "value": "old_user:%s" % self.SSHKEY
1255 }
1256 ]
1257 }
1258 expected_ssh_keys_exists = {
1259 "kind": "compute#metadata",
1260 "fingerprint": "a-23icsyx4E=",
1261 "items": [
1262 {
1263 "key": "sshKeys",
1264 "value": "old_user:%s\n%s" % (self.SSHKEY, new_entry)
1265 }
1266 ]
1267 }
1268
1269 self.compute_client.UpdateRsaInMetadata(
1270 "fake_zone",
1271 "fake_instance",
1272 fake_metadata_ssh_keys_exists,
1273 new_entry)
1274 self.compute_client.SetInstanceMetadata.assert_called_with(
1275 "fake_zone",
1276 "fake_instance",
1277 expected_ssh_keys_exists)
1278
1279 def testAddSshRsaToInstance(self):
1280 """Test add ssh rsa key to instance."""
1281 fake_user = "fake_user"
1282 instance_metadata_key_not_exist = {
1283 "metadata": {
Tri Vo29ac1822016-10-01 17:06:29 -07001284 "kind": "compute#metadata",
1285 "fingerprint": "a-23icsyx4E=",
1286 "items": [
1287 {
1288 "key": "sshKeys",
cylan64af2db2019-01-17 15:13:59 +08001289 "value": ""
1290 }
1291 ]
1292 }
1293 }
1294 instance_metadata_key_exist = {
1295 "metadata": {
1296 "kind": "compute#metadata",
1297 "fingerprint": "a-23icsyx4E=",
1298 "items": [
1299 {
1300 "key": "sshKeys",
1301 "value": "%s:%s" % (fake_user, self.SSHKEY)
Tri Vo29ac1822016-10-01 17:06:29 -07001302 }
1303 ]
1304 }
1305 }
1306 expected = {
1307 "kind": "compute#metadata",
1308 "fingerprint": "a-23icsyx4E=",
1309 "items": [
1310 {
1311 "key": "sshKeys",
cylan64af2db2019-01-17 15:13:59 +08001312 "value": "%s:%s" % (fake_user, self.SSHKEY)
Tri Vo29ac1822016-10-01 17:06:29 -07001313 }
1314 ]
1315 }
1316
1317 self.Patch(os.path, "exists", return_value=True)
cylan64af2db2019-01-17 15:13:59 +08001318 m = mock.mock_open(read_data=self.SSHKEY)
Tri Vo29ac1822016-10-01 17:06:29 -07001319 self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
Tri Vo29ac1822016-10-01 17:06:29 -07001320 resource_mock = mock.MagicMock()
cylan64af2db2019-01-17 15:13:59 +08001321 self.compute_client._service.instances = mock.MagicMock(
Tri Vo29ac1822016-10-01 17:06:29 -07001322 return_value=resource_mock)
cylan64af2db2019-01-17 15:13:59 +08001323 resource_mock.setMetadata = mock.MagicMock()
Tri Vo29ac1822016-10-01 17:06:29 -07001324
cylan64af2db2019-01-17 15:13:59 +08001325 # Test the key not exists in the metadata.
Tri Vo29ac1822016-10-01 17:06:29 -07001326 self.Patch(
cylan64af2db2019-01-17 15:13:59 +08001327 gcompute_client.ComputeClient, "GetInstance",
1328 return_value=instance_metadata_key_not_exist)
Kevin Chengda4f07a2018-06-26 10:25:05 -07001329 with mock.patch("__builtin__.open", m):
cylan64af2db2019-01-17 15:13:59 +08001330 self.compute_client.AddSshRsaInstanceMetadata(
1331 "fake_zone",
1332 fake_user,
1333 "/path/to/test_rsa.pub",
1334 "fake_instance")
1335 resource_mock.setMetadata.assert_called_with(
1336 project=PROJECT,
1337 zone="fake_zone",
1338 instance="fake_instance",
1339 body=expected)
1340
1341 # Test the key already exists in the metadata.
1342 resource_mock.setMetadata.call_count = 0
1343 self.Patch(
1344 gcompute_client.ComputeClient, "GetInstance",
1345 return_value=instance_metadata_key_exist)
1346 with mock.patch("__builtin__.open", m):
1347 self.compute_client.AddSshRsaInstanceMetadata(
1348 "fake_zone",
1349 fake_user,
1350 "/path/to/test_rsa.pub",
1351 "fake_instance")
1352 resource_mock.setMetadata.assert_not_called()
Tri Vo29ac1822016-10-01 17:06:29 -07001353
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001354 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
1355 def testDeleteDisks(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -07001356 """Test DeleteDisks."""
1357 self._SetupBatchHttpRequestMock()
Tri Vo29ac1822016-10-01 17:06:29 -07001358 fake_disks = ["fake_disk_1", "fake_disk_2"]
1359 mock_api = mock.MagicMock()
1360 resource_mock = mock.MagicMock()
1361 self.compute_client._service.disks = mock.MagicMock(
1362 return_value=resource_mock)
1363 resource_mock.delete = mock.MagicMock(return_value=mock_api)
1364 # Call the API.
1365 deleted, failed, error_msgs = self.compute_client.DeleteDisks(
1366 fake_disks, zone=self.ZONE)
1367 # Verify
Kevin Chengb5963882018-05-09 00:06:27 -07001368 calls = [
1369 mock.call(project=PROJECT, disk="fake_disk_1", zone=self.ZONE),
1370 mock.call(project=PROJECT, disk="fake_disk_2", zone=self.ZONE)
1371 ]
Tri Vo29ac1822016-10-01 17:06:29 -07001372 resource_mock.delete.assert_has_calls(calls, any_order=True)
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001373 self.assertEqual(mock_wait.call_count, 2)
Tri Vo29ac1822016-10-01 17:06:29 -07001374 self.assertEqual(error_msgs, [])
1375 self.assertEqual(failed, [])
1376 self.assertEqual(set(deleted), set(fake_disks))
1377
Kevin Chengb5963882018-05-09 00:06:27 -07001378 def testRetryOnFingerPrintError(self):
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001379 """Test RetryOnFingerPrintError."""
Kevin Chengb5963882018-05-09 00:06:27 -07001380 @utils.RetryOnException(gcompute_client._IsFingerPrintError, 10)
1381 def Raise412(sentinel):
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001382 """Raise 412 HTTP exception."""
1383 if not sentinel.hitFingerPrintConflict.called:
1384 sentinel.hitFingerPrintConflict()
1385 raise errors.HttpError(412, "resource labels have changed")
1386 return "Passed"
Kevin Chengb5963882018-05-09 00:06:27 -07001387
1388 sentinel = mock.MagicMock()
1389 result = Raise412(sentinel)
1390 self.assertEqual(1, sentinel.hitFingerPrintConflict.call_count)
1391 self.assertEqual("Passed", result)
1392
Tri Vo29ac1822016-10-01 17:06:29 -07001393
1394if __name__ == "__main__":
1395 unittest.main()