Statistics
| Branch: | Tag: | Revision:

root / kamaki / clients / connection / test.py @ bcd6c6e6

History | View | Annotate | Download (12 kB)

1
# Copyright 2013 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
#
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, self.list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, self.list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
#
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.
33

    
34
from unittest import TestCase, TestSuite, makeSuite, TextTestRunner
35
from mock import Mock, patch
36
from random import randrange
37

    
38
from kamaki.clients import connection
39
from kamaki.clients.connection import errors, kamakicon
40

    
41

    
42
class KamakiConnection(TestCase):
43
    v_samples = {'title': 'value', 5: 'value'}
44
    n_samples = {'title': None, 5: None}
45
    false_samples = {None: 'value', 0: 'value'}
46

    
47
    def setUp(self):
48
        from kamaki.clients.connection import KamakiConnection as HTTPC
49
        self.conn = HTTPC()
50

    
51
    def test_poolsize(self):
52

    
53
        def set_poolsize(poolsize):
54
            self.conn.poolsize = poolsize
55

    
56
        from kamaki.clients.connection import KamakiConnection as HTTPC
57
        for poolsize in ('non integer', -10, 0):
58
            err = AssertionError
59
            self.assertRaises(err, set_poolsize, poolsize)
60
        for poolsize in (1, 100, 1024 * 1024 * 1024 * 1024):
61
            self.conn.poolsize = poolsize
62
            self.assertEquals(self.conn.poolsize, poolsize)
63
            self.assertEquals(HTTPC(poolsize=poolsize).poolsize, poolsize)
64

    
65
    def test_set_header(self):
66
        cnn = self.conn
67
        for k, v in self.v_samples.items():
68
            cnn.set_header(k, v)
69
            self.assertEquals(cnn.headers[unicode(k)], unicode(v))
70
        for k, v in self.n_samples.items():
71
            cnn.set_header(k, v)
72
            self.assertEquals(cnn.headers[unicode(k)], unicode(v))
73
        for k, v in self.false_samples.items():
74
            self.assertRaises(AssertionError, cnn.set_header, k, v)
75
        self.assertEquals(len(cnn.headers), 2)
76

    
77
    def test_set_param(self):
78
        cnn = self.conn
79
        for k, v in self.v_samples.items():
80
            cnn.set_param(k, v)
81
            self.assertEquals(cnn.params[unicode(k)], v)
82
        for k, v in self.n_samples.items():
83
            cnn.set_param(k, v)
84
            self.assertEquals(cnn.params[unicode(k)], v)
85
        for k, v in self.false_samples.items():
86
            self.assertRaises(AssertionError, cnn.set_param, k, v)
87
        self.assertEquals(len(cnn.params), 2)
88

    
89
    def test_remove_header(self):
90
        cnn = self.conn
91
        for k, v in self.v_samples.items():
92
            cnn.headers[unicode(k)] = unicode(v)
93
        for k in self.v_samples:
94
            cnn.remove_header(k)
95
            self.assertFalse(k in cnn.headers)
96

    
97
    def test_remove_param(self):
98
        cnn = self.conn
99
        for k, v in self.v_samples.items():
100
            cnn.params[unicode(k)] = unicode(v)
101
        for k in self.v_samples:
102
            cnn.remove_param(k)
103
            self.assertFalse(k in cnn.params)
104

    
105
    def test_replace_headers(self):
106
        cnn = self.conn
107
        cnn.headers = self.v_samples
108
        cnn.replace_headers({1: 'one', 2: 'two'})
109
        for k in self.v_samples:
110
            self.assertFalse(k in cnn.headers)
111

    
112
    def test_replace_params(self):
113
        cnn = self.conn
114
        cnn.params = self.v_samples
115
        cnn.replace_params({1: 'one', 2: 'two'})
116
        for k in self.v_samples:
117
            self.assertFalse(k in cnn.params)
118

    
119
    def test_reset_headers(self):
120
        cnn = self.conn
121
        cnn.headers = self.v_samples
122
        cnn.reset_headers()
123
        self.assertFalse(cnn.headers)
124

    
125
    def test_reset_params(self):
126
        cnn = self.conn
127
        cnn.params = self.v_samples
128
        cnn.reset_params()
129
        self.assertFalse(cnn.params)
130

    
131
    def test_set_url(self):
132
        self.assertFalse(self.conn.url)
133
        sample_url = 'http://example.com'
134
        self.conn.set_url(sample_url)
135
        self.assertEquals(self.conn.url, sample_url)
136

    
137
    def test_set_path(self):
138
        self.assertFalse(self.conn.path)
139
        sample_path = '/example/local/path'
140
        self.conn.set_path(sample_path)
141
        self.assertEquals(self.conn.path, sample_path)
142

    
143
    def test_set_method(self):
144
        self.assertFalse(self.conn.method)
145
        sample_method = 'GET'
146
        self.conn.set_method(sample_method)
147
        self.assertEquals(self.conn.method, sample_method)
148

    
149
    def test_perform_request(self):
150
        self.assertRaises(NotImplementedError, self.conn.perform_request)
151

    
152

    
153
class KamakiHTTPConnection(TestCase):
154

    
155
    def setUp(self):
156
        self.conn = kamakicon.KamakiHTTPConnection()
157

    
158
    def test__retrieve_connection_info(self):
159
        async_params = dict(param1='val1', param2=None, param3=42)
160
        r = self.conn._retrieve_connection_info(async_params)
161
        self.assertEquals(r, ('http', '127.0.0.1'))
162
        expected = '?%s' % '&'.join([(
163
            '%s=%s' % (k, v)) if v else (
164
            '%s' % k) for k, v in async_params.items()])
165
        self.assertEquals('http://127.0.0.1%s' % expected, self.conn.url)
166

    
167
        for schnet in (
168
            ('http', 'www.example.com'), ('https', 'www.example.com'),
169
            ('ftp', 'www.example.com'), ('ftps', 'www.example.com'),
170
            ('http', 'www.example.com/v1'), ('https', 'www.example.com/v1')):
171
            self.conn = kamakicon.KamakiHTTPConnection(url='%s://%s' % schnet)
172
            self.conn.url = '%s://%s' % schnet
173
            r = self.conn._retrieve_connection_info(async_params)
174
            if schnet[1].endswith('v1'):
175
                self.assertEquals(r, (schnet[0], schnet[1][:-3]))
176
            else:
177
                self.assertEquals(r, schnet)
178
            self.assertEquals(
179
                '%s://%s/%s' % (schnet[0], schnet[1], expected),
180
                self.conn.url)
181

    
182
    def test_perform_request(self):
183
        from httplib import HTTPConnection
184
        from objpool import http
185
        pr = self.conn.perform_request
186
        kwargs = dict(
187
            data='',
188
            method='GET',
189
            async_headers=dict(),
190
            async_params=dict())
191

    
192
        KCError = errors.KamakiConnectionError
193
        fakecon = HTTPConnection('X', 'Y')
194

    
195
        with patch.object(http, 'get_http_connection', return_value=fakecon):
196
            with patch.object(HTTPConnection, 'request', return_value=None):
197
                r = pr(**kwargs)
198
                self.assertTrue(isinstance(r, kamakicon.KamakiHTTPResponse))
199

    
200
            err = IOError('IO Error')
201
            with patch.object(HTTPConnection, 'request', side_effect=err):
202
                self.assertRaises(KCError, pr, **kwargs)
203

    
204
        err = ValueError('Cannot Establish connection')
205
        with patch.object(http, 'get_http_connection', side_effect=err):
206
            self.assertRaises(KCError, pr, **kwargs)
207

    
208
        err = Exception('Any other error')
209
        with patch.object(http, 'get_http_connection', side_effect=err):
210
            self.assertRaises(KCError, pr, **kwargs)
211

    
212

    
213
class KamakiHTTPResponse(TestCase):
214

    
215
    class fakeResponse(object):
216
        sample = 'sample string'
217
        getheaders = Mock(return_value={})
218
        read = Mock(return_value=sample)
219
        status = Mock(return_value=None)
220
        reason = Mock(return_value=None)
221

    
222
    def setUp(self):
223
        from httplib import HTTPConnection
224
        self.HTC = HTTPConnection
225
        self.FR = self.fakeResponse
226

    
227
    def test_text(self):
228
        with patch.object(self.HTC, 'getresponse', return_value=self.FR()):
229
            self.resp = kamakicon.KamakiHTTPResponse(self.HTC('X', 'Y'))
230
            self.assertEquals(self.resp.text, self.FR.sample)
231
            sample2 = 'some other string'
232
            self.resp.text = sample2
233
            self.assertNotEquals(self.resp.text, sample2)
234

    
235
    def test_json(self):
236
        with patch.object(self.HTC, 'getresponse', return_value=self.FR()):
237
            self.resp = kamakicon.KamakiHTTPResponse(self.HTC('X', 'Y'))
238
            self.assertRaises(errors.KamakiResponseError, self.resp.json)
239
            sample2 = '{"antoher":"sample", "formated":"in_json"}'
240
            with patch.object(self.FR, 'read', return_value=sample2):
241
                self.resp = kamakicon.KamakiHTTPResponse(self.HTC('X', 'Y'))
242
                from json import loads
243
                self.assertEquals(loads(sample2), self.resp.json)
244

    
245
    def test_pool_lock(self):
246
        exceptions_left = 100
247
        while exceptions_left:
248
            kre = errors.KamakiResponseError
249
            with patch.object(self.HTC, 'close', return_value=True):
250
                self.resp = kamakicon.KamakiHTTPResponse(self.HTC('X', 'Y'))
251
                if randrange(10):
252
                    with patch.object(
253
                            self.HTC,
254
                            'getresponse',
255
                            return_value=self.FR()):
256
                        self.assertEquals(self.resp.text, self.FR.sample)
257
                else:
258
                    with patch.object(
259
                            self.HTC,
260
                            'getresponse',
261
                            side_effect=kre('A random error')):
262
                        try:
263
                            self.resp.text
264
                        except kre:
265
                            exceptions_left -= 1
266
                        else:
267
                            self.assertTrue(False)
268
                self.HTC.close.assert_called_with()
269

    
270

    
271
class KamakiResponse(TestCase):
272

    
273
    def setUp(self):
274
        self.resp = connection.KamakiResponse(
275
            'Abstract class, so test with fake request (str)')
276

    
277
    def _mock_get_response(foo):
278
        def mocker(self):
279
            self.resp._get_response = Mock()
280
            foo(self)
281
        return mocker
282

    
283
    def test_release(self):
284
        self.assertRaises(NotImplementedError, self.resp.release)
285

    
286
    def test_prefetched(self):
287
        self.assertFalse(self.resp.prefetched)
288
        self.resp.prefetched = True
289
        self.assertTrue(self.resp.prefetched)
290

    
291
    @_mock_get_response
292
    def test_content(self):
293
        rsp = self.resp
294
        for cont in ('Sample Content', u'\u03c7\u03cd\u03bd\u03c9\x00'):
295
            rsp.content = cont
296
            self.assertEquals(rsp.content, cont)
297

    
298
    (
299
        test_text,
300
        test_json,
301
        test_headers,
302
        test_status,
303
        test_status_code) = 5 * (test_content,)
304

    
305
    def test_request(self):
306
        r = self.resp.request
307
        self.assertTrue(isinstance(r, str))
308

    
309

    
310
def get_test_classes(module=__import__(__name__), name=''):
311
    from inspect import getmembers, isclass
312
    for objname, obj in getmembers(module):
313
        if (objname == name or not name) and isclass(obj) and (
314
                issubclass(obj, TestCase)):
315
            yield (obj, objname)
316

    
317

    
318
def main(argv):
319
    for cls, name in get_test_classes(name=argv[1] if len(argv) > 1 else ''):
320
        args = argv[2:]
321
        suite = TestSuite()
322
        if args:
323
            suite.addTest(cls('_'.join(['test'] + args)))
324
        else:
325
            suite.addTest(makeSuite(cls))
326
        print('Test %s' % name)
327
        TextTestRunner(verbosity=2).run(suite)
328

    
329

    
330
if __name__ == '__main__':
331
    from sys import argv
332
    main(argv)