Statistics
| Branch: | Tag: | Revision:

root / snf-pithos-app / pithos / api / test / accounts.py @ 1e47e49d

History | View | Annotate | Download (20.9 kB)

1
#!/usr/bin/env python
2
#coding=utf8
3

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

    
37
from pithos.api.test import (PithosAPITest, AssertMappingInvariant,
38
                             DATE_FORMATS)
39

    
40
from synnefo.lib import join_urls
41

    
42
import time as _time
43
import datetime
44

    
45
import django.utils.simplejson as json
46

    
47
class AccountHead(PithosAPITest):
48
    def test_get_account_meta(self):
49
        cnames = ['apples', 'bananas', 'kiwis', 'oranges', 'pears']
50

    
51
        # create containers
52
        uploaded_bytes = 0
53
        for cname in cnames:
54
            self.create_container(cname)
55

    
56
            # upload object
57
            name, data, resp = self.upload_object(cname)
58
            uploaded_bytes += len(data)
59

    
60
        # set account meta
61
        self.update_account_meta({'foo': 'bar'})
62

    
63
        account_info = self.get_account_info()
64
        self.assertTrue('X-Account-Meta-Foo' in account_info)
65
        self.assertEqual(account_info['X-Account-Meta-Foo'], 'bar')
66

    
67
        # list containers
68
        containers = self.list_containers()
69
        self.assertEqual(int(account_info['X-Account-Container-Count']),
70
                         len(containers))
71
        usage = 0
72
        for c in containers:
73
            # list objects
74
            objects = self.list_objects(c['name'])
75
            self.assertEqual(c['count'], len(objects))
76
            csum = sum([o['bytes'] for o in objects])
77
            self.assertEqual(int(c['bytes']), csum)
78
            usage += int(c['bytes'])
79

    
80
        self.assertEqual(
81
            int(account_info['x-account-bytes-used']) + uploaded_bytes,
82
            usage)
83

    
84
    def test_get_account_meta_until(self):
85
        cnames = ['apples', 'bananas', 'kiwis']
86

    
87
        # create containers
88
        uploaded_bytes = 0
89
        for cname in cnames:
90
            self.create_container(cname)
91

    
92
            # upload object
93
            name, data, resp = self.upload_object(cname)
94
            uploaded_bytes += len(data)
95

    
96
        self.update_account_meta({'foo': 'bar'})
97

    
98
        account_info = self.get_account_info()
99
        t = datetime.datetime.strptime(account_info['Last-Modified'],
100
                                       DATE_FORMATS[2])
101
        t1 = t + datetime.timedelta(seconds=1)
102
        until = int(_time.mktime(t1.timetuple()))
103

    
104
        _time.sleep(2)
105

    
106
        # add containers
107
        cnames = ['oranges', 'pears']
108
        for cname in cnames:
109
            self.create_container(cname)
110

    
111
            # upload object
112
            self.upload_object(cname)
113

    
114
        self.update_account_meta({'quality': 'AAA'})
115

    
116
        account_info = self.get_account_info()
117
        t = datetime.datetime.strptime(account_info['Last-Modified'],
118
                                       DATE_FORMATS[-1])
119
        last_modified = int(_time.mktime(t.timetuple()))
120
        assert until < last_modified
121

    
122
        self.assertTrue('X-Account-Meta-Quality' in account_info)
123
        self.assertTrue('X-Account-Meta-Foo' in account_info)
124

    
125
        account_info = self.get_account_info(until=until)
126
        self.assertTrue('X-Account-Meta-Quality' not in account_info)
127
        self.assertTrue('X-Account-Meta-Foo' in account_info)
128
        self.assertTrue('X-Account-Until-Timestamp' in account_info)
129
        t = datetime.datetime.strptime(
130
            account_info['X-Account-Until-Timestamp'], DATE_FORMATS[2])
131
        self.assertTrue(int(_time.mktime(t1.timetuple())) <= until)
132
        self.assertTrue('X-Account-Container-Count' in account_info)
133
        self.assertEqual(int(account_info['X-Account-Container-Count']), 3)
134
        self.assertTrue('X-Account-Bytes-Used' in account_info)
135

    
136
    def test_get_account_meta_until_invalid_date(self):
137
        self.update_account_meta({'quality': 'AAA'})
138
        meta = self.get_account_meta(until='-1')
139
        self.assertTrue('Quality' in meta)
140

    
141

    
142
class AccountGet(PithosAPITest):
143
    def setUp(self):
144
        PithosAPITest.setUp(self)
145
        cnames = ['apples', 'bananas', 'kiwis', 'oranges', 'pears']
146

    
147
        # create containers
148
        uploaded_bytes = 0
149
        for cname in cnames:
150
            self.create_container(cname)
151

    
152
            # upload object
153
            name, data, resp = self.upload_object(cname)
154
            uploaded_bytes += len(data)
155

    
156
    def test_list(self):
157
        #list containers: row format
158
        containers = self.list_containers(format=None)
159
        self.assertEquals(containers,
160
                          ['apples', 'bananas', 'kiwis', 'oranges', 'pears'])
161

    
162
    def test_list_until(self):
163
        account_info = self.get_account_info()
164
        t = datetime.datetime.strptime(account_info['Last-Modified'],
165
                                       DATE_FORMATS[2])
166
        t1 = t + datetime.timedelta(seconds=1)
167
        until = int(_time.mktime(t1.timetuple()))
168

    
169
        _time.sleep(2)
170

    
171
        self.create_container()
172
        
173
        url = join_urls(self.pithos_path, self.user)
174
        r = self.get('%s?until=%s' % (url, until))
175
        self.assertEqual(r.status_code, 200)
176
        containers = r.content.split('\n')
177
        if '' in containers:
178
            containers.remove('')
179
        self.assertEqual(containers,
180
                         ['apples', 'bananas', 'kiwis', 'oranges', 'pears'])
181

    
182
        
183
        r = self.get('%s?until=%s&format=json' % (url, until))
184
        self.assertEqual(r.status_code, 200)
185
        try:
186
            containers = json.loads(r.content)
187
        except:
188
            self.fail('json format expected')
189
        self.assertEqual([c['name'] for c in containers],
190
                         ['apples', 'bananas', 'kiwis', 'oranges', 'pears']) 
191

    
192
    def test_list_shared(self):
193
        # upload and publish object
194
        oname, data, resp = self.upload_object('apples')
195
        url = join_urls(self.pithos_path, self.user, 'apples', oname)
196
        r = self.post(url, content_type='', HTTP_X_OBJECT_PUBLIC='true')
197
        self.assertEqual(r.status_code, 202)
198

    
199
        # upload and share object
200
        other, data, resp = self.upload_object('bananas')
201
        url = join_urls(self.pithos_path, self.user, 'bananas', other)
202
        r = self.post(url, content_type='', HTTP_X_OBJECT_SHARING='read=alice')
203
        self.assertEqual(r.status_code, 202)
204

    
205
        url = join_urls(self.pithos_path, self.user)
206

    
207
        # list shared containers
208
        r = self.get('%s?public=' % url)
209
        objects = r.content.split('\n')
210
        if '' in objects:
211
            objects.remove('')
212
        self.assertEqual(objects, ['apples'])
213

    
214
        # list shared containers
215
        r = self.get('%s?shared=' % url)
216
        objects = r.content.split('\n')
217
        if '' in objects:
218
            objects.remove('')
219
        self.assertEqual(objects, ['bananas'])
220

    
221
        # list public and shared containers
222
        r = self.get('%s?public=&shared=' % url)
223
        objects = r.content.split('\n')
224
        if '' in objects:
225
            objects.remove('')
226
        self.assertEqual(objects, ['apples', 'bananas'])
227

    
228
        # assert forbidden public container listing
229
        r = self.get('%s?public=' % url, user='alice')
230
        self.assertEqual(r.status_code, 403)
231

    
232
        # assert forbidden shared & public container listing
233
        r = self.get('%s?public=&shared=' % url, user='alice')
234
        self.assertEqual(r.status_code, 403)
235

    
236
    def test_list_with_limit(self):
237
        containers = self.list_containers(format=None, limit=2)
238
        self.assertEquals(len(containers), 2)
239
        self.assertEquals(containers, ['apples', 'bananas'])
240

    
241
    def test_list_with_marker(self):
242
        containers = self.list_containers(format=None, limit=2,
243
                                          marker='bananas')
244
        self.assertEquals(containers, ['kiwis', 'oranges'])
245

    
246
        containers = self.list_containers(format=None, limit=2,
247
                                          marker='oranges')
248
        self.assertEquals(containers, ['pears'])
249

    
250
    def test_list_json_with_marker(self):
251
        containers = self.list_containers(format='json', limit=2,
252
                                          marker='bananas')
253
        self.assert_extended(containers, 'json', 'container', 2)
254
        self.assertEqual(containers[0]['name'], 'kiwis')
255
        self.assertEqual(containers[1]['name'], 'oranges')
256

    
257
        containers = self.list_containers(format='json', limit=2,
258
                                          marker='oranges')
259
        self.assert_extended(containers, 'json', 'container', 1)
260
        self.assertEqual(containers[0]['name'], 'pears')
261

    
262
    def test_list_xml_with_marker(self):
263
        xml = self.list_containers(format='xml', limit=2, marker='bananas')
264
        self.assert_extended(xml, 'xml', 'container', 2)
265
        nodes = xml.getElementsByTagName('name')
266
        self.assertTrue(len(nodes) <= 2)
267
        names = [n.childNodes[0].data for n in nodes]
268
        self.assertEqual(names, ['kiwis', 'oranges'])
269

    
270
        xml = self.list_containers(format='xml', limit=2, marker='oranges')
271
        self.assert_extended(xml, 'xml', 'container', 1)
272
        nodes = xml.getElementsByTagName('name')
273
        self.assertTrue(len(nodes) <= 2)
274
        names = [n.childNodes[0].data for n in nodes]
275
        self.assertEqual(names, ['pears'])
276

    
277
    def test_if_modified_since(self):
278
        account_info = self.get_account_info()
279
        last_modified = account_info['Last-Modified']
280
        t1 = datetime.datetime.strptime(last_modified, DATE_FORMATS[-1])
281
        t1_formats = map(t1.strftime, DATE_FORMATS)
282

    
283
        # Check not modified
284
        url = join_urls(self.pithos_path, self.user)
285
        for t in t1_formats:
286
            r = self.get(url, HTTP_IF_MODIFIED_SINCE=t)
287
            self.assertEqual(r.status_code, 304)
288

    
289
        # modify account: add container
290
        _time.sleep(1)
291
        self.create_container('c1')
292

    
293
        # Check modified
294
        for t in t1_formats:
295
            r = self.get(url, HTTP_IF_MODIFIED_SINCE=t)
296
            self.assertEqual(r.status_code, 200)
297
            self.assertEqual(
298
                r.content.split('\n')[:-1],
299
                ['apples', 'bananas', 'c1', 'kiwis', 'oranges', 'pears'])
300

    
301
        account_info = self.get_account_info()
302
        last_modified = account_info['Last-Modified']
303
        t2 = datetime.datetime.strptime(last_modified, DATE_FORMATS[-1])
304
        t2_formats = map(t2.strftime, DATE_FORMATS)
305

    
306
        # modify account: update account meta
307
        _time.sleep(1)
308
        self.update_account_meta({'foo': 'bar'})
309

    
310
        # Check modified
311
        for t in t2_formats:
312
            r = self.get(url, HTTP_IF_MODIFIED_SINCE=t)
313
            self.assertEqual(r.status_code, 200)
314
            self.assertEqual(
315
                r.content.split('\n')[:-1],
316
                ['apples', 'bananas', 'c1', 'kiwis', 'oranges', 'pears'])
317

    
318
    def test_if_modified_since_invalid_date(self):
319
        url = join_urls(self.pithos_path, self.user)
320
        r = self.get(url, HTTP_IF_MODIFIED_SINCE='Monday')
321
        self.assertEqual(r.status_code, 200)
322
        self.assertEqual(
323
            r.content.split('\n')[:-1],
324
            ['apples', 'bananas', 'kiwis', 'oranges', 'pears'])
325

    
326
    def test_if_not_modified_since(self):
327
        url = join_urls(self.pithos_path, self.user)
328
        account_info = self.get_account_info()
329
        last_modified = account_info['Last-Modified']
330
        t = datetime.datetime.strptime(last_modified, DATE_FORMATS[-1])
331

    
332
        # Check unmodified
333
        t1 = t + datetime.timedelta(seconds=1)
334
        t1_formats = map(t1.strftime, DATE_FORMATS)
335
        for t in t1_formats:
336
            r = self.get(url, HTTP_IF_UNMODIFIED_SINCE=t)
337
            self.assertEqual(r.status_code, 200)
338
            self.assertEqual(
339
                r.content.split('\n')[:-1],
340
                ['apples', 'bananas', 'kiwis', 'oranges', 'pears'])
341

    
342
        # modify account: add container
343
        _time.sleep(2)
344
        self.create_container('c1')
345

    
346
        account_info = self.get_account_info()
347
        last_modified = account_info['Last-Modified']
348
        t = datetime.datetime.strptime(last_modified, DATE_FORMATS[-1])
349
        t2 = t - datetime.timedelta(seconds=1)
350
        t2_formats = map(t2.strftime, DATE_FORMATS)
351

    
352
        # Check modified
353
        for t in t2_formats:
354
            r = self.get(url, HTTP_IF_UNMODIFIED_SINCE=t)
355
            self.assertEqual(r.status_code, 412)
356

    
357
        # modify account: update account meta
358
        _time.sleep(1)
359
        self.update_account_meta({'foo': 'bar'})
360

    
361
        account_info = self.get_account_info()
362
        last_modified = account_info['Last-Modified']
363
        t = datetime.datetime.strptime(last_modified, DATE_FORMATS[-1])
364
        t3 = t - datetime.timedelta(seconds=1)
365
        t3_formats = map(t3.strftime, DATE_FORMATS)
366

    
367
        # Check modified
368
        for t in t3_formats:
369
            r = self.get(url, HTTP_IF_UNMODIFIED_SINCE=t)
370
            self.assertEqual(r.status_code, 412)
371

    
372
    def test_if_unmodified_since_invalid_date(self):
373
        url = join_urls(self.pithos_path, self.user)
374
        r = self.get(url, HTTP_IF_UNMODIFIED_SINCE='Monday')
375
        self.assertEqual(r.status_code, 200)
376
        self.assertEqual(
377
            r.content.split('\n')[:-1],
378
            ['apples', 'bananas', 'kiwis', 'oranges', 'pears'])
379

    
380

    
381
class AccountPost(PithosAPITest):
382
    def setUp(self):
383
        PithosAPITest.setUp(self)
384
        cnames = ['apples', 'bananas', 'kiwis', 'oranges', 'pears']
385

    
386
        # create containers
387
        uploaded_bytes = 0
388
        for cname in cnames:
389
            self.create_container(cname)
390

    
391
            # upload object
392
            name, data, resp = self.upload_object(cname)
393
            uploaded_bytes += len(data)
394

    
395
        # set account meta
396
        self.update_account_meta({'foo': 'bar'})
397

    
398
    def test_update_meta(self):
399
        url = join_urls(self.pithos_path, self.user)
400
        with AssertMappingInvariant(self.get_account_groups):
401
            initial = self.get_account_meta()
402

    
403
            meta = {'test': 'tost', 'ping': 'pong'}
404
            kwargs = dict(('HTTP_X_ACCOUNT_META_%s' % k, str(v))
405
                          for k, v in meta.items())
406
            r = self.post('%s?update=' % url, **kwargs)
407
            self.assertEqual(r.status_code, 202)
408

    
409
            meta.update(initial)
410
            account_meta = self.get_account_meta()
411
            (self.assertTrue(k in account_meta) for k in meta.keys())
412
            (self.assertEqual(account_meta[k], v) for k, v in meta.items())
413

    
414
    def test_reset_meta(self):
415
        url = join_urls(self.pithos_path, self.user)
416
        with AssertMappingInvariant(self.get_account_groups):
417
            meta = {'test': 'tost', 'ping': 'pong'}
418
            self.update_account_meta(meta)
419

    
420
            new_meta = {'test': 'test33'}
421
            kwargs = dict((
422
                'HTTP_X_ACCOUNT_META_%s' % k, str(v)
423
            ) for k, v in new_meta.items())
424
            r = self.post(url, **kwargs)
425
            self.assertEqual(r.status_code, 202)
426

    
427
            account_meta = self.get_account_meta()
428
            (self.assertTrue(k in account_meta) for k in new_meta.keys())
429
            (self.assertEqual(account_meta[k], v) for k, v in new_meta.items())
430

    
431
            (self.assertTrue(k not in account_meta) for k in meta.keys())
432

    
433
    def test_delete_meta(self):
434
        url = join_urls(self.pithos_path, self.user)
435
        with AssertMappingInvariant(self.get_account_groups):
436
            meta = {'test': 'tost', 'ping': 'pong'}
437
            self.update_account_meta(meta)
438

    
439
            kwargs = dict(
440
                ('HTTP_X_ACCOUNT_META_%s' % k, '') for k, v in meta.items())
441
            r = self.post('%s?update=' % url, **kwargs)
442
            self.assertEqual(r.status_code, 202)
443

    
444
            account_meta = self.get_account_meta()
445

    
446
            (self.assertTrue(k not in account_meta) for k in meta.keys())
447

    
448
    def test_set_account_groups(self):
449
        url = join_urls(self.pithos_path, self.user)
450
        with AssertMappingInvariant(self.get_account_meta):
451
            pithosdevs = ['verigak', 'gtsouk', 'chazapis']
452
            r = self.post('%s?update=' % url,
453
                          HTTP_X_ACCOUNT_GROUP_PITHOSDEV=','.join(pithosdevs))
454
            self.assertEqual(r.status_code, 202)
455

    
456
            account_groups = self.get_account_groups()
457
            self.assertTrue('Pithosdev' in self.get_account_groups())
458
            self.assertEqual(account_groups['Pithosdev'],
459
                             ','.join(sorted(pithosdevs)))
460

    
461
            clientdevs = ['pkanavos', 'mvasilak']
462
            r = self.post('%s?update=' % url,
463
                          HTTP_X_ACCOUNT_GROUP_CLIENTSDEV=','.join(clientdevs))
464
            self.assertEqual(r.status_code, 202)
465

    
466
            account_groups = self.get_account_groups()
467
            self.assertTrue('Pithosdev' in account_groups)
468
            self.assertTrue('Clientsdev' in account_groups)
469
            self.assertEqual(account_groups['Pithosdev'],
470
                             ','.join(sorted(pithosdevs)))
471
            self.assertEqual(account_groups['Clientsdev'],
472
                             ','.join(sorted(clientdevs)))
473

    
474
            clientdevs = ['mvasilak']
475
            r = self.post('%s?update=' % url,
476
                          HTTP_X_ACCOUNT_GROUP_CLIENTSDEV=''.join(clientdevs))
477
            self.assertEqual(r.status_code, 202)
478

    
479
            account_groups = self.get_account_groups()
480
            self.assertTrue('Pithosdev' in account_groups)
481
            self.assertTrue('Clientsdev' in account_groups)
482
            self.assertEqual(account_groups['Pithosdev'],
483
                             ','.join(sorted(pithosdevs)))
484
            self.assertEqual(account_groups['Clientsdev'],
485
                             ','.join(sorted(clientdevs)))
486

    
487
    def test_reset_account_groups(self):
488
        url = join_urls(self.pithos_path, self.user)
489
        with AssertMappingInvariant(self.get_account_meta):
490
            groups = {'pithosdev': ['verigak', 'gtsouk', 'chazapis'],
491
                      'clientsdev': ['pkanavos', 'mvasilak']}
492
            headers = dict(('HTTP_X_ACCOUNT_GROUP_%s' % k, ','.join(v))
493
                           for k, v in groups.iteritems())
494
            r = self.post('%s?update=' % url, **headers)
495
            self.assertEqual(r.status_code, 202)
496

    
497
            groups = {'pithosdev': ['verigak',
498
                                    'gtsouk',
499
                                    'chazapis',
500
                                    'papagian']}
501
            headers = dict(('HTTP_X_ACCOUNT_GROUP_%s' % k, ','.join(v))
502
                           for k, v in groups.iteritems())
503
            account_meta = self.get_account_meta()
504
            headers.update(dict(('HTTP_X_ACCOUNT_META_%s' %
505
                                k.upper().replace('-', '_'), v) for
506
                                k, v in account_meta.iteritems()))
507
            r = self.post(url, **headers)
508
            self.assertEqual(r.status_code, 202)
509

    
510
            account_groups = self.get_account_groups()
511
            self.assertTrue('Pithosdev' in account_groups)
512
            self.assertTrue('Clientsdev' not in account_groups)
513
            self.assertEqual(account_groups['Pithosdev'],
514
                             ','.join(sorted(groups['pithosdev'])))
515

    
516
    def test_delete_account_groups(self):
517
        url = join_urls(self.pithos_path, self.user)
518
        with AssertMappingInvariant(self.get_account_meta):
519
            groups = {'pithosdev': ['verigak', 'gtsouk', 'chazapis'],
520
                      'clientsdev': ['pkanavos', 'mvasilak']}
521
            headers = dict(('HTTP_X_ACCOUNT_GROUP_%s' % k, ','.join(v))
522
                           for k, v in groups.iteritems())
523
            self.post('%s?update=' % url, **headers)
524

    
525
            kwargs = dict(('HTTP_X_ACCOUNT_GROUP_%s' % k, '')
526
                          for k, v in groups.items())
527
            r = self.post('%s?update=' % url, **kwargs)
528
            self.assertEqual(r.status_code, 202)
529

    
530
            account_groups = self.get_account_groups()
531
            self.assertTrue('Pithosdev' not in account_groups)
532
            self.assertTrue('Clientsdev' not in account_groups)