1
# vim: tabstop=4 shiftwidth=4 softtabstop=4
3
# Copyright 2013 OpenStack LLC
5
# Licensed under the Apache License, Version 2.0 (the "License"); you may
6
# not use this file except in compliance with the License. You may obtain
7
# a copy of the License at
9
# http://www.apache.org/licenses/LICENSE-2.0
11
# Unless required by applicable law or agreed to in writing, software
12
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
# License for the specific language governing permissions and limitations
26
from testtools import matchers
28
from keystoneclient import exceptions
29
from keystoneclient import httpclient
30
from tests import utils
33
FAKE_RESPONSE = utils.TestResponse({
35
"text": '{"hi": "there"}',
37
MOCK_REQUEST = mock.Mock(return_value=(FAKE_RESPONSE))
41
cl = httpclient.HTTPClient(username="username", password="password",
42
tenant_id="tenant", auth_url="auth_test")
46
def get_authed_client():
48
cl.management_url = "http://127.0.0.1:5000"
49
cl.auth_token = "token"
53
class FakeLog(object):
56
self.debug_log = str()
58
def warn(self, msg=None, *args, **kwargs):
59
self.warn_log = "%s\n%s" % (self.warn_log, (msg % args))
61
def debug(self, msg=None, *args, **kwargs):
62
self.debug_log = "%s\n%s" % (self.debug_log, (msg % args))
65
class ClientTest(utils.TestCase):
67
def test_unauthorized_client_requests(self):
69
self.assertRaises(exceptions.AuthorizationFailure, cl.get, '/hi')
70
self.assertRaises(exceptions.AuthorizationFailure, cl.post, '/hi')
71
self.assertRaises(exceptions.AuthorizationFailure, cl.put, '/hi')
72
self.assertRaises(exceptions.AuthorizationFailure, cl.delete, '/hi')
75
cl = get_authed_client()
77
with mock.patch.object(requests, "request", MOCK_REQUEST):
78
with mock.patch('time.time', mock.Mock(return_value=1234)):
79
resp, body = cl.get("/hi")
80
headers = {"X-Auth-Token": "token",
81
"User-Agent": httpclient.USER_AGENT}
82
MOCK_REQUEST.assert_called_with(
84
"http://127.0.0.1:5000/hi",
86
**self.TEST_REQUEST_BASE)
87
# Automatic JSON parsing
88
self.assertEqual(body, {"hi": "there"})
90
def test_get_error_with_plaintext_resp(self):
91
cl = get_authed_client()
93
fake_err_response = utils.TestResponse({
95
"text": 'Some evil plaintext string',
97
err_MOCK_REQUEST = mock.Mock(return_value=(fake_err_response))
99
with mock.patch.object(requests, "request", err_MOCK_REQUEST):
100
self.assertRaises(exceptions.BadRequest, cl.get, '/hi')
102
def test_get_error_with_json_resp(self):
103
cl = get_authed_client()
107
"title": "Error title",
108
"message": "Error message string"
111
fake_err_response = utils.TestResponse({
113
"text": json.dumps(err_response)
115
err_MOCK_REQUEST = mock.Mock(return_value=(fake_err_response))
117
with mock.patch.object(requests, "request", err_MOCK_REQUEST):
121
except exceptions.BadRequest as exc:
123
self.assertEqual(exc.message, "Error message string")
124
self.assertTrue(exc_raised, 'Exception not raised.')
127
cl = get_authed_client()
129
with mock.patch.object(requests, "request", MOCK_REQUEST):
130
cl.post("/hi", body=[1, 2, 3])
132
"X-Auth-Token": "token",
133
"Content-Type": "application/json",
134
"User-Agent": httpclient.USER_AGENT
136
MOCK_REQUEST.assert_called_with(
138
"http://127.0.0.1:5000/hi",
141
**self.TEST_REQUEST_BASE)
143
def test_forwarded_for(self):
144
ORIGINAL_IP = "10.100.100.1"
145
cl = httpclient.HTTPClient(username="username", password="password",
146
tenant_id="tenant", auth_url="auth_test",
147
original_ip=ORIGINAL_IP)
149
with mock.patch.object(requests, "request", MOCK_REQUEST):
150
res = cl.request('/', 'GET')
152
args, kwargs = MOCK_REQUEST.call_args
154
('Forwarded', "for=%s;by=%s" % (ORIGINAL_IP,
155
httpclient.USER_AGENT)),
156
kwargs['headers'].items())
158
def test_client_deprecated(self):
159
# Can resolve symbols from the keystoneclient.client module.
160
# keystoneclient.client was deprecated and renamed to
161
# keystoneclient.httpclient. This tests that keystoneclient.client
164
from keystoneclient import client
166
# These statements will raise an AttributeError if the symbol isn't
167
# defined in the module.
172
class BasicRequestTests(testtools.TestCase):
174
url = 'http://keystone.test.com/'
177
super(BasicRequestTests, self).setUp()
178
self.logger = FakeLog()
182
self.skipTest('httppretty is not installed')
186
super(BasicRequestTests, self).tearDown()
188
def request(self, method='GET', response='Test Response', status=200,
193
httpretty.register_uri(method, url, body=response, status=status)
195
return httpclient.request(url, method, debug=True,
196
logger=self.logger, **kwargs)
199
def last_request(self):
200
return httpretty.httpretty.last_request
202
def test_basic_params(self):
204
response = 'Test Response'
207
resp = self.request(method=method, status=status, response=response)
209
self.assertEqual(self.last_request.method, method)
211
self.assertThat(self.logger.debug_log, matchers.Contains('curl'))
212
self.assertThat(self.logger.debug_log, matchers.Contains('-X %s' %
214
self.assertThat(self.logger.debug_log, matchers.Contains(self.url))
216
self.assertThat(self.logger.debug_log, matchers.Contains(str(status)))
217
self.assertThat(self.logger.debug_log, matchers.Contains(response))
219
def test_headers(self):
220
headers = {'key': 'val', 'test': 'other'}
222
self.request(headers=headers)
224
for k, v in headers.iteritems():
225
self.assertEqual(self.last_request.headers[k], v)
227
for header in headers.iteritems():
228
self.assertThat(self.logger.debug_log,
229
matchers.Contains('-H "%s: %s"' % header))
233
resp = self.request(response=data)
234
self.assertThat(self.logger.debug_log, matchers.Contains('BODY:'))
235
self.assertThat(self.logger.debug_log, matchers.Contains(data))