Revision 3c50df2e

b/docs/developers/extending-clients-api.rst
131 131

  
132 132
    $ python test.py Client request
133 133

  
134
Each package contains a test module (test.py) which is also runnable from the command line. E.g. the pithos package contains a Pithos test which contains, among others, the download sub-test:
134
Each package contains a test module (test.py) which is also runnable from the command line. E.g. in the pithos package there is a test module which contains, among others, the **download** sub-test:
135 135

  
136 136
.. code-block:: console
137 137

  
......
146 146
    # Test kamaki.clients.pithos.PithosClient.download
147 147
    $ python test.py Pithos download
148 148

  
149
To fully test a specific package, run test.py from the package location. E.g. to test everything in kamaki.clients.pithos package:
150

  
151
.. code-block:: console
152

  
153
    $ cd pithos
154
    $ python test.py
155

  
149 156
Mechanism
150 157
^^^^^^^^^
151 158

  
152 159
Each folder / package contains a test.py file, that represents the test module of this package. All test modules contain a set of classes that extent the TestCase class. They also contain a main method to run the tests.
153 160

  
154
All classes in the tested package are tested by similarly-named classes in the test module. Methods that do no belong to a class are tested by testing classes named after the module tested methods belong to.
155

  
156
For example, the kamaki.clients.pithos.PithosClient class is tested by the kamaki.clients.pithos.test.Pithos class, which the method in the kamaki.clients.utils module are tested by the kamaki.clients.utils.test.Utils testing class.
161
By convention, testing classes are named as <Tested Class> where <Test Class> is the name of the tested class or module. Methods not grouped in classes are tested by classes named after their respective module.
157 162

  
163
For example, the kamaki.clients.pithos.PithosClient class is tested by the kamaki.clients.pithos.test.PithosClient class, while the methods in kamaki.clients.utils module are tested by the kamaki.clients.utils.test.Utils testing class.
158 164

  
159 165
Adding unit tests
160 166
^^^^^^^^^^^^^^^^^
161
After modifying or extending kamaki.clients method, classes, modules or packages, it is a good practice to also modify or extend the corresponding unit tests. What's more, it is recommended to modify or implement the tests that test the new behavior, before implementing the behavior itself.
167
After modifying or extending kamaki.clients method, classes, modules or packages, it is a good practice to also modify or extend the corresponding unit tests. What's more, it is recommended to modify or implement the testing of new behavior before implementing the behavior itself. The aim for kamaki.clients package is an 1 to 1 mapping between methods and their tests.
162 168

  
163 169
Modifying an existing method
164 170
""""""""""""""""""""""""""""
......
167 173

  
168 174
Example 1: to modify the kamaki.clients.utils.filter_in method, the programmer has to also adjust the kamaki.clients.utils.test.Utils.test_filter_in method.
169 175

  
170
Example 2: to modify the kamaki.clients.pithos.PithosRestClient.object_get, the programmer has to also adjust the kamaki.clients.pithos.test.PithosRest.test_object_get method.
176
Example 2: to modify the kamaki.clients.pithos.PithosRestClient.object_get, the programmer has to also adjust the kamaki.clients.pithos.test.PithosRestClient.test_object_get method.
171 177

  
172 178
Adding a new method
173 179
"""""""""""""""""""
174 180

  
175
Programmers who want to implement a new method in an existing class, are encouraged to implement the corresponding unit test first. In order to do that, they should first find the testing class that is mapped to the class they need to extend.
181
Programmers who want to implement a new method in an existing class, are encouraged to implement the corresponding unit test first. In order to do that, they should find the testing class that is mapped to the class or module they need to extend.
176 182

  
177
Example 1: To add a **list_special** method to kamaki.clients.astakos.AstakosClient, extend the kamaki.clients.astakos.test.Astakos test class, as shown bellow:
183
Example 1: To add a **list_special** method to kamaki.clients.astakos.AstakosClient, extend the kamaki.clients.astakos.test.AstakosClient class, as shown bellow:
178 184

  
179 185
.. code-block:: python
180 186

  
181
    class Astakos(TestCase):
187
    # file: ${kamaki}/kamaki/clients/astakos/__init__.py
188

  
189
    class AstakosClient(TestCase):
182 190
        ...
183 191
        def test_list_special(self):
184 192
            """Test the list_special method"""
......
188 196

  
189 197
.. code-block:: python
190 198

  
199
    # file: ${kamaki}/kamaki/clients/utils/__init__.py
200

  
191 201
    class Utils(TestCase):
192 202
        ...
193 203
        def test_get_random_int(self):
......
199 209

  
200 210
Each class or module needs a seperate test sub-module. By convention, each class or module under the kamaki.clients should be located in a separate directory.
201 211

  
202
Example 1: To add a NewService class, that extents the kamaki.clients.Client interface: 
212
Example 1: To add a NewService class that implements the kamaki.clients.Client interface: 
203 213

  
204 214
* create a new_service package and implement the unit tests in the kamaki.clients.new_service.test module:
205 215

  
......
217 227

  
218 228
.. code-block:: python
219 229

  
230
    # file: ${kamaki}/kamaki/clients/new_service/test.py
220 231
    from unittest import TestCase
221 232

  
222
    class NewServiceTest(TestCase):
233
    class NewService(TestCase):
223 234

  
224 235
        def test_method1(self):
225 236
            ...
......
228 239

  
229 240
.. code-block:: python
230 241

  
242
    # file: ${kamaki}/kamaki/clients/new_service/__init__.py
231 243
    from kamaki.clients import Client
232 244

  
233 245
    class NewService(Client):
......
239 251

  
240 252
..code-block:: python
241 253

  
242
    # kamaki.clients.test module
243
    ...
254
    # file: ${kamaki}/kamaki/clients/test.py
255

  
244 256
    from kamaki.clients.new_service.test import NewService
245 257

  
246
.. note:: If the new class or module is part of an existing sub-package, it is best to append its testing class in the existing test.py file of the sub-package it belongs to. For example, the kamaki.clients.pithos.PithosClient and kamaki.clients.pithos.rest_api.PithosRestClient classes are tested by two different classes (Pithos and PithosRest) in the same module (kamaki.clients.pithos.test).
258
.. note:: If the new class or module is part of an existing sub-package, it is acceptable to append its testing class in the existing test.py file of the sub-package it belongs to. For example, the kamaki.clients.pithos.PithosClient and kamaki.clients.pithos.rest_api.PithosRestClient classes are tested by two different classes (PithosClient and PithosRestClient respectively) in the same module (kamaki.clients.pithos.test).
247 259

  
b/kamaki/clients/astakos/test.py
32 32
# or implied, of GRNET S.A.
33 33

  
34 34
from mock import patch, call
35

  
36 35
from unittest import TestCase
37
from kamaki.clients.astakos import AstakosClient
36

  
37
from kamaki.clients import astakos
38 38

  
39 39

  
40 40
example = dict(
......
69 69
astakos_pkg = 'kamaki.clients.astakos.AstakosClient'
70 70

  
71 71

  
72
class Astakos(TestCase):
72
class AstakosClient(TestCase):
73 73

  
74 74
    cached = False
75 75

  
76 76
    def setUp(self):
77 77
        self.url = 'https://astakos.example.com'
78 78
        self.token = 'ast@k0sT0k3n=='
79
        self.client = AstakosClient(self.url, self.token)
79
        self.client = astakos.AstakosClient(self.url, self.token)
80 80

  
81 81
    def tearDown(self):
82 82
        FR.json = example
......
121 121
if __name__ == '__main__':
122 122
    from sys import argv
123 123
    from kamaki.clients.test import runTestCase
124
    runTestCase(Astakos, 'AstakosClient', argv[1:])
124
    runTestCase(AstakosClient, 'AstakosClient', argv[1:])
b/kamaki/clients/compute/test.py
36 36
from itertools import product
37 37
from json import dumps
38 38

  
39
from kamaki.clients.compute import ComputeClient, ComputeRestClient
40
from kamaki.clients import ClientError
39
from kamaki.clients import ClientError, compute
41 40

  
42 41

  
43 42
rest_pkg = 'kamaki.clients.compute.rest_api.ComputeRestClient'
......
111 110
        pass
112 111

  
113 112

  
114
class ComputeRest(TestCase):
113
class ComputeRestClient(TestCase):
115 114

  
116 115
    """Set up a ComputesRest thorough test"""
117 116
    def setUp(self):
118 117
        self.url = 'http://cyclades.example.com'
119 118
        self.token = 'cyc14d3s70k3n'
120
        self.client = ComputeRestClient(self.url, self.token)
119
        self.client = compute.ComputeRestClient(self.url, self.token)
121 120

  
122 121
    def tearDown(self):
123 122
        FR.json = vm_recv
......
232 231
        self._test_put('images')
233 232

  
234 233

  
235
class Compute(TestCase):
234
class ComputeClient(TestCase):
236 235

  
237 236
    def assert_dicts_are_equal(self, d1, d2):
238 237
        for k, v in d1.items():
......
246 245
    def setUp(self):
247 246
        self.url = 'http://cyclades.example.com'
248 247
        self.token = 'cyc14d3s70k3n'
249
        self.client = ComputeClient(self.url, self.token)
248
        self.client = compute.ComputeClient(self.url, self.token)
250 249

  
251 250
    def tearDown(self):
252 251
        FR.status_code = 200
......
257 256
        return_value=img_recv['image'])
258 257
    def test_create_server(self, GID):
259 258
        with patch.object(
260
                ComputeClient, 'servers_post',
259
                compute.ComputeClient, 'servers_post',
261 260
                side_effect=ClientError(
262 261
                    'REQUEST ENTITY TOO LARGE',
263 262
                    status=403)):
......
267 266
                vm_name, fid, img_ref)
268 267

  
269 268
        with patch.object(
270
                ComputeClient, 'servers_post',
269
                compute.ComputeClient, 'servers_post',
271 270
                return_value=FR()) as post:
272 271
            r = self.client.create_server(vm_name, fid, img_ref)
273 272
            self.assertEqual(r, FR.json['server'])
......
444 443
    from sys import argv
445 444
    from kamaki.clients.test import runTestCase
446 445
    not_found = True
447
    if not argv[1:] or argv[1] == 'Compute':
446
    if not argv[1:] or argv[1] == 'ComputeClient':
448 447
        not_found = False
449
        runTestCase(Compute, 'Compute Client', argv[2:])
448
        runTestCase(ComputeClient, 'Compute Client', argv[2:])
450 449
    if not argv[1:] or argv[1] == 'ComputeRest':
451 450
        not_found = False
452
        runTestCase(ComputeRest, 'ComputeRest Client', argv[2:])
451
        runTestCase(ComputeRestClient, 'ComputeRest Client', argv[2:])
453 452
    if not_found:
454 453
        print('TestCase %s not found' % argv[1])
b/kamaki/clients/cyclades/test.py
30 30
# documentation are those of the authors and should not be
31 31
# interpreted as representing official policies, either expressed
32 32
# or implied, of GRNET S.A.
33

  
33 34
from mock import patch, call
34 35
from unittest import TestCase
35 36
from itertools import product
36 37

  
37
from kamaki.clients import ClientError
38
from kamaki.clients.cyclades import CycladesClient, CycladesRestClient
38
from kamaki.clients import ClientError, cyclades
39 39

  
40 40
img_ref = "1m4g3-r3f3r3nc3"
41 41
vm_name = "my new VM"
......
94 94
cyclades_pkg = 'kamaki.clients.cyclades.CycladesClient'
95 95

  
96 96

  
97
class CycladesRest(TestCase):
97
class CycladesRestClient(TestCase):
98 98

  
99 99
    """Set up a Cyclades thorough test"""
100 100
    def setUp(self):
101 101
        self.url = 'http://cyclades.example.com'
102 102
        self.token = 'cyc14d3s70k3n'
103
        self.client = CycladesRestClient(self.url, self.token)
103
        self.client = cyclades.CycladesRestClient(self.url, self.token)
104 104

  
105 105
    def tearDown(self):
106 106
        FR.json = vm_recv
......
208 208
                **kwargs))
209 209

  
210 210

  
211
class Cyclades(TestCase):
211
class CycladesClient(TestCase):
212 212

  
213 213
    def assert_dicts_are_equal(self, d1, d2):
214 214
        for k, v in d1.items():
......
222 222
    def setUp(self):
223 223
        self.url = 'http://cyclades.example.com'
224 224
        self.token = 'cyc14d3s70k3n'
225
        self.client = CycladesClient(self.url, self.token)
225
        self.client = cyclades.CycladesClient(self.url, self.token)
226 226

  
227 227
    def tearDown(self):
228 228
        FR.status_code = 200
......
272 272
        vm_id = vm_recv['server']['id']
273 273
        v = firewalls['attachments']['values'][0]['firewallProfile']
274 274
        with patch.object(
275
                CycladesClient, 'get_server_details',
275
                cyclades.CycladesClient, 'get_server_details',
276 276
                return_value=firewalls) as GSD:
277 277
            r = self.client.get_firewall_profile(vm_id)
278 278
            GSD.assert_called_once_with(vm_id)
279 279
            self.assertEqual(r, v)
280 280
        with patch.object(
281
                CycladesClient, 'get_server_details',
281
                cyclades.CycladesClient, 'get_server_details',
282 282
                return_value=dict()):
283 283
            self.assertRaises(
284 284
                ClientError,
......
344 344
            dict(id='another-nic-id', network_id='another-net-id'),
345 345
            dict(id=nic_id * 2, network_id=net_id * 2)]
346 346
        with patch.object(
347
                CycladesClient,
347
                cyclades.CycladesClient,
348 348
                'list_server_nics',
349 349
                return_value=vm_nics) as LSN:
350 350
            r = self.client.disconnect_server(vm_id, nic_id)
......
392 392
        net_id = net_recv['network']['id']
393 393
        nics = ['nic1', 'nic2', 'nic3']
394 394
        with patch.object(
395
                CycladesClient,
395
                cyclades.CycladesClient,
396 396
                'list_network_nics',
397 397
                return_value=nics) as LNN:
398 398
            self.client.disconnect_network_nics(net_id)
......
422 422
    def test_delete_network(self):
423 423
        net_id = net_recv['network']['id']
424 424
        with patch.object(
425
                CycladesClient, 'networks_delete',
425
                cyclades.CycladesClient, 'networks_delete',
426 426
                return_value=FR()) as ND:
427 427
            self.client.delete_network(net_id)
428 428
            ND.assert_called_once_with(net_id)
429 429
        with patch.object(
430
                CycladesClient, 'networks_delete',
430
                cyclades.CycladesClient, 'networks_delete',
431 431
                side_effect=ClientError('A 421 Error', 421)):
432 432
            try:
433 433
                self.client.delete_network(421)
......
441 441
    from sys import argv
442 442
    from kamaki.clients.test import runTestCase
443 443
    not_found = True
444
    if not argv[1:] or argv[1] == 'Cyclades':
444
    if not argv[1:] or argv[1] == 'CycladesClient':
445 445
        not_found = False
446
        runTestCase(Cyclades, 'Cyclades Client', argv[2:])
447
    if not argv[1:] or argv[1] == 'CycladesRest':
446
        runTestCase(CycladesClient, 'Cyclades Client', argv[2:])
447
    if not argv[1:] or argv[1] == 'CycladesRestClient':
448 448
        not_found = False
449
        runTestCase(CycladesRest, 'CycladesRest Client', argv[2:])
449
        runTestCase(CycladesRestClient, 'CycladesRest Client', argv[2:])
450 450
    if not_found:
451 451
        print('TestCase %s not found' % argv[1])
b/kamaki/clients/image/test.py
138 138
image_pkg = 'kamaki.clients.image.ImageClient'
139 139

  
140 140

  
141
class Image(TestCase):
141
class ImageClient(TestCase):
142 142

  
143 143
    def assert_dicts_are_equal(self, d1, d2):
144 144
        for k, v in d1.items():
......
151 151
    def setUp(self):
152 152
        self.url = 'http://image.example.com'
153 153
        self.token = 'an1m@g370k3n=='
154
        from kamaki.clients.image import ImageClient
155
        self.client = ImageClient(self.url, self.token)
154
        from kamaki.clients import image
155
        self.client = image.ImageClient(self.url, self.token)
156 156

  
157 157
    def tearDown(self):
158 158
        FR.json = example_images
......
263 263
if __name__ == '__main__':
264 264
    from sys import argv
265 265
    from kamaki.clients.test import runTestCase
266
    runTestCase(Image, 'Plankton Client', argv[1:])
266
    runTestCase(ImageClient, 'Plankton Client', argv[1:])
b/kamaki/clients/pithos/test.py
43 43
except ImportError:
44 44
    from kamaki.clients.commisioning.utils.ordereddict import OrderedDict
45 45

  
46
from kamaki.clients import ClientError
47
from kamaki.clients.pithos import PithosClient, PithosRestClient
46
from kamaki.clients import pithos, ClientError
48 47

  
49 48

  
50 49
rest_pkg = 'kamaki.clients.pithos.rest_api.PithosRestClient'
......
158 157
        pass
159 158

  
160 159

  
161
class PithosRest(TestCase):
160
class PithosRestClient(TestCase):
162 161

  
163 162
    def setUp(self):
164 163
        self.url = 'https://www.example.com/pithos'
165 164
        self.token = 'p17h0570k3n'
166
        self.client = PithosRestClient(self.url, self.token)
165
        self.client = pithos.PithosRestClient(self.url, self.token)
167 166
        self.client.account = user_id
168 167
        self.client.container = 'c0nt@1n3r_i'
169 168

  
......
741 740
                **kwargs))
742 741

  
743 742

  
744
class Pithos(TestCase):
743
class PithosClient(TestCase):
745 744

  
746 745
    files = []
747 746

  
......
767 766
    def setUp(self):
768 767
        self.url = 'https://www.example.com/pithos'
769 768
        self.token = 'p17h0570k3n'
770
        self.client = PithosClient(self.url, self.token)
769
        self.client = pithos.PithosClient(self.url, self.token)
771 770
        self.client.account = user_id
772 771
        self.client.container = 'c0nt@1n3r_i'
773 772

  
......
927 926
        FR.headers = object_info
928 927
        version = 'v3r510n'
929 928
        with patch.object(
930
                PithosClient, 'object_head',
929
                pithos.PithosClient, 'object_head',
931 930
                return_value=FR()) as head:
932 931
            r = self.client.get_object_info(obj)
933 932
            self.assertEqual(r, object_info)
......
936 935
                call(obj, version=None),
937 936
                call(obj, version=version)])
938 937
        with patch.object(
939
                PithosClient, 'object_head',
938
                pithos.PithosClient, 'object_head',
940 939
                side_effect=ClientError('Obj not found', 404)):
941 940
            self.assertRaises(
942 941
                ClientError,
......
1174 1173
        FR.json = object_hashmap
1175 1174
        for empty in (304, 412):
1176 1175
            with patch.object(
1177
                    PithosClient, 'object_get',
1176
                    pithos.PithosClient, 'object_get',
1178 1177
                    side_effect=ClientError('Empty', status=empty)):
1179 1178
                r = self.client.get_object_hashmap(obj)
1180 1179
                self.assertEqual(r, {})
......
1194 1193
            if_unmodified_since='some date here',
1195 1194
            data_range='10-20')
1196 1195
        with patch.object(
1197
                PithosClient, 'object_get',
1196
                pithos.PithosClient, 'object_get',
1198 1197
                return_value=FR()) as get:
1199 1198
            r = self.client.get_object_hashmap(obj)
1200 1199
            self.assertEqual(r, object_hashmap)
......
1234 1233
    def test_get_account_meta(self):
1235 1234
        key = 'x-account-meta-'
1236 1235
        with patch.object(
1237
                PithosClient, 'get_account_info',
1236
                pithos.PithosClient, 'get_account_info',
1238 1237
                return_value=account_info):
1239 1238
            r = self.client.get_account_meta()
1240 1239
            keys = [k for k in r if k.startswith(key)]
......
1244 1243
        acc_info['%sk2' % key] = 'v2'
1245 1244
        acc_info['%sk3' % key] = 'v3'
1246 1245
        with patch.object(
1247
                PithosClient, 'get_account_info',
1246
                pithos.PithosClient, 'get_account_info',
1248 1247
                return_value=acc_info):
1249 1248
            r = self.client.get_account_meta()
1250 1249
            for k in [k for k in acc_info if k.startswith(key)]:
......
1253 1252
    def test_get_account_group(self):
1254 1253
        key = 'x-account-group-'
1255 1254
        with patch.object(
1256
                PithosClient, 'get_account_info',
1255
                pithos.PithosClient, 'get_account_info',
1257 1256
                return_value=account_info):
1258 1257
            r = self.client.get_account_group()
1259 1258
            keys = [k for k in r if k.startswith(key)]
......
1263 1262
        acc_info['%sk2' % key] = 'g2'
1264 1263
        acc_info['%sk3' % key] = 'g3'
1265 1264
        with patch.object(
1266
                PithosClient, 'get_account_info',
1265
                pithos.PithosClient, 'get_account_info',
1267 1266
                return_value=acc_info):
1268 1267
            r = self.client.get_account_group()
1269 1268
            for k in [k for k in acc_info if k.startswith(key)]:
......
1330 1329
        container_plus[key] = metaval
1331 1330
        for ret in ((container_info, {}), (container_plus, {key: metaval})):
1332 1331
            with patch.object(
1333
                    PithosClient,
1332
                    pithos.PithosClient,
1334 1333
                    'get_container_info',
1335 1334
                    return_value=ret[0]) as GCI:
1336 1335
                for until in (None, somedate):
......
1348 1347
                (container_info, {key: ''}),
1349 1348
                (container_plus, {key: metaval})):
1350 1349
            with patch.object(
1351
                    PithosClient,
1350
                    pithos.PithosClient,
1352 1351
                    'get_container_info',
1353 1352
                    return_value=ret[0]) as GCI:
1354 1353
                for until in (None, somedate):
......
1403 1402
        val = 'pubL1c'
1404 1403
        oinfo['x-object-public'] = val
1405 1404
        with patch.object(
1406
                PithosClient, 'get_object_info',
1405
                pithos.PithosClient, 'get_object_info',
1407 1406
                return_value=oinfo) as GOF:
1408 1407
            r = self.client.publish_object(obj)
1409 1408
            self.assertEqual(
......
1423 1422
        info['x-object-sharing'] = '; '.join(
1424 1423
            ['%s=%s' % (k, v) for k, v in expected.items()])
1425 1424
        with patch.object(
1426
                PithosClient, 'get_object_info',
1425
                pithos.PithosClient, 'get_object_info',
1427 1426
                return_value=info) as GOF:
1428 1427
            r = self.client.get_object_sharing(obj)
1429 1428
            self.assertEqual(GOF.mock_calls[-1], call(obj))
......
1529 1528
        info['content-length'] = file_size
1530 1529
        block_size = container_info['x-container-block-size']
1531 1530
        with patch.object(
1532
                PithosClient, 'get_object_info',
1531
                pithos.PithosClient, 'get_object_info',
1533 1532
                return_value=info) as GOI:
1534 1533
            for start, end in (
1535 1534
                    (0, file_size + 1),
......
1606 1605
    from sys import argv
1607 1606
    from kamaki.clients.test import runTestCase
1608 1607
    not_found = True
1609
    if not argv[1:] or argv[1] == 'Pithos':
1608
    if not argv[1:] or argv[1] == 'PithosClient':
1610 1609
        not_found = False
1611
        runTestCase(Pithos, 'Pithos Client', argv[2:])
1612
    if not argv[1:] or argv[1] == 'PithosRest':
1610
        runTestCase(PithosClient, 'Pithos Client', argv[2:])
1611
    if not argv[1:] or argv[1] == 'PithosRestClient':
1613 1612
        not_found = False
1614
        runTestCase(PithosRest, 'PithosRest Client', argv[2:])
1613
        runTestCase(PithosRestClient, 'PithosRest Client', argv[2:])
1615 1614
    if not_found:
1616 1615
        print('TestCase %s not found' % argv[1])
b/kamaki/clients/storage/test.py
138 138
        pass
139 139

  
140 140

  
141
class Storage(TestCase):
141
class StorageClient(TestCase):
142 142

  
143 143
    files = []
144 144

  
......
413 413
if __name__ == '__main__':
414 414
    from sys import argv
415 415
    from kamaki.clients.test import runTestCase
416
    runTestCase(Storage, 'Storage Client', argv[1:])
416
    runTestCase(StorageClient, 'Storage Client', argv[1:])
b/kamaki/clients/test.py
44 44
    KamakiResponse,
45 45
    KamakiHTTPResponse)
46 46
from kamaki.clients.utils.test import Utils
47
from kamaki.clients.astakos.test import Astakos
48
from kamaki.clients.compute.test import Compute, ComputeRest
49
from kamaki.clients.cyclades.test import Cyclades, CycladesRest
50
from kamaki.clients.image.test import Image
51
from kamaki.clients.storage.test import Storage
52
from kamaki.clients.pithos.test import Pithos, PithosRest
47
from kamaki.clients.astakos.test import AstakosClient
48
from kamaki.clients.compute.test import ComputeClient, ComputeRestClient
49
from kamaki.clients.cyclades.test import CycladesClient
50
from kamaki.clients.cyclades.test import CycladesRestClient
51
from kamaki.clients.image.test import ImageClient
52
from kamaki.clients.storage.test import StorageClient
53
from kamaki.clients.pithos.test import PithosClient, PithosRestClient
53 54

  
54 55

  
55 56
class ClientError(TestCase):

Also available in: Unified diff