Versioning extras, including account/container "time machine".
[pithos] / pithos / backends / tests.py
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 import unittest
35 import os
36 import types
37 import json
38
39 from simple import SimpleBackend
40
41
42 class TestAccount(unittest.TestCase):
43     def setUp(self):
44         self.basepath = './test/content'
45         self.b = SimpleBackend(self.basepath)
46         self.account = 'account1'
47     
48     def tearDown(self):
49         containers = [x[0] for x in self.b.list_containers('test', self.account)]
50         for container in containers:
51             try:
52                 self.b.delete_container('test', self.account, container)
53             except IndexError:
54                 # container not empty
55                 for obj in [x[0] for x in self.b.list_objects('test', self.account, container)]:
56                     self.b.delete_object('test', self.account, container, obj)
57                 self.b.delete_container('test', self.account, container)
58     
59     def test_list_containers(self):
60         l1 = ['images', 'movies', 'documents', 'backups']
61         for item in l1:
62             self.b.put_container('test', self.account, item)
63         l2 = [x[0] for x in self.b.list_containers('test', self.account)]
64         l1.sort()
65         self.assertEquals(l1, l2)
66     
67     def test_list_containers_with_limit_marker(self):
68         l1 = ['apples', 'bananas', 'kiwis', 'oranges', 'pears']
69         for item in l1:
70             self.b.put_container('test', self.account, item)
71         l2 = [x[0] for x in self.b.list_containers('test', self.account, limit=2)]
72         self.assertEquals(len(l2), 2)
73         self.assertEquals(l1[:2], l2)
74     
75         l2 = [x[0] for x in self.b.list_containers('test', self.account, limit=2, marker='bananas')]
76         self.assertTrue(len(l2) <= 2)
77         self.assertEquals(l1[2:4], l2)
78
79         l2 = [x[0] for x in self.b.list_containers('test', self.account, limit=2, marker='oranges')]
80         self.assertTrue(len(l2) <= 2)
81         self.assertEquals(l1[4:], l2)
82     
83     def test_get_account_meta(self):
84         meta = {
85             "name": "account1",
86             "username": "aaitest@uth.gr",
87             "email": "aaitest@uth.gr",
88             "fileroot": "http://hostname/gss/rest/aaitest@uth.gr/files",
89             "trash": "http://hostname/gss/rest/aaitest@uth.gr/trash",
90             "shared": "http://hostname/gss/rest/aaitest@uth.gr/shared",
91             "others": "http://hostname/gss/rest/aaitest@uth.gr/others",
92             "tags": "http://hostname/gss/rest/aaitest@uth.gr/tags",
93             "groups": "http://hostname/gss/rest/aaitest@uth.gr/groups",
94             "creationDate": 1223372769275,
95             "modificationDate": 1223372769275,
96             "lastLogin": 1223372769275}
97         self.b.update_account_meta('test', self.account, meta)
98         d = self.b.get_account_meta('test', self.account)
99         for k,v in meta.iteritems():
100             self.assertEquals(unicode(v), d[k])
101     
102     def test_get_non_existing_account_meta(self):
103         meta = self.b.get_account_meta('test', 'account2')
104         self.assertEquals(meta, {'name': 'account2', 'count': 0, 'bytes': 0})
105     
106     def test_update_account_meta(self):
107         meta = {
108             "name": "account1",
109             "username": "aaitest@uth.gr",
110             "email": "aaitest@uth.gr",
111             "fileroot": "http://hostname/gss/rest/aaitest@uth.gr/files",
112             "trash": "http://hostname/gss/rest/aaitest@uth.gr/trash",
113             "shared": "http://hostname/gss/rest/aaitest@uth.gr/shared",
114             "others": "http://hostname/gss/rest/aaitest@uth.gr/others",
115             "tags": "http://hostname/gss/rest/aaitest@uth.gr/tags",
116             "groups": "http://hostname/gss/rest/aaitest@uth.gr/groups",
117             "creationDate": 1223372769275,
118             "modificationDate": 1223372769275,
119             "lastLogin": 1223372769275}
120         self.b.update_account_meta('test', self.account, meta)
121         p = os.path.join(self.basepath, self.account)
122         
123         db_meta = self.b.get_account_meta('test', self.account)
124         for k,v in meta.iteritems():
125             self.assertTrue(k in db_meta)
126             db_value = db_meta[k]
127             self.assertEquals(unicode(v), db_value)
128
129 class TestContainer(unittest.TestCase):
130     def setUp(self):
131         self.basepath = './test/content'
132         self.b = SimpleBackend(self.basepath)
133         self.account = 'account1'
134     
135     def tearDown(self):
136         containers = [x[0] for x in self.b.list_containers('test', self.account)]
137         for container in containers:
138             try:
139                 self.b.delete_container('test', self.account, container)
140             except IndexError: # container not empty
141                 for obj in [x[0] for x in self.b.list_objects('test', self.account, container)]:
142                     self.b.delete_object('test', self.account, container, obj)
143                 self.b.delete_container('test', self.account, container)
144     
145     def test_list_non_existing_account_objects(self):
146         self.assertRaises(NameError, self.b.list_objects, 'test', 'account2', 'container1')
147     
148     def test_list_objects(self):
149         self.b.put_container('test', self.account, 'container1')
150         objects = [x[0] for x in self.b.list_objects('test', self.account, 'container1')]
151         self.assertEquals(len([]), len(objects))
152         l = [
153             {'name':'kate_beckinsale.jpg'},
154             {'name':'How To Win Friends And Influence People.pdf'},
155             {'name':'moms_birthday.jpg'},
156             {'name':'poodle_strut.mov'},
157             {'name':'Disturbed - Down With The Sickness.mp3'},
158             {'name':'army_of_darkness.avi'},
159             {'name':'the_mad.avi'}
160         ]
161         for item in l:
162             self.b.update_object_hashmap('test', self.account, 'container1', item['name'], 0, [])
163         objects = [x[0] for x in self.b.list_objects('test', self.account, 'container1')]
164         self.assertEquals(len(l), len(objects))
165     
166     def test_list_objects_with_limit_marker(self):
167         self.b.put_container('test', self.account, 'container1')
168         l = ['gala', 'grannysmith', 'honeycrisp', 'jonagold', 'reddelicious']
169         for item in l:
170             self.b.update_object_hashmap('test', self.account, 'container1', item, 0, [])
171         objects = [x[0] for x in self.b.list_objects('test', self.account, 'container1', limit=2)]
172         self.assertEquals(l[:2], objects)
173         
174         objects = [x[0] for x in self.b.list_objects('test', self.account, 'container1', limit=2, marker='grannysmith')]
175         self.assertEquals(l[2:4], objects)
176         
177         objects = [x[0] for x in self.b.list_objects('test', self.account, 'container1', limit=2, marker='jonagold')]
178         self.assertEquals(l[4:], objects)
179     
180     def test_list_pseudo_hierarchical_folders(self):
181         self.b.put_container('test', self.account, 'container1')
182         l = ['photos/animals/dogs/poodle.jpg',
183              'photos/animals/dogs/terrier.jpg',
184              'photos/animals/cats/persian.jpg',
185              'photos/animals/cats/siamese.jpg',
186              'photos/plants/fern.jpg',
187              'photos/plants/rose.jpg',
188              'photos/me.jpg'
189              ]
190         for item in l:
191             self.b.update_object_hashmap('test', self.account, 'container1', item, 0, [])
192         
193         objects = [x[0] for x in self.b.list_objects('test', self.account, 'container1', prefix='photos/', delimiter='/')]
194         self.assertEquals(['photos/animals/', 'photos/me.jpg', 'photos/plants/'], objects)
195         
196         objects = [x[0] for x in self.b.list_objects('test', self.account, 'container1', prefix='photos/animals/', delimiter='/')]
197         self.assertEquals(['photos/animals/cats/', 'photos/animals/dogs/'], objects)
198         
199         self.b.put_container('test', self.account, 'container2')
200         l = ['photos/photo1', 'photos/photo2', 'movieobject', 'videos', 'videos/movieobj4']
201         for item in l:
202             self.b.update_object_hashmap('test', self.account, 'container2', item, 0, [])
203         objects = [x[0] for x in self.b.list_objects('test', self.account, 'container2', delimiter='/')]
204         self.assertEquals(['movieobject', 'photos/', 'videos', 'videos/'], objects)
205     
206     def test_put_container(self):
207         cname = 'container1'
208         self.b.put_container('test', self.account, cname)
209         self.assertTrue(cname in [x[0] for x in self.b.list_containers('test', self.account)])
210     
211     def test_put_container_twice(self):
212         cname = 'container1'
213         self.b.put_container('test', self.account, cname)
214         self.assertRaises(NameError, self.b.put_container, 'test', self.account, cname)
215     
216     def test_delete_container(self):
217         cname = 'container1'
218         self.b.put_container('test', self.account, cname)
219         self.b.delete_container('test', self.account, cname)
220         self.assertTrue(cname not in [x[0] for x in self.b.list_containers('test', self.account)])
221     
222     def test_delete_non_exisitng_container(self):
223         cname = 'container1'
224         self.assertRaises(NameError, self.b.delete_container, 'test', self.account, cname)
225     
226     def test_delete_non_empty_container(self):
227         cname = 'container1'
228         self.b.put_container('test', self.account, cname)
229         self.b.update_object_hashmap('test', self.account, cname, 'object1', 0, [])
230         self.assertRaises(IndexError, self.b.delete_container, 'test', self.account, cname)
231     
232     def test_get_container_meta(self):
233         cname = 'container1'
234         self.b.put_container('test', self.account, cname)
235         meta = self.b.get_container_meta('test', self.account, cname)
236         self.assertEquals(meta['count'], 0)
237         
238         l = ['photos/photo1', 'photos/photo2', 'movieobject', 'videos/movieobj4']
239         for item in l:
240             self.b.update_object_hashmap('test', self.account, cname, item, 0, [])
241         meta = self.b.get_container_meta('test', self.account, cname)
242         self.assertEquals(meta['count'], 4)
243
244 class TestObject(unittest.TestCase):
245     def setUp(self):
246         self.basepath = './test/content'
247         self.b = SimpleBackend(self.basepath)
248         self.account = 'account1'
249     
250     def tearDown(self):
251         containers = [x[0] for x in self.b.list_containers('test', self.account)]
252         for container in containers:
253             try:
254                 self.b.delete_container('test', self.account, container)
255             except IndexError: # container not empty
256                 for obj in [x[0] for x in self.b.list_objects('test', self.account, container)]:
257                     self.b.delete_object('test', self.account, container, obj)
258                 self.b.delete_container('test', self.account, container)
259     
260     def test_get_non_existing_object(self):
261         cname = 'container1'
262         self.b.put_container('test', self.account, cname)
263         self.assertRaises(NameError, self.b.get_object_hashmap, 'test', self.account, 'cname', 'testobj')
264         self.assertRaises(NameError, self.b.get_object_hashmap, 'test', self.account, cname, 'testobj')
265     
266     def test_get_object(self):
267         cname = 'container1'
268         self.b.put_container('test', self.account, cname)
269         input = {'name':'kate_beckinsale.jpg'}
270         data = json.dumps(input)
271         hash = self.b.put_block(data)
272         self.b.update_object_hashmap('test', self.account, cname, input['name'], len(data), [hash])
273         size, hashmap = self.b.get_object_hashmap('test', self.account, cname, 'kate_beckinsale.jpg')
274         self.assertEquals(len(data), size)
275         self.assertEquals(hash, hashmap[0])
276         self.assertEquals(input, json.loads(self.b.get_block(hash)))
277     
278 #     def test_update_object(self):
279 #         cname = 'container1'
280 #         self.b.put_container('test', self.account, cname)
281 #         input = {'name':'kate_beckinsale.jpg'}
282 #         self.b.update_object('test', self.account, cname, input['name'], json.dumps(input))
283 #         meta = self.b.get_object_meta('test', self.account, cname, input['name'])
284     
285     def test_copy_object(self):
286         src_cname = 'container1'
287         src_obj = 'photos/me.jpg'
288         dest_cname = 'container2'
289         dest_obj = 'photos/personal/myself.jpg'
290         
291         # non existing source account
292         self.assertRaises(NameError,
293                           self.b.copy_object,
294                           'test',
295                           'account',
296                           src_cname,
297                           src_obj,
298                           dest_cname,
299                           dest_obj)
300         # non existing source container
301         self.assertRaises(NameError,
302                           self.b.copy_object,
303                           'test',
304                           self.account,
305                           src_cname,
306                           src_obj,
307                           dest_cname,
308                           dest_obj)
309         
310         self.b.put_container('test', self.account, src_cname)
311         # non existing source object
312         self.assertRaises(NameError,
313                           self.b.copy_object,
314                           'test',
315                           self.account,
316                           src_cname,
317                           src_obj,
318                           dest_cname,
319                           dest_obj)
320         
321         self.b.update_object_hashmap('test', self.account, src_cname, src_obj, 0, [])
322         # non existing destination container
323         self.assertRaises(NameError,
324                           self.b.copy_object,
325                           'test',
326                           self.account,
327                           src_cname,
328                           src_obj,
329                           dest_cname,
330                           dest_obj)
331         
332         self.b.put_container('test', self.account, dest_cname)
333         self.b.update_object_meta('test', self.account, src_cname, src_obj, {'tag':'sfsfssf'})
334         self.b.copy_object('test', self.account, src_cname, src_obj, dest_cname, dest_obj)
335         self.assertTrue(dest_obj in [x[0] for x in self.b.list_objects('test',
336                                                                         self.account,
337                                                                         dest_cname,
338                                                                         prefix='photos/personal/',
339                                                                         delimiter='/')])
340         # TODO: test metadata changes
341         meta_tag = self.b.get_object_meta('test', self.account, dest_cname, dest_obj)['tag']
342         self.assertEquals(meta_tag, unicode('sfsfssf'))
343     
344     def test_delete_non_existing_object(self):
345         cname = 'container1'
346         self.b.put_container('test', self.account, cname)
347         name = 'kate_beckinsale.jpg'
348         self.assertRaises(NameError, self.b.delete_object, 'test', self.account, cname, name)
349     
350     def test_delete_object(self):
351         cname = 'container1'
352         self.b.put_container('test', self.account, cname)
353         name = 'kate_beckinsale.jpg'
354         self.b.update_object_hashmap('test', self.account, cname, name, 0, [])
355         self.assertTrue(name in [x[0] for x in self.b.list_objects('test', self.account, cname)])
356         
357         self.b.delete_object('test', self.account, cname, name)
358         self.assertTrue(name not in [x[0] for x in self.b.list_objects('test', self.account, cname)])
359         self.assertRaises(NameError, self.b.delete_object, 'test', self.account, cname, name)
360     
361     def test_get_non_existing_object_meta(self):
362         cname = 'container1'
363         self.b.put_container('test', self.account, cname)
364         name = 'kate_beckinsale.jpg'
365         self.assertRaises(NameError, self.b.get_object_meta, 'test', self.account, cname, name)
366     
367     def test_get_update_object_meta(self):
368         cname = 'container1'
369         self.b.put_container('test', self.account, cname)
370         name = 'kate_beckinsale.jpg'
371         self.b.update_object_hashmap('test', self.account, cname, name, 0, [])
372         
373         m1 = {'X-Object-Meta-Meat': 'Bacon',
374              'X-Object-Meta-Fruit': 'Bacon',
375              'X-Object-Meta-Dairy': 'Bacon'}
376         self.b.update_object_meta('test', self.account, cname, name, m1)
377         meta = self.b.get_object_meta('test', self.account, cname, name)
378         for k,v in m1.iteritems():
379             self.assertTrue(k in meta)
380             self.assertEquals(unicode(v), meta[k])
381         
382         m2 = {'X-Object-Meta-Meat': 'Bacon',
383              'X-Object-Meta-Fruit': 'Bacon',
384              'X-Object-Meta-Veggie': 'Bacon',
385              'X-Object-Meta-Dairy': 'Chicken'}
386         self.b.update_object_meta('test', self.account, cname, name, m2)
387         meta = self.b.get_object_meta('test', self.account, cname, name)
388         m1.update(m2)
389         for k,v in m1.iteritems():
390             self.assertTrue(k in meta)
391             self.assertEquals(unicode(v), meta[k])
392     
393     def test_update_non_existing_object_meta(self):
394         cname = 'container1'
395         self.b.put_container('test', self.account, cname)
396         name = 'kate_beckinsale.jpg'
397         self.assertRaises(NameError, self.b.update_object_meta, 'test', self.account, cname, name, {})
398
399 if __name__ == "__main__":
400     unittest.main()