Statistics
| Branch: | Tag: | Revision:

root / kamaki / clients / livetest / __init__.py @ a8685edf

History | View | Annotate | Download (8.6 kB)

1
# Copyright 2012-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
import inspect
35
from unittest import TestCase, TestSuite, TextTestRunner
36
from argparse import ArgumentParser
37
from sys import stdout
38

    
39
from kamaki.cli.config import Config
40
from kamaki.cli.utils import spiner
41

    
42

    
43
def _add_value(foo, value):
44
    def wrap(self):
45
        return foo(self, value)
46
    return wrap
47

    
48

    
49
class Generic(TestCase):
50

    
51
    _waits = []
52
    _cnf = None
53
    _grp = None
54
    _fetched = {}
55

    
56
    def __init__(self, specific=None, config=None, group=None):
57
        super(Generic, self).__init__(specific)
58
        self._cnf = config or Config()
59
        self._grp = group
60
        self._waits.append(0.71828)
61
        for i in range(10):
62
            self._waits.append(self._waits[-1] * 2.71828)
63

    
64
    def __getitem__(self, key):
65
        key = self._key(key)
66
        try:
67
            r = self._fetched[key]
68
            return r
69
            return self._fetched[key]
70
        except KeyError:
71
            r = self._get_from_cnf(key)
72
            return r
73
            return self._get_from_cnf(key)
74

    
75
    def _key(self, key):
76
        return ('', key) if isinstance(key, str)\
77
            else ('', key[0]) if len(key) == 1\
78
            else key
79

    
80
    def _get_from_cnf(self, key):
81
        val = 0
82
        if key[0]:
83
            keystr = '%s_%s' % key
84
            val = self._cnf.get('livetest', keystr) or self._cnf.get(*key)
85
        if not val:
86
            val = self._cnf.get('livetest', key[1]) or self._cnf.get(
87
                'global',
88
                key[1])
89
        self._fetched[key] = val
90
        return val
91

    
92
    def _safe_progress_bar(self, msg):
93
        """Try to get a progress bar, but do not raise errors"""
94
        try:
95
            from progress.bar import ShadyBar
96
            wait_bar = ShadyBar(msg)
97

    
98
            def wait_gen(n):
99
                for i in wait_bar.iter(range(int(n))):
100
                    yield
101
                yield
102
            wait_cb = wait_gen
103
        except Exception:
104
            stdout.write('%s:' % msg)
105
            (wait_bar, wait_cb) = (None, spiner)
106
        return (wait_bar, wait_cb)
107

    
108
    def _safe_progress_bar_finish(self, progress_bar):
109
        try:
110
            progress_bar.finish()
111
        except Exception:
112
            print('\b DONE')
113

    
114
    def do_with_progress_bar(self, action, msg, items):
115
        if not items:
116
            print('%s: DONE' % msg)
117
            return
118
        (action_bar, action_cb) = self._safe_progress_bar(msg)
119
        action_gen = action_cb(len(items))
120
        try:
121
            action_gen.next()
122
        except Exception:
123
            pass
124
        for item in items:
125
            action(item)
126
            action_gen.next()
127
        self._safe_progress_bar_finish(action_bar)
128

    
129
    def assert_dicts_are_deeply_equal(self, d1, d2):
130
        (st1, st2) = (set(d1.keys()), set(d2.keys()))
131
        diff1 = st1.difference(st2)
132
        diff2 = st2.difference(st1)
133
        self.assertTrue(
134
            not (diff1 or diff2),
135
            'Key differences:\n\td1-d2=%s\n\td2-d1=%s' % (diff1, diff2))
136
        for k, v in d1.items():
137
            if isinstance(v, dict):
138
                self.assert_dicts_are_deeply_equal(v, d2[k])
139
            else:
140
                self.assertEqual(unicode(v), unicode(d2[k]))
141

    
142
    def test_000(self):
143
        print('')
144
        methods = [method for method in inspect.getmembers(
145
            self,
146
            predicate=inspect.ismethod) if method[0].startswith('_test_')]
147
        failures = 0
148
        for method in methods:
149
            stdout.write('Test %s ' % method[0][6:])
150
            stdout.flush()
151
            try:
152
                method[1]()
153
                print(' ...ok')
154
            except AssertionError:
155
                print('  FAIL: %s (%s)' % (method[0], method[1]))
156
                failures += 1
157
        if failures:
158
            raise AssertionError('%s failures' % failures)
159

    
160

    
161
def init_parser():
162
    parser = ArgumentParser(add_help=False)
163
    parser.add_argument(
164
        '-h', '--help',
165
        dest='help',
166
        action='store_true',
167
        default=False,
168
        help="Show this help message and exit")
169
    return parser
170

    
171

    
172
class Connection(Generic):
173

    
174
    def setUp(self):
175
        from kamaki.clients.connection import kamakicon
176
        self.conn = kamakicon.KamakiHTTPConnection
177
        self.resp = kamakicon.KamakiHTTPResponse
178
        self.rerr = kamakicon.KamakiResponseError
179
        self.url = self['store', 'url']
180
        self.token = self['store', 'token']
181

    
182
    def test_000(self):
183
        exceptions_left = 9
184
        from random import randrange
185
        from httplib import HTTPSConnection
186
        from mock import patch
187
        connection = self.conn(url=self.url)
188
        tries = 0
189
        while exceptions_left:
190
            from time import sleep
191
            sleep(0.5)
192
            tries += 1
193
            print('Try connection #%s' % tries)
194
            response = connection.perform_request('GET', async_headers={
195
                'X-Auth-Token': self.token})
196
            with patch.object(response.request, 'close', return_value=None):
197
                if randrange(2):
198
                    response.release()
199
                    #self.assertTrue(len(text) > 0)
200
                else:
201
                    print('\tRaise artificial exception (%s left)' % (
202
                        exceptions_left - 1))
203
                    with patch.object(
204
                            HTTPSConnection,
205
                            'getresponse',
206
                            side_effect=self.rerr('A random error')):
207
                        try:
208
                            response.text
209
                        except self.rerr:
210
                            exceptions_left -= 1
211
                        else:
212
                            assert False, 'Exception not raised as expected'
213
                response.request.close.assert_called_once_with()
214
            response.request.close()
215

    
216

    
217
def main(argv, config=None):
218
    suiteFew = TestSuite()
219
    if len(argv) == 0 or argv[0] == 'connection':
220
        test_method = 'test_%s' % (argv[1] if len(argv) > 1 else '000')
221
        suiteFew.addTest(Connection(test_method, config))
222
    if len(argv) == 0 or argv[0] == 'pithos':
223
        from kamaki.clients.livetest.pithos import Pithos
224
        test_method = 'test_%s' % (argv[1] if len(argv) > 1 else '000')
225
        suiteFew.addTest(Pithos(test_method, config))
226
    if len(argv) == 0 or argv[0] == 'cyclades':
227
        from kamaki.clients.livetest.cyclades import Cyclades
228
        test_method = 'test_%s' % (argv[1] if len(argv) > 1 else '000')
229
        suiteFew.addTest(Cyclades(test_method, config))
230
    if len(argv) == 0 or argv[0] == 'image':
231
        from kamaki.clients.livetest.image import Image
232
        test_method = 'test_%s' % (argv[1] if len(argv) > 1 else '000')
233
        suiteFew.addTest(Image(test_method, config))
234
    if len(argv) == 0 or argv[0] == 'astakos':
235
        from kamaki.clients.livetest.astakos import Astakos
236
        test_method = 'test_%s' % (argv[1] if len(argv) > 1 else '000')
237
        suiteFew.addTest(Astakos(test_method, config))
238

    
239
    TextTestRunner(verbosity=2).run(suiteFew)
240

    
241
if __name__ == '__main__':
242
    parser = init_parser()
243
    args, argv = parser.parse_known_args()
244
    if len(argv) > 2 or getattr(args, 'help') or len(argv) < 1:
245
        raise Exception('\tusage: livetest <group> [command]')
246
    main(argv)