blob: 6dbf8d3ab4b2da0b19e5aef96da8f7756ed4a047 [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
herbertxue1512f8a2019-06-27 13:56:23 +080033
Kevin Chengb5963882018-05-09 00:06:27 -070034GS_IMAGE_SOURCE_URI = "https://storage.googleapis.com/fake-bucket/fake.tar.gz"
35GS_IMAGE_SOURCE_DISK = (
36 "https://www.googleapis.com/compute/v1/projects/fake-project/zones/"
37 "us-east1-d/disks/fake-disk")
38PROJECT = "fake-project"
Tri Vo29ac1822016-10-01 17:06:29 -070039
herbertxue1512f8a2019-06-27 13:56:23 +080040
Kevin Cheng5c124ec2018-05-16 13:28:51 -070041# pylint: disable=protected-access, too-many-public-methods
Kevin Cheng070ae5c2018-08-02 16:03:00 -070042class ComputeClientTest(driver_test_lib.BaseDriverTest):
Tri Vo29ac1822016-10-01 17:06:29 -070043 """Test ComputeClient."""
44
Kevin Chengb5963882018-05-09 00:06:27 -070045 PROJECT_OTHER = "fake-project-other"
Tri Vo29ac1822016-10-01 17:06:29 -070046 INSTANCE = "fake-instance"
47 IMAGE = "fake-image"
48 IMAGE_URL = "http://fake-image-url"
Kevin Chengb5963882018-05-09 00:06:27 -070049 IMAGE_OTHER = "fake-image-other"
Tri Vo29ac1822016-10-01 17:06:29 -070050 MACHINE_TYPE = "fake-machine-type"
51 MACHINE_TYPE_URL = "http://fake-machine-type-url"
52 METADATA = ("metadata_key", "metadata_value")
Kevin Chengb5963882018-05-09 00:06:27 -070053 ACCELERATOR_URL = "http://speedy-gpu"
Tri Vo29ac1822016-10-01 17:06:29 -070054 NETWORK = "fake-network"
55 NETWORK_URL = "http://fake-network-url"
Kevin Cheng480e1212018-10-24 00:23:30 -070056 SUBNETWORK_URL = "http://fake-subnetwork-url"
Tri Vo29ac1822016-10-01 17:06:29 -070057 ZONE = "fake-zone"
58 REGION = "fake-region"
59 OPERATION_NAME = "fake-op"
Kevin Chengb5963882018-05-09 00:06:27 -070060 IMAGE_FINGERPRINT = "L_NWHuz7wTY="
61 GPU = "fancy-graphics"
cylan64af2db2019-01-17 15:13:59 +080062 SSHKEY = (
63 "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDBkTOTRze9v2VOqkkf7RG"
64 "jSkg6Z2kb9Q9UHsDGatvend3fmjIw1Tugg0O7nnjlPkskmlgyd4a/j99WOeLL"
65 "CPk6xPyoVjrPUVBU/pAk09ORTC4Zqk6YjlW7LOfzvqmXhmIZfYu6Q4Yt50pZzhl"
66 "lllfu26nYjY7Tg12D019nJi/kqPX5+NKgt0LGXTu8T1r2Gav/q4V7QRWQrB8Eiu"
67 "pxXR7I2YhynqovkEt/OXG4qWgvLEXGsWtSQs0CtCzqEVxz0Y9ECr7er4VdjSQxV"
68 "AaeLAsQsK9ROae8hMBFZ3//8zLVapBwpuffCu+fUoql9qeV9xagZcc9zj8XOUOW"
69 "ApiihqNL1111 test@test1.org")
Kevin Chengc330f6f2019-05-13 09:32:42 -070070 EXTRA_SCOPES = ["scope1"]
Tri Vo29ac1822016-10-01 17:06:29 -070071
72 def setUp(self):
73 """Set up test."""
74 super(ComputeClientTest, self).setUp()
75 self.Patch(gcompute_client.ComputeClient, "InitResourceHandle")
76 fake_cfg = mock.MagicMock()
Kevin Chengb5963882018-05-09 00:06:27 -070077 fake_cfg.project = PROJECT
Kevin Chengc330f6f2019-05-13 09:32:42 -070078 fake_cfg.extra_scopes = self.EXTRA_SCOPES
Kevin Chengb5963882018-05-09 00:06:27 -070079 self.compute_client = gcompute_client.ComputeClient(
80 fake_cfg, mock.MagicMock())
Tri Vo29ac1822016-10-01 17:06:29 -070081 self.compute_client._service = mock.MagicMock()
82
Kevin Cheng5c124ec2018-05-16 13:28:51 -070083 self._disk_args = copy.deepcopy(gcompute_client.BASE_DISK_ARGS)
84 self._disk_args["initializeParams"] = {"diskName": self.INSTANCE,
85 "sourceImage": self.IMAGE_URL}
86
87 # pylint: disable=invalid-name
Tri Vo29ac1822016-10-01 17:06:29 -070088 def _SetupMocksForGetOperationStatus(self, mock_result, operation_scope):
89 """A helper class for setting up mocks for testGetOperationStatus*.
90
Kevin Chengb5963882018-05-09 00:06:27 -070091 Args:
92 mock_result: The result to return by _GetOperationStatus.
93 operation_scope: A value of OperationScope.
Tri Vo29ac1822016-10-01 17:06:29 -070094
Kevin Chengb5963882018-05-09 00:06:27 -070095 Returns:
96 A mock for Resource object.
97 """
Tri Vo29ac1822016-10-01 17:06:29 -070098 resource_mock = mock.MagicMock()
99 mock_api = mock.MagicMock()
100 if operation_scope == gcompute_client.OperationScope.GLOBAL:
101 self.compute_client._service.globalOperations = mock.MagicMock(
102 return_value=resource_mock)
103 elif operation_scope == gcompute_client.OperationScope.ZONE:
104 self.compute_client._service.zoneOperations = mock.MagicMock(
105 return_value=resource_mock)
106 elif operation_scope == gcompute_client.OperationScope.REGION:
107 self.compute_client._service.regionOperations = mock.MagicMock(
108 return_value=resource_mock)
109 resource_mock.get = mock.MagicMock(return_value=mock_api)
110 mock_api.execute = mock.MagicMock(return_value=mock_result)
111 return resource_mock
112
113 def testGetOperationStatusGlobal(self):
114 """Test _GetOperationStatus for global."""
115 resource_mock = self._SetupMocksForGetOperationStatus(
116 {"status": "GOOD"}, gcompute_client.OperationScope.GLOBAL)
117 status = self.compute_client._GetOperationStatus(
118 {"name": self.OPERATION_NAME},
119 gcompute_client.OperationScope.GLOBAL)
120 self.assertEqual(status, "GOOD")
121 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700122 project=PROJECT, operation=self.OPERATION_NAME)
Tri Vo29ac1822016-10-01 17:06:29 -0700123
124 def testGetOperationStatusZone(self):
125 """Test _GetOperationStatus for zone."""
126 resource_mock = self._SetupMocksForGetOperationStatus(
127 {"status": "GOOD"}, gcompute_client.OperationScope.ZONE)
128 status = self.compute_client._GetOperationStatus(
129 {"name": self.OPERATION_NAME}, gcompute_client.OperationScope.ZONE,
130 self.ZONE)
131 self.assertEqual(status, "GOOD")
132 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700133 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -0700134 operation=self.OPERATION_NAME,
135 zone=self.ZONE)
136
137 def testGetOperationStatusRegion(self):
138 """Test _GetOperationStatus for region."""
139 resource_mock = self._SetupMocksForGetOperationStatus(
140 {"status": "GOOD"}, gcompute_client.OperationScope.REGION)
141 self.compute_client._GetOperationStatus(
142 {"name": self.OPERATION_NAME},
143 gcompute_client.OperationScope.REGION, self.REGION)
144 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700145 project=PROJECT, operation=self.OPERATION_NAME, region=self.REGION)
Tri Vo29ac1822016-10-01 17:06:29 -0700146
147 def testGetOperationStatusError(self):
148 """Test _GetOperationStatus failed."""
149 self._SetupMocksForGetOperationStatus(
150 {"error": {"errors": ["error1", "error2"]}},
151 gcompute_client.OperationScope.GLOBAL)
152 self.assertRaisesRegexp(errors.DriverError,
153 "Get operation state failed.*error1.*error2",
154 self.compute_client._GetOperationStatus,
155 {"name": self.OPERATION_NAME},
156 gcompute_client.OperationScope.GLOBAL)
157
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700158 @mock.patch.object(errors, "GceOperationTimeoutError")
159 @mock.patch.object(utils, "PollAndWait")
160 def testWaitOnOperation(self, mock_poll, mock_gce_operation_timeout_error):
Tri Vo29ac1822016-10-01 17:06:29 -0700161 """Test WaitOnOperation."""
162 mock_error = mock.MagicMock()
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700163 mock_gce_operation_timeout_error.return_value = mock_error
Tri Vo29ac1822016-10-01 17:06:29 -0700164 self.compute_client.WaitOnOperation(
165 operation={"name": self.OPERATION_NAME},
166 operation_scope=gcompute_client.OperationScope.REGION,
167 scope_name=self.REGION)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700168 mock_poll.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700169 func=self.compute_client._GetOperationStatus,
170 expected_return="DONE",
171 timeout_exception=mock_error,
172 timeout_secs=self.compute_client.OPERATION_TIMEOUT_SECS,
Kevin Chengb5963882018-05-09 00:06:27 -0700173 sleep_interval_secs=self.compute_client.OPERATION_POLL_INTERVAL_SECS,
Tri Vo29ac1822016-10-01 17:06:29 -0700174 operation={"name": self.OPERATION_NAME},
175 operation_scope=gcompute_client.OperationScope.REGION,
176 scope_name=self.REGION)
177
Kevin Chengb5963882018-05-09 00:06:27 -0700178 def testGetImage(self):
179 """Test GetImage."""
180 resource_mock = mock.MagicMock()
181 mock_api = mock.MagicMock()
182 self.compute_client._service.images = mock.MagicMock(
183 return_value=resource_mock)
184 resource_mock.get = mock.MagicMock(return_value=mock_api)
185 mock_api.execute = mock.MagicMock(return_value={"name": self.IMAGE})
186 result = self.compute_client.GetImage(self.IMAGE)
187 self.assertEqual(result, {"name": self.IMAGE})
188 resource_mock.get.assert_called_with(project=PROJECT, image=self.IMAGE)
189
190 def testGetImageOther(self):
191 """Test GetImage with other project."""
192 resource_mock = mock.MagicMock()
193 mock_api = mock.MagicMock()
194 self.compute_client._service.images = mock.MagicMock(
195 return_value=resource_mock)
196 resource_mock.get = mock.MagicMock(return_value=mock_api)
197 mock_api.execute = mock.MagicMock(return_value={"name": self.IMAGE_OTHER})
198 result = self.compute_client.GetImage(
199 image_name=self.IMAGE_OTHER,
200 image_project=self.PROJECT_OTHER)
201 self.assertEqual(result, {"name": self.IMAGE_OTHER})
202 resource_mock.get.assert_called_with(
203 project=self.PROJECT_OTHER, image=self.IMAGE_OTHER)
204
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700205 def testCreateImageWithSourceURI(self):
206 """Test CreateImage with src uri."""
207 source_uri = GS_IMAGE_SOURCE_URI
208 source_disk = None
209 labels = None
210 expected_body = {"name": self.IMAGE,
211 "rawDisk": {"source": GS_IMAGE_SOURCE_URI}}
212 mock_check = self.Patch(gcompute_client.ComputeClient,
213 "CheckImageExists",
214 return_value=False)
215 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
216 resource_mock = mock.MagicMock()
217 self.compute_client._service.images = mock.MagicMock(
218 return_value=resource_mock)
219 resource_mock.insert = mock.MagicMock()
220 self.compute_client.CreateImage(
221 image_name=self.IMAGE, source_uri=source_uri,
222 source_disk=source_disk, labels=labels)
223 resource_mock.insert.assert_called_with(
224 project=PROJECT, body=expected_body)
225 mock_wait.assert_called_with(
226 operation=mock.ANY,
227 operation_scope=gcompute_client.OperationScope.GLOBAL)
228 mock_check.assert_called_with(self.IMAGE)
229
230 def testCreateImageWithSourceDisk(self):
231 """Test CreateImage with src disk."""
232 source_uri = None
233 source_disk = GS_IMAGE_SOURCE_DISK
234 labels = None
235 expected_body = {"name": self.IMAGE,
236 "sourceDisk": GS_IMAGE_SOURCE_DISK}
237 mock_check = self.Patch(gcompute_client.ComputeClient,
238 "CheckImageExists",
239 return_value=False)
240 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
241 resource_mock = mock.MagicMock()
242 self.compute_client._service.images = mock.MagicMock(
243 return_value=resource_mock)
244 resource_mock.insert = mock.MagicMock()
245 self.compute_client.CreateImage(
246 image_name=self.IMAGE, source_uri=source_uri,
247 source_disk=source_disk, labels=labels)
248 resource_mock.insert.assert_called_with(
249 project=PROJECT, body=expected_body)
250 mock_wait.assert_called_with(
251 operation=mock.ANY,
252 operation_scope=gcompute_client.OperationScope.GLOBAL)
253 mock_check.assert_called_with(self.IMAGE)
254
255 def testCreateImageWithSourceDiskAndLabel(self):
256 """Test CreateImage with src disk and label."""
257 source_uri = None
258 source_disk = GS_IMAGE_SOURCE_DISK
259 labels = {"label1": "xxx"}
260 expected_body = {"name": self.IMAGE,
261 "sourceDisk": GS_IMAGE_SOURCE_DISK,
262 "labels": {"label1": "xxx"}}
herbertxue308f7662018-05-18 03:25:58 +0000263 mock_check = self.Patch(gcompute_client.ComputeClient,
264 "CheckImageExists",
265 return_value=False)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700266 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
Tri Vo29ac1822016-10-01 17:06:29 -0700267 resource_mock = mock.MagicMock()
268 self.compute_client._service.images = mock.MagicMock(
269 return_value=resource_mock)
270 resource_mock.insert = mock.MagicMock()
Tri Vo29ac1822016-10-01 17:06:29 -0700271 self.compute_client.CreateImage(
Kevin Chengb5963882018-05-09 00:06:27 -0700272 image_name=self.IMAGE, source_uri=source_uri,
273 source_disk=source_disk, labels=labels)
Tri Vo29ac1822016-10-01 17:06:29 -0700274 resource_mock.insert.assert_called_with(
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700275 project=PROJECT, body=expected_body)
276 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700277 operation=mock.ANY,
278 operation_scope=gcompute_client.OperationScope.GLOBAL)
herbertxue308f7662018-05-18 03:25:58 +0000279 mock_check.assert_called_with(self.IMAGE)
Tri Vo29ac1822016-10-01 17:06:29 -0700280
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700281 @mock.patch.object(gcompute_client.ComputeClient, "GetImage")
282 def testSetImageLabel(self, mock_get_image):
283 """Test SetImageLabel."""
284 with mock.patch.object(self.compute_client._service, "images",
285 return_value=mock.MagicMock(
286 setLabels=mock.MagicMock())) as _:
287 image = {"name": self.IMAGE,
288 "sourceDisk": GS_IMAGE_SOURCE_DISK,
289 "labelFingerprint": self.IMAGE_FINGERPRINT,
290 "labels": {"a": "aaa", "b": "bbb"}}
291 mock_get_image.return_value = image
292 new_labels = {"a": "xxx", "c": "ccc"}
293 # Test
294 self.compute_client.SetImageLabels(
295 self.IMAGE, new_labels)
296 # Check result
297 expected_labels = {"a": "xxx", "b": "bbb", "c": "ccc"}
298 self.compute_client._service.images().setLabels.assert_called_with(
299 project=PROJECT,
300 resource=self.IMAGE,
301 body={
302 "labels": expected_labels,
303 "labelFingerprint": self.IMAGE_FINGERPRINT
304 })
Kevin Chengb5963882018-05-09 00:06:27 -0700305
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700306 def testCreateImageRaiseDriverErrorWithValidInput(self):
307 """Test CreateImage with valid input."""
308 source_uri = GS_IMAGE_SOURCE_URI
309 source_disk = GS_IMAGE_SOURCE_DISK
herbertxue308f7662018-05-18 03:25:58 +0000310 self.Patch(gcompute_client.ComputeClient, "CheckImageExists", return_value=False)
Kevin Chengb5963882018-05-09 00:06:27 -0700311 self.assertRaises(errors.DriverError, self.compute_client.CreateImage,
312 image_name=self.IMAGE, source_uri=source_uri,
313 source_disk=source_disk)
314
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700315 def testCreateImageRaiseDriverErrorWithInvalidInput(self):
316 """Test CreateImage with valid input."""
317 source_uri = None
318 source_disk = None
319 self.Patch(gcompute_client.ComputeClient, "CheckImageExists", return_value=False)
320 self.assertRaises(errors.DriverError, self.compute_client.CreateImage,
321 image_name=self.IMAGE, source_uri=source_uri,
322 source_disk=source_disk)
Tri Vo29ac1822016-10-01 17:06:29 -0700323
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700324 @mock.patch.object(gcompute_client.ComputeClient, "DeleteImage")
325 @mock.patch.object(gcompute_client.ComputeClient, "CheckImageExists",
herbertxue308f7662018-05-18 03:25:58 +0000326 side_effect=[False, True])
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700327 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation",
328 side_effect=errors.DriverError("Expected fake error"))
329 def testCreateImageFail(self, mock_wait, mock_check, mock_delete):
330 """Test CreateImage fails."""
Tri Vo29ac1822016-10-01 17:06:29 -0700331 resource_mock = mock.MagicMock()
332 self.compute_client._service.images = mock.MagicMock(
333 return_value=resource_mock)
334 resource_mock.insert = mock.MagicMock()
335
336 expected_body = {
337 "name": self.IMAGE,
338 "rawDisk": {
Kevin Chengb5963882018-05-09 00:06:27 -0700339 "source": GS_IMAGE_SOURCE_URI,
Tri Vo29ac1822016-10-01 17:06:29 -0700340 },
341 }
342 self.assertRaisesRegexp(
343 errors.DriverError,
344 "Expected fake error",
345 self.compute_client.CreateImage,
346 image_name=self.IMAGE,
Kevin Chengb5963882018-05-09 00:06:27 -0700347 source_uri=GS_IMAGE_SOURCE_URI)
Tri Vo29ac1822016-10-01 17:06:29 -0700348 resource_mock.insert.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700349 project=PROJECT, body=expected_body)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700350 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700351 operation=mock.ANY,
352 operation_scope=gcompute_client.OperationScope.GLOBAL)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700353 mock_check.assert_called_with(self.IMAGE)
354 mock_delete.assert_called_with(self.IMAGE)
Tri Vo29ac1822016-10-01 17:06:29 -0700355
356 def testCheckImageExistsTrue(self):
357 """Test CheckImageExists return True."""
358 resource_mock = mock.MagicMock()
359 mock_api = mock.MagicMock()
360 self.compute_client._service.images = mock.MagicMock(
361 return_value=resource_mock)
362 resource_mock.get = mock.MagicMock(return_value=mock_api)
363 mock_api.execute = mock.MagicMock(return_value={"name": self.IMAGE})
364 self.assertTrue(self.compute_client.CheckImageExists(self.IMAGE))
365
366 def testCheckImageExistsFalse(self):
367 """Test CheckImageExists return False."""
368 resource_mock = mock.MagicMock()
369 mock_api = mock.MagicMock()
370 self.compute_client._service.images = mock.MagicMock(
371 return_value=resource_mock)
372 resource_mock.get = mock.MagicMock(return_value=mock_api)
373 mock_api.execute = mock.MagicMock(
374 side_effect=errors.ResourceNotFoundError(404, "no image"))
375 self.assertFalse(self.compute_client.CheckImageExists(self.IMAGE))
376
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700377 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
378 def testDeleteImage(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700379 """Test DeleteImage."""
Tri Vo29ac1822016-10-01 17:06:29 -0700380 resource_mock = mock.MagicMock()
381 self.compute_client._service.images = mock.MagicMock(
382 return_value=resource_mock)
383 resource_mock.delete = mock.MagicMock()
384 self.compute_client.DeleteImage(self.IMAGE)
385 resource_mock.delete.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700386 project=PROJECT, image=self.IMAGE)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700387 self.assertTrue(mock_wait.called)
Tri Vo29ac1822016-10-01 17:06:29 -0700388
389 def _SetupBatchHttpRequestMock(self):
390 """Setup BatchHttpRequest mock."""
391 requests = {}
392
393 def _Add(request, callback, request_id):
394 requests[request_id] = (request, callback)
395
396 def _Execute():
397 for rid in requests:
398 _, callback = requests[rid]
399 callback(
400 request_id=rid, response=mock.MagicMock(), exception=None)
Tri Vo29ac1822016-10-01 17:06:29 -0700401 mock_batch = mock.MagicMock()
402 mock_batch.add = _Add
403 mock_batch.execute = _Execute
404 self.Patch(apiclient.http, "BatchHttpRequest", return_value=mock_batch)
405
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700406 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
407 def testDeleteImages(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700408 """Test DeleteImages."""
409 self._SetupBatchHttpRequestMock()
Tri Vo29ac1822016-10-01 17:06:29 -0700410 fake_images = ["fake_image_1", "fake_image_2"]
411 mock_api = mock.MagicMock()
412 resource_mock = mock.MagicMock()
413 self.compute_client._service.images = mock.MagicMock(
414 return_value=resource_mock)
415 resource_mock.delete = mock.MagicMock(return_value=mock_api)
416 # Call the API.
417 deleted, failed, error_msgs = self.compute_client.DeleteImages(
418 fake_images)
419 # Verify
Kevin Chengb5963882018-05-09 00:06:27 -0700420 calls = [
421 mock.call(project=PROJECT, image="fake_image_1"),
422 mock.call(project=PROJECT, image="fake_image_2")
423 ]
Tri Vo29ac1822016-10-01 17:06:29 -0700424 resource_mock.delete.assert_has_calls(calls, any_order=True)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700425 self.assertEqual(mock_wait.call_count, 2)
Tri Vo29ac1822016-10-01 17:06:29 -0700426 self.assertEqual(error_msgs, [])
427 self.assertEqual(failed, [])
428 self.assertEqual(set(deleted), set(fake_images))
429
430 def testListImages(self):
431 """Test ListImages."""
432 fake_token = "fake_next_page_token"
433 image_1 = "image_1"
434 image_2 = "image_2"
435 response_1 = {"items": [image_1], "nextPageToken": fake_token}
436 response_2 = {"items": [image_2]}
437 self.Patch(
438 gcompute_client.ComputeClient,
439 "Execute",
440 side_effect=[response_1, response_2])
441 resource_mock = mock.MagicMock()
442 self.compute_client._service.images = mock.MagicMock(
443 return_value=resource_mock)
444 resource_mock.list = mock.MagicMock()
445 images = self.compute_client.ListImages()
446 calls = [
Kevin Chengb5963882018-05-09 00:06:27 -0700447 mock.call(project=PROJECT, filter=None, pageToken=None),
448 mock.call(project=PROJECT, filter=None, pageToken=fake_token)
Tri Vo29ac1822016-10-01 17:06:29 -0700449 ]
450 resource_mock.list.assert_has_calls(calls)
451 self.assertEqual(images, [image_1, image_2])
452
Kevin Chengb5963882018-05-09 00:06:27 -0700453 def testListImagesFromExternalProject(self):
454 """Test ListImages which accepts different project."""
455 image = "image_1"
456 response = {"items": [image]}
457 self.Patch(gcompute_client.ComputeClient, "Execute", side_effect=[response])
458 resource_mock = mock.MagicMock()
459 self.compute_client._service.images = mock.MagicMock(
460 return_value=resource_mock)
461 resource_mock.list = mock.MagicMock()
462 images = self.compute_client.ListImages(
463 image_project="fake-project-2")
464 calls = [
465 mock.call(project="fake-project-2", filter=None, pageToken=None)]
466 resource_mock.list.assert_has_calls(calls)
467 self.assertEqual(images, [image])
468
Tri Vo29ac1822016-10-01 17:06:29 -0700469 def testGetInstance(self):
470 """Test GetInstance."""
471 resource_mock = mock.MagicMock()
472 mock_api = mock.MagicMock()
473 self.compute_client._service.instances = mock.MagicMock(
474 return_value=resource_mock)
475 resource_mock.get = mock.MagicMock(return_value=mock_api)
476 mock_api.execute = mock.MagicMock(return_value={"name": self.INSTANCE})
477 result = self.compute_client.GetInstance(self.INSTANCE, self.ZONE)
478 self.assertEqual(result, {"name": self.INSTANCE})
479 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700480 project=PROJECT, zone=self.ZONE, instance=self.INSTANCE)
Tri Vo29ac1822016-10-01 17:06:29 -0700481
482 def testListInstances(self):
483 """Test ListInstances."""
484 fake_token = "fake_next_page_token"
485 instance_1 = "instance_1"
486 instance_2 = "instance_2"
487 response_1 = {"items": [instance_1], "nextPageToken": fake_token}
488 response_2 = {"items": [instance_2]}
489 self.Patch(
490 gcompute_client.ComputeClient,
491 "Execute",
492 side_effect=[response_1, response_2])
493 resource_mock = mock.MagicMock()
494 self.compute_client._service.instances = mock.MagicMock(
495 return_value=resource_mock)
496 resource_mock.list = mock.MagicMock()
497 instances = self.compute_client.ListInstances(self.ZONE)
498 calls = [
499 mock.call(
Kevin Chengb5963882018-05-09 00:06:27 -0700500 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -0700501 zone=self.ZONE,
502 filter=None,
503 pageToken=None),
504 mock.call(
Kevin Chengb5963882018-05-09 00:06:27 -0700505 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -0700506 zone=self.ZONE,
507 filter=None,
508 pageToken=fake_token),
509 ]
510 resource_mock.list.assert_has_calls(calls)
511 self.assertEqual(instances, [instance_1, instance_2])
512
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700513 @mock.patch.object(gcompute_client.ComputeClient, "GetImage")
514 @mock.patch.object(gcompute_client.ComputeClient, "GetNetworkUrl")
Kevin Cheng480e1212018-10-24 00:23:30 -0700515 @mock.patch.object(gcompute_client.ComputeClient, "GetSubnetworkUrl")
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700516 @mock.patch.object(gcompute_client.ComputeClient, "GetMachineType")
517 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
518 def testCreateInstance(self, mock_wait, mock_get_mach_type,
Kevin Cheng480e1212018-10-24 00:23:30 -0700519 mock_get_subnetwork_url, mock_get_network_url,
520 mock_get_image):
Tri Vo29ac1822016-10-01 17:06:29 -0700521 """Test CreateInstance."""
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700522 mock_get_mach_type.return_value = {"selfLink": self.MACHINE_TYPE_URL}
523 mock_get_network_url.return_value = self.NETWORK_URL
Kevin Cheng480e1212018-10-24 00:23:30 -0700524 mock_get_subnetwork_url.return_value = self.SUBNETWORK_URL
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700525 mock_get_image.return_value = {"selfLink": self.IMAGE_URL}
Tri Vo29ac1822016-10-01 17:06:29 -0700526 resource_mock = mock.MagicMock()
527 self.compute_client._service.instances = mock.MagicMock(
528 return_value=resource_mock)
529 resource_mock.insert = mock.MagicMock()
herbertxue308f7662018-05-18 03:25:58 +0000530 self.Patch(
531 self.compute_client,
532 "_GetExtraDiskArgs",
533 return_value=[{"fake_extra_arg": "fake_extra_value"}])
534 extra_disk_name = "gce-x86-userdebug-2345-abcd-data"
535 expected_disk_args = [self._disk_args]
536 expected_disk_args.extend([{"fake_extra_arg": "fake_extra_value"}])
Kevin Chengc330f6f2019-05-13 09:32:42 -0700537 expected_scope = []
538 expected_scope.extend(self.compute_client.DEFAULT_INSTANCE_SCOPE)
539 expected_scope.extend(self.EXTRA_SCOPES)
Tri Vo29ac1822016-10-01 17:06:29 -0700540
541 expected_body = {
542 "machineType": self.MACHINE_TYPE_URL,
543 "name": self.INSTANCE,
544 "networkInterfaces": [
545 {
546 "network": self.NETWORK_URL,
Kevin Cheng480e1212018-10-24 00:23:30 -0700547 "subnetwork": self.SUBNETWORK_URL,
Tri Vo29ac1822016-10-01 17:06:29 -0700548 "accessConfigs": [
549 {"name": "External NAT",
550 "type": "ONE_TO_ONE_NAT"}
551 ],
552 }
553 ],
herbertxue308f7662018-05-18 03:25:58 +0000554 "disks": expected_disk_args,
Tri Vo29ac1822016-10-01 17:06:29 -0700555 "serviceAccounts": [
556 {"email": "default",
Kevin Chengc330f6f2019-05-13 09:32:42 -0700557 "scopes": expected_scope}
Tri Vo29ac1822016-10-01 17:06:29 -0700558 ],
559 "metadata": {
560 "items": [{"key": self.METADATA[0],
561 "value": self.METADATA[1]}],
562 },
563 }
564
565 self.compute_client.CreateInstance(
566 instance=self.INSTANCE,
567 image_name=self.IMAGE,
568 machine_type=self.MACHINE_TYPE,
569 metadata={self.METADATA[0]: self.METADATA[1]},
570 network=self.NETWORK,
herbertxue308f7662018-05-18 03:25:58 +0000571 zone=self.ZONE,
Kevin Chengc330f6f2019-05-13 09:32:42 -0700572 extra_disk_name=extra_disk_name,
573 extra_scopes=self.EXTRA_SCOPES)
Tri Vo29ac1822016-10-01 17:06:29 -0700574
575 resource_mock.insert.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700576 project=PROJECT, zone=self.ZONE, body=expected_body)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700577 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700578 mock.ANY,
579 operation_scope=gcompute_client.OperationScope.ZONE,
580 scope_name=self.ZONE)
581
Erwin Jansenf39798d2019-05-14 21:06:44 -0700582
583 @mock.patch.object(gcompute_client.ComputeClient, "GetImage")
584 @mock.patch.object(gcompute_client.ComputeClient, "GetNetworkUrl")
585 @mock.patch.object(gcompute_client.ComputeClient, "GetSubnetworkUrl")
586 @mock.patch.object(gcompute_client.ComputeClient, "GetMachineType")
587 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
herbertxue1512f8a2019-06-27 13:56:23 +0800588 def testCreateInstanceWithTags(self,
589 mock_wait,
590 mock_get_mach_type,
591 mock_get_subnetwork_url,
592 mock_get_network_url,
593 mock_get_image):
Erwin Jansenf39798d2019-05-14 21:06:44 -0700594 """Test CreateInstance."""
595 mock_get_mach_type.return_value = {"selfLink": self.MACHINE_TYPE_URL}
596 mock_get_network_url.return_value = self.NETWORK_URL
597 mock_get_subnetwork_url.return_value = self.SUBNETWORK_URL
598 mock_get_image.return_value = {"selfLink": self.IMAGE_URL}
599 resource_mock = mock.MagicMock()
600 self.compute_client._service.instances = mock.MagicMock(
601 return_value=resource_mock)
602 resource_mock.insert = mock.MagicMock()
603 self.Patch(
604 self.compute_client,
605 "_GetExtraDiskArgs",
606 return_value=[{"fake_extra_arg": "fake_extra_value"}])
607 extra_disk_name = "gce-x86-userdebug-2345-abcd-data"
608 expected_disk_args = [self._disk_args]
609 expected_disk_args.extend([{"fake_extra_arg": "fake_extra_value"}])
610 expected_scope = []
611 expected_scope.extend(self.compute_client.DEFAULT_INSTANCE_SCOPE)
612 expected_scope.extend(self.EXTRA_SCOPES)
613
614 expected_body = {
615 "machineType": self.MACHINE_TYPE_URL,
616 "name": self.INSTANCE,
617 "networkInterfaces": [
618 {
619 "network": self.NETWORK_URL,
620 "subnetwork": self.SUBNETWORK_URL,
621 "accessConfigs": [
622 {"name": "External NAT",
623 "type": "ONE_TO_ONE_NAT"}
624 ],
625 }
626 ],
627 'tags': {'items': ['https-server']},
628 "disks": expected_disk_args,
629 "serviceAccounts": [
630 {"email": "default",
631 "scopes": expected_scope}
632 ],
633 "metadata": {
634 "items": [{"key": self.METADATA[0],
635 "value": self.METADATA[1]}],
636 },
637 }
638
639 self.compute_client.CreateInstance(
640 instance=self.INSTANCE,
641 image_name=self.IMAGE,
642 machine_type=self.MACHINE_TYPE,
643 metadata={self.METADATA[0]: self.METADATA[1]},
644 network=self.NETWORK,
645 zone=self.ZONE,
646 extra_disk_name=extra_disk_name,
647 tags=["https-server"],
648 extra_scopes=self.EXTRA_SCOPES)
649
650 resource_mock.insert.assert_called_with(
651 project=PROJECT, zone=self.ZONE, body=expected_body)
652 mock_wait.assert_called_with(
653 mock.ANY,
654 operation_scope=gcompute_client.OperationScope.ZONE,
655 scope_name=self.ZONE)
656
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700657 @mock.patch.object(gcompute_client.ComputeClient, "GetAcceleratorUrl")
658 @mock.patch.object(gcompute_client.ComputeClient, "GetImage")
659 @mock.patch.object(gcompute_client.ComputeClient, "GetNetworkUrl")
Kevin Cheng480e1212018-10-24 00:23:30 -0700660 @mock.patch.object(gcompute_client.ComputeClient, "GetSubnetworkUrl")
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700661 @mock.patch.object(gcompute_client.ComputeClient, "GetMachineType")
662 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
663 def testCreateInstanceWithGpu(self, mock_wait, mock_get_mach,
Kevin Cheng480e1212018-10-24 00:23:30 -0700664 mock_get_subnetwork, mock_get_network,
665 mock_get_image, mock_get_accel):
Kevin Chengb5963882018-05-09 00:06:27 -0700666 """Test CreateInstance with a GPU parameter not set to None."""
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700667 mock_get_mach.return_value = {"selfLink": self.MACHINE_TYPE_URL}
668 mock_get_network.return_value = self.NETWORK_URL
Kevin Cheng480e1212018-10-24 00:23:30 -0700669 mock_get_subnetwork.return_value = self.SUBNETWORK_URL
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700670 mock_get_accel.return_value = self.ACCELERATOR_URL
671 mock_get_image.return_value = {"selfLink": self.IMAGE_URL}
Kevin Chengb5963882018-05-09 00:06:27 -0700672
673 resource_mock = mock.MagicMock()
674 self.compute_client._service.instances = mock.MagicMock(
675 return_value=resource_mock)
676 resource_mock.insert = mock.MagicMock()
677
678 expected_body = {
679 "machineType":
680 self.MACHINE_TYPE_URL,
681 "name":
682 self.INSTANCE,
683 "networkInterfaces": [{
Kevin Cheng480e1212018-10-24 00:23:30 -0700684 "network": self.NETWORK_URL,
685 "subnetwork": self.SUBNETWORK_URL,
Kevin Chengb5963882018-05-09 00:06:27 -0700686 "accessConfigs": [{
687 "name": "External NAT",
688 "type": "ONE_TO_ONE_NAT"
689 }],
690 }],
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700691 "disks": [self._disk_args],
Kevin Chengb5963882018-05-09 00:06:27 -0700692 "serviceAccounts": [{
693 "email": "default",
694 "scopes": self.compute_client.DEFAULT_INSTANCE_SCOPE
695 }],
696 "scheduling": {
697 "onHostMaintenance": "terminate"
698 },
699 "guestAccelerators": [{
700 "acceleratorCount": 1,
701 "acceleratorType": "http://speedy-gpu"
702 }],
703 "metadata": {
704 "items": [{
705 "key": self.METADATA[0],
706 "value": self.METADATA[1]
707 }],
708 },
709 }
710
711 self.compute_client.CreateInstance(
712 instance=self.INSTANCE,
713 image_name=self.IMAGE,
714 machine_type=self.MACHINE_TYPE,
715 metadata={self.METADATA[0]: self.METADATA[1]},
716 network=self.NETWORK,
717 zone=self.ZONE,
Kevin Chengc330f6f2019-05-13 09:32:42 -0700718 gpu=self.GPU,
719 extra_scopes=None)
Kevin Chengb5963882018-05-09 00:06:27 -0700720
721 resource_mock.insert.assert_called_with(
722 project=PROJECT, zone=self.ZONE, body=expected_body)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700723 mock_wait.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700724 mock.ANY, operation_scope=gcompute_client.OperationScope.ZONE,
725 scope_name=self.ZONE)
726
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700727 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
728 def testDeleteInstance(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700729 """Test DeleteInstance."""
Tri Vo29ac1822016-10-01 17:06:29 -0700730 resource_mock = mock.MagicMock()
731 self.compute_client._service.instances = mock.MagicMock(
732 return_value=resource_mock)
733 resource_mock.delete = mock.MagicMock()
734 self.compute_client.DeleteInstance(
735 instance=self.INSTANCE, zone=self.ZONE)
736 resource_mock.delete.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700737 project=PROJECT, zone=self.ZONE, instance=self.INSTANCE)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700738 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700739 mock.ANY,
740 operation_scope=gcompute_client.OperationScope.ZONE,
741 scope_name=self.ZONE)
742
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700743 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
744 def testDeleteInstances(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700745 """Test DeleteInstances."""
746 self._SetupBatchHttpRequestMock()
Tri Vo29ac1822016-10-01 17:06:29 -0700747 fake_instances = ["fake_instance_1", "fake_instance_2"]
748 mock_api = mock.MagicMock()
749 resource_mock = mock.MagicMock()
750 self.compute_client._service.instances = mock.MagicMock(
751 return_value=resource_mock)
752 resource_mock.delete = mock.MagicMock(return_value=mock_api)
753 deleted, failed, error_msgs = self.compute_client.DeleteInstances(
754 fake_instances, self.ZONE)
755 calls = [
756 mock.call(
Kevin Chengb5963882018-05-09 00:06:27 -0700757 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -0700758 instance="fake_instance_1",
Kevin Chengb5963882018-05-09 00:06:27 -0700759 zone=self.ZONE),
760 mock.call(
761 project=PROJECT,
762 instance="fake_instance_2",
763 zone=self.ZONE)
Tri Vo29ac1822016-10-01 17:06:29 -0700764 ]
765 resource_mock.delete.assert_has_calls(calls, any_order=True)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700766 self.assertEqual(mock_wait.call_count, 2)
Tri Vo29ac1822016-10-01 17:06:29 -0700767 self.assertEqual(error_msgs, [])
768 self.assertEqual(failed, [])
769 self.assertEqual(set(deleted), set(fake_instances))
770
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700771 def testCreateDiskWithProject(self):
772 """Test CreateDisk with images using a set project."""
773 source_project = "fake-image-project"
774 expected_project_to_use = "fake-image-project"
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700775 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
Kevin Chengb5963882018-05-09 00:06:27 -0700776 resource_mock = mock.MagicMock()
777 self.compute_client._service.disks = mock.MagicMock(
778 return_value=resource_mock)
779 resource_mock.insert = mock.MagicMock()
780 self.compute_client.CreateDisk(
781 "fake_disk", "fake_image", 10, self.ZONE, source_project=source_project)
782 resource_mock.insert.assert_called_with(
783 project=PROJECT,
784 zone=self.ZONE,
785 sourceImage="projects/%s/global/images/fake_image" %
786 expected_project_to_use,
787 body={
788 "name":
789 "fake_disk",
790 "sizeGb":
791 10,
792 "type":
793 "projects/%s/zones/%s/diskTypes/pd-standard" % (PROJECT,
794 self.ZONE)
795 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700796 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700797
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700798 def testCreateDiskWithNoSourceProject(self):
799 """Test CreateDisk with images with no set project."""
800 source_project = None
801 expected_project_to_use = PROJECT
802 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
803 resource_mock = mock.MagicMock()
804 self.compute_client._service.disks = mock.MagicMock(
805 return_value=resource_mock)
806 resource_mock.insert = mock.MagicMock()
807 self.compute_client.CreateDisk(
808 "fake_disk", "fake_image", 10, self.ZONE, source_project=source_project)
809 resource_mock.insert.assert_called_with(
810 project=PROJECT,
811 zone=self.ZONE,
812 sourceImage="projects/%s/global/images/fake_image" %
813 expected_project_to_use,
814 body={
815 "name":
816 "fake_disk",
817 "sizeGb":
818 10,
819 "type":
820 "projects/%s/zones/%s/diskTypes/pd-standard" % (PROJECT,
821 self.ZONE)
822 })
823 self.assertTrue(mock_wait.called)
824
825 def testCreateDiskWithTypeStandard(self):
826 """Test CreateDisk with images using standard."""
827 disk_type = gcompute_client.PersistentDiskType.STANDARD
828 expected_disk_type_string = "pd-standard"
829 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
830 resource_mock = mock.MagicMock()
831 self.compute_client._service.disks = mock.MagicMock(
832 return_value=resource_mock)
833 resource_mock.insert = mock.MagicMock()
834 self.compute_client.CreateDisk(
835 "fake_disk",
836 "fake_image",
837 10,
838 self.ZONE,
839 source_project="fake-project",
840 disk_type=disk_type)
841 resource_mock.insert.assert_called_with(
842 project=PROJECT,
843 zone=self.ZONE,
844 sourceImage="projects/%s/global/images/fake_image" % "fake-project",
845 body={
846 "name":
847 "fake_disk",
848 "sizeGb":
849 10,
850 "type":
851 "projects/%s/zones/%s/diskTypes/%s" %
852 (PROJECT, self.ZONE, expected_disk_type_string)
853 })
854 self.assertTrue(mock_wait.called)
855
856 def testCreateDiskWithTypeSSD(self):
857 """Test CreateDisk with images using standard."""
858 disk_type = gcompute_client.PersistentDiskType.SSD
859 expected_disk_type_string = "pd-ssd"
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700860 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
Kevin Chengb5963882018-05-09 00:06:27 -0700861 resource_mock = mock.MagicMock()
862 self.compute_client._service.disks = mock.MagicMock(
863 return_value=resource_mock)
864 resource_mock.insert = mock.MagicMock()
865 self.compute_client.CreateDisk(
866 "fake_disk",
867 "fake_image",
868 10,
869 self.ZONE,
870 source_project="fake-project",
871 disk_type=disk_type)
872 resource_mock.insert.assert_called_with(
873 project=PROJECT,
874 zone=self.ZONE,
875 sourceImage="projects/%s/global/images/fake_image" % "fake-project",
876 body={
877 "name":
878 "fake_disk",
879 "sizeGb":
880 10,
881 "type":
882 "projects/%s/zones/%s/diskTypes/%s" %
883 (PROJECT, self.ZONE, expected_disk_type_string)
884 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700885 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700886
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700887 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
888 def testAttachDisk(self, mock_wait):
Kevin Chengb5963882018-05-09 00:06:27 -0700889 """Test AttachDisk."""
Kevin Chengb5963882018-05-09 00:06:27 -0700890 resource_mock = mock.MagicMock()
891 self.compute_client._service.instances = mock.MagicMock(
892 return_value=resource_mock)
893 resource_mock.attachDisk = mock.MagicMock()
894 self.compute_client.AttachDisk(
895 "fake_instance_1", self.ZONE, deviceName="fake_disk",
896 source="fake-selfLink")
897 resource_mock.attachDisk.assert_called_with(
898 project=PROJECT,
899 zone=self.ZONE,
900 instance="fake_instance_1",
901 body={
902 "deviceName": "fake_disk",
903 "source": "fake-selfLink"
904 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700905 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700906
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700907 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
908 def testDetachDisk(self, mock_wait):
Kevin Chengb5963882018-05-09 00:06:27 -0700909 """Test DetachDisk."""
Kevin Chengb5963882018-05-09 00:06:27 -0700910 resource_mock = mock.MagicMock()
911 self.compute_client._service.instances = mock.MagicMock(
912 return_value=resource_mock)
913 resource_mock.detachDisk = mock.MagicMock()
914 self.compute_client.DetachDisk("fake_instance_1", self.ZONE, "fake_disk")
915 resource_mock.detachDisk.assert_called_with(
916 project=PROJECT,
917 zone=self.ZONE,
918 instance="fake_instance_1",
919 deviceName="fake_disk")
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700920 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700921
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700922 @mock.patch.object(gcompute_client.ComputeClient, "GetAcceleratorUrl")
923 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
924 def testAttachAccelerator(self, mock_wait, mock_get_accel):
Kevin Chengb5963882018-05-09 00:06:27 -0700925 """Test AttachAccelerator."""
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700926 mock_get_accel.return_value = self.ACCELERATOR_URL
Kevin Chengb5963882018-05-09 00:06:27 -0700927 resource_mock = mock.MagicMock()
928 self.compute_client._service.instances = mock.MagicMock(
929 return_value=resource_mock)
930 resource_mock.attachAccelerator = mock.MagicMock()
931 self.compute_client.AttachAccelerator("fake_instance_1", self.ZONE, 1,
932 "nvidia-tesla-k80")
933 resource_mock.setMachineResources.assert_called_with(
934 project=PROJECT,
935 zone=self.ZONE,
936 instance="fake_instance_1",
937 body={
938 "guestAccelerators": [{
939 "acceleratorType": self.ACCELERATOR_URL,
940 "acceleratorCount": 1
941 }]
942 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700943 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700944
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700945 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
946 def testBatchExecuteOnInstances(self, mock_wait):
947 """Test BatchExecuteOnInstances."""
Tri Vo29ac1822016-10-01 17:06:29 -0700948 self._SetupBatchHttpRequestMock()
Tri Vo29ac1822016-10-01 17:06:29 -0700949 action = mock.MagicMock(return_value=mock.MagicMock())
950 fake_instances = ["fake_instance_1", "fake_instance_2"]
951 done, failed, error_msgs = self.compute_client._BatchExecuteOnInstances(
952 fake_instances, self.ZONE, action)
953 calls = [mock.call(instance="fake_instance_1"),
954 mock.call(instance="fake_instance_2")]
955 action.assert_has_calls(calls, any_order=True)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700956 self.assertEqual(mock_wait.call_count, 2)
Tri Vo29ac1822016-10-01 17:06:29 -0700957 self.assertEqual(set(done), set(fake_instances))
958 self.assertEqual(error_msgs, [])
959 self.assertEqual(failed, [])
960
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700961 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
962 def testResetInstance(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700963 """Test ResetInstance."""
Tri Vo29ac1822016-10-01 17:06:29 -0700964 resource_mock = mock.MagicMock()
965 self.compute_client._service.instances = mock.MagicMock(
966 return_value=resource_mock)
967 resource_mock.reset = mock.MagicMock()
968 self.compute_client.ResetInstance(
969 instance=self.INSTANCE, zone=self.ZONE)
970 resource_mock.reset.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700971 project=PROJECT, zone=self.ZONE, instance=self.INSTANCE)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700972 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700973 mock.ANY,
974 operation_scope=gcompute_client.OperationScope.ZONE,
975 scope_name=self.ZONE)
976
977 def _CompareMachineSizeTestHelper(self,
978 machine_info_1,
979 machine_info_2,
980 expected_result=None,
981 expected_error_type=None):
982 """Helper class for testing CompareMachineSize.
983
Kevin Chengb5963882018-05-09 00:06:27 -0700984 Args:
985 machine_info_1: A dictionary representing the first machine size.
986 machine_info_2: A dictionary representing the second machine size.
987 expected_result: An integer, 0, 1 or -1, or None if not set.
988 expected_error_type: An exception type, if set will check for exception.
989 """
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700990 mock_get_mach_type = self.Patch(
Tri Vo29ac1822016-10-01 17:06:29 -0700991 gcompute_client.ComputeClient,
992 "GetMachineType",
993 side_effect=[machine_info_1, machine_info_2])
994 if expected_error_type:
995 self.assertRaises(expected_error_type,
996 self.compute_client.CompareMachineSize, "name1",
997 "name2", self.ZONE)
998 else:
999 result = self.compute_client.CompareMachineSize("name1", "name2",
1000 self.ZONE)
1001 self.assertEqual(result, expected_result)
1002
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001003 mock_get_mach_type.assert_has_calls(
Tri Vo29ac1822016-10-01 17:06:29 -07001004 [mock.call("name1", self.ZONE), mock.call("name2", self.ZONE)])
1005
1006 def testCompareMachineSizeSmall(self):
1007 """Test CompareMachineSize where the first one is smaller."""
1008 machine_info_1 = {"guestCpus": 10, "memoryMb": 100}
1009 machine_info_2 = {"guestCpus": 10, "memoryMb": 200}
1010 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, -1)
1011
Kevin Cheng4ae42772018-10-02 11:39:48 -07001012 def testCompareMachineSizeSmallSmallerOnSecond(self):
1013 """Test CompareMachineSize where the first one is smaller."""
1014 machine_info_1 = {"guestCpus": 11, "memoryMb": 100}
1015 machine_info_2 = {"guestCpus": 10, "memoryMb": 200}
1016 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, -1)
1017
Tri Vo29ac1822016-10-01 17:06:29 -07001018 def testCompareMachineSizeLarge(self):
1019 """Test CompareMachineSize where the first one is larger."""
Kevin Cheng4ae42772018-10-02 11:39:48 -07001020 machine_info_1 = {"guestCpus": 11, "memoryMb": 200}
1021 machine_info_2 = {"guestCpus": 10, "memoryMb": 100}
1022 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, 1)
1023
1024 def testCompareMachineSizeLargeWithEqualElement(self):
1025 """Test CompareMachineSize where the first one is larger."""
Tri Vo29ac1822016-10-01 17:06:29 -07001026 machine_info_1 = {"guestCpus": 10, "memoryMb": 200}
1027 machine_info_2 = {"guestCpus": 10, "memoryMb": 100}
1028 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, 1)
1029
1030 def testCompareMachineSizeEqual(self):
1031 """Test CompareMachineSize where two machine sizes are equal."""
1032 machine_info = {"guestCpus": 10, "memoryMb": 100}
1033 self._CompareMachineSizeTestHelper(machine_info, machine_info, 0)
1034
1035 def testCompareMachineSizeBadMetric(self):
1036 """Test CompareMachineSize with bad metric."""
Kevin Chengb5963882018-05-09 00:06:27 -07001037 machine_info = {"unknown_metric": 10, "memoryMb": 100}
Tri Vo29ac1822016-10-01 17:06:29 -07001038 self._CompareMachineSizeTestHelper(
1039 machine_info, machine_info, expected_error_type=errors.DriverError)
1040
1041 def testGetMachineType(self):
1042 """Test GetMachineType."""
1043 resource_mock = mock.MagicMock()
1044 mock_api = mock.MagicMock()
1045 self.compute_client._service.machineTypes = mock.MagicMock(
1046 return_value=resource_mock)
1047 resource_mock.get = mock.MagicMock(return_value=mock_api)
1048 mock_api.execute = mock.MagicMock(
1049 return_value={"name": self.MACHINE_TYPE})
1050 result = self.compute_client.GetMachineType(self.MACHINE_TYPE,
1051 self.ZONE)
1052 self.assertEqual(result, {"name": self.MACHINE_TYPE})
1053 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -07001054 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -07001055 zone=self.ZONE,
1056 machineType=self.MACHINE_TYPE)
1057
1058 def _GetSerialPortOutputTestHelper(self, response):
1059 """Helper function for testing GetSerialPortOutput.
1060
Kevin Chengb5963882018-05-09 00:06:27 -07001061 Args:
1062 response: A dictionary representing a fake response.
1063 """
Tri Vo29ac1822016-10-01 17:06:29 -07001064 resource_mock = mock.MagicMock()
1065 mock_api = mock.MagicMock()
1066 self.compute_client._service.instances = mock.MagicMock(
1067 return_value=resource_mock)
1068 resource_mock.getSerialPortOutput = mock.MagicMock(
1069 return_value=mock_api)
1070 mock_api.execute = mock.MagicMock(return_value=response)
1071
1072 if "contents" in response:
1073 result = self.compute_client.GetSerialPortOutput(
1074 instance=self.INSTANCE, zone=self.ZONE)
1075 self.assertEqual(result, "fake contents")
1076 else:
1077 self.assertRaisesRegexp(
1078 errors.DriverError,
1079 "Malformed response.*",
1080 self.compute_client.GetSerialPortOutput,
1081 instance=self.INSTANCE,
1082 zone=self.ZONE)
1083 resource_mock.getSerialPortOutput.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -07001084 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -07001085 zone=self.ZONE,
1086 instance=self.INSTANCE,
1087 port=1)
1088
1089 def testGetSerialPortOutput(self):
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001090 """Test GetSerialPortOutput."""
Tri Vo29ac1822016-10-01 17:06:29 -07001091 response = {"contents": "fake contents"}
1092 self._GetSerialPortOutputTestHelper(response)
1093
1094 def testGetSerialPortOutputFail(self):
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001095 """Test GetSerialPortOutputFail."""
Tri Vo29ac1822016-10-01 17:06:29 -07001096 response = {"malformed": "fake contents"}
1097 self._GetSerialPortOutputTestHelper(response)
1098
1099 def testGetInstanceNamesByIPs(self):
1100 """Test GetInstanceNamesByIPs."""
1101 good_instance = {
1102 "name": "instance_1",
1103 "networkInterfaces": [
1104 {
1105 "accessConfigs": [
1106 {"natIP": "172.22.22.22"},
1107 ],
1108 },
1109 ],
1110 }
1111 bad_instance = {"name": "instance_2"}
1112 self.Patch(
1113 gcompute_client.ComputeClient,
1114 "ListInstances",
1115 return_value=[good_instance, bad_instance])
1116 ip_name_map = self.compute_client.GetInstanceNamesByIPs(
1117 ips=["172.22.22.22", "172.22.22.23"], zone=self.ZONE)
1118 self.assertEqual(ip_name_map, {"172.22.22.22": "instance_1",
1119 "172.22.22.23": None})
1120
cylan64af2db2019-01-17 15:13:59 +08001121 def testRsaNotInMetadata(self):
1122 """Test rsa not in metadata."""
Tri Vo29ac1822016-10-01 17:06:29 -07001123 fake_user = "fake_user"
cylan64af2db2019-01-17 15:13:59 +08001124 fake_ssh_key = "fake_ssh"
1125 metadata = {
1126 "kind": "compute#metadata",
1127 "fingerprint": "a-23icsyx4E=",
1128 "items": [
1129 {
1130 "key": "sshKeys",
1131 "value": "%s:%s" % (fake_user, self.SSHKEY)
1132 }
1133 ]
1134 }
1135 # Test rsa doesn't exist in metadata.
1136 new_entry = "%s:%s" % (fake_user, fake_ssh_key)
1137 self.assertEqual(True, gcompute_client.RsaNotInMetadata(metadata, new_entry))
1138
1139 # Test rsa exists in metadata.
1140 exist_entry = "%s:%s" %(fake_user, self.SSHKEY)
1141 self.assertEqual(False, gcompute_client.RsaNotInMetadata(metadata, exist_entry))
1142
1143 def testGetSshKeyFromMetadata(self):
1144 """Test get ssh key from metadata."""
1145 fake_user = "fake_user"
1146 metadata_key_exist_value_is_empty = {
1147 "kind": "compute#metadata",
1148 "fingerprint": "a-23icsyx4E=",
1149 "items": [
1150 {
1151 "key": "sshKeys",
1152 "value": ""
1153 }
1154 ]
1155 }
1156 metadata_key_exist = {
1157 "kind": "compute#metadata",
1158 "fingerprint": "a-23icsyx4E=",
1159 "items": [
1160 {
1161 "key": "sshKeys",
1162 "value": "%s:%s" % (fake_user, self.SSHKEY)
1163 }
1164 ]
1165 }
1166 metadata_key_not_exist = {
1167 "kind": "compute#metadata",
1168 "fingerprint": "a-23icsyx4E=",
1169 "items": [
1170 {
1171 }
1172 ]
1173 }
1174 expected_key_exist_value_is_empty = {
1175 "key": "sshKeys",
1176 "value": ""
1177 }
1178 expected_key_exist = {
1179 "key": "sshKeys",
1180 "value": "%s:%s" % (fake_user, self.SSHKEY)
1181 }
1182 self.assertEqual(expected_key_exist_value_is_empty,
1183 gcompute_client.GetSshKeyFromMetadata(metadata_key_exist_value_is_empty))
1184 self.assertEqual(expected_key_exist,
1185 gcompute_client.GetSshKeyFromMetadata(metadata_key_exist))
1186 self.assertEqual(None,
1187 gcompute_client.GetSshKeyFromMetadata(metadata_key_not_exist))
1188
1189
1190 def testGetRsaKeyPathExistsFalse(self):
1191 """Test the rsa key path not exists."""
1192 fake_ssh_rsa_path = "/path/to/test_rsa.pub"
1193 self.Patch(os.path, "exists", return_value=False)
1194 self.assertRaisesRegexp(errors.DriverError,
1195 "RSA file %s does not exist." % fake_ssh_rsa_path,
1196 gcompute_client.GetRsaKey,
1197 ssh_rsa_path=fake_ssh_rsa_path)
1198
1199 def testGetRsaKey(self):
1200 """Test get the rsa key."""
1201 fake_ssh_rsa_path = "/path/to/test_rsa.pub"
1202 self.Patch(os.path, "exists", return_value=True)
1203 m = mock.mock_open(read_data=self.SSHKEY)
1204 with mock.patch("__builtin__.open", m):
1205 result = gcompute_client.GetRsaKey(fake_ssh_rsa_path)
1206 self.assertEqual(self.SSHKEY, result)
1207
1208 def testUpdateRsaInMetadata(self):
1209 """Test update rsa in metadata."""
1210 fake_ssh_key = "fake_ssh"
1211 fake_metadata_sshkeys_not_exist = {
1212 "kind": "compute#metadata",
1213 "fingerprint": "a-23icsyx4E=",
1214 "items": [
1215 {
1216 "key": "not_sshKeys",
1217 "value": ""
1218 }
1219 ]
1220 }
1221 new_entry = "new_user:%s" % fake_ssh_key
1222 expected = {
1223 "kind": "compute#metadata",
1224 "fingerprint": "a-23icsyx4E=",
1225 "items": [
1226 {
1227 "key": "not_sshKeys",
1228 "value": ""
1229 },
1230 {
1231 "key": "sshKeys",
1232 "value": new_entry
1233 }
1234 ]
1235 }
1236 self.Patch(os.path, "exists", return_value=True)
1237 self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
1238 resource_mock = mock.MagicMock()
1239 self.compute_client.SetInstanceMetadata = mock.MagicMock(
1240 return_value=resource_mock)
1241 # Test the key item not exists in the metadata.
1242 self.compute_client.UpdateRsaInMetadata(
1243 "fake_zone",
1244 "fake_instance",
1245 fake_metadata_sshkeys_not_exist,
1246 new_entry)
1247 self.compute_client.SetInstanceMetadata.assert_called_with(
1248 "fake_zone",
1249 "fake_instance",
1250 expected)
1251
1252 # Test the key item exists in the metadata.
1253 fake_metadata_ssh_keys_exists = {
1254 "kind": "compute#metadata",
1255 "fingerprint": "a-23icsyx4E=",
1256 "items": [
1257 {
1258 "key": "sshKeys",
1259 "value": "old_user:%s" % self.SSHKEY
1260 }
1261 ]
1262 }
1263 expected_ssh_keys_exists = {
1264 "kind": "compute#metadata",
1265 "fingerprint": "a-23icsyx4E=",
1266 "items": [
1267 {
1268 "key": "sshKeys",
1269 "value": "old_user:%s\n%s" % (self.SSHKEY, new_entry)
1270 }
1271 ]
1272 }
1273
1274 self.compute_client.UpdateRsaInMetadata(
1275 "fake_zone",
1276 "fake_instance",
1277 fake_metadata_ssh_keys_exists,
1278 new_entry)
1279 self.compute_client.SetInstanceMetadata.assert_called_with(
1280 "fake_zone",
1281 "fake_instance",
1282 expected_ssh_keys_exists)
1283
1284 def testAddSshRsaToInstance(self):
1285 """Test add ssh rsa key to instance."""
1286 fake_user = "fake_user"
1287 instance_metadata_key_not_exist = {
1288 "metadata": {
Tri Vo29ac1822016-10-01 17:06:29 -07001289 "kind": "compute#metadata",
1290 "fingerprint": "a-23icsyx4E=",
1291 "items": [
1292 {
1293 "key": "sshKeys",
cylan64af2db2019-01-17 15:13:59 +08001294 "value": ""
1295 }
1296 ]
1297 }
1298 }
1299 instance_metadata_key_exist = {
1300 "metadata": {
1301 "kind": "compute#metadata",
1302 "fingerprint": "a-23icsyx4E=",
1303 "items": [
1304 {
1305 "key": "sshKeys",
1306 "value": "%s:%s" % (fake_user, self.SSHKEY)
Tri Vo29ac1822016-10-01 17:06:29 -07001307 }
1308 ]
1309 }
1310 }
1311 expected = {
1312 "kind": "compute#metadata",
1313 "fingerprint": "a-23icsyx4E=",
1314 "items": [
1315 {
1316 "key": "sshKeys",
cylan64af2db2019-01-17 15:13:59 +08001317 "value": "%s:%s" % (fake_user, self.SSHKEY)
Tri Vo29ac1822016-10-01 17:06:29 -07001318 }
1319 ]
1320 }
1321
1322 self.Patch(os.path, "exists", return_value=True)
cylan64af2db2019-01-17 15:13:59 +08001323 m = mock.mock_open(read_data=self.SSHKEY)
Tri Vo29ac1822016-10-01 17:06:29 -07001324 self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
Tri Vo29ac1822016-10-01 17:06:29 -07001325 resource_mock = mock.MagicMock()
cylan64af2db2019-01-17 15:13:59 +08001326 self.compute_client._service.instances = mock.MagicMock(
Tri Vo29ac1822016-10-01 17:06:29 -07001327 return_value=resource_mock)
cylan64af2db2019-01-17 15:13:59 +08001328 resource_mock.setMetadata = mock.MagicMock()
Tri Vo29ac1822016-10-01 17:06:29 -07001329
cylan64af2db2019-01-17 15:13:59 +08001330 # Test the key not exists in the metadata.
Tri Vo29ac1822016-10-01 17:06:29 -07001331 self.Patch(
cylan64af2db2019-01-17 15:13:59 +08001332 gcompute_client.ComputeClient, "GetInstance",
1333 return_value=instance_metadata_key_not_exist)
Kevin Chengda4f07a2018-06-26 10:25:05 -07001334 with mock.patch("__builtin__.open", m):
cylan64af2db2019-01-17 15:13:59 +08001335 self.compute_client.AddSshRsaInstanceMetadata(
1336 "fake_zone",
1337 fake_user,
1338 "/path/to/test_rsa.pub",
1339 "fake_instance")
1340 resource_mock.setMetadata.assert_called_with(
1341 project=PROJECT,
1342 zone="fake_zone",
1343 instance="fake_instance",
1344 body=expected)
1345
1346 # Test the key already exists in the metadata.
1347 resource_mock.setMetadata.call_count = 0
1348 self.Patch(
1349 gcompute_client.ComputeClient, "GetInstance",
1350 return_value=instance_metadata_key_exist)
1351 with mock.patch("__builtin__.open", m):
1352 self.compute_client.AddSshRsaInstanceMetadata(
1353 "fake_zone",
1354 fake_user,
1355 "/path/to/test_rsa.pub",
1356 "fake_instance")
1357 resource_mock.setMetadata.assert_not_called()
Tri Vo29ac1822016-10-01 17:06:29 -07001358
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001359 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
1360 def testDeleteDisks(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -07001361 """Test DeleteDisks."""
1362 self._SetupBatchHttpRequestMock()
Tri Vo29ac1822016-10-01 17:06:29 -07001363 fake_disks = ["fake_disk_1", "fake_disk_2"]
1364 mock_api = mock.MagicMock()
1365 resource_mock = mock.MagicMock()
1366 self.compute_client._service.disks = mock.MagicMock(
1367 return_value=resource_mock)
1368 resource_mock.delete = mock.MagicMock(return_value=mock_api)
1369 # Call the API.
1370 deleted, failed, error_msgs = self.compute_client.DeleteDisks(
1371 fake_disks, zone=self.ZONE)
1372 # Verify
Kevin Chengb5963882018-05-09 00:06:27 -07001373 calls = [
1374 mock.call(project=PROJECT, disk="fake_disk_1", zone=self.ZONE),
1375 mock.call(project=PROJECT, disk="fake_disk_2", zone=self.ZONE)
1376 ]
Tri Vo29ac1822016-10-01 17:06:29 -07001377 resource_mock.delete.assert_has_calls(calls, any_order=True)
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001378 self.assertEqual(mock_wait.call_count, 2)
Tri Vo29ac1822016-10-01 17:06:29 -07001379 self.assertEqual(error_msgs, [])
1380 self.assertEqual(failed, [])
1381 self.assertEqual(set(deleted), set(fake_disks))
1382
Kevin Chengb5963882018-05-09 00:06:27 -07001383 def testRetryOnFingerPrintError(self):
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001384 """Test RetryOnFingerPrintError."""
Kevin Chengb5963882018-05-09 00:06:27 -07001385 @utils.RetryOnException(gcompute_client._IsFingerPrintError, 10)
1386 def Raise412(sentinel):
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001387 """Raise 412 HTTP exception."""
1388 if not sentinel.hitFingerPrintConflict.called:
1389 sentinel.hitFingerPrintConflict()
1390 raise errors.HttpError(412, "resource labels have changed")
1391 return "Passed"
Kevin Chengb5963882018-05-09 00:06:27 -07001392
1393 sentinel = mock.MagicMock()
1394 result = Raise412(sentinel)
1395 self.assertEqual(1, sentinel.hitFingerPrintConflict.call_count)
1396 self.assertEqual("Passed", result)
1397
Tri Vo29ac1822016-10-01 17:06:29 -07001398
1399if __name__ == "__main__":
1400 unittest.main()