blob: d1c5cdb1b10764bc68c9fd741f6b00575322ec0e [file] [log] [blame]
# -*- coding: utf-8 -*-
# Copyright 2015 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Tests the gce module."""
from __future__ import print_function
import os
from chromite.lib import cros_test_lib
from chromite.lib import gce
from chromite.lib import osutils
from googleapiclient.errors import HttpError
from googleapiclient.http import HttpMockSequence
from oauth2client.client import GoogleCredentials
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.NetworkTest()
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.NetworkTest()
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.NetworkTest()
def testRetryOnServerErrorHttpRequest(self):
"""Tests that 500 erros 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