blob: dc9a44f55225441f0dc0424eb6b8dbac754bc78e [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
Tri Vo29ac1822016-10-01 17:06:29 -070028from acloud.internal.lib import driver_test_lib
29from acloud.internal.lib import gcompute_client
30from acloud.internal.lib import utils
31from acloud.public import errors
32
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"
54 ZONE = "fake-zone"
55 REGION = "fake-region"
56 OPERATION_NAME = "fake-op"
Kevin Chengb5963882018-05-09 00:06:27 -070057 IMAGE_FINGERPRINT = "L_NWHuz7wTY="
58 GPU = "fancy-graphics"
Tri Vo29ac1822016-10-01 17:06:29 -070059
60 def setUp(self):
61 """Set up test."""
62 super(ComputeClientTest, self).setUp()
63 self.Patch(gcompute_client.ComputeClient, "InitResourceHandle")
64 fake_cfg = mock.MagicMock()
Kevin Chengb5963882018-05-09 00:06:27 -070065 fake_cfg.project = PROJECT
66 self.compute_client = gcompute_client.ComputeClient(
67 fake_cfg, mock.MagicMock())
Tri Vo29ac1822016-10-01 17:06:29 -070068 self.compute_client._service = mock.MagicMock()
69
Kevin Cheng5c124ec2018-05-16 13:28:51 -070070 self._disk_args = copy.deepcopy(gcompute_client.BASE_DISK_ARGS)
71 self._disk_args["initializeParams"] = {"diskName": self.INSTANCE,
72 "sourceImage": self.IMAGE_URL}
73
74 # pylint: disable=invalid-name
Tri Vo29ac1822016-10-01 17:06:29 -070075 def _SetupMocksForGetOperationStatus(self, mock_result, operation_scope):
76 """A helper class for setting up mocks for testGetOperationStatus*.
77
Kevin Chengb5963882018-05-09 00:06:27 -070078 Args:
79 mock_result: The result to return by _GetOperationStatus.
80 operation_scope: A value of OperationScope.
Tri Vo29ac1822016-10-01 17:06:29 -070081
Kevin Chengb5963882018-05-09 00:06:27 -070082 Returns:
83 A mock for Resource object.
84 """
Tri Vo29ac1822016-10-01 17:06:29 -070085 resource_mock = mock.MagicMock()
86 mock_api = mock.MagicMock()
87 if operation_scope == gcompute_client.OperationScope.GLOBAL:
88 self.compute_client._service.globalOperations = mock.MagicMock(
89 return_value=resource_mock)
90 elif operation_scope == gcompute_client.OperationScope.ZONE:
91 self.compute_client._service.zoneOperations = mock.MagicMock(
92 return_value=resource_mock)
93 elif operation_scope == gcompute_client.OperationScope.REGION:
94 self.compute_client._service.regionOperations = mock.MagicMock(
95 return_value=resource_mock)
96 resource_mock.get = mock.MagicMock(return_value=mock_api)
97 mock_api.execute = mock.MagicMock(return_value=mock_result)
98 return resource_mock
99
100 def testGetOperationStatusGlobal(self):
101 """Test _GetOperationStatus for global."""
102 resource_mock = self._SetupMocksForGetOperationStatus(
103 {"status": "GOOD"}, gcompute_client.OperationScope.GLOBAL)
104 status = self.compute_client._GetOperationStatus(
105 {"name": self.OPERATION_NAME},
106 gcompute_client.OperationScope.GLOBAL)
107 self.assertEqual(status, "GOOD")
108 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700109 project=PROJECT, operation=self.OPERATION_NAME)
Tri Vo29ac1822016-10-01 17:06:29 -0700110
111 def testGetOperationStatusZone(self):
112 """Test _GetOperationStatus for zone."""
113 resource_mock = self._SetupMocksForGetOperationStatus(
114 {"status": "GOOD"}, gcompute_client.OperationScope.ZONE)
115 status = self.compute_client._GetOperationStatus(
116 {"name": self.OPERATION_NAME}, gcompute_client.OperationScope.ZONE,
117 self.ZONE)
118 self.assertEqual(status, "GOOD")
119 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700120 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -0700121 operation=self.OPERATION_NAME,
122 zone=self.ZONE)
123
124 def testGetOperationStatusRegion(self):
125 """Test _GetOperationStatus for region."""
126 resource_mock = self._SetupMocksForGetOperationStatus(
127 {"status": "GOOD"}, gcompute_client.OperationScope.REGION)
128 self.compute_client._GetOperationStatus(
129 {"name": self.OPERATION_NAME},
130 gcompute_client.OperationScope.REGION, self.REGION)
131 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700132 project=PROJECT, operation=self.OPERATION_NAME, region=self.REGION)
Tri Vo29ac1822016-10-01 17:06:29 -0700133
134 def testGetOperationStatusError(self):
135 """Test _GetOperationStatus failed."""
136 self._SetupMocksForGetOperationStatus(
137 {"error": {"errors": ["error1", "error2"]}},
138 gcompute_client.OperationScope.GLOBAL)
139 self.assertRaisesRegexp(errors.DriverError,
140 "Get operation state failed.*error1.*error2",
141 self.compute_client._GetOperationStatus,
142 {"name": self.OPERATION_NAME},
143 gcompute_client.OperationScope.GLOBAL)
144
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700145 @mock.patch.object(errors, "GceOperationTimeoutError")
146 @mock.patch.object(utils, "PollAndWait")
147 def testWaitOnOperation(self, mock_poll, mock_gce_operation_timeout_error):
Tri Vo29ac1822016-10-01 17:06:29 -0700148 """Test WaitOnOperation."""
149 mock_error = mock.MagicMock()
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700150 mock_gce_operation_timeout_error.return_value = mock_error
Tri Vo29ac1822016-10-01 17:06:29 -0700151 self.compute_client.WaitOnOperation(
152 operation={"name": self.OPERATION_NAME},
153 operation_scope=gcompute_client.OperationScope.REGION,
154 scope_name=self.REGION)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700155 mock_poll.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700156 func=self.compute_client._GetOperationStatus,
157 expected_return="DONE",
158 timeout_exception=mock_error,
159 timeout_secs=self.compute_client.OPERATION_TIMEOUT_SECS,
Kevin Chengb5963882018-05-09 00:06:27 -0700160 sleep_interval_secs=self.compute_client.OPERATION_POLL_INTERVAL_SECS,
Tri Vo29ac1822016-10-01 17:06:29 -0700161 operation={"name": self.OPERATION_NAME},
162 operation_scope=gcompute_client.OperationScope.REGION,
163 scope_name=self.REGION)
164
Kevin Chengb5963882018-05-09 00:06:27 -0700165 def testGetImage(self):
166 """Test GetImage."""
167 resource_mock = mock.MagicMock()
168 mock_api = mock.MagicMock()
169 self.compute_client._service.images = mock.MagicMock(
170 return_value=resource_mock)
171 resource_mock.get = mock.MagicMock(return_value=mock_api)
172 mock_api.execute = mock.MagicMock(return_value={"name": self.IMAGE})
173 result = self.compute_client.GetImage(self.IMAGE)
174 self.assertEqual(result, {"name": self.IMAGE})
175 resource_mock.get.assert_called_with(project=PROJECT, image=self.IMAGE)
176
177 def testGetImageOther(self):
178 """Test GetImage with other project."""
179 resource_mock = mock.MagicMock()
180 mock_api = mock.MagicMock()
181 self.compute_client._service.images = mock.MagicMock(
182 return_value=resource_mock)
183 resource_mock.get = mock.MagicMock(return_value=mock_api)
184 mock_api.execute = mock.MagicMock(return_value={"name": self.IMAGE_OTHER})
185 result = self.compute_client.GetImage(
186 image_name=self.IMAGE_OTHER,
187 image_project=self.PROJECT_OTHER)
188 self.assertEqual(result, {"name": self.IMAGE_OTHER})
189 resource_mock.get.assert_called_with(
190 project=self.PROJECT_OTHER, image=self.IMAGE_OTHER)
191
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700192 def testCreateImageWithSourceURI(self):
193 """Test CreateImage with src uri."""
194 source_uri = GS_IMAGE_SOURCE_URI
195 source_disk = None
196 labels = None
197 expected_body = {"name": self.IMAGE,
198 "rawDisk": {"source": GS_IMAGE_SOURCE_URI}}
199 mock_check = self.Patch(gcompute_client.ComputeClient,
200 "CheckImageExists",
201 return_value=False)
202 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
203 resource_mock = mock.MagicMock()
204 self.compute_client._service.images = mock.MagicMock(
205 return_value=resource_mock)
206 resource_mock.insert = mock.MagicMock()
207 self.compute_client.CreateImage(
208 image_name=self.IMAGE, source_uri=source_uri,
209 source_disk=source_disk, labels=labels)
210 resource_mock.insert.assert_called_with(
211 project=PROJECT, body=expected_body)
212 mock_wait.assert_called_with(
213 operation=mock.ANY,
214 operation_scope=gcompute_client.OperationScope.GLOBAL)
215 mock_check.assert_called_with(self.IMAGE)
216
217 def testCreateImageWithSourceDisk(self):
218 """Test CreateImage with src disk."""
219 source_uri = None
220 source_disk = GS_IMAGE_SOURCE_DISK
221 labels = None
222 expected_body = {"name": self.IMAGE,
223 "sourceDisk": GS_IMAGE_SOURCE_DISK}
224 mock_check = self.Patch(gcompute_client.ComputeClient,
225 "CheckImageExists",
226 return_value=False)
227 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
228 resource_mock = mock.MagicMock()
229 self.compute_client._service.images = mock.MagicMock(
230 return_value=resource_mock)
231 resource_mock.insert = mock.MagicMock()
232 self.compute_client.CreateImage(
233 image_name=self.IMAGE, source_uri=source_uri,
234 source_disk=source_disk, labels=labels)
235 resource_mock.insert.assert_called_with(
236 project=PROJECT, body=expected_body)
237 mock_wait.assert_called_with(
238 operation=mock.ANY,
239 operation_scope=gcompute_client.OperationScope.GLOBAL)
240 mock_check.assert_called_with(self.IMAGE)
241
242 def testCreateImageWithSourceDiskAndLabel(self):
243 """Test CreateImage with src disk and label."""
244 source_uri = None
245 source_disk = GS_IMAGE_SOURCE_DISK
246 labels = {"label1": "xxx"}
247 expected_body = {"name": self.IMAGE,
248 "sourceDisk": GS_IMAGE_SOURCE_DISK,
249 "labels": {"label1": "xxx"}}
herbertxue308f7662018-05-18 03:25:58 +0000250 mock_check = self.Patch(gcompute_client.ComputeClient,
251 "CheckImageExists",
252 return_value=False)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700253 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
Tri Vo29ac1822016-10-01 17:06:29 -0700254 resource_mock = mock.MagicMock()
255 self.compute_client._service.images = mock.MagicMock(
256 return_value=resource_mock)
257 resource_mock.insert = mock.MagicMock()
Tri Vo29ac1822016-10-01 17:06:29 -0700258 self.compute_client.CreateImage(
Kevin Chengb5963882018-05-09 00:06:27 -0700259 image_name=self.IMAGE, source_uri=source_uri,
260 source_disk=source_disk, labels=labels)
Tri Vo29ac1822016-10-01 17:06:29 -0700261 resource_mock.insert.assert_called_with(
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700262 project=PROJECT, body=expected_body)
263 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700264 operation=mock.ANY,
265 operation_scope=gcompute_client.OperationScope.GLOBAL)
herbertxue308f7662018-05-18 03:25:58 +0000266 mock_check.assert_called_with(self.IMAGE)
Tri Vo29ac1822016-10-01 17:06:29 -0700267
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700268 @mock.patch.object(gcompute_client.ComputeClient, "GetImage")
269 def testSetImageLabel(self, mock_get_image):
270 """Test SetImageLabel."""
271 with mock.patch.object(self.compute_client._service, "images",
272 return_value=mock.MagicMock(
273 setLabels=mock.MagicMock())) as _:
274 image = {"name": self.IMAGE,
275 "sourceDisk": GS_IMAGE_SOURCE_DISK,
276 "labelFingerprint": self.IMAGE_FINGERPRINT,
277 "labels": {"a": "aaa", "b": "bbb"}}
278 mock_get_image.return_value = image
279 new_labels = {"a": "xxx", "c": "ccc"}
280 # Test
281 self.compute_client.SetImageLabels(
282 self.IMAGE, new_labels)
283 # Check result
284 expected_labels = {"a": "xxx", "b": "bbb", "c": "ccc"}
285 self.compute_client._service.images().setLabels.assert_called_with(
286 project=PROJECT,
287 resource=self.IMAGE,
288 body={
289 "labels": expected_labels,
290 "labelFingerprint": self.IMAGE_FINGERPRINT
291 })
Kevin Chengb5963882018-05-09 00:06:27 -0700292
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700293 def testCreateImageRaiseDriverErrorWithValidInput(self):
294 """Test CreateImage with valid input."""
295 source_uri = GS_IMAGE_SOURCE_URI
296 source_disk = GS_IMAGE_SOURCE_DISK
herbertxue308f7662018-05-18 03:25:58 +0000297 self.Patch(gcompute_client.ComputeClient, "CheckImageExists", return_value=False)
Kevin Chengb5963882018-05-09 00:06:27 -0700298 self.assertRaises(errors.DriverError, self.compute_client.CreateImage,
299 image_name=self.IMAGE, source_uri=source_uri,
300 source_disk=source_disk)
301
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700302 def testCreateImageRaiseDriverErrorWithInvalidInput(self):
303 """Test CreateImage with valid input."""
304 source_uri = None
305 source_disk = None
306 self.Patch(gcompute_client.ComputeClient, "CheckImageExists", return_value=False)
307 self.assertRaises(errors.DriverError, self.compute_client.CreateImage,
308 image_name=self.IMAGE, source_uri=source_uri,
309 source_disk=source_disk)
Tri Vo29ac1822016-10-01 17:06:29 -0700310
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700311 @mock.patch.object(gcompute_client.ComputeClient, "DeleteImage")
312 @mock.patch.object(gcompute_client.ComputeClient, "CheckImageExists",
herbertxue308f7662018-05-18 03:25:58 +0000313 side_effect=[False, True])
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700314 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation",
315 side_effect=errors.DriverError("Expected fake error"))
316 def testCreateImageFail(self, mock_wait, mock_check, mock_delete):
317 """Test CreateImage fails."""
Tri Vo29ac1822016-10-01 17:06:29 -0700318 resource_mock = mock.MagicMock()
319 self.compute_client._service.images = mock.MagicMock(
320 return_value=resource_mock)
321 resource_mock.insert = mock.MagicMock()
322
323 expected_body = {
324 "name": self.IMAGE,
325 "rawDisk": {
Kevin Chengb5963882018-05-09 00:06:27 -0700326 "source": GS_IMAGE_SOURCE_URI,
Tri Vo29ac1822016-10-01 17:06:29 -0700327 },
328 }
329 self.assertRaisesRegexp(
330 errors.DriverError,
331 "Expected fake error",
332 self.compute_client.CreateImage,
333 image_name=self.IMAGE,
Kevin Chengb5963882018-05-09 00:06:27 -0700334 source_uri=GS_IMAGE_SOURCE_URI)
Tri Vo29ac1822016-10-01 17:06:29 -0700335 resource_mock.insert.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700336 project=PROJECT, body=expected_body)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700337 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700338 operation=mock.ANY,
339 operation_scope=gcompute_client.OperationScope.GLOBAL)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700340 mock_check.assert_called_with(self.IMAGE)
341 mock_delete.assert_called_with(self.IMAGE)
Tri Vo29ac1822016-10-01 17:06:29 -0700342
343 def testCheckImageExistsTrue(self):
344 """Test CheckImageExists return True."""
345 resource_mock = mock.MagicMock()
346 mock_api = mock.MagicMock()
347 self.compute_client._service.images = mock.MagicMock(
348 return_value=resource_mock)
349 resource_mock.get = mock.MagicMock(return_value=mock_api)
350 mock_api.execute = mock.MagicMock(return_value={"name": self.IMAGE})
351 self.assertTrue(self.compute_client.CheckImageExists(self.IMAGE))
352
353 def testCheckImageExistsFalse(self):
354 """Test CheckImageExists return False."""
355 resource_mock = mock.MagicMock()
356 mock_api = mock.MagicMock()
357 self.compute_client._service.images = mock.MagicMock(
358 return_value=resource_mock)
359 resource_mock.get = mock.MagicMock(return_value=mock_api)
360 mock_api.execute = mock.MagicMock(
361 side_effect=errors.ResourceNotFoundError(404, "no image"))
362 self.assertFalse(self.compute_client.CheckImageExists(self.IMAGE))
363
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700364 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
365 def testDeleteImage(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700366 """Test DeleteImage."""
Tri Vo29ac1822016-10-01 17:06:29 -0700367 resource_mock = mock.MagicMock()
368 self.compute_client._service.images = mock.MagicMock(
369 return_value=resource_mock)
370 resource_mock.delete = mock.MagicMock()
371 self.compute_client.DeleteImage(self.IMAGE)
372 resource_mock.delete.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700373 project=PROJECT, image=self.IMAGE)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700374 self.assertTrue(mock_wait.called)
Tri Vo29ac1822016-10-01 17:06:29 -0700375
376 def _SetupBatchHttpRequestMock(self):
377 """Setup BatchHttpRequest mock."""
378 requests = {}
379
380 def _Add(request, callback, request_id):
381 requests[request_id] = (request, callback)
382
383 def _Execute():
384 for rid in requests:
385 _, callback = requests[rid]
386 callback(
387 request_id=rid, response=mock.MagicMock(), exception=None)
Tri Vo29ac1822016-10-01 17:06:29 -0700388 mock_batch = mock.MagicMock()
389 mock_batch.add = _Add
390 mock_batch.execute = _Execute
391 self.Patch(apiclient.http, "BatchHttpRequest", return_value=mock_batch)
392
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700393 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
394 def testDeleteImages(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700395 """Test DeleteImages."""
396 self._SetupBatchHttpRequestMock()
Tri Vo29ac1822016-10-01 17:06:29 -0700397 fake_images = ["fake_image_1", "fake_image_2"]
398 mock_api = mock.MagicMock()
399 resource_mock = mock.MagicMock()
400 self.compute_client._service.images = mock.MagicMock(
401 return_value=resource_mock)
402 resource_mock.delete = mock.MagicMock(return_value=mock_api)
403 # Call the API.
404 deleted, failed, error_msgs = self.compute_client.DeleteImages(
405 fake_images)
406 # Verify
Kevin Chengb5963882018-05-09 00:06:27 -0700407 calls = [
408 mock.call(project=PROJECT, image="fake_image_1"),
409 mock.call(project=PROJECT, image="fake_image_2")
410 ]
Tri Vo29ac1822016-10-01 17:06:29 -0700411 resource_mock.delete.assert_has_calls(calls, any_order=True)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700412 self.assertEqual(mock_wait.call_count, 2)
Tri Vo29ac1822016-10-01 17:06:29 -0700413 self.assertEqual(error_msgs, [])
414 self.assertEqual(failed, [])
415 self.assertEqual(set(deleted), set(fake_images))
416
417 def testListImages(self):
418 """Test ListImages."""
419 fake_token = "fake_next_page_token"
420 image_1 = "image_1"
421 image_2 = "image_2"
422 response_1 = {"items": [image_1], "nextPageToken": fake_token}
423 response_2 = {"items": [image_2]}
424 self.Patch(
425 gcompute_client.ComputeClient,
426 "Execute",
427 side_effect=[response_1, response_2])
428 resource_mock = mock.MagicMock()
429 self.compute_client._service.images = mock.MagicMock(
430 return_value=resource_mock)
431 resource_mock.list = mock.MagicMock()
432 images = self.compute_client.ListImages()
433 calls = [
Kevin Chengb5963882018-05-09 00:06:27 -0700434 mock.call(project=PROJECT, filter=None, pageToken=None),
435 mock.call(project=PROJECT, filter=None, pageToken=fake_token)
Tri Vo29ac1822016-10-01 17:06:29 -0700436 ]
437 resource_mock.list.assert_has_calls(calls)
438 self.assertEqual(images, [image_1, image_2])
439
Kevin Chengb5963882018-05-09 00:06:27 -0700440 def testListImagesFromExternalProject(self):
441 """Test ListImages which accepts different project."""
442 image = "image_1"
443 response = {"items": [image]}
444 self.Patch(gcompute_client.ComputeClient, "Execute", side_effect=[response])
445 resource_mock = mock.MagicMock()
446 self.compute_client._service.images = mock.MagicMock(
447 return_value=resource_mock)
448 resource_mock.list = mock.MagicMock()
449 images = self.compute_client.ListImages(
450 image_project="fake-project-2")
451 calls = [
452 mock.call(project="fake-project-2", filter=None, pageToken=None)]
453 resource_mock.list.assert_has_calls(calls)
454 self.assertEqual(images, [image])
455
Tri Vo29ac1822016-10-01 17:06:29 -0700456 def testGetInstance(self):
457 """Test GetInstance."""
458 resource_mock = mock.MagicMock()
459 mock_api = mock.MagicMock()
460 self.compute_client._service.instances = mock.MagicMock(
461 return_value=resource_mock)
462 resource_mock.get = mock.MagicMock(return_value=mock_api)
463 mock_api.execute = mock.MagicMock(return_value={"name": self.INSTANCE})
464 result = self.compute_client.GetInstance(self.INSTANCE, self.ZONE)
465 self.assertEqual(result, {"name": self.INSTANCE})
466 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700467 project=PROJECT, zone=self.ZONE, instance=self.INSTANCE)
Tri Vo29ac1822016-10-01 17:06:29 -0700468
469 def testListInstances(self):
470 """Test ListInstances."""
471 fake_token = "fake_next_page_token"
472 instance_1 = "instance_1"
473 instance_2 = "instance_2"
474 response_1 = {"items": [instance_1], "nextPageToken": fake_token}
475 response_2 = {"items": [instance_2]}
476 self.Patch(
477 gcompute_client.ComputeClient,
478 "Execute",
479 side_effect=[response_1, response_2])
480 resource_mock = mock.MagicMock()
481 self.compute_client._service.instances = mock.MagicMock(
482 return_value=resource_mock)
483 resource_mock.list = mock.MagicMock()
484 instances = self.compute_client.ListInstances(self.ZONE)
485 calls = [
486 mock.call(
Kevin Chengb5963882018-05-09 00:06:27 -0700487 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -0700488 zone=self.ZONE,
489 filter=None,
490 pageToken=None),
491 mock.call(
Kevin Chengb5963882018-05-09 00:06:27 -0700492 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -0700493 zone=self.ZONE,
494 filter=None,
495 pageToken=fake_token),
496 ]
497 resource_mock.list.assert_has_calls(calls)
498 self.assertEqual(instances, [instance_1, instance_2])
499
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700500 @mock.patch.object(gcompute_client.ComputeClient, "GetImage")
501 @mock.patch.object(gcompute_client.ComputeClient, "GetNetworkUrl")
502 @mock.patch.object(gcompute_client.ComputeClient, "GetMachineType")
503 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
504 def testCreateInstance(self, mock_wait, mock_get_mach_type,
505 mock_get_network_url, mock_get_image):
Tri Vo29ac1822016-10-01 17:06:29 -0700506 """Test CreateInstance."""
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700507 mock_get_mach_type.return_value = {"selfLink": self.MACHINE_TYPE_URL}
508 mock_get_network_url.return_value = self.NETWORK_URL
509 mock_get_image.return_value = {"selfLink": self.IMAGE_URL}
Tri Vo29ac1822016-10-01 17:06:29 -0700510 resource_mock = mock.MagicMock()
511 self.compute_client._service.instances = mock.MagicMock(
512 return_value=resource_mock)
513 resource_mock.insert = mock.MagicMock()
herbertxue308f7662018-05-18 03:25:58 +0000514 self.Patch(
515 self.compute_client,
516 "_GetExtraDiskArgs",
517 return_value=[{"fake_extra_arg": "fake_extra_value"}])
518 extra_disk_name = "gce-x86-userdebug-2345-abcd-data"
519 expected_disk_args = [self._disk_args]
520 expected_disk_args.extend([{"fake_extra_arg": "fake_extra_value"}])
Tri Vo29ac1822016-10-01 17:06:29 -0700521
522 expected_body = {
523 "machineType": self.MACHINE_TYPE_URL,
524 "name": self.INSTANCE,
525 "networkInterfaces": [
526 {
527 "network": self.NETWORK_URL,
528 "accessConfigs": [
529 {"name": "External NAT",
530 "type": "ONE_TO_ONE_NAT"}
531 ],
532 }
533 ],
herbertxue308f7662018-05-18 03:25:58 +0000534 "disks": expected_disk_args,
Tri Vo29ac1822016-10-01 17:06:29 -0700535 "serviceAccounts": [
536 {"email": "default",
537 "scopes": self.compute_client.DEFAULT_INSTANCE_SCOPE}
538 ],
539 "metadata": {
540 "items": [{"key": self.METADATA[0],
541 "value": self.METADATA[1]}],
542 },
543 }
544
545 self.compute_client.CreateInstance(
546 instance=self.INSTANCE,
547 image_name=self.IMAGE,
548 machine_type=self.MACHINE_TYPE,
549 metadata={self.METADATA[0]: self.METADATA[1]},
550 network=self.NETWORK,
herbertxue308f7662018-05-18 03:25:58 +0000551 zone=self.ZONE,
552 extra_disk_name=extra_disk_name)
Tri Vo29ac1822016-10-01 17:06:29 -0700553
554 resource_mock.insert.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700555 project=PROJECT, zone=self.ZONE, body=expected_body)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700556 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700557 mock.ANY,
558 operation_scope=gcompute_client.OperationScope.ZONE,
559 scope_name=self.ZONE)
560
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700561 @mock.patch.object(gcompute_client.ComputeClient, "GetAcceleratorUrl")
562 @mock.patch.object(gcompute_client.ComputeClient, "GetImage")
563 @mock.patch.object(gcompute_client.ComputeClient, "GetNetworkUrl")
564 @mock.patch.object(gcompute_client.ComputeClient, "GetMachineType")
565 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
566 def testCreateInstanceWithGpu(self, mock_wait, mock_get_mach,
567 mock_get_network, mock_get_image,
568 mock_get_accel):
Kevin Chengb5963882018-05-09 00:06:27 -0700569 """Test CreateInstance with a GPU parameter not set to None."""
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700570 mock_get_mach.return_value = {"selfLink": self.MACHINE_TYPE_URL}
571 mock_get_network.return_value = self.NETWORK_URL
572 mock_get_accel.return_value = self.ACCELERATOR_URL
573 mock_get_image.return_value = {"selfLink": self.IMAGE_URL}
Kevin Chengb5963882018-05-09 00:06:27 -0700574
575 resource_mock = mock.MagicMock()
576 self.compute_client._service.instances = mock.MagicMock(
577 return_value=resource_mock)
578 resource_mock.insert = mock.MagicMock()
579
580 expected_body = {
581 "machineType":
582 self.MACHINE_TYPE_URL,
583 "name":
584 self.INSTANCE,
585 "networkInterfaces": [{
586 "network":
587 self.NETWORK_URL,
588 "accessConfigs": [{
589 "name": "External NAT",
590 "type": "ONE_TO_ONE_NAT"
591 }],
592 }],
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700593 "disks": [self._disk_args],
Kevin Chengb5963882018-05-09 00:06:27 -0700594 "serviceAccounts": [{
595 "email": "default",
596 "scopes": self.compute_client.DEFAULT_INSTANCE_SCOPE
597 }],
598 "scheduling": {
599 "onHostMaintenance": "terminate"
600 },
601 "guestAccelerators": [{
602 "acceleratorCount": 1,
603 "acceleratorType": "http://speedy-gpu"
604 }],
605 "metadata": {
606 "items": [{
607 "key": self.METADATA[0],
608 "value": self.METADATA[1]
609 }],
610 },
611 }
612
613 self.compute_client.CreateInstance(
614 instance=self.INSTANCE,
615 image_name=self.IMAGE,
616 machine_type=self.MACHINE_TYPE,
617 metadata={self.METADATA[0]: self.METADATA[1]},
618 network=self.NETWORK,
619 zone=self.ZONE,
620 gpu=self.GPU)
621
622 resource_mock.insert.assert_called_with(
623 project=PROJECT, zone=self.ZONE, body=expected_body)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700624 mock_wait.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700625 mock.ANY, operation_scope=gcompute_client.OperationScope.ZONE,
626 scope_name=self.ZONE)
627
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700628 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
629 def testDeleteInstance(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700630 """Test DeleteInstance."""
Tri Vo29ac1822016-10-01 17:06:29 -0700631 resource_mock = mock.MagicMock()
632 self.compute_client._service.instances = mock.MagicMock(
633 return_value=resource_mock)
634 resource_mock.delete = mock.MagicMock()
635 self.compute_client.DeleteInstance(
636 instance=self.INSTANCE, zone=self.ZONE)
637 resource_mock.delete.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700638 project=PROJECT, zone=self.ZONE, instance=self.INSTANCE)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700639 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700640 mock.ANY,
641 operation_scope=gcompute_client.OperationScope.ZONE,
642 scope_name=self.ZONE)
643
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700644 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
645 def testDeleteInstances(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700646 """Test DeleteInstances."""
647 self._SetupBatchHttpRequestMock()
Tri Vo29ac1822016-10-01 17:06:29 -0700648 fake_instances = ["fake_instance_1", "fake_instance_2"]
649 mock_api = mock.MagicMock()
650 resource_mock = mock.MagicMock()
651 self.compute_client._service.instances = mock.MagicMock(
652 return_value=resource_mock)
653 resource_mock.delete = mock.MagicMock(return_value=mock_api)
654 deleted, failed, error_msgs = self.compute_client.DeleteInstances(
655 fake_instances, self.ZONE)
656 calls = [
657 mock.call(
Kevin Chengb5963882018-05-09 00:06:27 -0700658 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -0700659 instance="fake_instance_1",
Kevin Chengb5963882018-05-09 00:06:27 -0700660 zone=self.ZONE),
661 mock.call(
662 project=PROJECT,
663 instance="fake_instance_2",
664 zone=self.ZONE)
Tri Vo29ac1822016-10-01 17:06:29 -0700665 ]
666 resource_mock.delete.assert_has_calls(calls, any_order=True)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700667 self.assertEqual(mock_wait.call_count, 2)
Tri Vo29ac1822016-10-01 17:06:29 -0700668 self.assertEqual(error_msgs, [])
669 self.assertEqual(failed, [])
670 self.assertEqual(set(deleted), set(fake_instances))
671
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700672 def testCreateDiskWithProject(self):
673 """Test CreateDisk with images using a set project."""
674 source_project = "fake-image-project"
675 expected_project_to_use = "fake-image-project"
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700676 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
Kevin Chengb5963882018-05-09 00:06:27 -0700677 resource_mock = mock.MagicMock()
678 self.compute_client._service.disks = mock.MagicMock(
679 return_value=resource_mock)
680 resource_mock.insert = mock.MagicMock()
681 self.compute_client.CreateDisk(
682 "fake_disk", "fake_image", 10, self.ZONE, source_project=source_project)
683 resource_mock.insert.assert_called_with(
684 project=PROJECT,
685 zone=self.ZONE,
686 sourceImage="projects/%s/global/images/fake_image" %
687 expected_project_to_use,
688 body={
689 "name":
690 "fake_disk",
691 "sizeGb":
692 10,
693 "type":
694 "projects/%s/zones/%s/diskTypes/pd-standard" % (PROJECT,
695 self.ZONE)
696 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700697 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700698
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700699 def testCreateDiskWithNoSourceProject(self):
700 """Test CreateDisk with images with no set project."""
701 source_project = None
702 expected_project_to_use = PROJECT
703 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
704 resource_mock = mock.MagicMock()
705 self.compute_client._service.disks = mock.MagicMock(
706 return_value=resource_mock)
707 resource_mock.insert = mock.MagicMock()
708 self.compute_client.CreateDisk(
709 "fake_disk", "fake_image", 10, self.ZONE, source_project=source_project)
710 resource_mock.insert.assert_called_with(
711 project=PROJECT,
712 zone=self.ZONE,
713 sourceImage="projects/%s/global/images/fake_image" %
714 expected_project_to_use,
715 body={
716 "name":
717 "fake_disk",
718 "sizeGb":
719 10,
720 "type":
721 "projects/%s/zones/%s/diskTypes/pd-standard" % (PROJECT,
722 self.ZONE)
723 })
724 self.assertTrue(mock_wait.called)
725
726 def testCreateDiskWithTypeStandard(self):
727 """Test CreateDisk with images using standard."""
728 disk_type = gcompute_client.PersistentDiskType.STANDARD
729 expected_disk_type_string = "pd-standard"
730 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
731 resource_mock = mock.MagicMock()
732 self.compute_client._service.disks = mock.MagicMock(
733 return_value=resource_mock)
734 resource_mock.insert = mock.MagicMock()
735 self.compute_client.CreateDisk(
736 "fake_disk",
737 "fake_image",
738 10,
739 self.ZONE,
740 source_project="fake-project",
741 disk_type=disk_type)
742 resource_mock.insert.assert_called_with(
743 project=PROJECT,
744 zone=self.ZONE,
745 sourceImage="projects/%s/global/images/fake_image" % "fake-project",
746 body={
747 "name":
748 "fake_disk",
749 "sizeGb":
750 10,
751 "type":
752 "projects/%s/zones/%s/diskTypes/%s" %
753 (PROJECT, self.ZONE, expected_disk_type_string)
754 })
755 self.assertTrue(mock_wait.called)
756
757 def testCreateDiskWithTypeSSD(self):
758 """Test CreateDisk with images using standard."""
759 disk_type = gcompute_client.PersistentDiskType.SSD
760 expected_disk_type_string = "pd-ssd"
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700761 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
Kevin Chengb5963882018-05-09 00:06:27 -0700762 resource_mock = mock.MagicMock()
763 self.compute_client._service.disks = mock.MagicMock(
764 return_value=resource_mock)
765 resource_mock.insert = mock.MagicMock()
766 self.compute_client.CreateDisk(
767 "fake_disk",
768 "fake_image",
769 10,
770 self.ZONE,
771 source_project="fake-project",
772 disk_type=disk_type)
773 resource_mock.insert.assert_called_with(
774 project=PROJECT,
775 zone=self.ZONE,
776 sourceImage="projects/%s/global/images/fake_image" % "fake-project",
777 body={
778 "name":
779 "fake_disk",
780 "sizeGb":
781 10,
782 "type":
783 "projects/%s/zones/%s/diskTypes/%s" %
784 (PROJECT, self.ZONE, expected_disk_type_string)
785 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700786 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700787
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700788 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
789 def testAttachDisk(self, mock_wait):
Kevin Chengb5963882018-05-09 00:06:27 -0700790 """Test AttachDisk."""
Kevin Chengb5963882018-05-09 00:06:27 -0700791 resource_mock = mock.MagicMock()
792 self.compute_client._service.instances = mock.MagicMock(
793 return_value=resource_mock)
794 resource_mock.attachDisk = mock.MagicMock()
795 self.compute_client.AttachDisk(
796 "fake_instance_1", self.ZONE, deviceName="fake_disk",
797 source="fake-selfLink")
798 resource_mock.attachDisk.assert_called_with(
799 project=PROJECT,
800 zone=self.ZONE,
801 instance="fake_instance_1",
802 body={
803 "deviceName": "fake_disk",
804 "source": "fake-selfLink"
805 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700806 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700807
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700808 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
809 def testDetachDisk(self, mock_wait):
Kevin Chengb5963882018-05-09 00:06:27 -0700810 """Test DetachDisk."""
Kevin Chengb5963882018-05-09 00:06:27 -0700811 resource_mock = mock.MagicMock()
812 self.compute_client._service.instances = mock.MagicMock(
813 return_value=resource_mock)
814 resource_mock.detachDisk = mock.MagicMock()
815 self.compute_client.DetachDisk("fake_instance_1", self.ZONE, "fake_disk")
816 resource_mock.detachDisk.assert_called_with(
817 project=PROJECT,
818 zone=self.ZONE,
819 instance="fake_instance_1",
820 deviceName="fake_disk")
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700821 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700822
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700823 @mock.patch.object(gcompute_client.ComputeClient, "GetAcceleratorUrl")
824 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
825 def testAttachAccelerator(self, mock_wait, mock_get_accel):
Kevin Chengb5963882018-05-09 00:06:27 -0700826 """Test AttachAccelerator."""
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700827 mock_get_accel.return_value = self.ACCELERATOR_URL
Kevin Chengb5963882018-05-09 00:06:27 -0700828 resource_mock = mock.MagicMock()
829 self.compute_client._service.instances = mock.MagicMock(
830 return_value=resource_mock)
831 resource_mock.attachAccelerator = mock.MagicMock()
832 self.compute_client.AttachAccelerator("fake_instance_1", self.ZONE, 1,
833 "nvidia-tesla-k80")
834 resource_mock.setMachineResources.assert_called_with(
835 project=PROJECT,
836 zone=self.ZONE,
837 instance="fake_instance_1",
838 body={
839 "guestAccelerators": [{
840 "acceleratorType": self.ACCELERATOR_URL,
841 "acceleratorCount": 1
842 }]
843 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700844 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700845
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700846 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
847 def testBatchExecuteOnInstances(self, mock_wait):
848 """Test BatchExecuteOnInstances."""
Tri Vo29ac1822016-10-01 17:06:29 -0700849 self._SetupBatchHttpRequestMock()
Tri Vo29ac1822016-10-01 17:06:29 -0700850 action = mock.MagicMock(return_value=mock.MagicMock())
851 fake_instances = ["fake_instance_1", "fake_instance_2"]
852 done, failed, error_msgs = self.compute_client._BatchExecuteOnInstances(
853 fake_instances, self.ZONE, action)
854 calls = [mock.call(instance="fake_instance_1"),
855 mock.call(instance="fake_instance_2")]
856 action.assert_has_calls(calls, any_order=True)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700857 self.assertEqual(mock_wait.call_count, 2)
Tri Vo29ac1822016-10-01 17:06:29 -0700858 self.assertEqual(set(done), set(fake_instances))
859 self.assertEqual(error_msgs, [])
860 self.assertEqual(failed, [])
861
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700862 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
863 def testResetInstance(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700864 """Test ResetInstance."""
Tri Vo29ac1822016-10-01 17:06:29 -0700865 resource_mock = mock.MagicMock()
866 self.compute_client._service.instances = mock.MagicMock(
867 return_value=resource_mock)
868 resource_mock.reset = mock.MagicMock()
869 self.compute_client.ResetInstance(
870 instance=self.INSTANCE, zone=self.ZONE)
871 resource_mock.reset.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700872 project=PROJECT, zone=self.ZONE, instance=self.INSTANCE)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700873 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700874 mock.ANY,
875 operation_scope=gcompute_client.OperationScope.ZONE,
876 scope_name=self.ZONE)
877
878 def _CompareMachineSizeTestHelper(self,
879 machine_info_1,
880 machine_info_2,
881 expected_result=None,
882 expected_error_type=None):
883 """Helper class for testing CompareMachineSize.
884
Kevin Chengb5963882018-05-09 00:06:27 -0700885 Args:
886 machine_info_1: A dictionary representing the first machine size.
887 machine_info_2: A dictionary representing the second machine size.
888 expected_result: An integer, 0, 1 or -1, or None if not set.
889 expected_error_type: An exception type, if set will check for exception.
890 """
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700891 mock_get_mach_type = self.Patch(
Tri Vo29ac1822016-10-01 17:06:29 -0700892 gcompute_client.ComputeClient,
893 "GetMachineType",
894 side_effect=[machine_info_1, machine_info_2])
895 if expected_error_type:
896 self.assertRaises(expected_error_type,
897 self.compute_client.CompareMachineSize, "name1",
898 "name2", self.ZONE)
899 else:
900 result = self.compute_client.CompareMachineSize("name1", "name2",
901 self.ZONE)
902 self.assertEqual(result, expected_result)
903
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700904 mock_get_mach_type.assert_has_calls(
Tri Vo29ac1822016-10-01 17:06:29 -0700905 [mock.call("name1", self.ZONE), mock.call("name2", self.ZONE)])
906
907 def testCompareMachineSizeSmall(self):
908 """Test CompareMachineSize where the first one is smaller."""
909 machine_info_1 = {"guestCpus": 10, "memoryMb": 100}
910 machine_info_2 = {"guestCpus": 10, "memoryMb": 200}
911 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, -1)
912
Kevin Cheng4ae42772018-10-02 11:39:48 -0700913 def testCompareMachineSizeSmallSmallerOnSecond(self):
914 """Test CompareMachineSize where the first one is smaller."""
915 machine_info_1 = {"guestCpus": 11, "memoryMb": 100}
916 machine_info_2 = {"guestCpus": 10, "memoryMb": 200}
917 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, -1)
918
Tri Vo29ac1822016-10-01 17:06:29 -0700919 def testCompareMachineSizeLarge(self):
920 """Test CompareMachineSize where the first one is larger."""
Kevin Cheng4ae42772018-10-02 11:39:48 -0700921 machine_info_1 = {"guestCpus": 11, "memoryMb": 200}
922 machine_info_2 = {"guestCpus": 10, "memoryMb": 100}
923 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, 1)
924
925 def testCompareMachineSizeLargeWithEqualElement(self):
926 """Test CompareMachineSize where the first one is larger."""
Tri Vo29ac1822016-10-01 17:06:29 -0700927 machine_info_1 = {"guestCpus": 10, "memoryMb": 200}
928 machine_info_2 = {"guestCpus": 10, "memoryMb": 100}
929 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, 1)
930
931 def testCompareMachineSizeEqual(self):
932 """Test CompareMachineSize where two machine sizes are equal."""
933 machine_info = {"guestCpus": 10, "memoryMb": 100}
934 self._CompareMachineSizeTestHelper(machine_info, machine_info, 0)
935
936 def testCompareMachineSizeBadMetric(self):
937 """Test CompareMachineSize with bad metric."""
Kevin Chengb5963882018-05-09 00:06:27 -0700938 machine_info = {"unknown_metric": 10, "memoryMb": 100}
Tri Vo29ac1822016-10-01 17:06:29 -0700939 self._CompareMachineSizeTestHelper(
940 machine_info, machine_info, expected_error_type=errors.DriverError)
941
942 def testGetMachineType(self):
943 """Test GetMachineType."""
944 resource_mock = mock.MagicMock()
945 mock_api = mock.MagicMock()
946 self.compute_client._service.machineTypes = mock.MagicMock(
947 return_value=resource_mock)
948 resource_mock.get = mock.MagicMock(return_value=mock_api)
949 mock_api.execute = mock.MagicMock(
950 return_value={"name": self.MACHINE_TYPE})
951 result = self.compute_client.GetMachineType(self.MACHINE_TYPE,
952 self.ZONE)
953 self.assertEqual(result, {"name": self.MACHINE_TYPE})
954 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700955 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -0700956 zone=self.ZONE,
957 machineType=self.MACHINE_TYPE)
958
959 def _GetSerialPortOutputTestHelper(self, response):
960 """Helper function for testing GetSerialPortOutput.
961
Kevin Chengb5963882018-05-09 00:06:27 -0700962 Args:
963 response: A dictionary representing a fake response.
964 """
Tri Vo29ac1822016-10-01 17:06:29 -0700965 resource_mock = mock.MagicMock()
966 mock_api = mock.MagicMock()
967 self.compute_client._service.instances = mock.MagicMock(
968 return_value=resource_mock)
969 resource_mock.getSerialPortOutput = mock.MagicMock(
970 return_value=mock_api)
971 mock_api.execute = mock.MagicMock(return_value=response)
972
973 if "contents" in response:
974 result = self.compute_client.GetSerialPortOutput(
975 instance=self.INSTANCE, zone=self.ZONE)
976 self.assertEqual(result, "fake contents")
977 else:
978 self.assertRaisesRegexp(
979 errors.DriverError,
980 "Malformed response.*",
981 self.compute_client.GetSerialPortOutput,
982 instance=self.INSTANCE,
983 zone=self.ZONE)
984 resource_mock.getSerialPortOutput.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700985 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -0700986 zone=self.ZONE,
987 instance=self.INSTANCE,
988 port=1)
989
990 def testGetSerialPortOutput(self):
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700991 """Test GetSerialPortOutput."""
Tri Vo29ac1822016-10-01 17:06:29 -0700992 response = {"contents": "fake contents"}
993 self._GetSerialPortOutputTestHelper(response)
994
995 def testGetSerialPortOutputFail(self):
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700996 """Test GetSerialPortOutputFail."""
Tri Vo29ac1822016-10-01 17:06:29 -0700997 response = {"malformed": "fake contents"}
998 self._GetSerialPortOutputTestHelper(response)
999
1000 def testGetInstanceNamesByIPs(self):
1001 """Test GetInstanceNamesByIPs."""
1002 good_instance = {
1003 "name": "instance_1",
1004 "networkInterfaces": [
1005 {
1006 "accessConfigs": [
1007 {"natIP": "172.22.22.22"},
1008 ],
1009 },
1010 ],
1011 }
1012 bad_instance = {"name": "instance_2"}
1013 self.Patch(
1014 gcompute_client.ComputeClient,
1015 "ListInstances",
1016 return_value=[good_instance, bad_instance])
1017 ip_name_map = self.compute_client.GetInstanceNamesByIPs(
1018 ips=["172.22.22.22", "172.22.22.23"], zone=self.ZONE)
1019 self.assertEqual(ip_name_map, {"172.22.22.22": "instance_1",
1020 "172.22.22.23": None})
1021
1022 def testAddSshRsa(self):
1023 """Test AddSshRsa.."""
1024 fake_user = "fake_user"
1025 sshkey = (
1026 "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDBkTOTRze9v2VOqkkf7RG"
1027 "jSkg6Z2kb9Q9UHsDGatvend3fmjIw1Tugg0O7nnjlPkskmlgyd4a/j99WOeLL"
1028 "CPk6xPyoVjrPUVBU/pAk09ORTC4Zqk6YjlW7LOfzvqmXhmIZfYu6Q4Yt50pZzhl"
1029 "lllfu26nYjY7Tg12D019nJi/kqPX5+NKgt0LGXTu8T1r2Gav/q4V7QRWQrB8Eiu"
1030 "pxXR7I2YhynqovkEt/OXG4qWgvLEXGsWtSQs0CtCzqEVxz0Y9ECr7er4VdjSQxV"
1031 "AaeLAsQsK9ROae8hMBFZ3//8zLVapBwpuffCu+fUoql9qeV9xagZcc9zj8XOUOW"
1032 "ApiihqNL1111 test@test1.org")
1033 project = {
1034 "commonInstanceMetadata": {
1035 "kind": "compute#metadata",
1036 "fingerprint": "a-23icsyx4E=",
1037 "items": [
1038 {
1039 "key": "sshKeys",
1040 "value": "user:key"
1041 }
1042 ]
1043 }
1044 }
1045 expected = {
1046 "kind": "compute#metadata",
1047 "fingerprint": "a-23icsyx4E=",
1048 "items": [
1049 {
1050 "key": "sshKeys",
1051 "value": "user:key\n%s:%s" % (fake_user, sshkey)
1052 }
1053 ]
1054 }
1055
1056 self.Patch(os.path, "exists", return_value=True)
1057 m = mock.mock_open(read_data=sshkey)
Tri Vo29ac1822016-10-01 17:06:29 -07001058 self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
1059 self.Patch(
1060 gcompute_client.ComputeClient, "GetProject", return_value=project)
1061 resource_mock = mock.MagicMock()
1062 self.compute_client._service.projects = mock.MagicMock(
1063 return_value=resource_mock)
1064 resource_mock.setCommonInstanceMetadata = mock.MagicMock()
1065
Kevin Chengda4f07a2018-06-26 10:25:05 -07001066 with mock.patch("__builtin__.open", m):
1067 self.compute_client.AddSshRsa(fake_user, "/path/to/test_rsa.pub")
1068 resource_mock.setCommonInstanceMetadata.assert_called_with(
1069 project=PROJECT, body=expected)
Tri Vo29ac1822016-10-01 17:06:29 -07001070
1071 def testAddSshRsaInvalidKey(self):
1072 """Test AddSshRsa.."""
1073 fake_user = "fake_user"
1074 sshkey = "ssh-rsa v2VOqkkf7RGL1111 test@test1.org"
1075 project = {
1076 "commonInstanceMetadata": {
1077 "kind": "compute#metadata",
1078 "fingerprint": "a-23icsyx4E=",
1079 "items": [
1080 {
1081 "key": "sshKeys",
1082 "value": "user:key"
1083 }
1084 ]
1085 }
1086 }
1087 self.Patch(os.path, "exists", return_value=True)
1088 m = mock.mock_open(read_data=sshkey)
Tri Vo29ac1822016-10-01 17:06:29 -07001089 self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
1090 self.Patch(
1091 gcompute_client.ComputeClient, "GetProject", return_value=project)
Kevin Chengda4f07a2018-06-26 10:25:05 -07001092 with mock.patch("__builtin__.open", m):
1093 self.assertRaisesRegexp(errors.DriverError, "rsa key is invalid:*",
1094 self.compute_client.AddSshRsa, fake_user,
1095 "/path/to/test_rsa.pub")
Tri Vo29ac1822016-10-01 17:06:29 -07001096
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001097 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
1098 def testDeleteDisks(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -07001099 """Test DeleteDisks."""
1100 self._SetupBatchHttpRequestMock()
Tri Vo29ac1822016-10-01 17:06:29 -07001101 fake_disks = ["fake_disk_1", "fake_disk_2"]
1102 mock_api = mock.MagicMock()
1103 resource_mock = mock.MagicMock()
1104 self.compute_client._service.disks = mock.MagicMock(
1105 return_value=resource_mock)
1106 resource_mock.delete = mock.MagicMock(return_value=mock_api)
1107 # Call the API.
1108 deleted, failed, error_msgs = self.compute_client.DeleteDisks(
1109 fake_disks, zone=self.ZONE)
1110 # Verify
Kevin Chengb5963882018-05-09 00:06:27 -07001111 calls = [
1112 mock.call(project=PROJECT, disk="fake_disk_1", zone=self.ZONE),
1113 mock.call(project=PROJECT, disk="fake_disk_2", zone=self.ZONE)
1114 ]
Tri Vo29ac1822016-10-01 17:06:29 -07001115 resource_mock.delete.assert_has_calls(calls, any_order=True)
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001116 self.assertEqual(mock_wait.call_count, 2)
Tri Vo29ac1822016-10-01 17:06:29 -07001117 self.assertEqual(error_msgs, [])
1118 self.assertEqual(failed, [])
1119 self.assertEqual(set(deleted), set(fake_disks))
1120
Kevin Chengb5963882018-05-09 00:06:27 -07001121 def testRetryOnFingerPrintError(self):
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001122 """Test RetryOnFingerPrintError."""
Kevin Chengb5963882018-05-09 00:06:27 -07001123 @utils.RetryOnException(gcompute_client._IsFingerPrintError, 10)
1124 def Raise412(sentinel):
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001125 """Raise 412 HTTP exception."""
1126 if not sentinel.hitFingerPrintConflict.called:
1127 sentinel.hitFingerPrintConflict()
1128 raise errors.HttpError(412, "resource labels have changed")
1129 return "Passed"
Kevin Chengb5963882018-05-09 00:06:27 -07001130
1131 sentinel = mock.MagicMock()
1132 result = Raise412(sentinel)
1133 self.assertEqual(1, sentinel.hitFingerPrintConflict.call_count)
1134 self.assertEqual("Passed", result)
1135
Tri Vo29ac1822016-10-01 17:06:29 -07001136
1137if __name__ == "__main__":
1138 unittest.main()