blob: ab1fac7358201ed296baf81e663f806af7030e22 [file] [log] [blame] [edit]
# Copyright 2015 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Tests the gce module."""
import os
from chromite.third_party.googleapiclient.errors import HttpError
from chromite.third_party.googleapiclient.http import HttpMockSequence
from chromite.third_party.oauth2client.client import GoogleCredentials
from chromite.lib import cros_test_lib
from chromite.lib import gce
from chromite.lib import osutils
class GceTest(cros_test_lib.MockTempDirTestCase):
"""Unit tests for the gce module."""
_PROJECT = "foo-project"
_ZONE = "foo-zone"
def setUp(self):
self.json_key_file = os.path.join(self.tempdir, "service_account.json")
osutils.Touch(self.json_key_file)
for cmd in ("from_stream", "create_scoped"):
self.PatchObject(GoogleCredentials, cmd, autospec=True)
self.PatchObject(
gce.GceContext,
"GetZoneRegion",
autospec=True,
return_value=self._ZONE,
)
@cros_test_lib.pytestmark_network_test
def testGetImage(self):
"""Tests that GetImage returns the correct image."""
good_http = HttpMockSequence(
[
(
{
"status": "200",
},
'{"name": "foo-image"}',
),
]
)
# Assert that GetImage does not complain if an image is found.
self.PatchObject(
gce.GceContext,
"_BuildRetriableRequest",
autospec=True,
side_effect=self._MockOutBuildRetriableRequest(good_http),
)
gce_context = gce.GceContext.ForServiceAccount(
self._PROJECT, self._ZONE, self.json_key_file
)
self.assertDictEqual(
gce_context.GetImage("foo-image"), dict(name="foo-image")
)
@cros_test_lib.pytestmark_network_test
def testGetImageRaisesIfImageNotFound(self):
"""Tests that GetImage raies exception when image is not found."""
bad_http = HttpMockSequence(
[
(
{
"status": "404",
},
"Image not found.",
),
]
)
# Assert that GetImage raises if image is not found.
self.PatchObject(
gce.GceContext,
"_BuildRetriableRequest",
autospec=True,
side_effect=self._MockOutBuildRetriableRequest(bad_http),
)
gce_context = gce.GceContext.ForServiceAccount(
self._PROJECT, self._ZONE, self.json_key_file
)
with self.assertRaises(gce.ResourceNotFoundError):
gce_context.GetImage("not-exising-image")
@cros_test_lib.pytestmark_network_test
def testRetryOnServerErrorHttpRequest(self):
"""Tests that 500 errors are retried."""
# Fake http sequence that does not return 200 until the third trial.
mock_http = HttpMockSequence(
[
({"status": "502"}, "Server error"),
({"status": "502"}, "Server error"),
({"status": "200"}, '{"name":"foo-image"}'),
]
)
self.PatchObject(
gce.GceContext,
"_BuildRetriableRequest",
autospec=True,
side_effect=self._MockOutBuildRetriableRequest(mock_http),
)
# Disable retry and expect the request to fail.
gce.GceContext.RETRIES = 0
gce_context = gce.GceContext.ForServiceAccount(
self._PROJECT, self._ZONE, self.json_key_file
)
with self.assertRaises(HttpError):
gce_context.GetImage("foo-image")
# Enable retry and expect the request to succeed.
gce.GceContext.RETRIES = 2
gce_context = gce.GceContext.ForServiceAccount(
self._PROJECT, self._ZONE, self.json_key_file
)
self.assertDictEqual(
gce_context.GetImage("foo-image"), dict(name="foo-image")
)
def _MockOutBuildRetriableRequest(self, mock_http):
"""Returns a mock closure of _BuildRetriableRequest.
Fake a GceContext._BuildRetriableRequest() that always uses |mock_http|
as transport.
"""
def _BuildRetriableRequest(
_self,
num_retries,
_http,
_thread_safe,
_credentials,
*args,
**kwargs,
):
return gce.RetryOnServerErrorHttpRequest(
num_retries, mock_http, *args, **kwargs
)
return _BuildRetriableRequest