Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / tests / api.py @ bd93595d

History | View | Annotate | Download (23.7 kB)

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

    
34
from astakos.im.tests.common import *
35

    
36
from django.test import TestCase
37

    
38
from urllib import quote
39
from urlparse import urlparse, parse_qs
40
from xml.dom import minidom
41

    
42
import json
43

    
44
ROOT = '/astakos/api/'
45
u = lambda url: ROOT + url
46

    
47

    
48
class QuotaAPITest(TestCase):
49
    def test_0(self):
50
        client = Client()
51
        # custom service resources
52
        service1 = Service.objects.create(
53
            name="service1", api_url="http://service1.api")
54
        resource11 = {"name": "service1.resource11",
55
                      "desc": "resource11 desc",
56
                      "allow_in_projects": True}
57
        r, _ = resources.add_resource(service1, resource11)
58
        resources.update_resource(r, 100)
59
        resource12 = {"name": "service1.resource12",
60
                      "desc": "resource11 desc",
61
                      "unit": "bytes"}
62
        r, _ = resources.add_resource(service1, resource12)
63
        resources.update_resource(r, 1024)
64

    
65
        # create user
66
        user = get_local_user('test@grnet.gr')
67
        quotas.qh_sync_user(user)
68

    
69
        # create another service
70
        service2 = Service.objects.create(
71
            name="service2", api_url="http://service2.api")
72
        resource21 = {"name": "service2.resource21",
73
                      "desc": "resource11 desc",
74
                      "allow_in_projects": False}
75
        r, _ = resources.add_resource(service2, resource21)
76
        resources.update_resource(r, 3)
77

    
78
        resource_names = [r['name'] for r in
79
                          [resource11, resource12, resource21]]
80

    
81
        # get resources
82
        r = client.get(u('resources'))
83
        self.assertEqual(r.status_code, 200)
84
        body = json.loads(r.content)
85
        for name in resource_names:
86
            assertIn(name, body)
87

    
88
        # get quota
89
        r = client.get(u('quotas'))
90
        self.assertEqual(r.status_code, 401)
91

    
92
        headers = {'HTTP_X_AUTH_TOKEN': user.auth_token}
93
        r = client.get(u('quotas/'), **headers)
94
        self.assertEqual(r.status_code, 200)
95
        body = json.loads(r.content)
96
        system_quota = body['system']
97
        assertIn('system', body)
98
        for name in resource_names:
99
            assertIn(name, system_quota)
100

    
101
        r = client.get(u('service_quotas'))
102
        self.assertEqual(r.status_code, 401)
103

    
104
        s1_headers = {'HTTP_X_AUTH_TOKEN': service1.auth_token}
105
        r = client.get(u('service_quotas'), **s1_headers)
106
        self.assertEqual(r.status_code, 200)
107
        body = json.loads(r.content)
108
        assertIn(user.uuid, body)
109

    
110
        r = client.get(u('commissions'), **s1_headers)
111
        self.assertEqual(r.status_code, 200)
112
        body = json.loads(r.content)
113
        self.assertEqual(body, [])
114

    
115
        # issue some commissions
116
        commission_request = {
117
            "force": False,
118
            "auto_accept": False,
119
            "name": "my commission",
120
            "provisions": [
121
                {
122
                    "holder": user.uuid,
123
                    "source": "system",
124
                    "resource": resource11['name'],
125
                    "quantity": 1
126
                },
127
                {
128
                    "holder": user.uuid,
129
                    "source": "system",
130
                    "resource": resource12['name'],
131
                    "quantity": 30000
132
                }]}
133

    
134
        post_data = json.dumps(commission_request)
135
        r = client.post(u('commissions'), post_data,
136
                        content_type='application/json', **s1_headers)
137
        self.assertEqual(r.status_code, 413)
138

    
139
        commission_request = {
140
            "force": False,
141
            "auto_accept": False,
142
            "name": "my commission",
143
            "provisions": [
144
                {
145
                    "holder": user.uuid,
146
                    "source": "system",
147
                    "resource": resource11['name'],
148
                    "quantity": 1
149
                },
150
                {
151
                    "holder": user.uuid,
152
                    "source": "system",
153
                    "resource": resource12['name'],
154
                    "quantity": 100
155
                }]}
156

    
157
        post_data = json.dumps(commission_request)
158
        r = client.post(u('commissions'), post_data,
159
                        content_type='application/json', **s1_headers)
160
        self.assertEqual(r.status_code, 201)
161
        body = json.loads(r.content)
162
        serial = body['serial']
163
        self.assertEqual(serial, 1)
164

    
165
        post_data = json.dumps(commission_request)
166
        r = client.post(u('commissions'), post_data,
167
                        content_type='application/json', **s1_headers)
168
        self.assertEqual(r.status_code, 201)
169
        body = json.loads(r.content)
170
        self.assertEqual(body['serial'], 2)
171

    
172
        post_data = json.dumps(commission_request)
173
        r = client.post(u('commissions'), post_data,
174
                        content_type='application/json', **s1_headers)
175
        self.assertEqual(r.status_code, 201)
176
        body = json.loads(r.content)
177
        self.assertEqual(body['serial'], 3)
178

    
179
        r = client.get(u('commissions'), **s1_headers)
180
        self.assertEqual(r.status_code, 200)
181
        body = json.loads(r.content)
182
        self.assertEqual(body, [1, 2, 3])
183

    
184
        r = client.get(u('commissions/' + str(serial)), **s1_headers)
185
        self.assertEqual(r.status_code, 200)
186
        body = json.loads(r.content)
187
        self.assertEqual(body['serial'], serial)
188
        assertIn('issue_time', body)
189
        self.assertEqual(body['provisions'], commission_request['provisions'])
190
        self.assertEqual(body['name'], commission_request['name'])
191

    
192
        r = client.get(u('service_quotas?user=' + user.uuid), **s1_headers)
193
        self.assertEqual(r.status_code, 200)
194
        body = json.loads(r.content)
195
        user_quota = body[user.uuid]
196
        system_quota = user_quota['system']
197
        r11 = system_quota[resource11['name']]
198
        self.assertEqual(r11['usage'], 3)
199
        self.assertEqual(r11['pending'], 3)
200

    
201
        # resolve pending commissions
202
        resolve_data = {
203
            "accept": [1, 3],
204
            "reject": [2, 3, 4],
205
        }
206
        post_data = json.dumps(resolve_data)
207

    
208
        r = client.post(u('commissions/action'), post_data,
209
                        content_type='application/json', **s1_headers)
210
        self.assertEqual(r.status_code, 200)
211
        body = json.loads(r.content)
212
        self.assertEqual(body['accepted'], [1])
213
        self.assertEqual(body['rejected'], [2])
214
        failed = body['failed']
215
        self.assertEqual(len(failed), 2)
216

    
217
        r = client.get(u('commissions/' + str(serial)), **s1_headers)
218
        self.assertEqual(r.status_code, 404)
219

    
220
        # auto accept
221
        commission_request = {
222
            "auto_accept": True,
223
            "name": "my commission",
224
            "provisions": [
225
                {
226
                    "holder": user.uuid,
227
                    "source": "system",
228
                    "resource": resource11['name'],
229
                    "quantity": 1
230
                },
231
                {
232
                    "holder": user.uuid,
233
                    "source": "system",
234
                    "resource": resource12['name'],
235
                    "quantity": 100
236
                }]}
237

    
238
        post_data = json.dumps(commission_request)
239
        r = client.post(u('commissions'), post_data,
240
                        content_type='application/json', **s1_headers)
241
        self.assertEqual(r.status_code, 201)
242
        body = json.loads(r.content)
243
        serial = body['serial']
244
        self.assertEqual(serial, 4)
245

    
246
        r = client.get(u('commissions/' + str(serial)), **s1_headers)
247
        self.assertEqual(r.status_code, 404)
248

    
249
        # malformed
250
        commission_request = {
251
            "auto_accept": True,
252
            "name": "my commission",
253
            "provisions": [
254
                {
255
                    "holder": user.uuid,
256
                    "source": "system",
257
                    "resource": resource11['name'],
258
                }
259
            ]}
260

    
261
        post_data = json.dumps(commission_request)
262
        r = client.post(u('commissions'), post_data,
263
                        content_type='application/json', **s1_headers)
264
        self.assertEqual(r.status_code, 400)
265

    
266
        commission_request = {
267
            "auto_accept": True,
268
            "name": "my commission",
269
            "provisions": "dummy"}
270

    
271
        post_data = json.dumps(commission_request)
272
        r = client.post(u('commissions'), post_data,
273
                        content_type='application/json', **s1_headers)
274
        self.assertEqual(r.status_code, 400)
275

    
276
        r = client.post(u('commissions'), commission_request,
277
                        content_type='application/json', **s1_headers)
278
        self.assertEqual(r.status_code, 400)
279

    
280
        # no holding
281
        commission_request = {
282
            "auto_accept": True,
283
            "name": "my commission",
284
            "provisions": [
285
                {
286
                    "holder": user.uuid,
287
                    "source": "system",
288
                    "resource": "non existent",
289
                    "quantity": 1
290
                },
291
                {
292
                    "holder": user.uuid,
293
                    "source": "system",
294
                    "resource": resource12['name'],
295
                    "quantity": 100
296
                }]}
297

    
298
        post_data = json.dumps(commission_request)
299
        r = client.post(u('commissions'), post_data,
300
                        content_type='application/json', **s1_headers)
301
        self.assertEqual(r.status_code, 404)
302

    
303
        # release
304
        commission_request = {
305
            "provisions": [
306
                {
307
                    "holder": user.uuid,
308
                    "source": "system",
309
                    "resource": resource11['name'],
310
                    "quantity": -1
311
                }
312
            ]}
313

    
314
        post_data = json.dumps(commission_request)
315
        r = client.post(u('commissions'), post_data,
316
                        content_type='application/json', **s1_headers)
317
        self.assertEqual(r.status_code, 201)
318
        body = json.loads(r.content)
319
        serial = body['serial']
320

    
321
        accept_data = {'accept': ""}
322
        post_data = json.dumps(accept_data)
323
        r = client.post(u('commissions/' + str(serial) + '/action'), post_data,
324
                        content_type='application/json', **s1_headers)
325
        self.assertEqual(r.status_code, 200)
326

    
327
        reject_data = {'reject': ""}
328
        post_data = json.dumps(accept_data)
329
        r = client.post(u('commissions/' + str(serial) + '/action'), post_data,
330
                        content_type='application/json', **s1_headers)
331
        self.assertEqual(r.status_code, 404)
332

    
333
        # force
334
        commission_request = {
335
            "force": True,
336
            "provisions": [
337
                {
338
                    "holder": user.uuid,
339
                    "source": "system",
340
                    "resource": resource11['name'],
341
                    "quantity": 100
342
                }]}
343

    
344
        post_data = json.dumps(commission_request)
345
        r = client.post(u('commissions'), post_data,
346
                        content_type='application/json', **s1_headers)
347
        self.assertEqual(r.status_code, 201)
348

    
349
        commission_request = {
350
            "force": True,
351
            "provisions": [
352
                {
353
                    "holder": user.uuid,
354
                    "source": "system",
355
                    "resource": resource11['name'],
356
                    "quantity": -200
357
                }]}
358

    
359
        post_data = json.dumps(commission_request)
360
        r = client.post(u('commissions'), post_data,
361
                        content_type='application/json', **s1_headers)
362
        self.assertEqual(r.status_code, 413)
363

    
364
        r = client.get(u('quotas'), **headers)
365
        self.assertEqual(r.status_code, 200)
366
        body = json.loads(r.content)
367
        system_quota = body['system']
368
        r11 = system_quota[resource11['name']]
369
        self.assertEqual(r11['usage'], 102)
370
        self.assertEqual(r11['pending'], 101)
371

    
372

    
373
class TokensApiTest(TestCase):
374
    def setUp(self):
375
        backend = activation_backends.get_backend()
376

    
377
        self.user1 = AstakosUser.objects.create(
378
            email='test1', email_verified=True, moderated=True,
379
            is_rejected=False)
380
        backend.activate_user(self.user1)
381
        assert self.user1.is_active is True
382

    
383
        self.user2 = AstakosUser.objects.create(
384
            email='test2', email_verified=True, moderated=True,
385
            is_rejected=False)
386
        backend.activate_user(self.user2)
387
        assert self.user2.is_active is True
388

    
389
        Service(name='service1', url='http://localhost/service1',
390
                api_url='http://localhost/api/service1',
391
                type='service1').save()
392
        Service(name='service2', url='http://localhost/service2',
393
                api_url='http://localhost/api/service2',
394
                type='service2').save()
395
        Service(name='service3', url='http://localhost/service3',
396
                api_url='http://localhost/api/service3',
397
                type='service3').save()
398

    
399
    def test_authenticate(self):
400
        client = Client()
401

    
402
        # Check not allowed method
403
        url = '/astakos/api/tokens'
404
        r = client.get(url, post_data={})
405
        self.assertEqual(r.status_code, 400)
406

    
407
        # Malformed request
408
        url = '/astakos/api/tokens'
409
        r = client.post(url, post_data={})
410
        self.assertEqual(r.status_code, 400)
411

    
412
        # Check unsupported xml input
413
        url = '/astakos/api/tokens'
414
        post_data = """
415
            <?xml version="1.0" encoding="UTF-8"?>
416
                <auth xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
417
                 xmlns="http://docs.openstack.org/identity/api/v2.0"
418
                 tenantName="%s">
419
                  <passwordCredentials username="%s" password="%s"/>
420
                </auth>""" % (self.user1.uuid, self.user1.uuid,
421
                              self.user1.auth_token)
422
        r = client.post(url, post_data, content_type='application/xml')
423
        self.assertEqual(r.status_code, 400)
424
        body = json.loads(r.content)
425
        self.assertEqual(body['badRequest']['message'],
426
                         "Unsupported Content-type: 'application/xml'")
427

    
428
        # Check malformed request: missing password
429
        url = '/astakos/api/tokens'
430
        post_data = """{"auth":{"passwordCredentials":{"username":"%s"},
431
                                "tenantName":"%s"}}""" % (
432
            self.user1.uuid, self.user1.uuid)
433
        r = client.post(url, post_data, content_type='application/json')
434
        self.assertEqual(r.status_code, 400)
435
        body = json.loads(r.content)
436
        self.assertEqual(body['badRequest']['message'],
437
                         'Malformed request')
438

    
439
        # Check malformed request: missing username
440
        url = '/astakos/api/tokens'
441
        post_data = """{"auth":{"passwordCredentials":{"password":"%s"},
442
                                "tenantName":"%s"}}""" % (
443
            self.user1.auth_token, self.user1.uuid)
444
        r = client.post(url, post_data, content_type='application/json')
445
        self.assertEqual(r.status_code, 400)
446
        body = json.loads(r.content)
447
        self.assertEqual(body['badRequest']['message'],
448
                         'Malformed request')
449

    
450
        # Check invalid pass
451
        url = '/astakos/api/tokens'
452
        post_data = """{"auth":{"passwordCredentials":{"username":"%s",
453
                                                       "password":"%s"},
454
                                "tenantName":"%s"}}""" % (
455
            self.user1.uuid, '', self.user1.uuid)
456
        r = client.post(url, post_data, content_type='application/json')
457
        self.assertEqual(r.status_code, 401)
458
        body = json.loads(r.content)
459
        self.assertEqual(body['unauthorized']['message'],
460
                         'Invalid token')
461

    
462
        # Check inconsistent pass
463
        url = '/astakos/api/tokens'
464
        post_data = """{"auth":{"passwordCredentials":{"username":"%s",
465
                                                       "password":"%s"},
466
                                "tenantName":"%s"}}""" % (
467
            self.user1.uuid, self.user2.auth_token, self.user2.uuid)
468
        r = client.post(url, post_data, content_type='application/json')
469
        self.assertEqual(r.status_code, 401)
470
        body = json.loads(r.content)
471
        self.assertEqual(body['unauthorized']['message'],
472
                         'Invalid credentials')
473

    
474
        # Check invalid json data
475
        url = '/astakos/api/tokens'
476
        r = client.post(url, "not json", content_type='application/json')
477
        self.assertEqual(r.status_code, 400)
478
        body = json.loads(r.content)
479
        self.assertEqual(body['badRequest']['message'], 'Invalid JSON data')
480

    
481
        # Check auth with token
482
        url = '/astakos/api/tokens'
483
        post_data = """{"auth":{"token": {"id":"%s"},
484
                        "tenantName":"%s"}}""" % (
485
            self.user1.auth_token, self.user1.uuid)
486
        r = client.post(url, post_data, content_type='application/json')
487
        self.assertEqual(r.status_code, 200)
488
        self.assertTrue(r['Content-Type'].startswith('application/json'))
489
        try:
490
            body = json.loads(r.content)
491
        except Exception, e:
492
            self.fail(e)
493

    
494
        # Check successful json response
495
        url = '/astakos/api/tokens'
496
        post_data = """{"auth":{"passwordCredentials":{"username":"%s",
497
                                                       "password":"%s"},
498
                                "tenantName":"%s"}}""" % (
499
            self.user1.uuid, self.user1.auth_token, self.user1.uuid)
500
        r = client.post(url, post_data, content_type='application/json')
501
        self.assertEqual(r.status_code, 200)
502
        self.assertTrue(r['Content-Type'].startswith('application/json'))
503
        try:
504
            body = json.loads(r.content)
505
        except Exception, e:
506
            self.fail(e)
507

    
508
        try:
509
            token = body['token']['id']
510
            user = body['user']['id']
511
            service_catalog = body['serviceCatalog']
512
        except KeyError:
513
            self.fail('Invalid response')
514

    
515
        self.assertEqual(token, self.user1.auth_token)
516
        self.assertEqual(user, self.user1.uuid)
517
        self.assertEqual(len(service_catalog), 3)
518

    
519
        # Check successful xml response
520
        url = '/astakos/api/tokens'
521
        headers = {'HTTP_ACCEPT': 'application/xml'}
522
        post_data = """{"auth":{"passwordCredentials":{"username":"%s",
523
                                                       "password":"%s"},
524
                                "tenantName":"%s"}}""" % (
525
            self.user1.uuid, self.user1.auth_token, self.user1.uuid)
526
        r = client.post(url, post_data, content_type='application/json',
527
                        **headers)
528
        self.assertEqual(r.status_code, 200)
529
        self.assertTrue(r['Content-Type'].startswith('application/xml'))
530
#        try:
531
#            body = minidom.parseString(r.content)
532
#        except Exception, e:
533
#            self.fail(e)
534

    
535
    def test_get_endpoints(self):
536
        client = Client()
537

    
538
        # Check in active user token
539
        inactive_user = AstakosUser.objects.create(email='test3')
540
        url = '/astakos/api/tokens/%s/endpoints' % quote(
541
            inactive_user.auth_token)
542
        r = client.get(url)
543
        self.assertEqual(r.status_code, 401)
544

    
545
        # Check invalid user token in path
546
        url = '/astakos/api/tokens/nouser/endpoints'
547
        r = client.get(url)
548
        self.assertEqual(r.status_code, 401)
549

    
550
        # Check forbidden
551
        url = '/astakos/api/tokens/%s/endpoints' % quote(self.user1.auth_token)
552
        headers = {'HTTP_X_AUTH_TOKEN': AstakosUser.objects.create(
553
            email='test4').auth_token}
554
        r = client.get(url, **headers)
555
        self.assertEqual(r.status_code, 401)
556

    
557
        # Check bad request method
558
        url = '/astakos/api/tokens/%s/endpoints' % quote(self.user1.auth_token)
559
        r = client.post(url)
560
        self.assertEqual(r.status_code, 400)
561

    
562
        # Check forbidden
563
        url = '/astakos/api/tokens/%s/endpoints' % quote(self.user1.auth_token)
564
        headers = {'HTTP_X_AUTH_TOKEN': self.user2.auth_token}
565
        r = client.get(url, **headers)
566
        self.assertEqual(r.status_code, 403)
567

    
568
        # Check belongsTo BadRequest
569
        url = '/astakos/api/tokens/%s/endpoints?belongsTo=%s' % (
570
            quote(self.user1.auth_token), quote(self.user2.uuid))
571
        headers = {'HTTP_X_AUTH_TOKEN': self.user1.auth_token}
572
        r = client.get(url, **headers)
573
        self.assertEqual(r.status_code, 400)
574

    
575
        # Check successful request
576
        url = '/astakos/api/tokens/%s/endpoints' % quote(self.user1.auth_token)
577
        headers = {'HTTP_X_AUTH_TOKEN': self.user1.auth_token}
578
        r = client.get(url, **headers)
579
        self.assertEqual(r.status_code, 200)
580
        self.assertEqual(r['Content-Type'], 'application/json; charset=UTF-8')
581
        try:
582
            body = json.loads(r.content)
583
        except:
584
            self.fail('json format expected')
585
        endpoints = body.get('endpoints')
586
        self.assertEqual(len(endpoints), 3)
587

    
588
         # Check xml serialization
589
        url = '/astakos/api/tokens/%s/endpoints?format=xml' %\
590
            quote(self.user1.auth_token)
591
        headers = {'HTTP_X_AUTH_TOKEN': self.user1.auth_token}
592
        r = client.get(url, **headers)
593
        self.assertEqual(r.status_code, 200)
594
        self.assertEqual(r['Content-Type'], 'application/xml; charset=UTF-8')
595
#        try:
596
#            body = minidom.parseString(r.content)
597
#        except Exception, e:
598
#            self.fail('xml format expected')
599
        endpoints = body.get('endpoints')
600
        self.assertEqual(len(endpoints), 3)
601

    
602
        # Check limit
603
        url = '/astakos/api/tokens/%s/endpoints?limit=2' %\
604
            quote(self.user1.auth_token)
605
        headers = {'HTTP_X_AUTH_TOKEN': self.user1.auth_token}
606
        r = client.get(url, **headers)
607
        self.assertEqual(r.status_code, 200)
608
        body = json.loads(r.content)
609
        endpoints = body.get('endpoints')
610
        self.assertEqual(len(endpoints), 2)
611

    
612
        endpoint_link = body.get('endpoint_links', [])[0]
613
        next = endpoint_link.get('href')
614
        p = urlparse(next)
615
        params = parse_qs(p.query)
616
        self.assertTrue('limit' in params)
617
        self.assertTrue('marker' in params)
618
        self.assertEqual(params['marker'][0], '2')
619

    
620
        # Check marker
621
        headers = {'HTTP_X_AUTH_TOKEN': self.user1.auth_token}
622
        r = client.get(next, **headers)
623
        self.assertEqual(r.status_code, 200)
624
        body = json.loads(r.content)
625
        endpoints = body.get('endpoints')
626
        self.assertEqual(len(endpoints), 1)