blob: b84cdbd319878c5d0029df753fa7b67d9989df42 [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"
Kevin Cheng480e1212018-10-24 00:23:30 -070054 SUBNETWORK_URL = "http://fake-subnetwork-url"
Tri Vo29ac1822016-10-01 17:06:29 -070055 ZONE = "fake-zone"
56 REGION = "fake-region"
57 OPERATION_NAME = "fake-op"
Kevin Chengb5963882018-05-09 00:06:27 -070058 IMAGE_FINGERPRINT = "L_NWHuz7wTY="
59 GPU = "fancy-graphics"
Tri Vo29ac1822016-10-01 17:06:29 -070060
61 def setUp(self):
62 """Set up test."""
63 super(ComputeClientTest, self).setUp()
64 self.Patch(gcompute_client.ComputeClient, "InitResourceHandle")
65 fake_cfg = mock.MagicMock()
Kevin Chengb5963882018-05-09 00:06:27 -070066 fake_cfg.project = PROJECT
67 self.compute_client = gcompute_client.ComputeClient(
68 fake_cfg, mock.MagicMock())
Tri Vo29ac1822016-10-01 17:06:29 -070069 self.compute_client._service = mock.MagicMock()
70
Kevin Cheng5c124ec2018-05-16 13:28:51 -070071 self._disk_args = copy.deepcopy(gcompute_client.BASE_DISK_ARGS)
72 self._disk_args["initializeParams"] = {"diskName": self.INSTANCE,
73 "sourceImage": self.IMAGE_URL}
74
75 # pylint: disable=invalid-name
Tri Vo29ac1822016-10-01 17:06:29 -070076 def _SetupMocksForGetOperationStatus(self, mock_result, operation_scope):
77 """A helper class for setting up mocks for testGetOperationStatus*.
78
Kevin Chengb5963882018-05-09 00:06:27 -070079 Args:
80 mock_result: The result to return by _GetOperationStatus.
81 operation_scope: A value of OperationScope.
Tri Vo29ac1822016-10-01 17:06:29 -070082
Kevin Chengb5963882018-05-09 00:06:27 -070083 Returns:
84 A mock for Resource object.
85 """
Tri Vo29ac1822016-10-01 17:06:29 -070086 resource_mock = mock.MagicMock()
87 mock_api = mock.MagicMock()
88 if operation_scope == gcompute_client.OperationScope.GLOBAL:
89 self.compute_client._service.globalOperations = mock.MagicMock(
90 return_value=resource_mock)
91 elif operation_scope == gcompute_client.OperationScope.ZONE:
92 self.compute_client._service.zoneOperations = mock.MagicMock(
93 return_value=resource_mock)
94 elif operation_scope == gcompute_client.OperationScope.REGION:
95 self.compute_client._service.regionOperations = mock.MagicMock(
96 return_value=resource_mock)
97 resource_mock.get = mock.MagicMock(return_value=mock_api)
98 mock_api.execute = mock.MagicMock(return_value=mock_result)
99 return resource_mock
100
101 def testGetOperationStatusGlobal(self):
102 """Test _GetOperationStatus for global."""
103 resource_mock = self._SetupMocksForGetOperationStatus(
104 {"status": "GOOD"}, gcompute_client.OperationScope.GLOBAL)
105 status = self.compute_client._GetOperationStatus(
106 {"name": self.OPERATION_NAME},
107 gcompute_client.OperationScope.GLOBAL)
108 self.assertEqual(status, "GOOD")
109 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700110 project=PROJECT, operation=self.OPERATION_NAME)
Tri Vo29ac1822016-10-01 17:06:29 -0700111
112 def testGetOperationStatusZone(self):
113 """Test _GetOperationStatus for zone."""
114 resource_mock = self._SetupMocksForGetOperationStatus(
115 {"status": "GOOD"}, gcompute_client.OperationScope.ZONE)
116 status = self.compute_client._GetOperationStatus(
117 {"name": self.OPERATION_NAME}, gcompute_client.OperationScope.ZONE,
118 self.ZONE)
119 self.assertEqual(status, "GOOD")
120 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700121 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -0700122 operation=self.OPERATION_NAME,
123 zone=self.ZONE)
124
125 def testGetOperationStatusRegion(self):
126 """Test _GetOperationStatus for region."""
127 resource_mock = self._SetupMocksForGetOperationStatus(
128 {"status": "GOOD"}, gcompute_client.OperationScope.REGION)
129 self.compute_client._GetOperationStatus(
130 {"name": self.OPERATION_NAME},
131 gcompute_client.OperationScope.REGION, self.REGION)
132 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700133 project=PROJECT, operation=self.OPERATION_NAME, region=self.REGION)
Tri Vo29ac1822016-10-01 17:06:29 -0700134
135 def testGetOperationStatusError(self):
136 """Test _GetOperationStatus failed."""
137 self._SetupMocksForGetOperationStatus(
138 {"error": {"errors": ["error1", "error2"]}},
139 gcompute_client.OperationScope.GLOBAL)
140 self.assertRaisesRegexp(errors.DriverError,
141 "Get operation state failed.*error1.*error2",
142 self.compute_client._GetOperationStatus,
143 {"name": self.OPERATION_NAME},
144 gcompute_client.OperationScope.GLOBAL)
145
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700146 @mock.patch.object(errors, "GceOperationTimeoutError")
147 @mock.patch.object(utils, "PollAndWait")
148 def testWaitOnOperation(self, mock_poll, mock_gce_operation_timeout_error):
Tri Vo29ac1822016-10-01 17:06:29 -0700149 """Test WaitOnOperation."""
150 mock_error = mock.MagicMock()
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700151 mock_gce_operation_timeout_error.return_value = mock_error
Tri Vo29ac1822016-10-01 17:06:29 -0700152 self.compute_client.WaitOnOperation(
153 operation={"name": self.OPERATION_NAME},
154 operation_scope=gcompute_client.OperationScope.REGION,
155 scope_name=self.REGION)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700156 mock_poll.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700157 func=self.compute_client._GetOperationStatus,
158 expected_return="DONE",
159 timeout_exception=mock_error,
160 timeout_secs=self.compute_client.OPERATION_TIMEOUT_SECS,
Kevin Chengb5963882018-05-09 00:06:27 -0700161 sleep_interval_secs=self.compute_client.OPERATION_POLL_INTERVAL_SECS,
Tri Vo29ac1822016-10-01 17:06:29 -0700162 operation={"name": self.OPERATION_NAME},
163 operation_scope=gcompute_client.OperationScope.REGION,
164 scope_name=self.REGION)
165
Kevin Chengb5963882018-05-09 00:06:27 -0700166 def testGetImage(self):
167 """Test GetImage."""
168 resource_mock = mock.MagicMock()
169 mock_api = mock.MagicMock()
170 self.compute_client._service.images = mock.MagicMock(
171 return_value=resource_mock)
172 resource_mock.get = mock.MagicMock(return_value=mock_api)
173 mock_api.execute = mock.MagicMock(return_value={"name": self.IMAGE})
174 result = self.compute_client.GetImage(self.IMAGE)
175 self.assertEqual(result, {"name": self.IMAGE})
176 resource_mock.get.assert_called_with(project=PROJECT, image=self.IMAGE)
177
178 def testGetImageOther(self):
179 """Test GetImage with other project."""
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_OTHER})
186 result = self.compute_client.GetImage(
187 image_name=self.IMAGE_OTHER,
188 image_project=self.PROJECT_OTHER)
189 self.assertEqual(result, {"name": self.IMAGE_OTHER})
190 resource_mock.get.assert_called_with(
191 project=self.PROJECT_OTHER, image=self.IMAGE_OTHER)
192
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700193 def testCreateImageWithSourceURI(self):
194 """Test CreateImage with src uri."""
195 source_uri = GS_IMAGE_SOURCE_URI
196 source_disk = None
197 labels = None
198 expected_body = {"name": self.IMAGE,
199 "rawDisk": {"source": GS_IMAGE_SOURCE_URI}}
200 mock_check = self.Patch(gcompute_client.ComputeClient,
201 "CheckImageExists",
202 return_value=False)
203 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
204 resource_mock = mock.MagicMock()
205 self.compute_client._service.images = mock.MagicMock(
206 return_value=resource_mock)
207 resource_mock.insert = mock.MagicMock()
208 self.compute_client.CreateImage(
209 image_name=self.IMAGE, source_uri=source_uri,
210 source_disk=source_disk, labels=labels)
211 resource_mock.insert.assert_called_with(
212 project=PROJECT, body=expected_body)
213 mock_wait.assert_called_with(
214 operation=mock.ANY,
215 operation_scope=gcompute_client.OperationScope.GLOBAL)
216 mock_check.assert_called_with(self.IMAGE)
217
218 def testCreateImageWithSourceDisk(self):
219 """Test CreateImage with src disk."""
220 source_uri = None
221 source_disk = GS_IMAGE_SOURCE_DISK
222 labels = None
223 expected_body = {"name": self.IMAGE,
224 "sourceDisk": GS_IMAGE_SOURCE_DISK}
225 mock_check = self.Patch(gcompute_client.ComputeClient,
226 "CheckImageExists",
227 return_value=False)
228 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
229 resource_mock = mock.MagicMock()
230 self.compute_client._service.images = mock.MagicMock(
231 return_value=resource_mock)
232 resource_mock.insert = mock.MagicMock()
233 self.compute_client.CreateImage(
234 image_name=self.IMAGE, source_uri=source_uri,
235 source_disk=source_disk, labels=labels)
236 resource_mock.insert.assert_called_with(
237 project=PROJECT, body=expected_body)
238 mock_wait.assert_called_with(
239 operation=mock.ANY,
240 operation_scope=gcompute_client.OperationScope.GLOBAL)
241 mock_check.assert_called_with(self.IMAGE)
242
243 def testCreateImageWithSourceDiskAndLabel(self):
244 """Test CreateImage with src disk and label."""
245 source_uri = None
246 source_disk = GS_IMAGE_SOURCE_DISK
247 labels = {"label1": "xxx"}
248 expected_body = {"name": self.IMAGE,
249 "sourceDisk": GS_IMAGE_SOURCE_DISK,
250 "labels": {"label1": "xxx"}}
herbertxue308f7662018-05-18 03:25:58 +0000251 mock_check = self.Patch(gcompute_client.ComputeClient,
252 "CheckImageExists",
253 return_value=False)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700254 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
Tri Vo29ac1822016-10-01 17:06:29 -0700255 resource_mock = mock.MagicMock()
256 self.compute_client._service.images = mock.MagicMock(
257 return_value=resource_mock)
258 resource_mock.insert = mock.MagicMock()
Tri Vo29ac1822016-10-01 17:06:29 -0700259 self.compute_client.CreateImage(
Kevin Chengb5963882018-05-09 00:06:27 -0700260 image_name=self.IMAGE, source_uri=source_uri,
261 source_disk=source_disk, labels=labels)
Tri Vo29ac1822016-10-01 17:06:29 -0700262 resource_mock.insert.assert_called_with(
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700263 project=PROJECT, body=expected_body)
264 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700265 operation=mock.ANY,
266 operation_scope=gcompute_client.OperationScope.GLOBAL)
herbertxue308f7662018-05-18 03:25:58 +0000267 mock_check.assert_called_with(self.IMAGE)
Tri Vo29ac1822016-10-01 17:06:29 -0700268
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700269 @mock.patch.object(gcompute_client.ComputeClient, "GetImage")
270 def testSetImageLabel(self, mock_get_image):
271 """Test SetImageLabel."""
272 with mock.patch.object(self.compute_client._service, "images",
273 return_value=mock.MagicMock(
274 setLabels=mock.MagicMock())) as _:
275 image = {"name": self.IMAGE,
276 "sourceDisk": GS_IMAGE_SOURCE_DISK,
277 "labelFingerprint": self.IMAGE_FINGERPRINT,
278 "labels": {"a": "aaa", "b": "bbb"}}
279 mock_get_image.return_value = image
280 new_labels = {"a": "xxx", "c": "ccc"}
281 # Test
282 self.compute_client.SetImageLabels(
283 self.IMAGE, new_labels)
284 # Check result
285 expected_labels = {"a": "xxx", "b": "bbb", "c": "ccc"}
286 self.compute_client._service.images().setLabels.assert_called_with(
287 project=PROJECT,
288 resource=self.IMAGE,
289 body={
290 "labels": expected_labels,
291 "labelFingerprint": self.IMAGE_FINGERPRINT
292 })
Kevin Chengb5963882018-05-09 00:06:27 -0700293
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700294 def testCreateImageRaiseDriverErrorWithValidInput(self):
295 """Test CreateImage with valid input."""
296 source_uri = GS_IMAGE_SOURCE_URI
297 source_disk = GS_IMAGE_SOURCE_DISK
herbertxue308f7662018-05-18 03:25:58 +0000298 self.Patch(gcompute_client.ComputeClient, "CheckImageExists", return_value=False)
Kevin Chengb5963882018-05-09 00:06:27 -0700299 self.assertRaises(errors.DriverError, self.compute_client.CreateImage,
300 image_name=self.IMAGE, source_uri=source_uri,
301 source_disk=source_disk)
302
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700303 def testCreateImageRaiseDriverErrorWithInvalidInput(self):
304 """Test CreateImage with valid input."""
305 source_uri = None
306 source_disk = None
307 self.Patch(gcompute_client.ComputeClient, "CheckImageExists", return_value=False)
308 self.assertRaises(errors.DriverError, self.compute_client.CreateImage,
309 image_name=self.IMAGE, source_uri=source_uri,
310 source_disk=source_disk)
Tri Vo29ac1822016-10-01 17:06:29 -0700311
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700312 @mock.patch.object(gcompute_client.ComputeClient, "DeleteImage")
313 @mock.patch.object(gcompute_client.ComputeClient, "CheckImageExists",
herbertxue308f7662018-05-18 03:25:58 +0000314 side_effect=[False, True])
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700315 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation",
316 side_effect=errors.DriverError("Expected fake error"))
317 def testCreateImageFail(self, mock_wait, mock_check, mock_delete):
318 """Test CreateImage fails."""
Tri Vo29ac1822016-10-01 17:06:29 -0700319 resource_mock = mock.MagicMock()
320 self.compute_client._service.images = mock.MagicMock(
321 return_value=resource_mock)
322 resource_mock.insert = mock.MagicMock()
323
324 expected_body = {
325 "name": self.IMAGE,
326 "rawDisk": {
Kevin Chengb5963882018-05-09 00:06:27 -0700327 "source": GS_IMAGE_SOURCE_URI,
Tri Vo29ac1822016-10-01 17:06:29 -0700328 },
329 }
330 self.assertRaisesRegexp(
331 errors.DriverError,
332 "Expected fake error",
333 self.compute_client.CreateImage,
334 image_name=self.IMAGE,
Kevin Chengb5963882018-05-09 00:06:27 -0700335 source_uri=GS_IMAGE_SOURCE_URI)
Tri Vo29ac1822016-10-01 17:06:29 -0700336 resource_mock.insert.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700337 project=PROJECT, body=expected_body)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700338 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700339 operation=mock.ANY,
340 operation_scope=gcompute_client.OperationScope.GLOBAL)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700341 mock_check.assert_called_with(self.IMAGE)
342 mock_delete.assert_called_with(self.IMAGE)
Tri Vo29ac1822016-10-01 17:06:29 -0700343
344 def testCheckImageExistsTrue(self):
345 """Test CheckImageExists return True."""
346 resource_mock = mock.MagicMock()
347 mock_api = mock.MagicMock()
348 self.compute_client._service.images = mock.MagicMock(
349 return_value=resource_mock)
350 resource_mock.get = mock.MagicMock(return_value=mock_api)
351 mock_api.execute = mock.MagicMock(return_value={"name": self.IMAGE})
352 self.assertTrue(self.compute_client.CheckImageExists(self.IMAGE))
353
354 def testCheckImageExistsFalse(self):
355 """Test CheckImageExists return False."""
356 resource_mock = mock.MagicMock()
357 mock_api = mock.MagicMock()
358 self.compute_client._service.images = mock.MagicMock(
359 return_value=resource_mock)
360 resource_mock.get = mock.MagicMock(return_value=mock_api)
361 mock_api.execute = mock.MagicMock(
362 side_effect=errors.ResourceNotFoundError(404, "no image"))
363 self.assertFalse(self.compute_client.CheckImageExists(self.IMAGE))
364
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700365 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
366 def testDeleteImage(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700367 """Test DeleteImage."""
Tri Vo29ac1822016-10-01 17:06:29 -0700368 resource_mock = mock.MagicMock()
369 self.compute_client._service.images = mock.MagicMock(
370 return_value=resource_mock)
371 resource_mock.delete = mock.MagicMock()
372 self.compute_client.DeleteImage(self.IMAGE)
373 resource_mock.delete.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700374 project=PROJECT, image=self.IMAGE)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700375 self.assertTrue(mock_wait.called)
Tri Vo29ac1822016-10-01 17:06:29 -0700376
377 def _SetupBatchHttpRequestMock(self):
378 """Setup BatchHttpRequest mock."""
379 requests = {}
380
381 def _Add(request, callback, request_id):
382 requests[request_id] = (request, callback)
383
384 def _Execute():
385 for rid in requests:
386 _, callback = requests[rid]
387 callback(
388 request_id=rid, response=mock.MagicMock(), exception=None)
Tri Vo29ac1822016-10-01 17:06:29 -0700389 mock_batch = mock.MagicMock()
390 mock_batch.add = _Add
391 mock_batch.execute = _Execute
392 self.Patch(apiclient.http, "BatchHttpRequest", return_value=mock_batch)
393
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700394 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
395 def testDeleteImages(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700396 """Test DeleteImages."""
397 self._SetupBatchHttpRequestMock()
Tri Vo29ac1822016-10-01 17:06:29 -0700398 fake_images = ["fake_image_1", "fake_image_2"]
399 mock_api = mock.MagicMock()
400 resource_mock = mock.MagicMock()
401 self.compute_client._service.images = mock.MagicMock(
402 return_value=resource_mock)
403 resource_mock.delete = mock.MagicMock(return_value=mock_api)
404 # Call the API.
405 deleted, failed, error_msgs = self.compute_client.DeleteImages(
406 fake_images)
407 # Verify
Kevin Chengb5963882018-05-09 00:06:27 -0700408 calls = [
409 mock.call(project=PROJECT, image="fake_image_1"),
410 mock.call(project=PROJECT, image="fake_image_2")
411 ]
Tri Vo29ac1822016-10-01 17:06:29 -0700412 resource_mock.delete.assert_has_calls(calls, any_order=True)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700413 self.assertEqual(mock_wait.call_count, 2)
Tri Vo29ac1822016-10-01 17:06:29 -0700414 self.assertEqual(error_msgs, [])
415 self.assertEqual(failed, [])
416 self.assertEqual(set(deleted), set(fake_images))
417
418 def testListImages(self):
419 """Test ListImages."""
420 fake_token = "fake_next_page_token"
421 image_1 = "image_1"
422 image_2 = "image_2"
423 response_1 = {"items": [image_1], "nextPageToken": fake_token}
424 response_2 = {"items": [image_2]}
425 self.Patch(
426 gcompute_client.ComputeClient,
427 "Execute",
428 side_effect=[response_1, response_2])
429 resource_mock = mock.MagicMock()
430 self.compute_client._service.images = mock.MagicMock(
431 return_value=resource_mock)
432 resource_mock.list = mock.MagicMock()
433 images = self.compute_client.ListImages()
434 calls = [
Kevin Chengb5963882018-05-09 00:06:27 -0700435 mock.call(project=PROJECT, filter=None, pageToken=None),
436 mock.call(project=PROJECT, filter=None, pageToken=fake_token)
Tri Vo29ac1822016-10-01 17:06:29 -0700437 ]
438 resource_mock.list.assert_has_calls(calls)
439 self.assertEqual(images, [image_1, image_2])
440
Kevin Chengb5963882018-05-09 00:06:27 -0700441 def testListImagesFromExternalProject(self):
442 """Test ListImages which accepts different project."""
443 image = "image_1"
444 response = {"items": [image]}
445 self.Patch(gcompute_client.ComputeClient, "Execute", side_effect=[response])
446 resource_mock = mock.MagicMock()
447 self.compute_client._service.images = mock.MagicMock(
448 return_value=resource_mock)
449 resource_mock.list = mock.MagicMock()
450 images = self.compute_client.ListImages(
451 image_project="fake-project-2")
452 calls = [
453 mock.call(project="fake-project-2", filter=None, pageToken=None)]
454 resource_mock.list.assert_has_calls(calls)
455 self.assertEqual(images, [image])
456
Tri Vo29ac1822016-10-01 17:06:29 -0700457 def testGetInstance(self):
458 """Test GetInstance."""
459 resource_mock = mock.MagicMock()
460 mock_api = mock.MagicMock()
461 self.compute_client._service.instances = mock.MagicMock(
462 return_value=resource_mock)
463 resource_mock.get = mock.MagicMock(return_value=mock_api)
464 mock_api.execute = mock.MagicMock(return_value={"name": self.INSTANCE})
465 result = self.compute_client.GetInstance(self.INSTANCE, self.ZONE)
466 self.assertEqual(result, {"name": self.INSTANCE})
467 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700468 project=PROJECT, zone=self.ZONE, instance=self.INSTANCE)
Tri Vo29ac1822016-10-01 17:06:29 -0700469
470 def testListInstances(self):
471 """Test ListInstances."""
472 fake_token = "fake_next_page_token"
473 instance_1 = "instance_1"
474 instance_2 = "instance_2"
475 response_1 = {"items": [instance_1], "nextPageToken": fake_token}
476 response_2 = {"items": [instance_2]}
477 self.Patch(
478 gcompute_client.ComputeClient,
479 "Execute",
480 side_effect=[response_1, response_2])
481 resource_mock = mock.MagicMock()
482 self.compute_client._service.instances = mock.MagicMock(
483 return_value=resource_mock)
484 resource_mock.list = mock.MagicMock()
485 instances = self.compute_client.ListInstances(self.ZONE)
486 calls = [
487 mock.call(
Kevin Chengb5963882018-05-09 00:06:27 -0700488 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -0700489 zone=self.ZONE,
490 filter=None,
491 pageToken=None),
492 mock.call(
Kevin Chengb5963882018-05-09 00:06:27 -0700493 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -0700494 zone=self.ZONE,
495 filter=None,
496 pageToken=fake_token),
497 ]
498 resource_mock.list.assert_has_calls(calls)
499 self.assertEqual(instances, [instance_1, instance_2])
500
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700501 @mock.patch.object(gcompute_client.ComputeClient, "GetImage")
502 @mock.patch.object(gcompute_client.ComputeClient, "GetNetworkUrl")
Kevin Cheng480e1212018-10-24 00:23:30 -0700503 @mock.patch.object(gcompute_client.ComputeClient, "GetSubnetworkUrl")
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700504 @mock.patch.object(gcompute_client.ComputeClient, "GetMachineType")
505 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
506 def testCreateInstance(self, mock_wait, mock_get_mach_type,
Kevin Cheng480e1212018-10-24 00:23:30 -0700507 mock_get_subnetwork_url, mock_get_network_url,
508 mock_get_image):
Tri Vo29ac1822016-10-01 17:06:29 -0700509 """Test CreateInstance."""
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700510 mock_get_mach_type.return_value = {"selfLink": self.MACHINE_TYPE_URL}
511 mock_get_network_url.return_value = self.NETWORK_URL
Kevin Cheng480e1212018-10-24 00:23:30 -0700512 mock_get_subnetwork_url.return_value = self.SUBNETWORK_URL
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700513 mock_get_image.return_value = {"selfLink": self.IMAGE_URL}
Tri Vo29ac1822016-10-01 17:06:29 -0700514 resource_mock = mock.MagicMock()
515 self.compute_client._service.instances = mock.MagicMock(
516 return_value=resource_mock)
517 resource_mock.insert = mock.MagicMock()
herbertxue308f7662018-05-18 03:25:58 +0000518 self.Patch(
519 self.compute_client,
520 "_GetExtraDiskArgs",
521 return_value=[{"fake_extra_arg": "fake_extra_value"}])
522 extra_disk_name = "gce-x86-userdebug-2345-abcd-data"
523 expected_disk_args = [self._disk_args]
524 expected_disk_args.extend([{"fake_extra_arg": "fake_extra_value"}])
Tri Vo29ac1822016-10-01 17:06:29 -0700525
526 expected_body = {
527 "machineType": self.MACHINE_TYPE_URL,
528 "name": self.INSTANCE,
529 "networkInterfaces": [
530 {
531 "network": self.NETWORK_URL,
Kevin Cheng480e1212018-10-24 00:23:30 -0700532 "subnetwork": self.SUBNETWORK_URL,
Tri Vo29ac1822016-10-01 17:06:29 -0700533 "accessConfigs": [
534 {"name": "External NAT",
535 "type": "ONE_TO_ONE_NAT"}
536 ],
537 }
538 ],
herbertxue308f7662018-05-18 03:25:58 +0000539 "disks": expected_disk_args,
Tri Vo29ac1822016-10-01 17:06:29 -0700540 "serviceAccounts": [
541 {"email": "default",
542 "scopes": self.compute_client.DEFAULT_INSTANCE_SCOPE}
543 ],
544 "metadata": {
545 "items": [{"key": self.METADATA[0],
546 "value": self.METADATA[1]}],
547 },
548 }
549
550 self.compute_client.CreateInstance(
551 instance=self.INSTANCE,
552 image_name=self.IMAGE,
553 machine_type=self.MACHINE_TYPE,
554 metadata={self.METADATA[0]: self.METADATA[1]},
555 network=self.NETWORK,
herbertxue308f7662018-05-18 03:25:58 +0000556 zone=self.ZONE,
557 extra_disk_name=extra_disk_name)
Tri Vo29ac1822016-10-01 17:06:29 -0700558
559 resource_mock.insert.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700560 project=PROJECT, zone=self.ZONE, body=expected_body)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700561 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700562 mock.ANY,
563 operation_scope=gcompute_client.OperationScope.ZONE,
564 scope_name=self.ZONE)
565
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700566 @mock.patch.object(gcompute_client.ComputeClient, "GetAcceleratorUrl")
567 @mock.patch.object(gcompute_client.ComputeClient, "GetImage")
568 @mock.patch.object(gcompute_client.ComputeClient, "GetNetworkUrl")
Kevin Cheng480e1212018-10-24 00:23:30 -0700569 @mock.patch.object(gcompute_client.ComputeClient, "GetSubnetworkUrl")
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700570 @mock.patch.object(gcompute_client.ComputeClient, "GetMachineType")
571 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
572 def testCreateInstanceWithGpu(self, mock_wait, mock_get_mach,
Kevin Cheng480e1212018-10-24 00:23:30 -0700573 mock_get_subnetwork, mock_get_network,
574 mock_get_image, mock_get_accel):
Kevin Chengb5963882018-05-09 00:06:27 -0700575 """Test CreateInstance with a GPU parameter not set to None."""
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700576 mock_get_mach.return_value = {"selfLink": self.MACHINE_TYPE_URL}
577 mock_get_network.return_value = self.NETWORK_URL
Kevin Cheng480e1212018-10-24 00:23:30 -0700578 mock_get_subnetwork.return_value = self.SUBNETWORK_URL
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700579 mock_get_accel.return_value = self.ACCELERATOR_URL
580 mock_get_image.return_value = {"selfLink": self.IMAGE_URL}
Kevin Chengb5963882018-05-09 00:06:27 -0700581
582 resource_mock = mock.MagicMock()
583 self.compute_client._service.instances = mock.MagicMock(
584 return_value=resource_mock)
585 resource_mock.insert = mock.MagicMock()
586
587 expected_body = {
588 "machineType":
589 self.MACHINE_TYPE_URL,
590 "name":
591 self.INSTANCE,
592 "networkInterfaces": [{
Kevin Cheng480e1212018-10-24 00:23:30 -0700593 "network": self.NETWORK_URL,
594 "subnetwork": self.SUBNETWORK_URL,
Kevin Chengb5963882018-05-09 00:06:27 -0700595 "accessConfigs": [{
596 "name": "External NAT",
597 "type": "ONE_TO_ONE_NAT"
598 }],
599 }],
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700600 "disks": [self._disk_args],
Kevin Chengb5963882018-05-09 00:06:27 -0700601 "serviceAccounts": [{
602 "email": "default",
603 "scopes": self.compute_client.DEFAULT_INSTANCE_SCOPE
604 }],
605 "scheduling": {
606 "onHostMaintenance": "terminate"
607 },
608 "guestAccelerators": [{
609 "acceleratorCount": 1,
610 "acceleratorType": "http://speedy-gpu"
611 }],
612 "metadata": {
613 "items": [{
614 "key": self.METADATA[0],
615 "value": self.METADATA[1]
616 }],
617 },
618 }
619
620 self.compute_client.CreateInstance(
621 instance=self.INSTANCE,
622 image_name=self.IMAGE,
623 machine_type=self.MACHINE_TYPE,
624 metadata={self.METADATA[0]: self.METADATA[1]},
625 network=self.NETWORK,
626 zone=self.ZONE,
627 gpu=self.GPU)
628
629 resource_mock.insert.assert_called_with(
630 project=PROJECT, zone=self.ZONE, body=expected_body)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700631 mock_wait.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700632 mock.ANY, operation_scope=gcompute_client.OperationScope.ZONE,
633 scope_name=self.ZONE)
634
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700635 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
636 def testDeleteInstance(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700637 """Test DeleteInstance."""
Tri Vo29ac1822016-10-01 17:06:29 -0700638 resource_mock = mock.MagicMock()
639 self.compute_client._service.instances = mock.MagicMock(
640 return_value=resource_mock)
641 resource_mock.delete = mock.MagicMock()
642 self.compute_client.DeleteInstance(
643 instance=self.INSTANCE, zone=self.ZONE)
644 resource_mock.delete.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700645 project=PROJECT, zone=self.ZONE, instance=self.INSTANCE)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700646 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700647 mock.ANY,
648 operation_scope=gcompute_client.OperationScope.ZONE,
649 scope_name=self.ZONE)
650
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700651 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
652 def testDeleteInstances(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700653 """Test DeleteInstances."""
654 self._SetupBatchHttpRequestMock()
Tri Vo29ac1822016-10-01 17:06:29 -0700655 fake_instances = ["fake_instance_1", "fake_instance_2"]
656 mock_api = mock.MagicMock()
657 resource_mock = mock.MagicMock()
658 self.compute_client._service.instances = mock.MagicMock(
659 return_value=resource_mock)
660 resource_mock.delete = mock.MagicMock(return_value=mock_api)
661 deleted, failed, error_msgs = self.compute_client.DeleteInstances(
662 fake_instances, self.ZONE)
663 calls = [
664 mock.call(
Kevin Chengb5963882018-05-09 00:06:27 -0700665 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -0700666 instance="fake_instance_1",
Kevin Chengb5963882018-05-09 00:06:27 -0700667 zone=self.ZONE),
668 mock.call(
669 project=PROJECT,
670 instance="fake_instance_2",
671 zone=self.ZONE)
Tri Vo29ac1822016-10-01 17:06:29 -0700672 ]
673 resource_mock.delete.assert_has_calls(calls, any_order=True)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700674 self.assertEqual(mock_wait.call_count, 2)
Tri Vo29ac1822016-10-01 17:06:29 -0700675 self.assertEqual(error_msgs, [])
676 self.assertEqual(failed, [])
677 self.assertEqual(set(deleted), set(fake_instances))
678
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700679 def testCreateDiskWithProject(self):
680 """Test CreateDisk with images using a set project."""
681 source_project = "fake-image-project"
682 expected_project_to_use = "fake-image-project"
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700683 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
Kevin Chengb5963882018-05-09 00:06:27 -0700684 resource_mock = mock.MagicMock()
685 self.compute_client._service.disks = mock.MagicMock(
686 return_value=resource_mock)
687 resource_mock.insert = mock.MagicMock()
688 self.compute_client.CreateDisk(
689 "fake_disk", "fake_image", 10, self.ZONE, source_project=source_project)
690 resource_mock.insert.assert_called_with(
691 project=PROJECT,
692 zone=self.ZONE,
693 sourceImage="projects/%s/global/images/fake_image" %
694 expected_project_to_use,
695 body={
696 "name":
697 "fake_disk",
698 "sizeGb":
699 10,
700 "type":
701 "projects/%s/zones/%s/diskTypes/pd-standard" % (PROJECT,
702 self.ZONE)
703 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700704 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700705
Kevin Cheng070ae5c2018-08-02 16:03:00 -0700706 def testCreateDiskWithNoSourceProject(self):
707 """Test CreateDisk with images with no set project."""
708 source_project = None
709 expected_project_to_use = PROJECT
710 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
711 resource_mock = mock.MagicMock()
712 self.compute_client._service.disks = mock.MagicMock(
713 return_value=resource_mock)
714 resource_mock.insert = mock.MagicMock()
715 self.compute_client.CreateDisk(
716 "fake_disk", "fake_image", 10, self.ZONE, source_project=source_project)
717 resource_mock.insert.assert_called_with(
718 project=PROJECT,
719 zone=self.ZONE,
720 sourceImage="projects/%s/global/images/fake_image" %
721 expected_project_to_use,
722 body={
723 "name":
724 "fake_disk",
725 "sizeGb":
726 10,
727 "type":
728 "projects/%s/zones/%s/diskTypes/pd-standard" % (PROJECT,
729 self.ZONE)
730 })
731 self.assertTrue(mock_wait.called)
732
733 def testCreateDiskWithTypeStandard(self):
734 """Test CreateDisk with images using standard."""
735 disk_type = gcompute_client.PersistentDiskType.STANDARD
736 expected_disk_type_string = "pd-standard"
737 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
738 resource_mock = mock.MagicMock()
739 self.compute_client._service.disks = mock.MagicMock(
740 return_value=resource_mock)
741 resource_mock.insert = mock.MagicMock()
742 self.compute_client.CreateDisk(
743 "fake_disk",
744 "fake_image",
745 10,
746 self.ZONE,
747 source_project="fake-project",
748 disk_type=disk_type)
749 resource_mock.insert.assert_called_with(
750 project=PROJECT,
751 zone=self.ZONE,
752 sourceImage="projects/%s/global/images/fake_image" % "fake-project",
753 body={
754 "name":
755 "fake_disk",
756 "sizeGb":
757 10,
758 "type":
759 "projects/%s/zones/%s/diskTypes/%s" %
760 (PROJECT, self.ZONE, expected_disk_type_string)
761 })
762 self.assertTrue(mock_wait.called)
763
764 def testCreateDiskWithTypeSSD(self):
765 """Test CreateDisk with images using standard."""
766 disk_type = gcompute_client.PersistentDiskType.SSD
767 expected_disk_type_string = "pd-ssd"
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700768 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
Kevin Chengb5963882018-05-09 00:06:27 -0700769 resource_mock = mock.MagicMock()
770 self.compute_client._service.disks = mock.MagicMock(
771 return_value=resource_mock)
772 resource_mock.insert = mock.MagicMock()
773 self.compute_client.CreateDisk(
774 "fake_disk",
775 "fake_image",
776 10,
777 self.ZONE,
778 source_project="fake-project",
779 disk_type=disk_type)
780 resource_mock.insert.assert_called_with(
781 project=PROJECT,
782 zone=self.ZONE,
783 sourceImage="projects/%s/global/images/fake_image" % "fake-project",
784 body={
785 "name":
786 "fake_disk",
787 "sizeGb":
788 10,
789 "type":
790 "projects/%s/zones/%s/diskTypes/%s" %
791 (PROJECT, self.ZONE, expected_disk_type_string)
792 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700793 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700794
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700795 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
796 def testAttachDisk(self, mock_wait):
Kevin Chengb5963882018-05-09 00:06:27 -0700797 """Test AttachDisk."""
Kevin Chengb5963882018-05-09 00:06:27 -0700798 resource_mock = mock.MagicMock()
799 self.compute_client._service.instances = mock.MagicMock(
800 return_value=resource_mock)
801 resource_mock.attachDisk = mock.MagicMock()
802 self.compute_client.AttachDisk(
803 "fake_instance_1", self.ZONE, deviceName="fake_disk",
804 source="fake-selfLink")
805 resource_mock.attachDisk.assert_called_with(
806 project=PROJECT,
807 zone=self.ZONE,
808 instance="fake_instance_1",
809 body={
810 "deviceName": "fake_disk",
811 "source": "fake-selfLink"
812 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700813 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700814
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700815 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
816 def testDetachDisk(self, mock_wait):
Kevin Chengb5963882018-05-09 00:06:27 -0700817 """Test DetachDisk."""
Kevin Chengb5963882018-05-09 00:06:27 -0700818 resource_mock = mock.MagicMock()
819 self.compute_client._service.instances = mock.MagicMock(
820 return_value=resource_mock)
821 resource_mock.detachDisk = mock.MagicMock()
822 self.compute_client.DetachDisk("fake_instance_1", self.ZONE, "fake_disk")
823 resource_mock.detachDisk.assert_called_with(
824 project=PROJECT,
825 zone=self.ZONE,
826 instance="fake_instance_1",
827 deviceName="fake_disk")
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700828 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700829
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700830 @mock.patch.object(gcompute_client.ComputeClient, "GetAcceleratorUrl")
831 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
832 def testAttachAccelerator(self, mock_wait, mock_get_accel):
Kevin Chengb5963882018-05-09 00:06:27 -0700833 """Test AttachAccelerator."""
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700834 mock_get_accel.return_value = self.ACCELERATOR_URL
Kevin Chengb5963882018-05-09 00:06:27 -0700835 resource_mock = mock.MagicMock()
836 self.compute_client._service.instances = mock.MagicMock(
837 return_value=resource_mock)
838 resource_mock.attachAccelerator = mock.MagicMock()
839 self.compute_client.AttachAccelerator("fake_instance_1", self.ZONE, 1,
840 "nvidia-tesla-k80")
841 resource_mock.setMachineResources.assert_called_with(
842 project=PROJECT,
843 zone=self.ZONE,
844 instance="fake_instance_1",
845 body={
846 "guestAccelerators": [{
847 "acceleratorType": self.ACCELERATOR_URL,
848 "acceleratorCount": 1
849 }]
850 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700851 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700852
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700853 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
854 def testBatchExecuteOnInstances(self, mock_wait):
855 """Test BatchExecuteOnInstances."""
Tri Vo29ac1822016-10-01 17:06:29 -0700856 self._SetupBatchHttpRequestMock()
Tri Vo29ac1822016-10-01 17:06:29 -0700857 action = mock.MagicMock(return_value=mock.MagicMock())
858 fake_instances = ["fake_instance_1", "fake_instance_2"]
859 done, failed, error_msgs = self.compute_client._BatchExecuteOnInstances(
860 fake_instances, self.ZONE, action)
861 calls = [mock.call(instance="fake_instance_1"),
862 mock.call(instance="fake_instance_2")]
863 action.assert_has_calls(calls, any_order=True)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700864 self.assertEqual(mock_wait.call_count, 2)
Tri Vo29ac1822016-10-01 17:06:29 -0700865 self.assertEqual(set(done), set(fake_instances))
866 self.assertEqual(error_msgs, [])
867 self.assertEqual(failed, [])
868
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700869 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
870 def testResetInstance(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700871 """Test ResetInstance."""
Tri Vo29ac1822016-10-01 17:06:29 -0700872 resource_mock = mock.MagicMock()
873 self.compute_client._service.instances = mock.MagicMock(
874 return_value=resource_mock)
875 resource_mock.reset = mock.MagicMock()
876 self.compute_client.ResetInstance(
877 instance=self.INSTANCE, zone=self.ZONE)
878 resource_mock.reset.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700879 project=PROJECT, zone=self.ZONE, instance=self.INSTANCE)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700880 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700881 mock.ANY,
882 operation_scope=gcompute_client.OperationScope.ZONE,
883 scope_name=self.ZONE)
884
885 def _CompareMachineSizeTestHelper(self,
886 machine_info_1,
887 machine_info_2,
888 expected_result=None,
889 expected_error_type=None):
890 """Helper class for testing CompareMachineSize.
891
Kevin Chengb5963882018-05-09 00:06:27 -0700892 Args:
893 machine_info_1: A dictionary representing the first machine size.
894 machine_info_2: A dictionary representing the second machine size.
895 expected_result: An integer, 0, 1 or -1, or None if not set.
896 expected_error_type: An exception type, if set will check for exception.
897 """
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700898 mock_get_mach_type = self.Patch(
Tri Vo29ac1822016-10-01 17:06:29 -0700899 gcompute_client.ComputeClient,
900 "GetMachineType",
901 side_effect=[machine_info_1, machine_info_2])
902 if expected_error_type:
903 self.assertRaises(expected_error_type,
904 self.compute_client.CompareMachineSize, "name1",
905 "name2", self.ZONE)
906 else:
907 result = self.compute_client.CompareMachineSize("name1", "name2",
908 self.ZONE)
909 self.assertEqual(result, expected_result)
910
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700911 mock_get_mach_type.assert_has_calls(
Tri Vo29ac1822016-10-01 17:06:29 -0700912 [mock.call("name1", self.ZONE), mock.call("name2", self.ZONE)])
913
914 def testCompareMachineSizeSmall(self):
915 """Test CompareMachineSize where the first one is smaller."""
916 machine_info_1 = {"guestCpus": 10, "memoryMb": 100}
917 machine_info_2 = {"guestCpus": 10, "memoryMb": 200}
918 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, -1)
919
Kevin Cheng4ae42772018-10-02 11:39:48 -0700920 def testCompareMachineSizeSmallSmallerOnSecond(self):
921 """Test CompareMachineSize where the first one is smaller."""
922 machine_info_1 = {"guestCpus": 11, "memoryMb": 100}
923 machine_info_2 = {"guestCpus": 10, "memoryMb": 200}
924 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, -1)
925
Tri Vo29ac1822016-10-01 17:06:29 -0700926 def testCompareMachineSizeLarge(self):
927 """Test CompareMachineSize where the first one is larger."""
Kevin Cheng4ae42772018-10-02 11:39:48 -0700928 machine_info_1 = {"guestCpus": 11, "memoryMb": 200}
929 machine_info_2 = {"guestCpus": 10, "memoryMb": 100}
930 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, 1)
931
932 def testCompareMachineSizeLargeWithEqualElement(self):
933 """Test CompareMachineSize where the first one is larger."""
Tri Vo29ac1822016-10-01 17:06:29 -0700934 machine_info_1 = {"guestCpus": 10, "memoryMb": 200}
935 machine_info_2 = {"guestCpus": 10, "memoryMb": 100}
936 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, 1)
937
938 def testCompareMachineSizeEqual(self):
939 """Test CompareMachineSize where two machine sizes are equal."""
940 machine_info = {"guestCpus": 10, "memoryMb": 100}
941 self._CompareMachineSizeTestHelper(machine_info, machine_info, 0)
942
943 def testCompareMachineSizeBadMetric(self):
944 """Test CompareMachineSize with bad metric."""
Kevin Chengb5963882018-05-09 00:06:27 -0700945 machine_info = {"unknown_metric": 10, "memoryMb": 100}
Tri Vo29ac1822016-10-01 17:06:29 -0700946 self._CompareMachineSizeTestHelper(
947 machine_info, machine_info, expected_error_type=errors.DriverError)
948
949 def testGetMachineType(self):
950 """Test GetMachineType."""
951 resource_mock = mock.MagicMock()
952 mock_api = mock.MagicMock()
953 self.compute_client._service.machineTypes = mock.MagicMock(
954 return_value=resource_mock)
955 resource_mock.get = mock.MagicMock(return_value=mock_api)
956 mock_api.execute = mock.MagicMock(
957 return_value={"name": self.MACHINE_TYPE})
958 result = self.compute_client.GetMachineType(self.MACHINE_TYPE,
959 self.ZONE)
960 self.assertEqual(result, {"name": self.MACHINE_TYPE})
961 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700962 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -0700963 zone=self.ZONE,
964 machineType=self.MACHINE_TYPE)
965
966 def _GetSerialPortOutputTestHelper(self, response):
967 """Helper function for testing GetSerialPortOutput.
968
Kevin Chengb5963882018-05-09 00:06:27 -0700969 Args:
970 response: A dictionary representing a fake response.
971 """
Tri Vo29ac1822016-10-01 17:06:29 -0700972 resource_mock = mock.MagicMock()
973 mock_api = mock.MagicMock()
974 self.compute_client._service.instances = mock.MagicMock(
975 return_value=resource_mock)
976 resource_mock.getSerialPortOutput = mock.MagicMock(
977 return_value=mock_api)
978 mock_api.execute = mock.MagicMock(return_value=response)
979
980 if "contents" in response:
981 result = self.compute_client.GetSerialPortOutput(
982 instance=self.INSTANCE, zone=self.ZONE)
983 self.assertEqual(result, "fake contents")
984 else:
985 self.assertRaisesRegexp(
986 errors.DriverError,
987 "Malformed response.*",
988 self.compute_client.GetSerialPortOutput,
989 instance=self.INSTANCE,
990 zone=self.ZONE)
991 resource_mock.getSerialPortOutput.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700992 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -0700993 zone=self.ZONE,
994 instance=self.INSTANCE,
995 port=1)
996
997 def testGetSerialPortOutput(self):
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700998 """Test GetSerialPortOutput."""
Tri Vo29ac1822016-10-01 17:06:29 -0700999 response = {"contents": "fake contents"}
1000 self._GetSerialPortOutputTestHelper(response)
1001
1002 def testGetSerialPortOutputFail(self):
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001003 """Test GetSerialPortOutputFail."""
Tri Vo29ac1822016-10-01 17:06:29 -07001004 response = {"malformed": "fake contents"}
1005 self._GetSerialPortOutputTestHelper(response)
1006
1007 def testGetInstanceNamesByIPs(self):
1008 """Test GetInstanceNamesByIPs."""
1009 good_instance = {
1010 "name": "instance_1",
1011 "networkInterfaces": [
1012 {
1013 "accessConfigs": [
1014 {"natIP": "172.22.22.22"},
1015 ],
1016 },
1017 ],
1018 }
1019 bad_instance = {"name": "instance_2"}
1020 self.Patch(
1021 gcompute_client.ComputeClient,
1022 "ListInstances",
1023 return_value=[good_instance, bad_instance])
1024 ip_name_map = self.compute_client.GetInstanceNamesByIPs(
1025 ips=["172.22.22.22", "172.22.22.23"], zone=self.ZONE)
1026 self.assertEqual(ip_name_map, {"172.22.22.22": "instance_1",
1027 "172.22.22.23": None})
1028
1029 def testAddSshRsa(self):
1030 """Test AddSshRsa.."""
1031 fake_user = "fake_user"
1032 sshkey = (
1033 "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDBkTOTRze9v2VOqkkf7RG"
1034 "jSkg6Z2kb9Q9UHsDGatvend3fmjIw1Tugg0O7nnjlPkskmlgyd4a/j99WOeLL"
1035 "CPk6xPyoVjrPUVBU/pAk09ORTC4Zqk6YjlW7LOfzvqmXhmIZfYu6Q4Yt50pZzhl"
1036 "lllfu26nYjY7Tg12D019nJi/kqPX5+NKgt0LGXTu8T1r2Gav/q4V7QRWQrB8Eiu"
1037 "pxXR7I2YhynqovkEt/OXG4qWgvLEXGsWtSQs0CtCzqEVxz0Y9ECr7er4VdjSQxV"
1038 "AaeLAsQsK9ROae8hMBFZ3//8zLVapBwpuffCu+fUoql9qeV9xagZcc9zj8XOUOW"
1039 "ApiihqNL1111 test@test1.org")
1040 project = {
1041 "commonInstanceMetadata": {
1042 "kind": "compute#metadata",
1043 "fingerprint": "a-23icsyx4E=",
1044 "items": [
1045 {
1046 "key": "sshKeys",
1047 "value": "user:key"
1048 }
1049 ]
1050 }
1051 }
1052 expected = {
1053 "kind": "compute#metadata",
1054 "fingerprint": "a-23icsyx4E=",
1055 "items": [
1056 {
1057 "key": "sshKeys",
1058 "value": "user:key\n%s:%s" % (fake_user, sshkey)
1059 }
1060 ]
1061 }
1062
1063 self.Patch(os.path, "exists", return_value=True)
1064 m = mock.mock_open(read_data=sshkey)
Tri Vo29ac1822016-10-01 17:06:29 -07001065 self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
1066 self.Patch(
1067 gcompute_client.ComputeClient, "GetProject", return_value=project)
1068 resource_mock = mock.MagicMock()
1069 self.compute_client._service.projects = mock.MagicMock(
1070 return_value=resource_mock)
1071 resource_mock.setCommonInstanceMetadata = mock.MagicMock()
1072
Kevin Chengda4f07a2018-06-26 10:25:05 -07001073 with mock.patch("__builtin__.open", m):
1074 self.compute_client.AddSshRsa(fake_user, "/path/to/test_rsa.pub")
1075 resource_mock.setCommonInstanceMetadata.assert_called_with(
1076 project=PROJECT, body=expected)
Tri Vo29ac1822016-10-01 17:06:29 -07001077
1078 def testAddSshRsaInvalidKey(self):
1079 """Test AddSshRsa.."""
1080 fake_user = "fake_user"
1081 sshkey = "ssh-rsa v2VOqkkf7RGL1111 test@test1.org"
1082 project = {
1083 "commonInstanceMetadata": {
1084 "kind": "compute#metadata",
1085 "fingerprint": "a-23icsyx4E=",
1086 "items": [
1087 {
1088 "key": "sshKeys",
1089 "value": "user:key"
1090 }
1091 ]
1092 }
1093 }
1094 self.Patch(os.path, "exists", return_value=True)
1095 m = mock.mock_open(read_data=sshkey)
Tri Vo29ac1822016-10-01 17:06:29 -07001096 self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
1097 self.Patch(
1098 gcompute_client.ComputeClient, "GetProject", return_value=project)
Kevin Chengda4f07a2018-06-26 10:25:05 -07001099 with mock.patch("__builtin__.open", m):
1100 self.assertRaisesRegexp(errors.DriverError, "rsa key is invalid:*",
1101 self.compute_client.AddSshRsa, fake_user,
1102 "/path/to/test_rsa.pub")
Tri Vo29ac1822016-10-01 17:06:29 -07001103
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001104 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
1105 def testDeleteDisks(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -07001106 """Test DeleteDisks."""
1107 self._SetupBatchHttpRequestMock()
Tri Vo29ac1822016-10-01 17:06:29 -07001108 fake_disks = ["fake_disk_1", "fake_disk_2"]
1109 mock_api = mock.MagicMock()
1110 resource_mock = mock.MagicMock()
1111 self.compute_client._service.disks = mock.MagicMock(
1112 return_value=resource_mock)
1113 resource_mock.delete = mock.MagicMock(return_value=mock_api)
1114 # Call the API.
1115 deleted, failed, error_msgs = self.compute_client.DeleteDisks(
1116 fake_disks, zone=self.ZONE)
1117 # Verify
Kevin Chengb5963882018-05-09 00:06:27 -07001118 calls = [
1119 mock.call(project=PROJECT, disk="fake_disk_1", zone=self.ZONE),
1120 mock.call(project=PROJECT, disk="fake_disk_2", zone=self.ZONE)
1121 ]
Tri Vo29ac1822016-10-01 17:06:29 -07001122 resource_mock.delete.assert_has_calls(calls, any_order=True)
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001123 self.assertEqual(mock_wait.call_count, 2)
Tri Vo29ac1822016-10-01 17:06:29 -07001124 self.assertEqual(error_msgs, [])
1125 self.assertEqual(failed, [])
1126 self.assertEqual(set(deleted), set(fake_disks))
1127
Kevin Chengb5963882018-05-09 00:06:27 -07001128 def testRetryOnFingerPrintError(self):
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001129 """Test RetryOnFingerPrintError."""
Kevin Chengb5963882018-05-09 00:06:27 -07001130 @utils.RetryOnException(gcompute_client._IsFingerPrintError, 10)
1131 def Raise412(sentinel):
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001132 """Raise 412 HTTP exception."""
1133 if not sentinel.hitFingerPrintConflict.called:
1134 sentinel.hitFingerPrintConflict()
1135 raise errors.HttpError(412, "resource labels have changed")
1136 return "Passed"
Kevin Chengb5963882018-05-09 00:06:27 -07001137
1138 sentinel = mock.MagicMock()
1139 result = Raise412(sentinel)
1140 self.assertEqual(1, sentinel.hitFingerPrintConflict.call_count)
1141 self.assertEqual("Passed", result)
1142
Tri Vo29ac1822016-10-01 17:06:29 -07001143
1144if __name__ == "__main__":
1145 unittest.main()