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

"""Unit Tests for the astakos-client module

Provides unit tests for the code implementing
the astakos client library

"""

43
import sys
44
import socket
45
import simplejson
46
47

import astakosclient
48
49
from astakosclient import AstakosClient
from astakosclient.errors import \
50
    AstakosClientException, Unauthorized, BadRequest, NotFound, \
51
    NoUserName, NoUUID
52
53

# Use backported unittest functionality if Python < 2.7
54
55
56
57
58
59
try:
    import unittest2 as unittest
except ImportError:
    if sys.version_info < (2, 7):
        raise Exception("The unittest2 package is required for Python < 2.7")
    import unittest
60
61
62
63
64
65
66


# --------------------------------------------------------------------
# Helper functions

# ----------------------------
# This functions will be used as mocked requests
67
def _request_offline(conn, method, url, **kwargs):
68
69
70
71
    """This request behaves as we were offline"""
    raise socket.gaierror


72
def _request_status_302(conn, method, url, **kwargs):
73
74
75
76
77
    """This request returns 302"""
    status = 302
    data = '<html>\r\n<head><title>302 Found</title></head>\r\n' \
        '<body bgcolor="white">\r\n<center><h1>302 Found</h1></center>\r\n' \
        '<hr><center>nginx/0.7.67</center>\r\n</body>\r\n</html>\r\n'
78
    return (data, status)
79
80


81
def _request_status_404(conn, method, url, **kwargs):
82
83
84
85
86
87
    """This request returns 404"""
    status = 404
    data = '<html><head><title>404 Not Found</title></head>' \
        '<body><h1>Not Found</h1><p>The requested URL /foo was ' \
        'not found on this server.</p><hr><address>Apache Server ' \
        'at example.com Port 80</address></body></html>'
88
    return (data, status)
89
90


91
def _request_status_401(conn, method, url, **kwargs):
92
93
94
    """This request returns 401"""
    status = 401
    data = "Invalid X-Auth-Token\n"
95
    return (data, status)
96
97


98
def _request_status_400(conn, method, url, **kwargs):
99
100
101
    """This request returns 400"""
    status = 400
    data = "Method not allowed.\n"
102
    return (data, status)
103
104


105
def _request_ok(conn, method, url, **kwargs):
106
    """This request behaves like original Astakos does"""
107
    if url[0:16] == "/im/authenticate":
108
        return _req_authenticate(conn, method, url, **kwargs)
109
    elif url[0:14] == "/user_catalogs":
110
        return _req_catalogs(conn, method, url, **kwargs)
111
    else:
112
        return _request_status_404(conn, method, url, **kwargs)
113
114


115
def _req_authenticate(conn, method, url, **kwargs):
116
    """Check if user exists and return his profile"""
117
    global user_1, user_2
118

119
    # Check input
120
    if conn.__class__.__name__ != "HTTPSConnection":
121
        return _request_status_302(conn, method, url, **kwargs)
122
123

    if method != "GET":
124
        return _request_status_400(conn, method, url, **kwargs)
125
126
127

    token = kwargs['headers']['X-Auth-Token']
    if token == token_1:
128
        user = dict(user_1)
129
    elif token == token_2:
130
        user = dict(user_2)
131
132
    else:
        # No user found
133
        return _request_status_401(conn, method, url, **kwargs)
134

135
    # Return
136
    if "usage=1" not in url:
137
        # Strip `usage' key from `user'
138
        del user['usage']
139
    return (simplejson.dumps(user), 200)
140
141


142
def _req_catalogs(conn, method, url, **kwargs):
143
    """Return user catalogs"""
144
145
    global token_1, token_2, user_1, user_2

146
    # Check input
147
    if conn.__class__.__name__ != "HTTPSConnection":
148
        return _request_status_302(conn, method, url, **kwargs)
149
150

    if method != "POST":
151
        return _request_status_400(conn, method, url, **kwargs)
152

153
154
    token = kwargs['headers']['X-Auth-Token']
    if token != token_1 and token != token_2:
155
        return _request_status_401(conn, method, url, **kwargs)
156
157
158

    # Return
    body = simplejson.loads(kwargs['body'])
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
    if 'uuids' in body:
        # Return uuid_catalog
        uuids = body['uuids']
        catalogs = {}
        if user_1['uuid'] in uuids:
            catalogs[user_1['uuid']] = user_1['username']
        if user_2['uuid'] in uuids:
            catalogs[user_2['uuid']] = user_2['username']
        return_catalog = {"displayname_catalog": {}, "uuid_catalog": catalogs}
    elif 'displaynames' in body:
        # Return displayname_catalog
        names = body['displaynames']
        catalogs = {}
        if user_1['username'] in names:
            catalogs[user_1['username']] = user_1['uuid']
        if user_2['username'] in names:
            catalogs[user_2['username']] = user_2['uuid']
        return_catalog = {"displayname_catalog": catalogs, "uuid_catalog": {}}
    else:
        return_catalog = {"displayname_catalog": {}, "uuid_catalog": {}}
179
    return (simplejson.dumps(return_catalog), 200)
180
181
182
183


# ----------------------------
# Mock the actual _doRequest
184
def _mock_request(new_requests):
185
186
187
188
189
190
191
192
193
194
195
196
197
    """Mock the actual request

    Given a list of requests to use (in rotation),
    replace the original _doRequest function with
    a new one

    """
    def _mock(conn, method, url, **kwargs):
        # Get first request
        request = _mock.requests[0]
        # Rotate requests
        _mock.requests = _mock.requests[1:] + _mock.requests[:1]
        # Use first request
198
        return request(conn, method, url, **kwargs)
199
200
201

    _mock.requests = new_requests
    # Replace `_doRequest' with our `_mock'
202
    astakosclient._do_request = _mock
203
204
205
206
207


# ----------------------------
# Local users
token_1 = "skzleaFlBl+fasFdaf24sx=="
208
user_1 = \
209
210
211
212
213
214
    {"username": "user1@example.com",
     "auth_token_created": 1359386939000,
     "name": "Example User One",
     "email": ["user1@example.com"],
     "auth_token_expires": 1361978939000,
     "id": 108,
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
     "uuid": "73917abc-abcd-477e-a1f1-1763abcdefab",
     "usage": [
         {"currValue": 42949672960,
          "display_name": "System Disk",
          "name": "cyclades.disk"},
         {"currValue": 4,
          "display_name": "CPU",
          "name": "cyclades.cpu"},
         {"currValue": 4294967296,
          "display_name": "RAM",
          "name": "cyclades.ram"},
         {"currValue": 3,
          "display_name": "VM",
          "name": "cyclades.vm"},
         {"currValue": 0,
          "display_name": "private network",
          "name": "cyclades.network.private"},
         {"currValue": 152,
          "display_name": "Storage Space",
          "name": "pithos+.diskspace"}]}
235
236

token_2 = "fasdfDSFdf98923DF+sdfk=="
237
user_2 = \
238
239
240
241
242
243
    {"username": "user2@example.com",
     "auth_token_created": 1358386938997,
     "name": "Example User Two",
     "email": ["user1@example.com"],
     "auth_token_expires": 1461998939000,
     "id": 109,
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
     "uuid": "73917bca-1234-5678-a1f1-1763abcdefab",
     "usage": [
         {"currValue": 68719476736,
          "display_name": "System Disk",
          "name": "cyclades.disk"},
         {"currValue": 1,
          "display_name": "CPU",
          "name": "cyclades.cpu"},
         {"currValue": 1073741824,
          "display_name": "RAM",
          "name": "cyclades.ram"},
         {"currValue": 2,
          "display_name": "VM",
          "name": "cyclades.vm"},
         {"currValue": 1,
          "display_name": "private network",
          "name": "cyclades.network.private"},
         {"currValue": 2341634510,
          "display_name": "Storage Space",
          "name": "pithos+.diskspace"}]}
264
265
266
267
268
269
270
271


# --------------------------------------------------------------------
# The actual tests

class TestCallAstakos(unittest.TestCase):
    """Test cases for function _callAstakos"""

272
273
274
    # ----------------------------------
    # Test the response we get if we don't have internet access
    def _offline(self, pool):
275
        global token_1
276
        _mock_request([_request_offline])
277
        try:
Ilias Tsitsimpis's avatar
Ilias Tsitsimpis committed
278
            client = AstakosClient("https://example.com", use_pool=pool)
279
            client._call_astakos(token_1, "/im/authenticate")
280
        except AstakosClientException:
281
282
            pass
        else:
283
            self.fail("Should have raised AstakosClientException")
284

285
    def test_offline(self):
286
287
288
        """Test _offline without pool"""
        self._offline(False)

289
    def test_offline_pool(self):
290
291
292
293
294
        """Test _offline using pool"""
        self._offline(True)

    # ----------------------------------
    # Test the response we get if we send invalid token
295
    def _invalid_token(self, pool):
296
        token = "skaksaFlBl+fasFdaf24sx=="
297
        _mock_request([_request_ok])
298
        try:
Ilias Tsitsimpis's avatar
Ilias Tsitsimpis committed
299
            client = AstakosClient("https://example.com", use_pool=pool)
300
            client._call_astakos(token, "/im/authenticate")
301
        except Unauthorized:
302
303
304
            pass
        except Exception:
            self.fail("Should have returned 401 (Invalid X-Auth-Token)")
305
306
307
        else:
            self.fail("Should have returned 401 (Invalid X-Auth-Token)")

308
309
310
    def test_invalid_token(self):
        """Test _invalid_token without pool"""
        self._invalid_token(False)
311

312
313
314
    def test_invalid_token_pool(self):
        """Test _invalid_token using pool"""
        self._invalid_token(True)
315
316
317

    # ----------------------------------
    # Test the response we get if we send invalid url
318
    def _invalid_url(self, pool):
319
        global token_1
320
        _mock_request([_request_ok])
321
        try:
Ilias Tsitsimpis's avatar
Ilias Tsitsimpis committed
322
            client = AstakosClient("https://example.com", use_pool=pool)
323
            client._call_astakos(token_1, "/im/misspelled")
324
        except NotFound:
325
326
327
            pass
        except Exception:
            self.fail("Should have returned 404 (Not Found)")
328
329
330
        else:
            self.fail("Should have returned 404 (Not Found)")

331
332
333
    def test_invalid_url(self):
        """Test _invalid_url without pool"""
        self._invalid_url(False)
334

335
336
337
    def test_invalid_url_pool(self):
        """Test _invalid_url using pool"""
        self._invalid_url(True)
338
339
340

    # ----------------------------------
    # Test the response we get if we use an unsupported scheme
341
    def _unsupported_scheme(self, pool):
342
        global token_1
343
        _mock_request([_request_ok])
344
        try:
Ilias Tsitsimpis's avatar
Ilias Tsitsimpis committed
345
            client = AstakosClient("ftp://example.com", use_pool=pool)
346
            client._call_astakos(token_1, "/im/authenticate")
347
        except ValueError:
348
349
            pass
        except Exception:
350
            self.fail("Should have raise ValueError Exception")
351
        else:
352
353
            self.fail("Should have raise ValueError Exception")

354
355
356
    def test_unsupported_scheme(self):
        """Test _unsupported_scheme without pool"""
        self._unsupported_scheme(False)
357

358
359
360
    def test_unsupported_scheme_pool(self):
        """Test _unsupported_scheme using pool"""
        self._unsupported_scheme(True)
361
362
363

    # ----------------------------------
    # Test the response we get if we use http instead of https
364
    def _http_scheme(self, pool):
365
        global token_1
366
        _mock_request([_request_ok])
367
        try:
Ilias Tsitsimpis's avatar
Ilias Tsitsimpis committed
368
            client = AstakosClient("http://example.com", use_pool=pool)
369
            client._call_astakos(token_1, "/im/authenticate")
370
371
        except AstakosClientException as err:
            if err.status != 302:
372
373
374
375
                self.fail("Should have returned 302 (Found)")
        else:
            self.fail("Should have returned 302 (Found)")

376
377
378
    def test_http_scheme(self):
        """Test _http_scheme without pool"""
        self._http_scheme(False)
379

380
381
382
    def test_http_scheme_pool(self):
        """Test _http_scheme using pool"""
        self._http_scheme(True)
383
384
385

    # ----------------------------------
    # Test the response we get if we use authenticate with POST
386
    def _post_authenticate(self, pool):
387
        global token_1
388
        _mock_request([_request_ok])
389
        try:
Ilias Tsitsimpis's avatar
Ilias Tsitsimpis committed
390
            client = AstakosClient("https://example.com", use_pool=pool)
391
            client._call_astakos(token_1, "/im/authenticate", method="POST")
392
        except BadRequest:
393
394
395
            pass
        except Exception:
            self.fail("Should have returned 400 (Method not allowed)")
396
397
398
        else:
            self.fail("Should have returned 400 (Method not allowed)")

399
400
401
    def test_post_authenticate(self):
        """Test _post_authenticate without pool"""
        self._post_authenticate(False)
402

403
404
405
    def test_post_authenticate_pool(self):
        """Test _post_authenticate using pool"""
        self._post_authenticate(True)
406

407
408
    # ----------------------------------
    # Test the response if we request user_catalogs with GET
409
    def _get_user_catalogs(self, pool):
410
        global token_1
411
        _mock_request([_request_ok])
412
        try:
Ilias Tsitsimpis's avatar
Ilias Tsitsimpis committed
413
            client = AstakosClient("https://example.com", use_pool=pool)
414
            client._call_astakos(token_1, "/user_catalogs")
415
        except BadRequest:
416
417
418
            pass
        except Exception:
            self.fail("Should have returned 400 (Method not allowed)")
419
420
421
        else:
            self.fail("Should have returned 400 (Method not allowed)")

422
423
424
    def test_get_user_catalogs(self):
        """Test _get_user_catalogs without pool"""
        self._get_user_catalogs(False)
425

426
427
428
    def test_get_user_catalogs_pool(self):
        """Test _get_user_catalogs using pool"""
        self._get_user_catalogs(True)
429

430

431
class TestAuthenticate(unittest.TestCase):
432
    """Test cases for function getUserInfo"""
433
434
435

    # ----------------------------------
    # Test the response we get if we don't have internet access
436
    def test_offline(self):
437
438
        """Test offline after 3 retries"""
        global token_1
439
        _mock_request([_request_offline])
440
        try:
Ilias Tsitsimpis's avatar
Ilias Tsitsimpis committed
441
            client = AstakosClient("https://example.com", retry=3)
442
            client.get_user_info(token_1)
443
444
445
446
447
448
449
        except AstakosClientException:
            pass
        else:
            self.fail("Should have raised AstakosClientException exception")

    # ----------------------------------
    # Test the response we get for invalid token
450
    def _invalid_token(self, pool):
451
        token = "skaksaFlBl+fasFdaf24sx=="
452
        _mock_request([_request_ok])
453
        try:
Ilias Tsitsimpis's avatar
Ilias Tsitsimpis committed
454
            client = AstakosClient("https://example.com", use_pool=pool)
455
            client.get_user_info(token)
456
        except Unauthorized:
457
458
459
            pass
        except Exception:
            self.fail("Should have returned 401 (Invalid X-Auth-Token)")
460
        else:
461
            self.fail("Should have returned 401 (Invalid X-Auth-Token)")
462

463
464
465
    def test_invalid_token(self):
        """Test _invalid_token without pool"""
        self._invalid_token(False)
466

467
468
469
    def test_invalid_token_pool(self):
        """Test _invalid_token using pool"""
        self._invalid_token(True)
470
471
472

    #- ---------------------------------
    # Test response for user 1
473
474
    def _auth_user(self, token, user_info, usage, pool):
        _mock_request([_request_ok])
475
        try:
Ilias Tsitsimpis's avatar
Ilias Tsitsimpis committed
476
            client = AstakosClient("https://example.com", use_pool=pool)
477
            auth_info = client.get_user_info(token, usage=usage)
478
479
480
481
        except:
            self.fail("Shouldn't raise an Exception")
        self.assertEqual(user_info, auth_info)

482
483
    def test_auth_user_one(self):
        """Test _auth_user for User 1 without pool, without usage"""
484
485
486
        global token_1, user_1
        user_info = dict(user_1)
        del user_info['usage']
487
        self._auth_user(token_1, user_info, False, False)
488

489
490
    def test_auth_user_one_usage(self):
        """Test _auth_user for User 1 without pool, with usage"""
491
        global token_1, user_1
492
        self._auth_user(token_1, user_1, True, False)
493

494
495
    def test_auth_user_one_usage_pool(self):
        """Test _auth_user for User 1 using pool, with usage"""
496
        global token_1, user_1
497
        self._auth_user(token_1, user_1, True, True)
498

499
500
    def test_auth_user_two(self):
        """Test _auth_user for User 2 without pool, without usage"""
501
502
503
        global token_2, user_2
        user_info = dict(user_2)
        del user_info['usage']
504
        self._auth_user(token_2, user_info, False, False)
505

506
507
    def test_auth_user_two_usage(self):
        """Test _auth_user for User 2 without pool, with usage"""
508
        global token_2, user_2
509
        self._auth_user(token_2, user_2, True, False)
510

511
512
    def test_auth_user_two_usage_pool(self):
        """Test _auth_user for User 2 using pool, with usage"""
513
        global token_2, user_2
514
        self._auth_user(token_2, user_2, True, True)
515
516
517

    # ----------------------------------
    # Test retry functionality
518
    def test_offline_retry(self):
519
        """Test retry functionality for getUserInfo"""
520
        global token_1, user_1
521
        _mock_request([_request_offline, _request_offline, _request_ok])
522
        try:
Ilias Tsitsimpis's avatar
Ilias Tsitsimpis committed
523
            client = AstakosClient("https://example.com", retry=2)
524
            auth_info = client.get_user_info(token_1, usage=True)
525
526
527
        except:
            self.fail("Shouldn't raise an Exception")
        self.assertEqual(user_1, auth_info)
528
529


530
531
532
533
534
class TestDisplayNames(unittest.TestCase):
    """Test cases for functions getDisplayNames/getDisplayName"""

    # ----------------------------------
    # Test the response we get for invalid token
535
    def test_invalid_token(self):
536
537
538
        """Test the response we get for invalid token (without pool)"""
        global user_1
        token = "skaksaFlBl+fasFdaf24sx=="
539
        _mock_request([_request_ok])
540
        try:
Ilias Tsitsimpis's avatar
Ilias Tsitsimpis committed
541
            client = AstakosClient("https://example.com")
542
            client.get_usernames(token, [user_1['uuid']])
543
        except Unauthorized:
544
545
546
            pass
        except Exception:
            self.fail("Should have returned 401 (Invalid X-Auth-Token)")
547
548
549
550
551
        else:
            self.fail("Should have returned 401 (Invalid X-Auth-Token)")

    # ----------------------------------
    # Get Info for both users
552
553
    def test_usernames(self):
        """Test get_usernames with both users"""
554
        global token_1, user_1, user_2
555
        _mock_request([_request_ok])
556
        try:
Ilias Tsitsimpis's avatar
Ilias Tsitsimpis committed
557
            client = AstakosClient("https://example.com")
558
            catalog = client.get_usernames(
Ilias Tsitsimpis's avatar
Ilias Tsitsimpis committed
559
                token_1, [user_1['uuid'], user_2['uuid']])
560
561
562
563
564
565
566
        except:
            self.fail("Shouldn't raise an Exception")
        self.assertEqual(catalog[user_1['uuid']], user_1['username'])
        self.assertEqual(catalog[user_2['uuid']], user_2['username'])

    # ----------------------------------
    # Get info for user 1
567
568
    def test_username_user_one(self):
        """Test get_username for User One"""
569
        global token_2, user_1
570
        _mock_request([_request_offline, _request_ok])
571
572
        try:
            client = AstakosClient(
Ilias Tsitsimpis's avatar
Ilias Tsitsimpis committed
573
                "https://example.com", use_pool=True, retry=2)
574
            info = client.get_username(token_2, user_1['uuid'])
575
576
577
578
        except:
            self.fail("Shouldn't raise an Exception")
        self.assertEqual(info, user_1['username'])

579
580
    # ----------------------------------
    # Get info with wrong uuid
581
    def test_no_username(self):
582
        global token_1
583
        _mock_request([_request_ok])
584
585
        try:
            client = AstakosClient("https://example.com")
586
587
            client.get_username(token_1, "1234")
        except NoUserName:
588
589
590
591
592
593
            pass
        except:
            self.fail("Should have raised NoDisplayName exception")
        else:
            self.fail("Should have raised NoDisplayName exception")

594

595
596
597
598
599
class TestGetUUIDs(unittest.TestCase):
    """Test cases for functions getUUIDs/getUUID"""

    # ----------------------------------
    # Test the response we get for invalid token
600
    def test_invalid_token(self):
601
602
603
        """Test the response we get for invalid token (using pool)"""
        global user_1
        token = "skaksaFlBl+fasFdaf24sx=="
604
        _mock_request([_request_ok])
605
606
        try:
            client = AstakosClient("https://example.com")
607
            client.get_uuids(token, [user_1['username']])
608
        except Unauthorized:
609
610
611
            pass
        except Exception:
            self.fail("Should have returned 401 (Invalid X-Auth-Token)")
612
613
614
615
616
        else:
            self.fail("Should have returned 401 (Invalid X-Auth-Token)")

    # ----------------------------------
    # Get info for both users
617
618
    def test_uuids(self):
        """Test get_uuids with both users"""
619
        global token_1, user_1, user_2
620
        _mock_request([_request_ok])
621
622
        try:
            client = AstakosClient("https://example.com")
623
            catalog = client.get_uuids(
624
625
626
627
628
629
630
631
                token_1, [user_1['username'], user_2['username']])
        except:
            self.fail("Shouldn't raise an Exception")
        self.assertEqual(catalog[user_1['username']], user_1['uuid'])
        self.assertEqual(catalog[user_2['username']], user_2['uuid'])

    # ----------------------------------
    # Get uuid for user 2
632
633
    def test_get_uuid_user_two(self):
        """Test get_uuid for User Two"""
634
        global token_1, user_2
635
        _mock_request([_request_offline, _request_ok])
636
637
        try:
            client = AstakosClient("https://example.com", retry=1)
638
            info = client.get_uuid(token_2, user_1['username'])
639
640
641
642
        except:
            self.fail("Shouldn't raise an Exception")
        self.assertEqual(info, user_1['uuid'])

643
644
    # ----------------------------------
    # Get uuid with wrong username
645
    def test_no_uuid(self):
646
        global token_1
647
        _mock_request([_request_ok])
648
649
        try:
            client = AstakosClient("https://example.com")
650
            client.get_uuid(token_1, "1234")
651
652
653
654
655
656
657
        except NoUUID:
            pass
        except:
            self.fail("Should have raised NoUUID exception")
        else:
            self.fail("Should have raised NoUUID exception")

658

659
660
661
662
# ----------------------------
# Run tests
if __name__ == "__main__":
    unittest.main()