Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (21.6 kB)

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

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

    
36
from django.test import TestCase
37
from django.core.urlresolvers import reverse
38

    
39
#from xml.dom import minidom
40

    
41
import json
42

    
43
ROOT = "/%s/%s/%s/" % (
44
    astakos_settings.BASE_PATH, astakos_settings.ACCOUNTS_PREFIX, 'v1.0')
45
u = lambda url: ROOT + url
46

    
47

    
48
class QuotaAPITest(TestCase):
49
    def test_0(self):
50
        client = Client()
51

    
52
        component1 = Component.objects.create(name="comp1")
53
        register.add_service(component1, "service1", "type1", [])
54
        # custom service resources
55
        resource11 = {"name": "service1.resource11",
56
                      "desc": "resource11 desc",
57
                      "service_type": "type1",
58
                      "service_origin": "service1",
59
                      "allow_in_projects": True}
60
        r, _ = register.add_resource(resource11)
61
        register.update_resource(r, 100)
62
        resource12 = {"name": "service1.resource12",
63
                      "desc": "resource11 desc",
64
                      "service_type": "type1",
65
                      "service_origin": "service1",
66
                      "unit": "bytes"}
67
        r, _ = register.add_resource(resource12)
68
        register.update_resource(r, 1024)
69

    
70
        # create user
71
        user = get_local_user('test@grnet.gr')
72
        quotas.qh_sync_user(user)
73

    
74
        component2 = Component.objects.create(name="comp2")
75
        register.add_service(component2, "service2", "type2", [])
76
        # create another service
77
        resource21 = {"name": "service2.resource21",
78
                      "desc": "resource11 desc",
79
                      "service_type": "type2",
80
                      "service_origin": "service2",
81
                      "allow_in_projects": False}
82
        r, _ = register.add_resource(resource21)
83
        register.update_resource(r, 3)
84

    
85
        resource_names = [r['name'] for r in
86
                          [resource11, resource12, resource21]]
87

    
88
        # get resources
89
        r = client.get(u('resources'))
90
        self.assertEqual(r.status_code, 200)
91
        body = json.loads(r.content)
92
        for name in resource_names:
93
            assertIn(name, body)
94

    
95
        # get quota
96
        r = client.get(u('quotas'))
97
        self.assertEqual(r.status_code, 401)
98

    
99
        headers = {'HTTP_X_AUTH_TOKEN': user.auth_token}
100
        r = client.get(u('quotas/'), **headers)
101
        self.assertEqual(r.status_code, 200)
102
        body = json.loads(r.content)
103
        system_quota = body['system']
104
        assertIn('system', body)
105
        for name in resource_names:
106
            assertIn(name, system_quota)
107

    
108
        r = client.get(u('service_quotas'))
109
        self.assertEqual(r.status_code, 401)
110

    
111
        s1_headers = {'HTTP_X_AUTH_TOKEN': component1.auth_token}
112
        r = client.get(u('service_quotas'), **s1_headers)
113
        self.assertEqual(r.status_code, 200)
114
        body = json.loads(r.content)
115
        assertIn(user.uuid, body)
116

    
117
        r = client.get(u('commissions'), **s1_headers)
118
        self.assertEqual(r.status_code, 200)
119
        body = json.loads(r.content)
120
        self.assertEqual(body, [])
121

    
122
        # issue some commissions
123
        commission_request = {
124
            "force": False,
125
            "auto_accept": False,
126
            "name": "my commission",
127
            "provisions": [
128
                {
129
                    "holder": user.uuid,
130
                    "source": "system",
131
                    "resource": resource11['name'],
132
                    "quantity": 1
133
                },
134
                {
135
                    "holder": user.uuid,
136
                    "source": "system",
137
                    "resource": resource12['name'],
138
                    "quantity": 30000
139
                }]}
140

    
141
        post_data = json.dumps(commission_request)
142
        r = client.post(u('commissions'), post_data,
143
                        content_type='application/json', **s1_headers)
144
        self.assertEqual(r.status_code, 413)
145

    
146
        commission_request = {
147
            "force": False,
148
            "auto_accept": False,
149
            "name": "my commission",
150
            "provisions": [
151
                {
152
                    "holder": user.uuid,
153
                    "source": "system",
154
                    "resource": resource11['name'],
155
                    "quantity": 1
156
                },
157
                {
158
                    "holder": user.uuid,
159
                    "source": "system",
160
                    "resource": resource12['name'],
161
                    "quantity": 100
162
                }]}
163

    
164
        post_data = json.dumps(commission_request)
165
        r = client.post(u('commissions'), post_data,
166
                        content_type='application/json', **s1_headers)
167
        self.assertEqual(r.status_code, 201)
168
        body = json.loads(r.content)
169
        serial = body['serial']
170
        self.assertEqual(serial, 1)
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'], 2)
178

    
179
        post_data = json.dumps(commission_request)
180
        r = client.post(u('commissions'), post_data,
181
                        content_type='application/json', **s1_headers)
182
        self.assertEqual(r.status_code, 201)
183
        body = json.loads(r.content)
184
        self.assertEqual(body['serial'], 3)
185

    
186
        r = client.get(u('commissions'), **s1_headers)
187
        self.assertEqual(r.status_code, 200)
188
        body = json.loads(r.content)
189
        self.assertEqual(body, [1, 2, 3])
190

    
191
        r = client.get(u('commissions/' + str(serial)), **s1_headers)
192
        self.assertEqual(r.status_code, 200)
193
        body = json.loads(r.content)
194
        self.assertEqual(body['serial'], serial)
195
        assertIn('issue_time', body)
196
        self.assertEqual(body['provisions'], commission_request['provisions'])
197
        self.assertEqual(body['name'], commission_request['name'])
198

    
199
        r = client.get(u('service_quotas?user=' + user.uuid), **s1_headers)
200
        self.assertEqual(r.status_code, 200)
201
        body = json.loads(r.content)
202
        user_quota = body[user.uuid]
203
        system_quota = user_quota['system']
204
        r11 = system_quota[resource11['name']]
205
        self.assertEqual(r11['usage'], 3)
206
        self.assertEqual(r11['pending'], 3)
207

    
208
        # resolve pending commissions
209
        resolve_data = {
210
            "accept": [1, 3],
211
            "reject": [2, 3, 4],
212
        }
213
        post_data = json.dumps(resolve_data)
214

    
215
        r = client.post(u('commissions/action'), post_data,
216
                        content_type='application/json', **s1_headers)
217
        self.assertEqual(r.status_code, 200)
218
        body = json.loads(r.content)
219
        self.assertEqual(body['accepted'], [1])
220
        self.assertEqual(body['rejected'], [2])
221
        failed = body['failed']
222
        self.assertEqual(len(failed), 2)
223

    
224
        r = client.get(u('commissions/' + str(serial)), **s1_headers)
225
        self.assertEqual(r.status_code, 404)
226

    
227
        # auto accept
228
        commission_request = {
229
            "auto_accept": True,
230
            "name": "my commission",
231
            "provisions": [
232
                {
233
                    "holder": user.uuid,
234
                    "source": "system",
235
                    "resource": resource11['name'],
236
                    "quantity": 1
237
                },
238
                {
239
                    "holder": user.uuid,
240
                    "source": "system",
241
                    "resource": resource12['name'],
242
                    "quantity": 100
243
                }]}
244

    
245
        post_data = json.dumps(commission_request)
246
        r = client.post(u('commissions'), post_data,
247
                        content_type='application/json', **s1_headers)
248
        self.assertEqual(r.status_code, 201)
249
        body = json.loads(r.content)
250
        serial = body['serial']
251
        self.assertEqual(serial, 4)
252

    
253
        r = client.get(u('commissions/' + str(serial)), **s1_headers)
254
        self.assertEqual(r.status_code, 404)
255

    
256
        # malformed
257
        commission_request = {
258
            "auto_accept": True,
259
            "name": "my commission",
260
            "provisions": [
261
                {
262
                    "holder": user.uuid,
263
                    "source": "system",
264
                    "resource": resource11['name'],
265
                }
266
            ]}
267

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

    
273
        commission_request = {
274
            "auto_accept": True,
275
            "name": "my commission",
276
            "provisions": "dummy"}
277

    
278
        post_data = json.dumps(commission_request)
279
        r = client.post(u('commissions'), post_data,
280
                        content_type='application/json', **s1_headers)
281
        self.assertEqual(r.status_code, 400)
282

    
283
        r = client.post(u('commissions'), commission_request,
284
                        content_type='application/json', **s1_headers)
285
        self.assertEqual(r.status_code, 400)
286

    
287
        # no holding
288
        commission_request = {
289
            "auto_accept": True,
290
            "name": "my commission",
291
            "provisions": [
292
                {
293
                    "holder": user.uuid,
294
                    "source": "system",
295
                    "resource": "non existent",
296
                    "quantity": 1
297
                },
298
                {
299
                    "holder": user.uuid,
300
                    "source": "system",
301
                    "resource": resource12['name'],
302
                    "quantity": 100
303
                }]}
304

    
305
        post_data = json.dumps(commission_request)
306
        r = client.post(u('commissions'), post_data,
307
                        content_type='application/json', **s1_headers)
308
        self.assertEqual(r.status_code, 404)
309

    
310
        # release
311
        commission_request = {
312
            "provisions": [
313
                {
314
                    "holder": user.uuid,
315
                    "source": "system",
316
                    "resource": resource11['name'],
317
                    "quantity": -1
318
                }
319
            ]}
320

    
321
        post_data = json.dumps(commission_request)
322
        r = client.post(u('commissions'), post_data,
323
                        content_type='application/json', **s1_headers)
324
        self.assertEqual(r.status_code, 201)
325
        body = json.loads(r.content)
326
        serial = body['serial']
327

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

    
334
        reject_data = {'reject': ""}
335
        post_data = json.dumps(accept_data)
336
        r = client.post(u('commissions/' + str(serial) + '/action'), post_data,
337
                        content_type='application/json', **s1_headers)
338
        self.assertEqual(r.status_code, 404)
339

    
340
        # force
341
        commission_request = {
342
            "force": True,
343
            "provisions": [
344
                {
345
                    "holder": user.uuid,
346
                    "source": "system",
347
                    "resource": resource11['name'],
348
                    "quantity": 100
349
                }]}
350

    
351
        post_data = json.dumps(commission_request)
352
        r = client.post(u('commissions'), post_data,
353
                        content_type='application/json', **s1_headers)
354
        self.assertEqual(r.status_code, 201)
355

    
356
        commission_request = {
357
            "force": True,
358
            "provisions": [
359
                {
360
                    "holder": user.uuid,
361
                    "source": "system",
362
                    "resource": resource11['name'],
363
                    "quantity": -200
364
                }]}
365

    
366
        post_data = json.dumps(commission_request)
367
        r = client.post(u('commissions'), post_data,
368
                        content_type='application/json', **s1_headers)
369
        self.assertEqual(r.status_code, 413)
370

    
371
        r = client.get(u('quotas'), **headers)
372
        self.assertEqual(r.status_code, 200)
373
        body = json.loads(r.content)
374
        system_quota = body['system']
375
        r11 = system_quota[resource11['name']]
376
        self.assertEqual(r11['usage'], 102)
377
        self.assertEqual(r11['pending'], 101)
378

    
379

    
380
class TokensApiTest(TestCase):
381
    def setUp(self):
382
        backend = activation_backends.get_backend()
383

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

    
390
        self.user2 = AstakosUser.objects.create(
391
            email='test2', email_verified=True, moderated=True,
392
            is_rejected=False)
393
        backend.activate_user(self.user2)
394
        assert self.user2.is_active is True
395

    
396
        c1 = Component(name='component1', url='http://localhost/component1')
397
        c1.save()
398
        s1 = Service(component=c1, type='type1', name='service1')
399
        s1.save()
400
        e1 = Endpoint(service=s1)
401
        e1.save()
402
        e1.data.create(key='versionId', value='v1.0')
403
        e1.data.create(key='publicURL', value='http://localhost:8000/s1/v1.0')
404

    
405
        s2 = Service(component=c1, type='type2', name='service2')
406
        s2.save()
407
        e2 = Endpoint(service=s2)
408
        e2.save()
409
        e2.data.create(key='versionId', value='v1.0')
410
        e2.data.create(key='publicURL', value='http://localhost:8000/s2/v1.0')
411

    
412
        c2 = Component(name='component2', url='http://localhost/component2')
413
        c2.save()
414
        s3 = Service(component=c2, type='type3', name='service3')
415
        s3.save()
416
        e3 = Endpoint(service=s3)
417
        e3.save()
418
        e3.data.create(key='versionId', value='v2.0')
419
        e3.data.create(key='publicURL', value='http://localhost:8000/s3/v2.0')
420

    
421
    def test_authenticate(self):
422
        client = Client()
423

    
424
        # Check not allowed method
425
        url = reverse('astakos.api.tokens.authenticate')
426
        r = client.get(url, post_data={})
427
        self.assertEqual(r.status_code, 400)
428

    
429
        # check public mode
430
        r = client.post(url, CONTENT_LENGTH=0)
431
        self.assertEqual(r.status_code, 200)
432
        self.assertTrue(r['Content-Type'].startswith('application/json'))
433
        try:
434
            body = json.loads(r.content)
435
        except Exception, e:
436
            self.fail(e)
437
        self.assertTrue('token' not in body.get('access'))
438
        self.assertTrue('user' not in body.get('access'))
439
        self.assertTrue('serviceCatalog' in body.get('access'))
440

    
441
        # Check unsupported xml input
442
        url = reverse('astakos.api.tokens.authenticate')
443
        post_data = """
444
            <?xml version="1.0" encoding="UTF-8"?>
445
                <auth xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
446
                 xmlns="http://docs.openstack.org/identity/api/v2.0"
447
                 tenantName="%s">
448
                  <passwordCredentials username="%s" password="%s"/>
449
                </auth>""" % (self.user1.uuid, self.user1.uuid,
450
                              self.user1.auth_token)
451
        r = client.post(url, post_data, content_type='application/xml')
452
        self.assertEqual(r.status_code, 400)
453
        body = json.loads(r.content)
454
        self.assertEqual(body['badRequest']['message'],
455
                         "Unsupported Content-type: 'application/xml'")
456

    
457
        # Check malformed request: missing password
458
        url = reverse('astakos.api.tokens.authenticate')
459
        post_data = """{"auth":{"passwordCredentials":{"username":"%s"},
460
                                "tenantName":"%s"}}""" % (
461
            self.user1.uuid, self.user1.uuid)
462
        r = client.post(url, post_data, content_type='application/json')
463
        self.assertEqual(r.status_code, 400)
464
        body = json.loads(r.content)
465
        self.assertEqual(body['badRequest']['message'],
466
                         'Malformed request')
467

    
468
        # Check malformed request: missing username
469
        url = reverse('astakos.api.tokens.authenticate')
470
        post_data = """{"auth":{"passwordCredentials":{"password":"%s"},
471
                                "tenantName":"%s"}}""" % (
472
            self.user1.auth_token, self.user1.uuid)
473
        r = client.post(url, post_data, content_type='application/json')
474
        self.assertEqual(r.status_code, 400)
475
        body = json.loads(r.content)
476
        self.assertEqual(body['badRequest']['message'],
477
                         'Malformed request')
478

    
479
        # Check invalid pass
480
        url = reverse('astakos.api.tokens.authenticate')
481
        post_data = """{"auth":{"passwordCredentials":{"username":"%s",
482
                                                       "password":"%s"},
483
                                "tenantName":"%s"}}""" % (
484
            self.user1.uuid, '', self.user1.uuid)
485
        r = client.post(url, post_data, content_type='application/json')
486
        self.assertEqual(r.status_code, 401)
487
        body = json.loads(r.content)
488
        self.assertEqual(body['unauthorized']['message'],
489
                         'Invalid token')
490

    
491
        # Check inconsistent pass
492
        url = reverse('astakos.api.tokens.authenticate')
493
        post_data = """{"auth":{"passwordCredentials":{"username":"%s",
494
                                                       "password":"%s"},
495
                                "tenantName":"%s"}}""" % (
496
            self.user1.uuid, self.user2.auth_token, self.user2.uuid)
497
        r = client.post(url, post_data, content_type='application/json')
498
        self.assertEqual(r.status_code, 401)
499
        body = json.loads(r.content)
500
        self.assertEqual(body['unauthorized']['message'],
501
                         'Invalid credentials')
502

    
503
        # Check invalid json data
504
        url = reverse('astakos.api.tokens.authenticate')
505
        r = client.post(url, "not json", content_type='application/json')
506
        self.assertEqual(r.status_code, 400)
507
        body = json.loads(r.content)
508
        self.assertEqual(body['badRequest']['message'], 'Invalid JSON data')
509

    
510
        # Check auth with token
511
        url = reverse('astakos.api.tokens.authenticate')
512
        post_data = """{"auth":{"token": {"id":"%s"},
513
                        "tenantName":"%s"}}""" % (
514
            self.user1.auth_token, self.user1.uuid)
515
        r = client.post(url, post_data, content_type='application/json')
516
        self.assertEqual(r.status_code, 200)
517
        self.assertTrue(r['Content-Type'].startswith('application/json'))
518
        try:
519
            body = json.loads(r.content)
520
        except Exception, e:
521
            self.fail(e)
522

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

    
537
        try:
538
            token = body['access']['token']['id']
539
            user = body['access']['user']['id']
540
            service_catalog = body['access']['serviceCatalog']
541
        except KeyError:
542
            self.fail('Invalid response')
543

    
544
        self.assertEqual(token, self.user1.auth_token)
545
        self.assertEqual(user, self.user1.uuid)
546
        self.assertEqual(len(service_catalog), 3)
547

    
548
        # Check successful xml response
549
        url = reverse('astakos.api.tokens.authenticate')
550
        headers = {'HTTP_ACCEPT': 'application/xml'}
551
        post_data = """{"auth":{"passwordCredentials":{"username":"%s",
552
                                                       "password":"%s"},
553
                                "tenantName":"%s"}}""" % (
554
            self.user1.uuid, self.user1.auth_token, self.user1.uuid)
555
        r = client.post(url, post_data, content_type='application/json',
556
                        **headers)
557
        self.assertEqual(r.status_code, 200)
558
        self.assertTrue(r['Content-Type'].startswith('application/xml'))
559
#        try:
560
#            body = minidom.parseString(r.content)
561
#        except Exception, e:
562
#            self.fail(e)
563

    
564
        # test public mode: json response