391 lines
13 KiB
Python
391 lines
13 KiB
Python
|
# Copyright 2014 Google Inc. All rights reserved.
|
||
|
#
|
||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
# you may not use this file except in compliance with the License.
|
||
|
# You may obtain a copy of the License at
|
||
|
#
|
||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||
|
#
|
||
|
# Unless required by applicable law or agreed to in writing, software
|
||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
# See the License for the specific language governing permissions and
|
||
|
# limitations under the License.
|
||
|
|
||
|
import unittest2
|
||
|
|
||
|
|
||
|
class TestConnection(unittest2.TestCase):
|
||
|
|
||
|
def _getTargetClass(self):
|
||
|
from gcloud.connection import Connection
|
||
|
return Connection
|
||
|
|
||
|
def _makeOne(self, *args, **kw):
|
||
|
return self._getTargetClass()(*args, **kw)
|
||
|
|
||
|
def test_ctor_defaults(self):
|
||
|
conn = self._makeOne()
|
||
|
self.assertEqual(conn.credentials, None)
|
||
|
|
||
|
def test_ctor_explicit(self):
|
||
|
credentials = _Credentials()
|
||
|
self.assertEqual(credentials._create_scoped_calls, 0)
|
||
|
conn = self._makeOne(credentials)
|
||
|
self.assertEqual(credentials._create_scoped_calls, 1)
|
||
|
self.assertTrue(conn.credentials is credentials)
|
||
|
self.assertEqual(conn._http, None)
|
||
|
|
||
|
def test_ctor_explicit_http(self):
|
||
|
http = object()
|
||
|
conn = self._makeOne(http=http)
|
||
|
self.assertEqual(conn.credentials, None)
|
||
|
self.assertTrue(conn.http is http)
|
||
|
|
||
|
def test_ctor_credentials_wo_create_scoped(self):
|
||
|
credentials = object()
|
||
|
conn = self._makeOne(credentials)
|
||
|
self.assertTrue(conn.credentials is credentials)
|
||
|
self.assertEqual(conn._http, None)
|
||
|
|
||
|
def test_http_w_existing(self):
|
||
|
conn = self._makeOne()
|
||
|
conn._http = http = object()
|
||
|
self.assertTrue(conn.http is http)
|
||
|
|
||
|
def test_http_wo_creds(self):
|
||
|
import httplib2
|
||
|
conn = self._makeOne()
|
||
|
self.assertTrue(isinstance(conn.http, httplib2.Http))
|
||
|
|
||
|
def test_http_w_creds(self):
|
||
|
import httplib2
|
||
|
|
||
|
authorized = object()
|
||
|
credentials = _Credentials(authorized)
|
||
|
conn = self._makeOne(credentials)
|
||
|
self.assertTrue(conn.http is authorized)
|
||
|
self.assertTrue(isinstance(credentials._called_with, httplib2.Http))
|
||
|
|
||
|
def test_user_agent_format(self):
|
||
|
from pkg_resources import get_distribution
|
||
|
expected_ua = 'gcloud-python/{0}'.format(
|
||
|
get_distribution('gcloud').version)
|
||
|
conn = self._makeOne()
|
||
|
self.assertEqual(conn.USER_AGENT, expected_ua)
|
||
|
|
||
|
|
||
|
class TestJSONConnection(unittest2.TestCase):
|
||
|
|
||
|
def _getTargetClass(self):
|
||
|
from gcloud.connection import JSONConnection
|
||
|
return JSONConnection
|
||
|
|
||
|
def _makeOne(self, *args, **kw):
|
||
|
return self._getTargetClass()(*args, **kw)
|
||
|
|
||
|
def _makeMockOne(self, *args, **kw):
|
||
|
class MockConnection(self._getTargetClass()):
|
||
|
API_URL_TEMPLATE = '{api_base_url}/mock/{api_version}{path}'
|
||
|
API_BASE_URL = 'http://mock'
|
||
|
API_VERSION = 'vMOCK'
|
||
|
return MockConnection(*args, **kw)
|
||
|
|
||
|
def test_class_defaults(self):
|
||
|
klass = self._getTargetClass()
|
||
|
self.assertIsNone(klass.API_URL_TEMPLATE)
|
||
|
self.assertIsNone(klass.API_BASE_URL)
|
||
|
self.assertIsNone(klass.API_VERSION)
|
||
|
|
||
|
def test_ctor_defaults(self):
|
||
|
conn = self._makeOne()
|
||
|
self.assertEqual(conn.credentials, None)
|
||
|
|
||
|
def test_ctor_explicit(self):
|
||
|
credentials = _Credentials()
|
||
|
conn = self._makeOne(credentials)
|
||
|
self.assertTrue(conn.credentials is credentials)
|
||
|
|
||
|
def test_http_w_existing(self):
|
||
|
conn = self._makeOne()
|
||
|
conn._http = http = object()
|
||
|
self.assertTrue(conn.http is http)
|
||
|
|
||
|
def test_http_wo_creds(self):
|
||
|
import httplib2
|
||
|
conn = self._makeOne()
|
||
|
self.assertTrue(isinstance(conn.http, httplib2.Http))
|
||
|
|
||
|
def test_http_w_creds(self):
|
||
|
import httplib2
|
||
|
|
||
|
authorized = object()
|
||
|
credentials = _Credentials(authorized)
|
||
|
conn = self._makeOne(credentials)
|
||
|
self.assertTrue(conn.http is authorized)
|
||
|
self.assertTrue(isinstance(credentials._called_with, httplib2.Http))
|
||
|
|
||
|
def test_build_api_url_no_extra_query_params(self):
|
||
|
conn = self._makeMockOne()
|
||
|
# Intended to emulate self.mock_template
|
||
|
URI = '/'.join([
|
||
|
conn.API_BASE_URL,
|
||
|
'mock',
|
||
|
conn.API_VERSION,
|
||
|
'foo',
|
||
|
])
|
||
|
self.assertEqual(conn.build_api_url('/foo'), URI)
|
||
|
|
||
|
def test_build_api_url_w_extra_query_params(self):
|
||
|
from six.moves.urllib.parse import parse_qsl
|
||
|
from six.moves.urllib.parse import urlsplit
|
||
|
conn = self._makeMockOne()
|
||
|
uri = conn.build_api_url('/foo', {'bar': 'baz'})
|
||
|
|
||
|
scheme, netloc, path, qs, _ = urlsplit(uri)
|
||
|
self.assertEqual('%s://%s' % (scheme, netloc), conn.API_BASE_URL)
|
||
|
# Intended to emulate mock_template
|
||
|
PATH = '/'.join([
|
||
|
'',
|
||
|
'mock',
|
||
|
conn.API_VERSION,
|
||
|
'foo',
|
||
|
])
|
||
|
self.assertEqual(path, PATH)
|
||
|
parms = dict(parse_qsl(qs))
|
||
|
self.assertEqual(parms['bar'], 'baz')
|
||
|
|
||
|
def test__make_request_no_data_no_content_type_no_headers(self):
|
||
|
conn = self._makeOne()
|
||
|
URI = 'http://example.com/test'
|
||
|
http = conn._http = _Http(
|
||
|
{'status': '200', 'content-type': 'text/plain'},
|
||
|
b'',
|
||
|
)
|
||
|
headers, content = conn._make_request('GET', URI)
|
||
|
self.assertEqual(headers['status'], '200')
|
||
|
self.assertEqual(headers['content-type'], 'text/plain')
|
||
|
self.assertEqual(content, b'')
|
||
|
self.assertEqual(http._called_with['method'], 'GET')
|
||
|
self.assertEqual(http._called_with['uri'], URI)
|
||
|
self.assertEqual(http._called_with['body'], None)
|
||
|
expected_headers = {
|
||
|
'Accept-Encoding': 'gzip',
|
||
|
'Content-Length': '0',
|
||
|
'User-Agent': conn.USER_AGENT,
|
||
|
}
|
||
|
self.assertEqual(http._called_with['headers'], expected_headers)
|
||
|
|
||
|
def test__make_request_w_data_no_extra_headers(self):
|
||
|
conn = self._makeOne()
|
||
|
URI = 'http://example.com/test'
|
||
|
http = conn._http = _Http(
|
||
|
{'status': '200', 'content-type': 'text/plain'},
|
||
|
b'',
|
||
|
)
|
||
|
conn._make_request('GET', URI, {}, 'application/json')
|
||
|
self.assertEqual(http._called_with['method'], 'GET')
|
||
|
self.assertEqual(http._called_with['uri'], URI)
|
||
|
self.assertEqual(http._called_with['body'], {})
|
||
|
expected_headers = {
|
||
|
'Accept-Encoding': 'gzip',
|
||
|
'Content-Length': '0',
|
||
|
'Content-Type': 'application/json',
|
||
|
'User-Agent': conn.USER_AGENT,
|
||
|
}
|
||
|
self.assertEqual(http._called_with['headers'], expected_headers)
|
||
|
|
||
|
def test__make_request_w_extra_headers(self):
|
||
|
conn = self._makeOne()
|
||
|
URI = 'http://example.com/test'
|
||
|
http = conn._http = _Http(
|
||
|
{'status': '200', 'content-type': 'text/plain'},
|
||
|
b'',
|
||
|
)
|
||
|
conn._make_request('GET', URI, headers={'X-Foo': 'foo'})
|
||
|
self.assertEqual(http._called_with['method'], 'GET')
|
||
|
self.assertEqual(http._called_with['uri'], URI)
|
||
|
self.assertEqual(http._called_with['body'], None)
|
||
|
expected_headers = {
|
||
|
'Accept-Encoding': 'gzip',
|
||
|
'Content-Length': '0',
|
||
|
'X-Foo': 'foo',
|
||
|
'User-Agent': conn.USER_AGENT,
|
||
|
}
|
||
|
self.assertEqual(http._called_with['headers'], expected_headers)
|
||
|
|
||
|
def test_api_request_defaults(self):
|
||
|
PATH = '/path/required'
|
||
|
conn = self._makeMockOne()
|
||
|
# Intended to emulate self.mock_template
|
||
|
URI = '/'.join([
|
||
|
conn.API_BASE_URL,
|
||
|
'mock',
|
||
|
'%s%s' % (conn.API_VERSION, PATH),
|
||
|
])
|
||
|
http = conn._http = _Http(
|
||
|
{'status': '200', 'content-type': 'application/json'},
|
||
|
b'{}',
|
||
|
)
|
||
|
self.assertEqual(conn.api_request('GET', PATH), {})
|
||
|
self.assertEqual(http._called_with['method'], 'GET')
|
||
|
self.assertEqual(http._called_with['uri'], URI)
|
||
|
self.assertEqual(http._called_with['body'], None)
|
||
|
expected_headers = {
|
||
|
'Accept-Encoding': 'gzip',
|
||
|
'Content-Length': '0',
|
||
|
'User-Agent': conn.USER_AGENT,
|
||
|
}
|
||
|
self.assertEqual(http._called_with['headers'], expected_headers)
|
||
|
|
||
|
def test_api_request_w_non_json_response(self):
|
||
|
conn = self._makeMockOne()
|
||
|
conn._http = _Http(
|
||
|
{'status': '200', 'content-type': 'text/plain'},
|
||
|
b'CONTENT',
|
||
|
)
|
||
|
|
||
|
self.assertRaises(TypeError, conn.api_request, 'GET', '/')
|
||
|
|
||
|
def test_api_request_wo_json_expected(self):
|
||
|
conn = self._makeMockOne()
|
||
|
conn._http = _Http(
|
||
|
{'status': '200', 'content-type': 'text/plain'},
|
||
|
b'CONTENT',
|
||
|
)
|
||
|
self.assertEqual(conn.api_request('GET', '/', expect_json=False),
|
||
|
b'CONTENT')
|
||
|
|
||
|
def test_api_request_w_query_params(self):
|
||
|
from six.moves.urllib.parse import parse_qsl
|
||
|
from six.moves.urllib.parse import urlsplit
|
||
|
conn = self._makeMockOne()
|
||
|
http = conn._http = _Http(
|
||
|
{'status': '200', 'content-type': 'application/json'},
|
||
|
b'{}',
|
||
|
)
|
||
|
self.assertEqual(conn.api_request('GET', '/', {'foo': 'bar'}), {})
|
||
|
self.assertEqual(http._called_with['method'], 'GET')
|
||
|
uri = http._called_with['uri']
|
||
|
scheme, netloc, path, qs, _ = urlsplit(uri)
|
||
|
self.assertEqual('%s://%s' % (scheme, netloc), conn.API_BASE_URL)
|
||
|
# Intended to emulate self.mock_template
|
||
|
PATH = '/'.join([
|
||
|
'',
|
||
|
'mock',
|
||
|
conn.API_VERSION,
|
||
|
'',
|
||
|
])
|
||
|
self.assertEqual(path, PATH)
|
||
|
parms = dict(parse_qsl(qs))
|
||
|
self.assertEqual(parms['foo'], 'bar')
|
||
|
self.assertEqual(http._called_with['body'], None)
|
||
|
expected_headers = {
|
||
|
'Accept-Encoding': 'gzip',
|
||
|
'Content-Length': '0',
|
||
|
'User-Agent': conn.USER_AGENT,
|
||
|
}
|
||
|
self.assertEqual(http._called_with['headers'], expected_headers)
|
||
|
|
||
|
def test_api_request_w_data(self):
|
||
|
import json
|
||
|
DATA = {'foo': 'bar'}
|
||
|
DATAJ = json.dumps(DATA)
|
||
|
conn = self._makeMockOne()
|
||
|
# Intended to emulate self.mock_template
|
||
|
URI = '/'.join([
|
||
|
conn.API_BASE_URL,
|
||
|
'mock',
|
||
|
conn.API_VERSION,
|
||
|
'',
|
||
|
])
|
||
|
http = conn._http = _Http(
|
||
|
{'status': '200', 'content-type': 'application/json'},
|
||
|
b'{}',
|
||
|
)
|
||
|
self.assertEqual(conn.api_request('POST', '/', data=DATA), {})
|
||
|
self.assertEqual(http._called_with['method'], 'POST')
|
||
|
self.assertEqual(http._called_with['uri'], URI)
|
||
|
self.assertEqual(http._called_with['body'], DATAJ)
|
||
|
expected_headers = {
|
||
|
'Accept-Encoding': 'gzip',
|
||
|
'Content-Length': str(len(DATAJ)),
|
||
|
'Content-Type': 'application/json',
|
||
|
'User-Agent': conn.USER_AGENT,
|
||
|
}
|
||
|
self.assertEqual(http._called_with['headers'], expected_headers)
|
||
|
|
||
|
def test_api_request_w_404(self):
|
||
|
from gcloud.exceptions import NotFound
|
||
|
conn = self._makeMockOne()
|
||
|
conn._http = _Http(
|
||
|
{'status': '404', 'content-type': 'text/plain'},
|
||
|
b'{}'
|
||
|
)
|
||
|
self.assertRaises(NotFound, conn.api_request, 'GET', '/')
|
||
|
|
||
|
def test_api_request_w_500(self):
|
||
|
from gcloud.exceptions import InternalServerError
|
||
|
conn = self._makeMockOne()
|
||
|
conn._http = _Http(
|
||
|
{'status': '500', 'content-type': 'text/plain'},
|
||
|
b'{}',
|
||
|
)
|
||
|
self.assertRaises(InternalServerError, conn.api_request, 'GET', '/')
|
||
|
|
||
|
def test_api_request_non_binary_response(self):
|
||
|
conn = self._makeMockOne()
|
||
|
http = conn._http = _Http(
|
||
|
{'status': '200', 'content-type': 'application/json'},
|
||
|
u'{}',
|
||
|
)
|
||
|
result = conn.api_request('GET', '/')
|
||
|
# Intended to emulate self.mock_template
|
||
|
URI = '/'.join([
|
||
|
conn.API_BASE_URL,
|
||
|
'mock',
|
||
|
conn.API_VERSION,
|
||
|
'',
|
||
|
])
|
||
|
self.assertEqual(result, {})
|
||
|
self.assertEqual(http._called_with['method'], 'GET')
|
||
|
self.assertEqual(http._called_with['uri'], URI)
|
||
|
self.assertEqual(http._called_with['body'], None)
|
||
|
expected_headers = {
|
||
|
'Accept-Encoding': 'gzip',
|
||
|
'Content-Length': '0',
|
||
|
'User-Agent': conn.USER_AGENT,
|
||
|
}
|
||
|
self.assertEqual(http._called_with['headers'], expected_headers)
|
||
|
|
||
|
|
||
|
class _Http(object):
|
||
|
|
||
|
_called_with = None
|
||
|
|
||
|
def __init__(self, headers, content):
|
||
|
from httplib2 import Response
|
||
|
self._response = Response(headers)
|
||
|
self._content = content
|
||
|
|
||
|
def request(self, **kw):
|
||
|
self._called_with = kw
|
||
|
return self._response, self._content
|
||
|
|
||
|
|
||
|
class _Credentials(object):
|
||
|
|
||
|
_scopes = None
|
||
|
|
||
|
def __init__(self, authorized=None):
|
||
|
self._authorized = authorized
|
||
|
self._create_scoped_calls = 0
|
||
|
|
||
|
def authorize(self, http):
|
||
|
self._called_with = http
|
||
|
return self._authorized
|
||
|
|
||
|
def create_scoped_required(self):
|
||
|
self._create_scoped_calls += 1
|
||
|
return False
|