Statistics
| Branch: | Tag: | Revision:

root / astakosclient / astakosclient / tests.py @ 81875157

History | View | Annotate | Download (36.9 kB)

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

    
36
"""Unit Tests for the astakos-client module
37

38
Provides unit tests for the code implementing
39
the astakos client library
40

41
"""
42

    
43
import sys
44
import socket
45
import simplejson
46

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

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

    
61

    
62
# --------------------------------------------------------------------
63
# Helper functions
64

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

    
71

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

    
81

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

    
92

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

    
100

    
101
def _request_status_400(conn, method, url, **kwargs):
102
    """This request returns 400"""
103
    message = "BAD REQUEST"
104
    status = 400
105
    data = "Method not allowed.\n"
106
    return (message, data, status)
107

    
108

    
109
def _request_ok(conn, method, url, **kwargs):
110
    """This request behaves like original Astakos does"""
111
    if url.startswith("/im/authenticate"):
112
        return _req_authenticate(conn, method, url, **kwargs)
113
    elif url.startswith("/user_catalogs"):
114
        return _req_catalogs(conn, method, url, **kwargs)
115
    elif url.startswith("/astakos/api/resources"):
116
        return _req_resources(conn, method, url, **kwargs)
117
    elif url.startswith("/astakos/api/quotas"):
118
        return _req_quotas(conn, method, url, **kwargs)
119
    elif url.startswith("/astakos/api/commissions"):
120
        return _req_commission(conn, method, url, **kwargs)
121
    else:
122
        return _request_status_404(conn, method, url, **kwargs)
123

    
124

    
125
def _req_authenticate(conn, method, url, **kwargs):
126
    """Check if user exists and return his profile"""
127
    global user_1, user_2, token_1, token_2
128

    
129
    # Check input
130
    if conn.__class__.__name__ != "HTTPSConnection":
131
        return _request_status_302(conn, method, url, **kwargs)
132
    if method != "GET":
133
        return _request_status_400(conn, method, url, **kwargs)
134
    token = kwargs['headers'].get('X-Auth-Token')
135
    if token == token_1:
136
        user = dict(user_1)
137
    elif token == token_2:
138
        user = dict(user_2)
139
    else:
140
        # No user found
141
        return _request_status_401(conn, method, url, **kwargs)
142

    
143
    # Return
144
    if "usage=1" not in url:
145
        # Strip `usage' key from `user'
146
        del user['usage']
147
    return ("", simplejson.dumps(user), 200)
148

    
149

    
150
def _req_catalogs(conn, method, url, **kwargs):
151
    """Return user catalogs"""
152
    global token_1, token_2, user_1, user_2
153

    
154
    # Check input
155
    if conn.__class__.__name__ != "HTTPSConnection":
156
        return _request_status_302(conn, method, url, **kwargs)
157
    if method != "POST":
158
        return _request_status_400(conn, method, url, **kwargs)
159
    token = kwargs['headers'].get('X-Auth-Token')
160
    if token != token_1 and token != token_2:
161
        return _request_status_401(conn, method, url, **kwargs)
162

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

    
187

    
188
def _req_resources(conn, method, url, **kwargs):
189
    """Return quota resources"""
190
    global resources
191

    
192
    # Check input
193
    if conn.__class__.__name__ != "HTTPSConnection":
194
        return _request_status_302(conn, method, url, **kwargs)
195
    if method != "GET":
196
        return _request_status_400(conn, method, url, **kwargs)
197

    
198
    # Return
199
    return ("", simplejson.dumps(resources), 200)
200

    
201

    
202
def _req_quotas(conn, method, url, **kwargs):
203
    """Return quotas for user_1"""
204
    global token_1, quotas
205

    
206
    # Check input
207
    if conn.__class__.__name__ != "HTTPSConnection":
208
        return _request_status_302(conn, method, url, **kwargs)
209
    if method != "GET":
210
        return _request_status_400(conn, method, url, **kwargs)
211
    token = kwargs['headers'].get('X-Auth-Token')
212
    if token != token_1:
213
        return _request_status_401(conn, method, url, **kwargs)
214

    
215
    # Return
216
    return ("", simplejson.dumps(quotas), 200)
217

    
218

    
219
def _req_commission(conn, method, url, **kwargs):
220
    """Perform a commission for user_1"""
221
    global token_1, pending_commissions, \
222
        commission_successful_response, commission_failure_response
223

    
224
    # Check input
225
    if conn.__class__.__name__ != "HTTPSConnection":
226
        return _request_status_302(conn, method, url, **kwargs)
227
    token = kwargs['headers'].get('X-Auth-Token')
228
    if token != token_1:
229
        return _request_status_401(conn, method, url, **kwargs)
230

    
231
    if method == "POST":
232
        if 'body' not in kwargs:
233
            return _request_status_400(conn, method, url, **kwargs)
234
        body = simplejson.loads(unicode(kwargs['body']))
235
        if url == "/astakos/api/commissions":
236
            # Issue Commission
237
            # Check if we have enough resources to give
238
            if body['provisions'][1]['quantity'] > 420000000:
239
                return ("", simplejson.dumps(commission_failure_response), 413)
240
            else:
241
                return \
242
                    ("", simplejson.dumps(commission_successful_response), 200)
243
        else:
244
            # Issue commission action
245
            serial = url.split('/')[4]
246
            if serial == "action":
247
                # Resolve multiple actions
248
                if body == resolve_commissions_req:
249
                    return ("", simplejson.dumps(resolve_commissions_rep), 200)
250
                else:
251
                    return _request_status_400(conn, method, url, **kwargs)
252
            else:
253
                # Issue action for one commission
254
                if serial != str(57):
255
                    return _request_status_404(conn, method, url, **kwargs)
256
                if len(body) != 1:
257
                    return _request_status_400(conn, method, url, **kwargs)
258
                if "accept" not in body.keys() and "reject" not in body.keys():
259
                    return _request_status_400(conn, method, url, **kwargs)
260
                return ("", "", 200)
261

    
262
    elif method == "GET":
263
        if url == "/astakos/api/commissions":
264
            # Return pending commission
265
            return ("", simplejson.dumps(pending_commissions), 200)
266
        else:
267
            # Return commissions's description
268
            serial = url[25:]
269
            if serial == str(57):
270
                return ("", simplejson.dumps(commission_description), 200)
271
            else:
272
                return _request_status_404(conn, method, url, **kwargs)
273
    else:
274
        return _request_status_400(conn, method, url, **kwargs)
275

    
276

    
277
# ----------------------------
278
# Mock the actual _doRequest
279
def _mock_request(new_requests):
280
    """Mock the actual request
281

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

286
    """
287
    def _mock(conn, method, url, **kwargs):
288
        # Get first request
289
        request = _mock.requests[0]
290
        # Rotate requests
291
        _mock.requests = _mock.requests[1:] + _mock.requests[:1]
292
        # Use first request
293
        return request(conn, method, url, **kwargs)
294

    
295
    _mock.requests = new_requests
296
    # Replace `_doRequest' with our `_mock'
297
    astakosclient._do_request = _mock
298

    
299

    
300
# ----------------------------
301
# Local users
302
token_1 = "skzleaFlBl+fasFdaf24sx=="
303
user_1 = \
304
    {"username": "user1@example.com",
305
     "auth_token_created": 1359386939000,
306
     "name": "Example User One",
307
     "email": ["user1@example.com"],
308
     "auth_token_expires": 1361978939000,
309
     "id": 108,
310
     "uuid": "73917abc-abcd-477e-a1f1-1763abcdefab",
311
     "usage": [
312
         {"currValue": 42949672960,
313
          "display_name": "System Disk",
314
          "name": "cyclades.disk"},
315
         {"currValue": 4,
316
          "display_name": "CPU",
317
          "name": "cyclades.cpu"},
318
         {"currValue": 4294967296,
319
          "display_name": "RAM",
320
          "name": "cyclades.ram"},
321
         {"currValue": 3,
322
          "display_name": "VM",
323
          "name": "cyclades.vm"},
324
         {"currValue": 0,
325
          "display_name": "private network",
326
          "name": "cyclades.network.private"},
327
         {"currValue": 152,
328
          "display_name": "Storage Space",
329
          "name": "pithos+.diskspace"}]}
330

    
331
token_2 = "fasdfDSFdf98923DF+sdfk=="
332
user_2 = \
333
    {"username": "user2@example.com",
334
     "auth_token_created": 1358386938997,
335
     "name": "Example User Two",
336
     "email": ["user1@example.com"],
337
     "auth_token_expires": 1461998939000,
338
     "id": 109,
339
     "uuid": "73917bca-1234-5678-a1f1-1763abcdefab",
340
     "usage": [
341
         {"currValue": 68719476736,
342
          "display_name": "System Disk",
343
          "name": "cyclades.disk"},
344
         {"currValue": 1,
345
          "display_name": "CPU",
346
          "name": "cyclades.cpu"},
347
         {"currValue": 1073741824,
348
          "display_name": "RAM",
349
          "name": "cyclades.ram"},
350
         {"currValue": 2,
351
          "display_name": "VM",
352
          "name": "cyclades.vm"},
353
         {"currValue": 1,
354
          "display_name": "private network",
355
          "name": "cyclades.network.private"},
356
         {"currValue": 2341634510,
357
          "display_name": "Storage Space",
358
          "name": "pithos+.diskspace"}]}
359

    
360
resources = {
361
    "cyclades.vm": {
362
        "unit": None,
363
        "description": "Number of virtual machines",
364
        "service": "cyclades"},
365
    "cyclades.ram": {
366
        "unit": "bytes",
367
        "description": "Virtual machine memory",
368
        "service": "cyclades"}}
369

    
370
quotas = {
371
    "system": {
372
        "cyclades.ram": {
373
            "available": 536870912,
374
            "limit": 1073741824,
375
            "used": 536870912},
376
        "cyclades.vm": {
377
            "available": 0,
378
            "limit": 2,
379
            "used": 2}},
380
    "project:1": {
381
        "cyclades.ram": {
382
            "available": 0,
383
            "limit": 2147483648,
384
            "used": 2147483648},
385
        "cyclades.vm": {
386
            "available": 3,
387
            "limit": 5,
388
            "used": 2}}}
389

    
390
commission_request = {
391
    "force": False,
392
    "auto_accept": False,
393
    "provisions": [
394
        {
395
            "holder": "c02f315b-7d84-45bc-a383-552a3f97d2ad",
396
            "source": "system",
397
            "resource": "cyclades.vm",
398
            "quantity": 1
399
        },
400
        {
401
            "holder": "c02f315b-7d84-45bc-a383-552a3f97d2ad",
402
            "source": "system",
403
            "resource": "cyclades.ram",
404
            "quantity": 30000
405
        }]}
406

    
407
commission_successful_response = {"serial": 57}
408

    
409
commission_failure_response = {
410
    "overLimit": {
411
        "message": "a human-readable error message",
412
        "code": 413,
413
        "data": {
414
            "provision": {
415
                "holder": "c02f315b-7d84-45bc-a383-552a3f97d2ad",
416
                "source": "system",
417
                "resource": "cyclades.ram",
418
                "quantity": 520000000},
419
            "name": "NoCapacityError",
420
            "available": 420000000}}}
421

    
422
pending_commissions = [100, 200]
423

    
424
commission_description = {
425
    "serial": 57,
426
    "issue_time": "2013-04-08T10:19:15.0373",
427
    "provisions": [
428
        {
429
            "holder": "c02f315b-7d84-45bc-a383-552a3f97d2ad",
430
            "source": "system",
431
            "resource": "cyclades.vm",
432
            "quantity": 1
433
        },
434
        {
435
            "holder": "c02f315b-7d84-45bc-a383-552a3f97d2ad",
436
            "source": "system",
437
            "resource": "cyclades.ram",
438
            "quantity": 536870912
439
        }]}
440

    
441
resolve_commissions_req = {
442
    "accept": [56, 57],
443
    "reject": [56, 58, 59]}
444

    
445
resolve_commissions_rep = {
446
    "accepted": [57],
447
    "rejected": [59],
448
    "failed": [
449
        [56, {
450
            "badRequest": {
451
                "message": "cannot both accept and reject serial 56",
452
                "code": 400}}],
453
        [58, {
454
            "itemNotFound": {
455
                "message": "serial 58 does not exist",
456
                "code": 404}}]]}
457

    
458

    
459
# --------------------------------------------------------------------
460
# The actual tests
461

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

    
465
    # ----------------------------------
466
    # Test the response we get if we don't have internet access
467
    def _offline(self, pool):
468
        global token_1
469
        _mock_request([_request_offline])
470
        try:
471
            client = AstakosClient("https://example.com", use_pool=pool)
472
            client._call_astakos(token_1, "/im/authenticate")
473
        except AstakosClientException:
474
            pass
475
        else:
476
            self.fail("Should have raised AstakosClientException")
477

    
478
    def test_offline(self):
479
        """Test _offline without pool"""
480
        self._offline(False)
481

    
482
    def test_offline_pool(self):
483
        """Test _offline using pool"""
484
        self._offline(True)
485

    
486
    # ----------------------------------
487
    # Test the response we get if we send invalid token
488
    def _invalid_token(self, pool):
489
        token = "skaksaFlBl+fasFdaf24sx=="
490
        _mock_request([_request_ok])
491
        try:
492
            client = AstakosClient("https://example.com", use_pool=pool)
493
            client._call_astakos(token, "/im/authenticate")
494
        except Unauthorized:
495
            pass
496
        except Exception:
497
            self.fail("Should have returned 401 (Invalid X-Auth-Token)")
498
        else:
499
            self.fail("Should have returned 401 (Invalid X-Auth-Token)")
500

    
501
    def test_invalid_token(self):
502
        """Test _invalid_token without pool"""
503
        self._invalid_token(False)
504

    
505
    def test_invalid_token_pool(self):
506
        """Test _invalid_token using pool"""
507
        self._invalid_token(True)
508

    
509
    # ----------------------------------
510
    # Test the response we get if we send invalid url
511
    def _invalid_url(self, pool):
512
        global token_1
513
        _mock_request([_request_ok])
514
        try:
515
            client = AstakosClient("https://example.com", use_pool=pool)
516
            client._call_astakos(token_1, "/im/misspelled")
517
        except NotFound:
518
            pass
519
        except Exception:
520
            self.fail("Should have returned 404 (Not Found)")
521
        else:
522
            self.fail("Should have returned 404 (Not Found)")
523

    
524
    def test_invalid_url(self):
525
        """Test _invalid_url without pool"""
526
        self._invalid_url(False)
527

    
528
    def test_invalid_url_pool(self):
529
        """Test _invalid_url using pool"""
530
        self._invalid_url(True)
531

    
532
    # ----------------------------------
533
    # Test the response we get if we use an unsupported scheme
534
    def _unsupported_scheme(self, pool):
535
        global token_1
536
        _mock_request([_request_ok])
537
        try:
538
            client = AstakosClient("ftp://example.com", use_pool=pool)
539
            client._call_astakos(token_1, "/im/authenticate")
540
        except BadValue:
541
            pass
542
        except Exception:
543
            self.fail("Should have raise BadValue Exception")
544
        else:
545
            self.fail("Should have raise BadValue Exception")
546

    
547
    def test_unsupported_scheme(self):
548
        """Test _unsupported_scheme without pool"""
549
        self._unsupported_scheme(False)
550

    
551
    def test_unsupported_scheme_pool(self):
552
        """Test _unsupported_scheme using pool"""
553
        self._unsupported_scheme(True)
554

    
555
    # ----------------------------------
556
    # Test the response we get if we use http instead of https
557
    def _http_scheme(self, pool):
558
        global token_1
559
        _mock_request([_request_ok])
560
        try:
561
            client = AstakosClient("http://example.com", use_pool=pool)
562
            client._call_astakos(token_1, "/im/authenticate")
563
        except AstakosClientException as err:
564
            if err.status != 302:
565
                self.fail("Should have returned 302 (Found)")
566
        else:
567
            self.fail("Should have returned 302 (Found)")
568

    
569
    def test_http_scheme(self):
570
        """Test _http_scheme without pool"""
571
        self._http_scheme(False)
572

    
573
    def test_http_scheme_pool(self):
574
        """Test _http_scheme using pool"""
575
        self._http_scheme(True)
576

    
577
    # ----------------------------------
578
    # Test the response we get if we use authenticate with POST
579
    def _post_authenticate(self, pool):
580
        global token_1
581
        _mock_request([_request_ok])
582
        try:
583
            client = AstakosClient("https://example.com", use_pool=pool)
584
            client._call_astakos(token_1, "/im/authenticate", method="POST")
585
        except BadRequest:
586
            pass
587
        except Exception:
588
            self.fail("Should have returned 400 (Method not allowed)")
589
        else:
590
            self.fail("Should have returned 400 (Method not allowed)")
591

    
592
    def test_post_authenticate(self):
593
        """Test _post_authenticate without pool"""
594
        self._post_authenticate(False)
595

    
596
    def test_post_authenticate_pool(self):
597
        """Test _post_authenticate using pool"""
598
        self._post_authenticate(True)
599

    
600
    # ----------------------------------
601
    # Test the response if we request user_catalogs with GET
602
    def _get_user_catalogs(self, pool):
603
        global token_1
604
        _mock_request([_request_ok])
605
        try:
606
            client = AstakosClient("https://example.com", use_pool=pool)
607
            client._call_astakos(token_1, "/user_catalogs")
608
        except BadRequest:
609
            pass
610
        except Exception:
611
            self.fail("Should have returned 400 (Method not allowed)")
612
        else:
613
            self.fail("Should have returned 400 (Method not allowed)")
614

    
615
    def test_get_user_catalogs(self):
616
        """Test _get_user_catalogs without pool"""
617
        self._get_user_catalogs(False)
618

    
619
    def test_get_user_catalogs_pool(self):
620
        """Test _get_user_catalogs using pool"""
621
        self._get_user_catalogs(True)
622

    
623

    
624
class TestAuthenticate(unittest.TestCase):
625
    """Test cases for function getUserInfo"""
626

    
627
    # ----------------------------------
628
    # Test the response we get if we don't have internet access
629
    def test_offline(self):
630
        """Test offline after 3 retries"""
631
        global token_1
632
        _mock_request([_request_offline])
633
        try:
634
            client = AstakosClient("https://example.com", retry=3)
635
            client.get_user_info(token_1)
636
        except AstakosClientException:
637
            pass
638
        else:
639
            self.fail("Should have raised AstakosClientException exception")
640

    
641
    # ----------------------------------
642
    # Test the response we get for invalid token
643
    def _invalid_token(self, pool):
644
        token = "skaksaFlBl+fasFdaf24sx=="
645
        _mock_request([_request_ok])
646
        try:
647
            client = AstakosClient("https://example.com", use_pool=pool)
648
            client.get_user_info(token)
649
        except Unauthorized:
650
            pass
651
        except Exception:
652
            self.fail("Should have returned 401 (Invalid X-Auth-Token)")
653
        else:
654
            self.fail("Should have returned 401 (Invalid X-Auth-Token)")
655

    
656
    def test_invalid_token(self):
657
        """Test _invalid_token without pool"""
658
        self._invalid_token(False)
659

    
660
    def test_invalid_token_pool(self):
661
        """Test _invalid_token using pool"""
662
        self._invalid_token(True)
663

    
664
    #- ---------------------------------
665
    # Test response for user 1
666
    def _auth_user(self, token, user_info, usage, pool):
667
        _mock_request([_request_ok])
668
        try:
669
            client = AstakosClient("https://example.com", use_pool=pool)
670
            auth_info = client.get_user_info(token, usage=usage)
671
        except:
672
            self.fail("Shouldn't raise an Exception")
673
        self.assertEqual(user_info, auth_info)
674

    
675
    def test_auth_user_one(self):
676
        """Test _auth_user for User 1 without pool, without usage"""
677
        global token_1, user_1
678
        user_info = dict(user_1)
679
        del user_info['usage']
680
        self._auth_user(token_1, user_info, False, False)
681

    
682
    def test_auth_user_one_usage(self):
683
        """Test _auth_user for User 1 without pool, with usage"""
684
        global token_1, user_1
685
        self._auth_user(token_1, user_1, True, False)
686

    
687
    def test_auth_user_one_usage_pool(self):
688
        """Test _auth_user for User 1 using pool, with usage"""
689
        global token_1, user_1
690
        self._auth_user(token_1, user_1, True, True)
691

    
692
    def test_auth_user_two(self):
693
        """Test _auth_user for User 2 without pool, without usage"""
694
        global token_2, user_2
695
        user_info = dict(user_2)
696
        del user_info['usage']
697
        self._auth_user(token_2, user_info, False, False)
698

    
699
    def test_auth_user_two_usage(self):
700
        """Test _auth_user for User 2 without pool, with usage"""
701
        global token_2, user_2
702
        self._auth_user(token_2, user_2, True, False)
703

    
704
    def test_auth_user_two_usage_pool(self):
705
        """Test _auth_user for User 2 using pool, with usage"""
706
        global token_2, user_2
707
        self._auth_user(token_2, user_2, True, True)
708

    
709
    # ----------------------------------
710
    # Test retry functionality
711
    def test_offline_retry(self):
712
        """Test retry functionality for getUserInfo"""
713
        global token_1, user_1
714
        _mock_request([_request_offline, _request_offline, _request_ok])
715
        try:
716
            client = AstakosClient("https://example.com", retry=2)
717
            auth_info = client.get_user_info(token_1, usage=True)
718
        except:
719
            self.fail("Shouldn't raise an Exception")
720
        self.assertEqual(user_1, auth_info)
721

    
722

    
723
class TestDisplayNames(unittest.TestCase):
724
    """Test cases for functions getDisplayNames/getDisplayName"""
725

    
726
    # ----------------------------------
727
    # Test the response we get for invalid token
728
    def test_invalid_token(self):
729
        """Test the response we get for invalid token (without pool)"""
730
        global user_1
731
        token = "skaksaFlBl+fasFdaf24sx=="
732
        _mock_request([_request_ok])
733
        try:
734
            client = AstakosClient("https://example.com")
735
            client.get_usernames(token, [user_1['uuid']])
736
        except Unauthorized:
737
            pass
738
        except Exception:
739
            self.fail("Should have returned 401 (Invalid X-Auth-Token)")
740
        else:
741
            self.fail("Should have returned 401 (Invalid X-Auth-Token)")
742

    
743
    # ----------------------------------
744
    # Get Info for both users
745
    def test_usernames(self):
746
        """Test get_usernames with both users"""
747
        global token_1, user_1, user_2
748
        _mock_request([_request_ok])
749
        try:
750
            client = AstakosClient("https://example.com")
751
            catalog = client.get_usernames(
752
                token_1, [user_1['uuid'], user_2['uuid']])
753
        except:
754
            self.fail("Shouldn't raise an Exception")
755
        self.assertEqual(catalog[user_1['uuid']], user_1['username'])
756
        self.assertEqual(catalog[user_2['uuid']], user_2['username'])
757

    
758
    # ----------------------------------
759
    # Get info for user 1
760
    def test_username_user_one(self):
761
        """Test get_username for User One"""
762
        global token_2, user_1
763
        _mock_request([_request_offline, _request_ok])
764
        try:
765
            client = AstakosClient(
766
                "https://example.com", use_pool=True, retry=2)
767
            info = client.get_username(token_2, user_1['uuid'])
768
        except:
769
            self.fail("Shouldn't raise an Exception")
770
        self.assertEqual(info, user_1['username'])
771

    
772
    # ----------------------------------
773
    # Get info with wrong uuid
774
    def test_no_username(self):
775
        global token_1
776
        _mock_request([_request_ok])
777
        try:
778
            client = AstakosClient("https://example.com")
779
            client.get_username(token_1, "1234")
780
        except NoUserName:
781
            pass
782
        except:
783
            self.fail("Should have raised NoDisplayName exception")
784
        else:
785
            self.fail("Should have raised NoDisplayName exception")
786

    
787

    
788
class TestGetUUIDs(unittest.TestCase):
789
    """Test cases for functions getUUIDs/getUUID"""
790

    
791
    # ----------------------------------
792
    # Test the response we get for invalid token
793
    def test_invalid_token(self):
794
        """Test the response we get for invalid token (using pool)"""
795
        global user_1
796
        token = "skaksaFlBl+fasFdaf24sx=="
797
        _mock_request([_request_ok])
798
        try:
799
            client = AstakosClient("https://example.com")
800
            client.get_uuids(token, [user_1['username']])
801
        except Unauthorized:
802
            pass
803
        except Exception:
804
            self.fail("Should have returned 401 (Invalid X-Auth-Token)")
805
        else:
806
            self.fail("Should have returned 401 (Invalid X-Auth-Token)")
807

    
808
    # ----------------------------------
809
    # Get info for both users
810
    def test_uuids(self):
811
        """Test get_uuids with both users"""
812
        global token_1, user_1, user_2
813
        _mock_request([_request_ok])
814
        try:
815
            client = AstakosClient("https://example.com")
816
            catalog = client.get_uuids(
817
                token_1, [user_1['username'], user_2['username']])
818
        except:
819
            self.fail("Shouldn't raise an Exception")
820
        self.assertEqual(catalog[user_1['username']], user_1['uuid'])
821
        self.assertEqual(catalog[user_2['username']], user_2['uuid'])
822

    
823
    # ----------------------------------
824
    # Get uuid for user 2
825
    def test_get_uuid_user_two(self):
826
        """Test get_uuid for User Two"""
827
        global token_1, user_2
828
        _mock_request([_request_offline, _request_ok])
829
        try:
830
            client = AstakosClient("https://example.com", retry=1)
831
            info = client.get_uuid(token_2, user_1['username'])
832
        except:
833
            self.fail("Shouldn't raise an Exception")
834
        self.assertEqual(info, user_1['uuid'])
835

    
836
    # ----------------------------------
837
    # Get uuid with wrong username
838
    def test_no_uuid(self):
839
        global token_1
840
        _mock_request([_request_ok])
841
        try:
842
            client = AstakosClient("https://example.com")
843
            client.get_uuid(token_1, "1234")
844
        except NoUUID:
845
            pass
846
        except:
847
            self.fail("Should have raised NoUUID exception")
848
        else:
849
            self.fail("Should have raised NoUUID exception")
850

    
851

    
852
class TestResources(unittest.TestCase):
853
    """Test cases for function get_resources"""
854

    
855
    # ----------------------------------
856
    def test_get_resources(self):
857
        """Test function call of get_resources"""
858
        global resources
859
        _mock_request([_request_offline, _request_ok])
860
        try:
861
            client = AstakosClient("https://example.com", retry=1)
862
            result = client.get_resources()
863
        except Exception as err:
864
            self.fail("Shouldn't raise Exception %s" % err)
865
        self.assertEqual(resources, result)
866

    
867

    
868
class TestQuotas(unittest.TestCase):
869
    """Test cases for function get_quotas"""
870

    
871
    # ----------------------------------
872
    def test_get_quotas(self):
873
        """Test function call of get_quotas"""
874
        global quotas, token_1
875
        _mock_request([_request_ok])
876
        try:
877
            client = AstakosClient("https://example.com")
878
            result = client.get_quotas(token_1)
879
        except Exception as err:
880
            self.fail("Shouldn't raise Exception %s" % err)
881
        self.assertEqual(quotas, result)
882

    
883
    # -----------------------------------
884
    def test_get_quotas_unauthorized(self):
885
        """Test function call of get_quotas with wrong token"""
886
        global token_2
887
        _mock_request([_request_ok])
888
        try:
889
            client = AstakosClient("https://example.com")
890
            client.get_quotas(token_2)
891
        except Unauthorized:
892
            pass
893
        except Exception as err:
894
            self.fail("Shouldn't raise Exception %s" % err)
895
        else:
896
            self.fail("Should have raised Unauthorized Exception")
897

    
898
    # ----------------------------------
899
    def test_get_quotas_without_token(self):
900
        """Test function call of get_quotas without token"""
901
        _mock_request([_request_ok])
902
        try:
903
            client = AstakosClient("https://example.com")
904
            client.get_quotas(None)
905
        except Unauthorized:
906
            pass
907
        except Exception as err:
908
            self.fail("Shouldn't raise Exception %s" % err)
909
        else:
910
            self.fail("Should have raised Unauthorized Exception")
911

    
912

    
913
class TestCommissions(unittest.TestCase):
914
    """Test cases for quota commissions"""
915

    
916
    # ----------------------------------
917
    def test_issue_commission(self):
918
        """Test function call of issue_commission_core"""
919
        global token_1, commission_request, commission_successful_reqsponse
920
        _mock_request([_request_ok])
921
        try:
922
            client = AstakosClient("https://example.com")
923
            response = client.issue_commission(token_1, commission_request)
924
        except Exception as err:
925
            self.fail("Shouldn't raise Exception %s" % err)
926
        self.assertEqual(response, commission_successful_response['serial'])
927

    
928
    # ----------------------------------
929
    def test_issue_commission_quota_limit(self):
930
        """Test function call of issue_commission_core with limit exceeded"""
931
        global token_1, commission_request, commission_failure_response
932
        _mock_request([_request_ok])
933
        new_request = dict(commission_request)
934
        new_request['provisions'][1]['quantity'] = 520000000
935
        try:
936
            client = AstakosClient("https://example.com")
937
            client.issue_commission(token_1, new_request)
938
        except QuotaLimit:
939
            pass
940
        except Exception as err:
941
            self.fail("Shouldn't raise Exception %s" % err)
942
        else:
943
            self.fail("Should have raised QuotaLimit Exception")
944

    
945
    # ----------------------------------
946
    def test_get_pending_commissions(self):
947
        """Test function call of get_pending_commissions"""
948
        global token_1, pending_commissions
949
        _mock_request([_request_ok])
950
        try:
951
            client = AstakosClient("https://example.com")
952
            response = client.get_pending_commissions(token_1)
953
        except Exception as err:
954
            self.fail("Shouldn't raise Exception %s" % err)
955
        self.assertEqual(response, pending_commissions)
956

    
957
    # ----------------------------------
958
    def test_get_commission_info(self):
959
        """Test function call of get_commission_info"""
960
        global token_1, commission_description
961
        _mock_request([_request_ok])
962
        try:
963
            client = \
964
                AstakosClient("https://example.com", use_pool=True, pool_size=2)
965
            response = client.get_commission_info(token_1, 57)
966
        except Exception as err:
967
            self.fail("Shouldn't raise Exception %s" % err)
968
        self.assertEqual(response, commission_description)
969

    
970
    # ----------------------------------
971
    def test_get_commission_info_not_found(self):
972
        """Test function call of get_commission_info with invalid serial"""
973
        global token_1
974
        _mock_request([_request_ok])
975
        try:
976
            client = AstakosClient("https://example.com")
977
            client.get_commission_info(token_1, "57lala")
978
        except NotFound:
979
            pass
980
        except Exception as err:
981
            self.fail("Shouldn't raise Exception %s" % err)
982
        else:
983
            self.fail("Should have raised NotFound")
984

    
985
    # ----------------------------------
986
    def test_get_commission_info_without_serial(self):
987
        """Test function call of get_commission_info without serial"""
988
        global token_1
989
        _mock_request([_request_ok])
990
        try:
991
            client = AstakosClient("https://example.com")
992
            client.get_commission_info(token_1, None)
993
        except BadValue:
994
            pass
995
        except Exception as err:
996
            self.fail("Shouldn't raise Exception %s" % err)
997
        else:
998
            self.fail("Should have raise BadValue")
999

    
1000
    # ----------------------------------
1001
    def test_commision_action(self):
1002
        """Test function call of commision_action with wrong action"""
1003
        global token_1
1004
        _mock_request([_request_ok])
1005
        try:
1006
            client = AstakosClient("https://example.com")
1007
            client.commission_action(token_1, 57, "lala")
1008
        except BadRequest:
1009
            pass
1010
        except Exception as err:
1011
            self.fail("Shouldn't raise Exception %s" % err)
1012
        else:
1013
            self.fail("Should have raised BadRequest")
1014

    
1015
    # ----------------------------------
1016
    def test_accept_commission(self):
1017
        """Test function call of accept_commission"""
1018
        global token_1
1019
        _mock_request([_request_ok])
1020
        try:
1021
            client = AstakosClient("https://example.com")
1022
            client.accept_commission(token_1, 57)
1023
        except Exception as err:
1024
            self.fail("Shouldn't raise Exception %s" % err)
1025

    
1026
    # ----------------------------------
1027
    def test_reject_commission(self):
1028
        """Test function call of reject_commission"""
1029
        global token_1
1030
        _mock_request([_request_ok])
1031
        try:
1032
            client = AstakosClient("https://example.com")
1033
            client.reject_commission(token_1, 57)
1034
        except Exception as err:
1035
            self.fail("Shouldn't raise Exception %s" % err)
1036

    
1037
    # ----------------------------------
1038
    def test_accept_commission_not_found(self):
1039
        """Test function call of accept_commission with wrong serial"""
1040
        global token_1
1041
        _mock_request([_request_ok])
1042
        try:
1043
            client = AstakosClient("https://example.com")
1044
            client.reject_commission(token_1, 20)
1045
        except NotFound:
1046
            pass
1047
        except Exception as err:
1048
            self.fail("Shouldn't raise Exception %s" % err)
1049
        else:
1050
            self.fail("Should have raised NotFound")
1051

    
1052
    # ----------------------------------
1053
    def test_resolve_commissions(self):
1054
        """Test function call of resolve_commissions"""
1055
        global token_1
1056
        _mock_request([_request_ok])
1057
        try:
1058
            client = AstakosClient("https://example.com")
1059
            result = client.resolve_commissions(token_1, [56, 57], [56, 58, 59])
1060
        except Exception as err:
1061
            self.fail("Shouldn't raise Exception %s" % err)
1062
        self.assertEqual(result, resolve_commissions_rep)
1063

    
1064

    
1065
# ----------------------------
1066
# Run tests
1067
if __name__ == "__main__":
1068
    unittest.main()