Statistics
| Branch: | Tag: | Revision:

root / kamaki / clients / test.py @ 27abfa9f

History | View | Annotate | Download (7.3 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, this list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this 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 makeSuite, TestSuite, TextTestRunner, TestCase
35
from time import sleep
36
from inspect import getmembers, isclass
37
from json import loads
38

    
39
from kamaki.clients.connection.test import (
40
    KamakiConnection,
41
    KamakiHTTPConnection,
42
    KamakiResponse,
43
    KamakiHTTPResponse)
44
from kamaki.clients.utils.test import Utils
45
from kamaki.clients.astakos.test import Astakos
46
from kamaki.clients.compute.test import Compute, ComputeRest
47
from kamaki.clients.cyclades.test import Cyclades, CycladesRest
48
from kamaki.clients.image.test import Image
49
from kamaki.clients.storage.test import Storage
50
from kamaki.clients.pithos.test import Pithos, PithosRest
51

    
52

    
53
class ClientError(TestCase):
54

    
55
    def test___init__(self):
56
        from kamaki.clients import ClientError
57
        for msg, status, details, exp_msg, exp_status, exp_details in (
58
                ('some msg', 42, 0.28, 0, 0, 0),
59
                ('some msg', 'fail', [], 0, 0, 0),
60
                ('some msg', 42, 'details on error', 0, 0, 0),
61
                (
62
                    '404 {"ExampleError":'
63
                    ' {"message": "a msg", "code": 42, "details": "dets"}}',
64
                    404,
65
                    0,
66
                    '404 ExampleError (a msg)\n',
67
                    42,
68
                    ['dets']),
69
                (
70
                    '404 {"ExampleError":'
71
                    ' {"message": "a msg", "code": 42}}',
72
                    404,
73
                    'details on error',
74
                    '404 ExampleError (a msg)\n',
75
                    42,
76
                    0),
77
                (
78
                    '404 {"ExampleError":'
79
                    ' {"details": "Explain your error"}}',
80
                    404,
81
                    'details on error',
82
                    '404 ExampleError',
83
                    0,
84
                    ['details on error', 'Explain your error']),
85
                ('some msg\n', -10, ['details', 'on', 'error'], 0, 0, 0)):
86
            ce = ClientError(msg, status, details)
87
            exp_msg = exp_msg or (msg if msg.endswith('\n') else msg + '\n')
88
            exp_status = exp_status or status
89
            exp_details = exp_details or details
90
            self.assertEqual('%s' % ce, exp_msg)
91
            self.assertEqual(
92
                exp_status if isinstance(exp_status, int) else 0,
93
                ce.status)
94
            self.assertEqual(exp_details, ce.details)
95

    
96

    
97
class SilentEvent(TestCase):
98

    
99
    def thread_content(self, methodid, raiseException=0):
100
        wait = 0.1
101
        self.can_finish = -1
102
        while self.can_finish < methodid and wait < 4:
103
            sleep(wait)
104
            wait = 2 * wait
105
        if raiseException and raiseException == methodid:
106
            raise Exception('Some exception')
107
        self._value = methodid
108
        self.assertTrue(wait < 4)
109

    
110
    def setUp(self):
111
        from kamaki.clients import SilentEvent
112
        self.SE = SilentEvent
113

    
114
    def test_run(self):
115
        threads = [self.SE(self.thread_content, i) for i in range(4)]
116
        for t in threads:
117
            t.start()
118

    
119
        for i in range(4):
120
            self.assertTrue(threads[i].is_alive())
121
            self.can_finish = i
122
            threads[i].join()
123
            self.assertFalse(threads[i].is_alive())
124

    
125
    def test_value(self):
126
        threads = [self.SE(self.thread_content, i) for i in range(4)]
127
        for t in threads:
128
            t.start()
129

    
130
        for mid, t in enumerate(threads):
131
            if t.is_alive():
132
                self.can_finish = mid
133
                continue
134
            self.assertTrue(mid, t.value)
135

    
136
    def test_exception(self):
137
        threads = [self.SE(self.thread_content, i, (i % 2)) for i in range(4)]
138
        for t in threads:
139
            t.start()
140

    
141
        for i, t in enumerate(threads):
142
            if t.is_alive():
143
                self.can_finish = i
144
                continue
145
            if i % 2:
146
                self.assertTrue(isinstance(t.exception, Exception))
147
            else:
148
                self.assertFalse(t.exception)
149

    
150

    
151
#  TestCase auxiliary methods
152

    
153
def runTestCase(cls, test_name, args=[], failure_collector=[]):
154
    """
155
    :param cls: (TestCase) a set of Tests
156

157
    :param test_name: (str)
158

159
    :param args: (list) these are prefixed with test_ and used as params when
160
        instantiating cls
161

162
    :param failure_collector: (list) collects info of test failures
163

164
    :returns: (int) total # of run tests
165
    """
166
    suite = TestSuite()
167
    if args:
168
        suite.addTest(cls('_'.join(['test'] + args)))
169
    else:
170
        suite.addTest(makeSuite(cls))
171
    print('* Test * %s *' % test_name)
172
    r = TextTestRunner(verbosity=2).run(suite)
173
    failure_collector += r.failures
174
    return r.testsRun
175

    
176

    
177
def _add_value(foo, value):
178
    def wrap(self):
179
        return foo(self, value)
180
    return wrap
181

    
182

    
183
def get_test_classes(module=__import__(__name__), name=''):
184
    module_stack = [module]
185
    while module_stack:
186
        module = module_stack[-1]
187
        module_stack = module_stack[:-1]
188
        for objname, obj in getmembers(module):
189
            if (objname == name or not name):
190
                if isclass(obj) and objname != 'TestCase' and (
191
                        issubclass(obj, TestCase)):
192
                    yield (obj, objname)
193

    
194

    
195
def main(argv):
196
    found = False
197
    failure_collector = list()
198
    num_of_tests = 0
199
    for cls, name in get_test_classes(name=argv[1] if len(argv) > 1 else ''):
200
        found = True
201
        num_of_tests += runTestCase(cls, name, argv[2:], failure_collector)
202
    if not found:
203
        print('Test "%s" not found' % ' '.join(argv[1:]))
204
    else:
205
        for i, failure in enumerate(failure_collector):
206
            print('Failure %s: ' % (i + 1))
207
            for field in failure:
208
                print('\t%s' % field)
209
        print('\nTotal tests run: %s' % num_of_tests)
210
        print('Total failures: %s' % len(failure_collector))
211

    
212

    
213
if __name__ == '__main__':
214
    from sys import argv
215
    main(argv)