blob: 2f8aa03da5b3504380a879ed59d6aa2f64d811d8 [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 Chengb5963882018-05-09 00:06:27 -070026from absl.testing import parameterized
Kevin Chengda4f07a2018-06-26 10:25:05 -070027import apiclient.http
Tri Vo29ac1822016-10-01 17:06:29 -070028
Tri Vo29ac1822016-10-01 17:06:29 -070029from acloud.internal.lib import driver_test_lib
30from acloud.internal.lib import gcompute_client
31from acloud.internal.lib import utils
32from acloud.public import errors
33
Kevin Chengb5963882018-05-09 00:06:27 -070034GS_IMAGE_SOURCE_URI = "https://storage.googleapis.com/fake-bucket/fake.tar.gz"
35GS_IMAGE_SOURCE_DISK = (
36 "https://www.googleapis.com/compute/v1/projects/fake-project/zones/"
37 "us-east1-d/disks/fake-disk")
38PROJECT = "fake-project"
Tri Vo29ac1822016-10-01 17:06:29 -070039
Kevin Cheng5c124ec2018-05-16 13:28:51 -070040# pylint: disable=protected-access, too-many-public-methods
Kevin Chengb5963882018-05-09 00:06:27 -070041class ComputeClientTest(driver_test_lib.BaseDriverTest, parameterized.TestCase):
Tri Vo29ac1822016-10-01 17:06:29 -070042 """Test ComputeClient."""
43
Kevin Chengb5963882018-05-09 00:06:27 -070044 PROJECT_OTHER = "fake-project-other"
Tri Vo29ac1822016-10-01 17:06:29 -070045 INSTANCE = "fake-instance"
46 IMAGE = "fake-image"
47 IMAGE_URL = "http://fake-image-url"
Kevin Chengb5963882018-05-09 00:06:27 -070048 IMAGE_OTHER = "fake-image-other"
Tri Vo29ac1822016-10-01 17:06:29 -070049 MACHINE_TYPE = "fake-machine-type"
50 MACHINE_TYPE_URL = "http://fake-machine-type-url"
51 METADATA = ("metadata_key", "metadata_value")
Kevin Chengb5963882018-05-09 00:06:27 -070052 ACCELERATOR_URL = "http://speedy-gpu"
Tri Vo29ac1822016-10-01 17:06:29 -070053 NETWORK = "fake-network"
54 NETWORK_URL = "http://fake-network-url"
55 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
193 # pyformat: disable
194 @parameterized.parameters(
195 (GS_IMAGE_SOURCE_URI, None, None,
196 {"name": IMAGE,
197 "rawDisk": {"source": GS_IMAGE_SOURCE_URI}}),
198 (None, GS_IMAGE_SOURCE_DISK, None,
199 {"name": IMAGE,
200 "sourceDisk": GS_IMAGE_SOURCE_DISK}),
201 (None, GS_IMAGE_SOURCE_DISK, {"label1": "xxx"},
202 {"name": IMAGE,
203 "sourceDisk": GS_IMAGE_SOURCE_DISK,
204 "labels": {"label1": "xxx"}}))
205 # pyformat: enable
206 def testCreateImage(self, source_uri, source_disk, labels, expected_body):
Tri Vo29ac1822016-10-01 17:06:29 -0700207 """Test CreateImage."""
herbertxue308f7662018-05-18 03:25:58 +0000208 mock_check = self.Patch(gcompute_client.ComputeClient,
209 "CheckImageExists",
210 return_value=False)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700211 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
Tri Vo29ac1822016-10-01 17:06:29 -0700212 resource_mock = mock.MagicMock()
213 self.compute_client._service.images = mock.MagicMock(
214 return_value=resource_mock)
215 resource_mock.insert = mock.MagicMock()
Tri Vo29ac1822016-10-01 17:06:29 -0700216 self.compute_client.CreateImage(
Kevin Chengb5963882018-05-09 00:06:27 -0700217 image_name=self.IMAGE, source_uri=source_uri,
218 source_disk=source_disk, labels=labels)
Tri Vo29ac1822016-10-01 17:06:29 -0700219 resource_mock.insert.assert_called_with(
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700220 project=PROJECT, body=expected_body)
221 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700222 operation=mock.ANY,
223 operation_scope=gcompute_client.OperationScope.GLOBAL)
herbertxue308f7662018-05-18 03:25:58 +0000224 mock_check.assert_called_with(self.IMAGE)
Tri Vo29ac1822016-10-01 17:06:29 -0700225
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700226 @mock.patch.object(gcompute_client.ComputeClient, "GetImage")
227 def testSetImageLabel(self, mock_get_image):
228 """Test SetImageLabel."""
229 with mock.patch.object(self.compute_client._service, "images",
230 return_value=mock.MagicMock(
231 setLabels=mock.MagicMock())) as _:
232 image = {"name": self.IMAGE,
233 "sourceDisk": GS_IMAGE_SOURCE_DISK,
234 "labelFingerprint": self.IMAGE_FINGERPRINT,
235 "labels": {"a": "aaa", "b": "bbb"}}
236 mock_get_image.return_value = image
237 new_labels = {"a": "xxx", "c": "ccc"}
238 # Test
239 self.compute_client.SetImageLabels(
240 self.IMAGE, new_labels)
241 # Check result
242 expected_labels = {"a": "xxx", "b": "bbb", "c": "ccc"}
243 self.compute_client._service.images().setLabels.assert_called_with(
244 project=PROJECT,
245 resource=self.IMAGE,
246 body={
247 "labels": expected_labels,
248 "labelFingerprint": self.IMAGE_FINGERPRINT
249 })
Kevin Chengb5963882018-05-09 00:06:27 -0700250
251 @parameterized.parameters(
252 (GS_IMAGE_SOURCE_URI, GS_IMAGE_SOURCE_DISK),
253 (None, None))
254 def testCreateImageRaiseDriverError(self, source_uri, source_disk):
255 """Test CreateImage."""
herbertxue308f7662018-05-18 03:25:58 +0000256 self.Patch(gcompute_client.ComputeClient, "CheckImageExists", return_value=False)
Kevin Chengb5963882018-05-09 00:06:27 -0700257 self.assertRaises(errors.DriverError, self.compute_client.CreateImage,
258 image_name=self.IMAGE, source_uri=source_uri,
259 source_disk=source_disk)
260
Tri Vo29ac1822016-10-01 17:06:29 -0700261
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700262 @mock.patch.object(gcompute_client.ComputeClient, "DeleteImage")
263 @mock.patch.object(gcompute_client.ComputeClient, "CheckImageExists",
herbertxue308f7662018-05-18 03:25:58 +0000264 side_effect=[False, True])
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700265 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation",
266 side_effect=errors.DriverError("Expected fake error"))
267 def testCreateImageFail(self, mock_wait, mock_check, mock_delete):
268 """Test CreateImage fails."""
Tri Vo29ac1822016-10-01 17:06:29 -0700269 resource_mock = mock.MagicMock()
270 self.compute_client._service.images = mock.MagicMock(
271 return_value=resource_mock)
272 resource_mock.insert = mock.MagicMock()
273
274 expected_body = {
275 "name": self.IMAGE,
276 "rawDisk": {
Kevin Chengb5963882018-05-09 00:06:27 -0700277 "source": GS_IMAGE_SOURCE_URI,
Tri Vo29ac1822016-10-01 17:06:29 -0700278 },
279 }
280 self.assertRaisesRegexp(
281 errors.DriverError,
282 "Expected fake error",
283 self.compute_client.CreateImage,
284 image_name=self.IMAGE,
Kevin Chengb5963882018-05-09 00:06:27 -0700285 source_uri=GS_IMAGE_SOURCE_URI)
Tri Vo29ac1822016-10-01 17:06:29 -0700286 resource_mock.insert.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700287 project=PROJECT, body=expected_body)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700288 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700289 operation=mock.ANY,
290 operation_scope=gcompute_client.OperationScope.GLOBAL)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700291 mock_check.assert_called_with(self.IMAGE)
292 mock_delete.assert_called_with(self.IMAGE)
Tri Vo29ac1822016-10-01 17:06:29 -0700293
294 def testCheckImageExistsTrue(self):
295 """Test CheckImageExists return True."""
296 resource_mock = mock.MagicMock()
297 mock_api = mock.MagicMock()
298 self.compute_client._service.images = mock.MagicMock(
299 return_value=resource_mock)
300 resource_mock.get = mock.MagicMock(return_value=mock_api)
301 mock_api.execute = mock.MagicMock(return_value={"name": self.IMAGE})
302 self.assertTrue(self.compute_client.CheckImageExists(self.IMAGE))
303
304 def testCheckImageExistsFalse(self):
305 """Test CheckImageExists return False."""
306 resource_mock = mock.MagicMock()
307 mock_api = mock.MagicMock()
308 self.compute_client._service.images = mock.MagicMock(
309 return_value=resource_mock)
310 resource_mock.get = mock.MagicMock(return_value=mock_api)
311 mock_api.execute = mock.MagicMock(
312 side_effect=errors.ResourceNotFoundError(404, "no image"))
313 self.assertFalse(self.compute_client.CheckImageExists(self.IMAGE))
314
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700315 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
316 def testDeleteImage(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700317 """Test DeleteImage."""
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.delete = mock.MagicMock()
322 self.compute_client.DeleteImage(self.IMAGE)
323 resource_mock.delete.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700324 project=PROJECT, image=self.IMAGE)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700325 self.assertTrue(mock_wait.called)
Tri Vo29ac1822016-10-01 17:06:29 -0700326
327 def _SetupBatchHttpRequestMock(self):
328 """Setup BatchHttpRequest mock."""
329 requests = {}
330
331 def _Add(request, callback, request_id):
332 requests[request_id] = (request, callback)
333
334 def _Execute():
335 for rid in requests:
336 _, callback = requests[rid]
337 callback(
338 request_id=rid, response=mock.MagicMock(), exception=None)
Tri Vo29ac1822016-10-01 17:06:29 -0700339 mock_batch = mock.MagicMock()
340 mock_batch.add = _Add
341 mock_batch.execute = _Execute
342 self.Patch(apiclient.http, "BatchHttpRequest", return_value=mock_batch)
343
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700344 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
345 def testDeleteImages(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700346 """Test DeleteImages."""
347 self._SetupBatchHttpRequestMock()
Tri Vo29ac1822016-10-01 17:06:29 -0700348 fake_images = ["fake_image_1", "fake_image_2"]
349 mock_api = mock.MagicMock()
350 resource_mock = mock.MagicMock()
351 self.compute_client._service.images = mock.MagicMock(
352 return_value=resource_mock)
353 resource_mock.delete = mock.MagicMock(return_value=mock_api)
354 # Call the API.
355 deleted, failed, error_msgs = self.compute_client.DeleteImages(
356 fake_images)
357 # Verify
Kevin Chengb5963882018-05-09 00:06:27 -0700358 calls = [
359 mock.call(project=PROJECT, image="fake_image_1"),
360 mock.call(project=PROJECT, image="fake_image_2")
361 ]
Tri Vo29ac1822016-10-01 17:06:29 -0700362 resource_mock.delete.assert_has_calls(calls, any_order=True)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700363 self.assertEqual(mock_wait.call_count, 2)
Tri Vo29ac1822016-10-01 17:06:29 -0700364 self.assertEqual(error_msgs, [])
365 self.assertEqual(failed, [])
366 self.assertEqual(set(deleted), set(fake_images))
367
368 def testListImages(self):
369 """Test ListImages."""
370 fake_token = "fake_next_page_token"
371 image_1 = "image_1"
372 image_2 = "image_2"
373 response_1 = {"items": [image_1], "nextPageToken": fake_token}
374 response_2 = {"items": [image_2]}
375 self.Patch(
376 gcompute_client.ComputeClient,
377 "Execute",
378 side_effect=[response_1, response_2])
379 resource_mock = mock.MagicMock()
380 self.compute_client._service.images = mock.MagicMock(
381 return_value=resource_mock)
382 resource_mock.list = mock.MagicMock()
383 images = self.compute_client.ListImages()
384 calls = [
Kevin Chengb5963882018-05-09 00:06:27 -0700385 mock.call(project=PROJECT, filter=None, pageToken=None),
386 mock.call(project=PROJECT, filter=None, pageToken=fake_token)
Tri Vo29ac1822016-10-01 17:06:29 -0700387 ]
388 resource_mock.list.assert_has_calls(calls)
389 self.assertEqual(images, [image_1, image_2])
390
Kevin Chengb5963882018-05-09 00:06:27 -0700391 def testListImagesFromExternalProject(self):
392 """Test ListImages which accepts different project."""
393 image = "image_1"
394 response = {"items": [image]}
395 self.Patch(gcompute_client.ComputeClient, "Execute", side_effect=[response])
396 resource_mock = mock.MagicMock()
397 self.compute_client._service.images = mock.MagicMock(
398 return_value=resource_mock)
399 resource_mock.list = mock.MagicMock()
400 images = self.compute_client.ListImages(
401 image_project="fake-project-2")
402 calls = [
403 mock.call(project="fake-project-2", filter=None, pageToken=None)]
404 resource_mock.list.assert_has_calls(calls)
405 self.assertEqual(images, [image])
406
Tri Vo29ac1822016-10-01 17:06:29 -0700407 def testGetInstance(self):
408 """Test GetInstance."""
409 resource_mock = mock.MagicMock()
410 mock_api = mock.MagicMock()
411 self.compute_client._service.instances = mock.MagicMock(
412 return_value=resource_mock)
413 resource_mock.get = mock.MagicMock(return_value=mock_api)
414 mock_api.execute = mock.MagicMock(return_value={"name": self.INSTANCE})
415 result = self.compute_client.GetInstance(self.INSTANCE, self.ZONE)
416 self.assertEqual(result, {"name": self.INSTANCE})
417 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700418 project=PROJECT, zone=self.ZONE, instance=self.INSTANCE)
Tri Vo29ac1822016-10-01 17:06:29 -0700419
420 def testListInstances(self):
421 """Test ListInstances."""
422 fake_token = "fake_next_page_token"
423 instance_1 = "instance_1"
424 instance_2 = "instance_2"
425 response_1 = {"items": [instance_1], "nextPageToken": fake_token}
426 response_2 = {"items": [instance_2]}
427 self.Patch(
428 gcompute_client.ComputeClient,
429 "Execute",
430 side_effect=[response_1, response_2])
431 resource_mock = mock.MagicMock()
432 self.compute_client._service.instances = mock.MagicMock(
433 return_value=resource_mock)
434 resource_mock.list = mock.MagicMock()
435 instances = self.compute_client.ListInstances(self.ZONE)
436 calls = [
437 mock.call(
Kevin Chengb5963882018-05-09 00:06:27 -0700438 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -0700439 zone=self.ZONE,
440 filter=None,
441 pageToken=None),
442 mock.call(
Kevin Chengb5963882018-05-09 00:06:27 -0700443 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -0700444 zone=self.ZONE,
445 filter=None,
446 pageToken=fake_token),
447 ]
448 resource_mock.list.assert_has_calls(calls)
449 self.assertEqual(instances, [instance_1, instance_2])
450
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700451 @mock.patch.object(gcompute_client.ComputeClient, "GetImage")
452 @mock.patch.object(gcompute_client.ComputeClient, "GetNetworkUrl")
453 @mock.patch.object(gcompute_client.ComputeClient, "GetMachineType")
454 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
455 def testCreateInstance(self, mock_wait, mock_get_mach_type,
456 mock_get_network_url, mock_get_image):
Tri Vo29ac1822016-10-01 17:06:29 -0700457 """Test CreateInstance."""
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700458 mock_get_mach_type.return_value = {"selfLink": self.MACHINE_TYPE_URL}
459 mock_get_network_url.return_value = self.NETWORK_URL
460 mock_get_image.return_value = {"selfLink": self.IMAGE_URL}
Tri Vo29ac1822016-10-01 17:06:29 -0700461 resource_mock = mock.MagicMock()
462 self.compute_client._service.instances = mock.MagicMock(
463 return_value=resource_mock)
464 resource_mock.insert = mock.MagicMock()
herbertxue308f7662018-05-18 03:25:58 +0000465 self.Patch(
466 self.compute_client,
467 "_GetExtraDiskArgs",
468 return_value=[{"fake_extra_arg": "fake_extra_value"}])
469 extra_disk_name = "gce-x86-userdebug-2345-abcd-data"
470 expected_disk_args = [self._disk_args]
471 expected_disk_args.extend([{"fake_extra_arg": "fake_extra_value"}])
Tri Vo29ac1822016-10-01 17:06:29 -0700472
473 expected_body = {
474 "machineType": self.MACHINE_TYPE_URL,
475 "name": self.INSTANCE,
476 "networkInterfaces": [
477 {
478 "network": self.NETWORK_URL,
479 "accessConfigs": [
480 {"name": "External NAT",
481 "type": "ONE_TO_ONE_NAT"}
482 ],
483 }
484 ],
herbertxue308f7662018-05-18 03:25:58 +0000485 "disks": expected_disk_args,
Tri Vo29ac1822016-10-01 17:06:29 -0700486 "serviceAccounts": [
487 {"email": "default",
488 "scopes": self.compute_client.DEFAULT_INSTANCE_SCOPE}
489 ],
490 "metadata": {
491 "items": [{"key": self.METADATA[0],
492 "value": self.METADATA[1]}],
493 },
494 }
495
496 self.compute_client.CreateInstance(
497 instance=self.INSTANCE,
498 image_name=self.IMAGE,
499 machine_type=self.MACHINE_TYPE,
500 metadata={self.METADATA[0]: self.METADATA[1]},
501 network=self.NETWORK,
herbertxue308f7662018-05-18 03:25:58 +0000502 zone=self.ZONE,
503 extra_disk_name=extra_disk_name)
Tri Vo29ac1822016-10-01 17:06:29 -0700504
505 resource_mock.insert.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700506 project=PROJECT, zone=self.ZONE, body=expected_body)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700507 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700508 mock.ANY,
509 operation_scope=gcompute_client.OperationScope.ZONE,
510 scope_name=self.ZONE)
511
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700512 @mock.patch.object(gcompute_client.ComputeClient, "GetAcceleratorUrl")
513 @mock.patch.object(gcompute_client.ComputeClient, "GetImage")
514 @mock.patch.object(gcompute_client.ComputeClient, "GetNetworkUrl")
515 @mock.patch.object(gcompute_client.ComputeClient, "GetMachineType")
516 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
517 def testCreateInstanceWithGpu(self, mock_wait, mock_get_mach,
518 mock_get_network, mock_get_image,
519 mock_get_accel):
Kevin Chengb5963882018-05-09 00:06:27 -0700520 """Test CreateInstance with a GPU parameter not set to None."""
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700521 mock_get_mach.return_value = {"selfLink": self.MACHINE_TYPE_URL}
522 mock_get_network.return_value = self.NETWORK_URL
523 mock_get_accel.return_value = self.ACCELERATOR_URL
524 mock_get_image.return_value = {"selfLink": self.IMAGE_URL}
Kevin Chengb5963882018-05-09 00:06:27 -0700525
526 resource_mock = mock.MagicMock()
527 self.compute_client._service.instances = mock.MagicMock(
528 return_value=resource_mock)
529 resource_mock.insert = mock.MagicMock()
530
531 expected_body = {
532 "machineType":
533 self.MACHINE_TYPE_URL,
534 "name":
535 self.INSTANCE,
536 "networkInterfaces": [{
537 "network":
538 self.NETWORK_URL,
539 "accessConfigs": [{
540 "name": "External NAT",
541 "type": "ONE_TO_ONE_NAT"
542 }],
543 }],
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700544 "disks": [self._disk_args],
Kevin Chengb5963882018-05-09 00:06:27 -0700545 "serviceAccounts": [{
546 "email": "default",
547 "scopes": self.compute_client.DEFAULT_INSTANCE_SCOPE
548 }],
549 "scheduling": {
550 "onHostMaintenance": "terminate"
551 },
552 "guestAccelerators": [{
553 "acceleratorCount": 1,
554 "acceleratorType": "http://speedy-gpu"
555 }],
556 "metadata": {
557 "items": [{
558 "key": self.METADATA[0],
559 "value": self.METADATA[1]
560 }],
561 },
562 }
563
564 self.compute_client.CreateInstance(
565 instance=self.INSTANCE,
566 image_name=self.IMAGE,
567 machine_type=self.MACHINE_TYPE,
568 metadata={self.METADATA[0]: self.METADATA[1]},
569 network=self.NETWORK,
570 zone=self.ZONE,
571 gpu=self.GPU)
572
573 resource_mock.insert.assert_called_with(
574 project=PROJECT, zone=self.ZONE, body=expected_body)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700575 mock_wait.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700576 mock.ANY, operation_scope=gcompute_client.OperationScope.ZONE,
577 scope_name=self.ZONE)
578
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700579 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
580 def testDeleteInstance(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700581 """Test DeleteInstance."""
Tri Vo29ac1822016-10-01 17:06:29 -0700582 resource_mock = mock.MagicMock()
583 self.compute_client._service.instances = mock.MagicMock(
584 return_value=resource_mock)
585 resource_mock.delete = mock.MagicMock()
586 self.compute_client.DeleteInstance(
587 instance=self.INSTANCE, zone=self.ZONE)
588 resource_mock.delete.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700589 project=PROJECT, zone=self.ZONE, instance=self.INSTANCE)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700590 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700591 mock.ANY,
592 operation_scope=gcompute_client.OperationScope.ZONE,
593 scope_name=self.ZONE)
594
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700595 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
596 def testDeleteInstances(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700597 """Test DeleteInstances."""
598 self._SetupBatchHttpRequestMock()
Tri Vo29ac1822016-10-01 17:06:29 -0700599 fake_instances = ["fake_instance_1", "fake_instance_2"]
600 mock_api = mock.MagicMock()
601 resource_mock = mock.MagicMock()
602 self.compute_client._service.instances = mock.MagicMock(
603 return_value=resource_mock)
604 resource_mock.delete = mock.MagicMock(return_value=mock_api)
605 deleted, failed, error_msgs = self.compute_client.DeleteInstances(
606 fake_instances, self.ZONE)
607 calls = [
608 mock.call(
Kevin Chengb5963882018-05-09 00:06:27 -0700609 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -0700610 instance="fake_instance_1",
Kevin Chengb5963882018-05-09 00:06:27 -0700611 zone=self.ZONE),
612 mock.call(
613 project=PROJECT,
614 instance="fake_instance_2",
615 zone=self.ZONE)
Tri Vo29ac1822016-10-01 17:06:29 -0700616 ]
617 resource_mock.delete.assert_has_calls(calls, any_order=True)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700618 self.assertEqual(mock_wait.call_count, 2)
Tri Vo29ac1822016-10-01 17:06:29 -0700619 self.assertEqual(error_msgs, [])
620 self.assertEqual(failed, [])
621 self.assertEqual(set(deleted), set(fake_instances))
622
Kevin Chengb5963882018-05-09 00:06:27 -0700623 @parameterized.parameters(("fake-image-project", "fake-image-project"),
624 (None, PROJECT))
625 def testCreateDisk(self, source_project, expected_project_to_use):
626 """Test CreateDisk with images."""
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700627 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
Kevin Chengb5963882018-05-09 00:06:27 -0700628 resource_mock = mock.MagicMock()
629 self.compute_client._service.disks = mock.MagicMock(
630 return_value=resource_mock)
631 resource_mock.insert = mock.MagicMock()
632 self.compute_client.CreateDisk(
633 "fake_disk", "fake_image", 10, self.ZONE, source_project=source_project)
634 resource_mock.insert.assert_called_with(
635 project=PROJECT,
636 zone=self.ZONE,
637 sourceImage="projects/%s/global/images/fake_image" %
638 expected_project_to_use,
639 body={
640 "name":
641 "fake_disk",
642 "sizeGb":
643 10,
644 "type":
645 "projects/%s/zones/%s/diskTypes/pd-standard" % (PROJECT,
646 self.ZONE)
647 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700648 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700649
650 @parameterized.parameters(
651 (gcompute_client.PersistentDiskType.STANDARD, "pd-standard"),
652 (gcompute_client.PersistentDiskType.SSD, "pd-ssd"))
653 def testCreateDiskWithType(self, disk_type, expected_disk_type_string):
654 """Test CreateDisk with images."""
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700655 mock_wait = self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
Kevin Chengb5963882018-05-09 00:06:27 -0700656 resource_mock = mock.MagicMock()
657 self.compute_client._service.disks = mock.MagicMock(
658 return_value=resource_mock)
659 resource_mock.insert = mock.MagicMock()
660 self.compute_client.CreateDisk(
661 "fake_disk",
662 "fake_image",
663 10,
664 self.ZONE,
665 source_project="fake-project",
666 disk_type=disk_type)
667 resource_mock.insert.assert_called_with(
668 project=PROJECT,
669 zone=self.ZONE,
670 sourceImage="projects/%s/global/images/fake_image" % "fake-project",
671 body={
672 "name":
673 "fake_disk",
674 "sizeGb":
675 10,
676 "type":
677 "projects/%s/zones/%s/diskTypes/%s" %
678 (PROJECT, self.ZONE, expected_disk_type_string)
679 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700680 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700681
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700682 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
683 def testAttachDisk(self, mock_wait):
Kevin Chengb5963882018-05-09 00:06:27 -0700684 """Test AttachDisk."""
Kevin Chengb5963882018-05-09 00:06:27 -0700685 resource_mock = mock.MagicMock()
686 self.compute_client._service.instances = mock.MagicMock(
687 return_value=resource_mock)
688 resource_mock.attachDisk = mock.MagicMock()
689 self.compute_client.AttachDisk(
690 "fake_instance_1", self.ZONE, deviceName="fake_disk",
691 source="fake-selfLink")
692 resource_mock.attachDisk.assert_called_with(
693 project=PROJECT,
694 zone=self.ZONE,
695 instance="fake_instance_1",
696 body={
697 "deviceName": "fake_disk",
698 "source": "fake-selfLink"
699 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700700 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700701
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700702 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
703 def testDetachDisk(self, mock_wait):
Kevin Chengb5963882018-05-09 00:06:27 -0700704 """Test DetachDisk."""
Kevin Chengb5963882018-05-09 00:06:27 -0700705 resource_mock = mock.MagicMock()
706 self.compute_client._service.instances = mock.MagicMock(
707 return_value=resource_mock)
708 resource_mock.detachDisk = mock.MagicMock()
709 self.compute_client.DetachDisk("fake_instance_1", self.ZONE, "fake_disk")
710 resource_mock.detachDisk.assert_called_with(
711 project=PROJECT,
712 zone=self.ZONE,
713 instance="fake_instance_1",
714 deviceName="fake_disk")
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700715 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700716
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700717 @mock.patch.object(gcompute_client.ComputeClient, "GetAcceleratorUrl")
718 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
719 def testAttachAccelerator(self, mock_wait, mock_get_accel):
Kevin Chengb5963882018-05-09 00:06:27 -0700720 """Test AttachAccelerator."""
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700721 mock_get_accel.return_value = self.ACCELERATOR_URL
Kevin Chengb5963882018-05-09 00:06:27 -0700722 resource_mock = mock.MagicMock()
723 self.compute_client._service.instances = mock.MagicMock(
724 return_value=resource_mock)
725 resource_mock.attachAccelerator = mock.MagicMock()
726 self.compute_client.AttachAccelerator("fake_instance_1", self.ZONE, 1,
727 "nvidia-tesla-k80")
728 resource_mock.setMachineResources.assert_called_with(
729 project=PROJECT,
730 zone=self.ZONE,
731 instance="fake_instance_1",
732 body={
733 "guestAccelerators": [{
734 "acceleratorType": self.ACCELERATOR_URL,
735 "acceleratorCount": 1
736 }]
737 })
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700738 self.assertTrue(mock_wait.called)
Kevin Chengb5963882018-05-09 00:06:27 -0700739
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700740 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
741 def testBatchExecuteOnInstances(self, mock_wait):
742 """Test BatchExecuteOnInstances."""
Tri Vo29ac1822016-10-01 17:06:29 -0700743 self._SetupBatchHttpRequestMock()
Tri Vo29ac1822016-10-01 17:06:29 -0700744 action = mock.MagicMock(return_value=mock.MagicMock())
745 fake_instances = ["fake_instance_1", "fake_instance_2"]
746 done, failed, error_msgs = self.compute_client._BatchExecuteOnInstances(
747 fake_instances, self.ZONE, action)
748 calls = [mock.call(instance="fake_instance_1"),
749 mock.call(instance="fake_instance_2")]
750 action.assert_has_calls(calls, any_order=True)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700751 self.assertEqual(mock_wait.call_count, 2)
Tri Vo29ac1822016-10-01 17:06:29 -0700752 self.assertEqual(set(done), set(fake_instances))
753 self.assertEqual(error_msgs, [])
754 self.assertEqual(failed, [])
755
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700756 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
757 def testResetInstance(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700758 """Test ResetInstance."""
Tri Vo29ac1822016-10-01 17:06:29 -0700759 resource_mock = mock.MagicMock()
760 self.compute_client._service.instances = mock.MagicMock(
761 return_value=resource_mock)
762 resource_mock.reset = mock.MagicMock()
763 self.compute_client.ResetInstance(
764 instance=self.INSTANCE, zone=self.ZONE)
765 resource_mock.reset.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700766 project=PROJECT, zone=self.ZONE, instance=self.INSTANCE)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700767 mock_wait.assert_called_with(
Tri Vo29ac1822016-10-01 17:06:29 -0700768 mock.ANY,
769 operation_scope=gcompute_client.OperationScope.ZONE,
770 scope_name=self.ZONE)
771
772 def _CompareMachineSizeTestHelper(self,
773 machine_info_1,
774 machine_info_2,
775 expected_result=None,
776 expected_error_type=None):
777 """Helper class for testing CompareMachineSize.
778
Kevin Chengb5963882018-05-09 00:06:27 -0700779 Args:
780 machine_info_1: A dictionary representing the first machine size.
781 machine_info_2: A dictionary representing the second machine size.
782 expected_result: An integer, 0, 1 or -1, or None if not set.
783 expected_error_type: An exception type, if set will check for exception.
784 """
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700785 mock_get_mach_type = self.Patch(
Tri Vo29ac1822016-10-01 17:06:29 -0700786 gcompute_client.ComputeClient,
787 "GetMachineType",
788 side_effect=[machine_info_1, machine_info_2])
789 if expected_error_type:
790 self.assertRaises(expected_error_type,
791 self.compute_client.CompareMachineSize, "name1",
792 "name2", self.ZONE)
793 else:
794 result = self.compute_client.CompareMachineSize("name1", "name2",
795 self.ZONE)
796 self.assertEqual(result, expected_result)
797
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700798 mock_get_mach_type.assert_has_calls(
Tri Vo29ac1822016-10-01 17:06:29 -0700799 [mock.call("name1", self.ZONE), mock.call("name2", self.ZONE)])
800
801 def testCompareMachineSizeSmall(self):
802 """Test CompareMachineSize where the first one is smaller."""
803 machine_info_1 = {"guestCpus": 10, "memoryMb": 100}
804 machine_info_2 = {"guestCpus": 10, "memoryMb": 200}
805 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, -1)
806
807 def testCompareMachineSizeLarge(self):
808 """Test CompareMachineSize where the first one is larger."""
809 machine_info_1 = {"guestCpus": 10, "memoryMb": 200}
810 machine_info_2 = {"guestCpus": 10, "memoryMb": 100}
811 self._CompareMachineSizeTestHelper(machine_info_1, machine_info_2, 1)
812
813 def testCompareMachineSizeEqual(self):
814 """Test CompareMachineSize where two machine sizes are equal."""
815 machine_info = {"guestCpus": 10, "memoryMb": 100}
816 self._CompareMachineSizeTestHelper(machine_info, machine_info, 0)
817
818 def testCompareMachineSizeBadMetric(self):
819 """Test CompareMachineSize with bad metric."""
Kevin Chengb5963882018-05-09 00:06:27 -0700820 machine_info = {"unknown_metric": 10, "memoryMb": 100}
Tri Vo29ac1822016-10-01 17:06:29 -0700821 self._CompareMachineSizeTestHelper(
822 machine_info, machine_info, expected_error_type=errors.DriverError)
823
824 def testGetMachineType(self):
825 """Test GetMachineType."""
826 resource_mock = mock.MagicMock()
827 mock_api = mock.MagicMock()
828 self.compute_client._service.machineTypes = mock.MagicMock(
829 return_value=resource_mock)
830 resource_mock.get = mock.MagicMock(return_value=mock_api)
831 mock_api.execute = mock.MagicMock(
832 return_value={"name": self.MACHINE_TYPE})
833 result = self.compute_client.GetMachineType(self.MACHINE_TYPE,
834 self.ZONE)
835 self.assertEqual(result, {"name": self.MACHINE_TYPE})
836 resource_mock.get.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700837 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -0700838 zone=self.ZONE,
839 machineType=self.MACHINE_TYPE)
840
841 def _GetSerialPortOutputTestHelper(self, response):
842 """Helper function for testing GetSerialPortOutput.
843
Kevin Chengb5963882018-05-09 00:06:27 -0700844 Args:
845 response: A dictionary representing a fake response.
846 """
Tri Vo29ac1822016-10-01 17:06:29 -0700847 resource_mock = mock.MagicMock()
848 mock_api = mock.MagicMock()
849 self.compute_client._service.instances = mock.MagicMock(
850 return_value=resource_mock)
851 resource_mock.getSerialPortOutput = mock.MagicMock(
852 return_value=mock_api)
853 mock_api.execute = mock.MagicMock(return_value=response)
854
855 if "contents" in response:
856 result = self.compute_client.GetSerialPortOutput(
857 instance=self.INSTANCE, zone=self.ZONE)
858 self.assertEqual(result, "fake contents")
859 else:
860 self.assertRaisesRegexp(
861 errors.DriverError,
862 "Malformed response.*",
863 self.compute_client.GetSerialPortOutput,
864 instance=self.INSTANCE,
865 zone=self.ZONE)
866 resource_mock.getSerialPortOutput.assert_called_with(
Kevin Chengb5963882018-05-09 00:06:27 -0700867 project=PROJECT,
Tri Vo29ac1822016-10-01 17:06:29 -0700868 zone=self.ZONE,
869 instance=self.INSTANCE,
870 port=1)
871
872 def testGetSerialPortOutput(self):
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700873 """Test GetSerialPortOutput."""
Tri Vo29ac1822016-10-01 17:06:29 -0700874 response = {"contents": "fake contents"}
875 self._GetSerialPortOutputTestHelper(response)
876
877 def testGetSerialPortOutputFail(self):
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700878 """Test GetSerialPortOutputFail."""
Tri Vo29ac1822016-10-01 17:06:29 -0700879 response = {"malformed": "fake contents"}
880 self._GetSerialPortOutputTestHelper(response)
881
882 def testGetInstanceNamesByIPs(self):
883 """Test GetInstanceNamesByIPs."""
884 good_instance = {
885 "name": "instance_1",
886 "networkInterfaces": [
887 {
888 "accessConfigs": [
889 {"natIP": "172.22.22.22"},
890 ],
891 },
892 ],
893 }
894 bad_instance = {"name": "instance_2"}
895 self.Patch(
896 gcompute_client.ComputeClient,
897 "ListInstances",
898 return_value=[good_instance, bad_instance])
899 ip_name_map = self.compute_client.GetInstanceNamesByIPs(
900 ips=["172.22.22.22", "172.22.22.23"], zone=self.ZONE)
901 self.assertEqual(ip_name_map, {"172.22.22.22": "instance_1",
902 "172.22.22.23": None})
903
904 def testAddSshRsa(self):
905 """Test AddSshRsa.."""
906 fake_user = "fake_user"
907 sshkey = (
908 "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDBkTOTRze9v2VOqkkf7RG"
909 "jSkg6Z2kb9Q9UHsDGatvend3fmjIw1Tugg0O7nnjlPkskmlgyd4a/j99WOeLL"
910 "CPk6xPyoVjrPUVBU/pAk09ORTC4Zqk6YjlW7LOfzvqmXhmIZfYu6Q4Yt50pZzhl"
911 "lllfu26nYjY7Tg12D019nJi/kqPX5+NKgt0LGXTu8T1r2Gav/q4V7QRWQrB8Eiu"
912 "pxXR7I2YhynqovkEt/OXG4qWgvLEXGsWtSQs0CtCzqEVxz0Y9ECr7er4VdjSQxV"
913 "AaeLAsQsK9ROae8hMBFZ3//8zLVapBwpuffCu+fUoql9qeV9xagZcc9zj8XOUOW"
914 "ApiihqNL1111 test@test1.org")
915 project = {
916 "commonInstanceMetadata": {
917 "kind": "compute#metadata",
918 "fingerprint": "a-23icsyx4E=",
919 "items": [
920 {
921 "key": "sshKeys",
922 "value": "user:key"
923 }
924 ]
925 }
926 }
927 expected = {
928 "kind": "compute#metadata",
929 "fingerprint": "a-23icsyx4E=",
930 "items": [
931 {
932 "key": "sshKeys",
933 "value": "user:key\n%s:%s" % (fake_user, sshkey)
934 }
935 ]
936 }
937
938 self.Patch(os.path, "exists", return_value=True)
939 m = mock.mock_open(read_data=sshkey)
Tri Vo29ac1822016-10-01 17:06:29 -0700940 self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
941 self.Patch(
942 gcompute_client.ComputeClient, "GetProject", return_value=project)
943 resource_mock = mock.MagicMock()
944 self.compute_client._service.projects = mock.MagicMock(
945 return_value=resource_mock)
946 resource_mock.setCommonInstanceMetadata = mock.MagicMock()
947
Kevin Chengda4f07a2018-06-26 10:25:05 -0700948 with mock.patch("__builtin__.open", m):
949 self.compute_client.AddSshRsa(fake_user, "/path/to/test_rsa.pub")
950 resource_mock.setCommonInstanceMetadata.assert_called_with(
951 project=PROJECT, body=expected)
Tri Vo29ac1822016-10-01 17:06:29 -0700952
953 def testAddSshRsaInvalidKey(self):
954 """Test AddSshRsa.."""
955 fake_user = "fake_user"
956 sshkey = "ssh-rsa v2VOqkkf7RGL1111 test@test1.org"
957 project = {
958 "commonInstanceMetadata": {
959 "kind": "compute#metadata",
960 "fingerprint": "a-23icsyx4E=",
961 "items": [
962 {
963 "key": "sshKeys",
964 "value": "user:key"
965 }
966 ]
967 }
968 }
969 self.Patch(os.path, "exists", return_value=True)
970 m = mock.mock_open(read_data=sshkey)
Tri Vo29ac1822016-10-01 17:06:29 -0700971 self.Patch(gcompute_client.ComputeClient, "WaitOnOperation")
972 self.Patch(
973 gcompute_client.ComputeClient, "GetProject", return_value=project)
Kevin Chengda4f07a2018-06-26 10:25:05 -0700974 with mock.patch("__builtin__.open", m):
975 self.assertRaisesRegexp(errors.DriverError, "rsa key is invalid:*",
976 self.compute_client.AddSshRsa, fake_user,
977 "/path/to/test_rsa.pub")
Tri Vo29ac1822016-10-01 17:06:29 -0700978
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700979 @mock.patch.object(gcompute_client.ComputeClient, "WaitOnOperation")
980 def testDeleteDisks(self, mock_wait):
Tri Vo29ac1822016-10-01 17:06:29 -0700981 """Test DeleteDisks."""
982 self._SetupBatchHttpRequestMock()
Tri Vo29ac1822016-10-01 17:06:29 -0700983 fake_disks = ["fake_disk_1", "fake_disk_2"]
984 mock_api = mock.MagicMock()
985 resource_mock = mock.MagicMock()
986 self.compute_client._service.disks = mock.MagicMock(
987 return_value=resource_mock)
988 resource_mock.delete = mock.MagicMock(return_value=mock_api)
989 # Call the API.
990 deleted, failed, error_msgs = self.compute_client.DeleteDisks(
991 fake_disks, zone=self.ZONE)
992 # Verify
Kevin Chengb5963882018-05-09 00:06:27 -0700993 calls = [
994 mock.call(project=PROJECT, disk="fake_disk_1", zone=self.ZONE),
995 mock.call(project=PROJECT, disk="fake_disk_2", zone=self.ZONE)
996 ]
Tri Vo29ac1822016-10-01 17:06:29 -0700997 resource_mock.delete.assert_has_calls(calls, any_order=True)
Kevin Cheng5c124ec2018-05-16 13:28:51 -0700998 self.assertEqual(mock_wait.call_count, 2)
Tri Vo29ac1822016-10-01 17:06:29 -0700999 self.assertEqual(error_msgs, [])
1000 self.assertEqual(failed, [])
1001 self.assertEqual(set(deleted), set(fake_disks))
1002
Kevin Chengb5963882018-05-09 00:06:27 -07001003 def testRetryOnFingerPrintError(self):
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001004 """Test RetryOnFingerPrintError."""
Kevin Chengb5963882018-05-09 00:06:27 -07001005 @utils.RetryOnException(gcompute_client._IsFingerPrintError, 10)
1006 def Raise412(sentinel):
Kevin Cheng5c124ec2018-05-16 13:28:51 -07001007 """Raise 412 HTTP exception."""
1008 if not sentinel.hitFingerPrintConflict.called:
1009 sentinel.hitFingerPrintConflict()
1010 raise errors.HttpError(412, "resource labels have changed")
1011 return "Passed"
Kevin Chengb5963882018-05-09 00:06:27 -07001012
1013 sentinel = mock.MagicMock()
1014 result = Raise412(sentinel)
1015 self.assertEqual(1, sentinel.hitFingerPrintConflict.call_count)
1016 self.assertEqual("Passed", result)
1017
Tri Vo29ac1822016-10-01 17:06:29 -07001018
1019if __name__ == "__main__":
1020 unittest.main()