31 |
31 |
# interpreted as representing official policies, either expressed
|
32 |
32 |
# or implied, of GRNET S.A.
|
33 |
33 |
|
34 |
|
from pithos.lib.client import Client, Fault
|
|
34 |
from pithos.lib.client import Pithos_Client, Fault
|
35 |
35 |
import unittest
|
36 |
36 |
from django.utils import simplejson as json
|
37 |
37 |
from xml.dom import minidom
|
|
38 |
from StringIO import StringIO
|
38 |
39 |
import types
|
39 |
40 |
import hashlib
|
40 |
41 |
import os
|
... | ... | |
59 |
60 |
class BaseTestCase(unittest.TestCase):
|
60 |
61 |
#TODO unauthorized request
|
61 |
62 |
def setUp(self):
|
62 |
|
self.client = Client(DEFAULT_HOST, DEFAULT_AUTH, DEFAULT_USER, DEFAULT_API)
|
63 |
|
self.invalid_client = Client(DEFAULT_HOST, DEFAULT_AUTH, 'non-existing', DEFAULT_API)
|
64 |
|
self.unauthorised_client = Client(DEFAULT_HOST, '', DEFAULT_USER, DEFAULT_API)
|
|
63 |
self.client = Pithos_Client(DEFAULT_HOST, DEFAULT_AUTH, DEFAULT_USER, DEFAULT_API)
|
65 |
64 |
self.headers = {
|
66 |
65 |
'account': ('x-account-container-count',
|
67 |
66 |
'x-account-bytes-used',
|
68 |
67 |
'last-modified',
|
69 |
68 |
'content-length',
|
70 |
69 |
'date',
|
71 |
|
'content-type',
|
|
70 |
'content_type',
|
72 |
71 |
'server',),
|
73 |
72 |
'object': ('etag',
|
74 |
73 |
'content-length',
|
75 |
|
'content-type',
|
|
74 |
'content_type',
|
76 |
75 |
'content-encoding',
|
77 |
76 |
'last-modified',
|
78 |
77 |
'date',
|
... | ... | |
84 |
83 |
'server',),
|
85 |
84 |
'container': ('x-container-object-count',
|
86 |
85 |
'x-container-bytes-used',
|
87 |
|
'content-type',
|
|
86 |
'content_type',
|
88 |
87 |
'last-modified',
|
89 |
88 |
'content-length',
|
90 |
89 |
'date',
|
... | ... | |
96 |
95 |
'x-container-object-meta',
|
97 |
96 |
'x-container-policy-versioning',
|
98 |
97 |
'server',)}
|
99 |
|
|
|
98 |
|
100 |
99 |
self.contentTypes = {'xml':'application/xml',
|
101 |
100 |
'json':'application/json',
|
102 |
101 |
'':'text/plain'}
|
... | ... | |
114 |
113 |
'content_encoding',
|
115 |
114 |
'last_modified',)}
|
116 |
115 |
self.return_codes = (400, 401, 404, 503,)
|
117 |
|
|
|
116 |
|
|
117 |
def tearDown(self):
|
|
118 |
for c in self.client.list_containers():
|
|
119 |
for o in self.client.list_objects(c):
|
|
120 |
self.client.delete_object(c, o)
|
|
121 |
self.client.delete_container(c)
|
|
122 |
|
118 |
123 |
def assert_status(self, status, codes):
|
119 |
124 |
l = [elem for elem in self.return_codes]
|
120 |
125 |
if type(codes) == types.ListType:
|
... | ... | |
123 |
128 |
l.append(codes)
|
124 |
129 |
self.assertTrue(status in l)
|
125 |
130 |
|
126 |
|
def assert_list(self, path, entity, limit=10000, format='text', params=None, **headers):
|
127 |
|
status, headers, data = self.client.get(path, format=format,
|
128 |
|
headers=headers, params=params)
|
129 |
|
|
130 |
|
self.assert_status(status, [200, 204, 304, 412])
|
131 |
|
if format == 'text':
|
132 |
|
data = data.strip().split('\n') if data else []
|
133 |
|
self.assertTrue(len(data) <= limit)
|
134 |
|
else:
|
135 |
|
exp_content_type = self.contentTypes[format]
|
136 |
|
self.assertEqual(headers['content-type'].find(exp_content_type), 0)
|
137 |
|
#self.assert_extended(data, format, entity, limit)
|
138 |
|
if format == 'json':
|
139 |
|
data = json.loads(data) if data else []
|
140 |
|
elif format == 'xml':
|
141 |
|
data = minidom.parseString(data)
|
142 |
|
return status, headers, data
|
143 |
|
|
144 |
|
def list_containers(self, limit=10000, marker='', format='text', **headers):
|
145 |
|
params = locals()
|
146 |
|
params.pop('self')
|
147 |
|
return self.assert_list('', 'account', limit, format, params, **headers)
|
148 |
|
|
149 |
|
def list_objects(self, container, limit=10000, marker='',
|
150 |
|
prefix='', format='', path='', delimiter='', meta='',
|
151 |
|
**headers):
|
152 |
|
params = locals()
|
153 |
|
params.pop('self')
|
154 |
|
params.pop('container')
|
155 |
|
path = '/' + container
|
156 |
|
format = 'text' if format == '' else format
|
157 |
|
return self.assert_list(path, 'container', limit, format, params, **headers)
|
158 |
|
|
159 |
|
def _assert_get_meta(self, path, entity, params=None, **exp_meta):
|
160 |
|
status, headers, data = self.client.head(path, params)
|
161 |
|
self.assert_status(status, 204)
|
162 |
|
#self.assert_headers(headers, entity, **exp_meta)
|
163 |
|
return status, headers, data
|
164 |
|
|
165 |
|
def get_account_meta(self, params=None, **exp_meta):
|
166 |
|
return self._assert_get_meta('', 'account', params, **exp_meta)
|
167 |
|
|
168 |
|
def get_container_meta(self, container, params=None, **exp_meta):
|
169 |
|
path = '/%s' % container
|
170 |
|
return self._assert_get_meta(path, 'container', params, **exp_meta)
|
171 |
|
|
172 |
|
def create_container(self, name, **meta):
|
173 |
|
headers = {}
|
174 |
|
for k,v in meta.items():
|
175 |
|
headers['x-container-meta-%s' %k.strip().upper()] = v.strip()
|
176 |
|
status, header, data = self.client.put('/' + name, headers=headers)
|
177 |
|
self.assert_status(status, [201, 202])
|
178 |
|
return status, header, data
|
179 |
|
|
180 |
|
def get_object(self, container, name, format='', version=None, **headers):
|
181 |
|
path = '/%s/%s' % (container, name)
|
182 |
|
params = {'version':version} if version else None
|
183 |
|
status, headers, data = self.client.get(path, format, headers, params)
|
184 |
|
self.assert_status(status, [200, 206, 304, 412, 416])
|
185 |
|
#if status in [200, 206]:
|
186 |
|
# self.assert_headers(headers, 'object')
|
187 |
|
return status, headers, data
|
188 |
|
|
189 |
|
def update_object(self, container, name, data='', content_type='', **headers):
|
190 |
|
if content_type != '':
|
191 |
|
headers['content-type'] = content_type
|
192 |
|
status, headers, data = self.client.update_object_data(container,
|
193 |
|
name,
|
194 |
|
data,
|
195 |
|
headers)
|
196 |
|
self.assert_status(status, [202, 204, 416])
|
197 |
|
return status, headers, data
|
198 |
|
|
|
131 |
#def assert_list(self, path, entity, limit=10000, format='text', params=None, **headers):
|
|
132 |
# status, headers, data = self.client.get(path, format=format,
|
|
133 |
# headers=headers, params=params)
|
|
134 |
#
|
|
135 |
# self.assert_status(status, [200, 204, 304, 412])
|
|
136 |
# if format == 'text':
|
|
137 |
# data = data.strip().split('\n') if data else []
|
|
138 |
# self.assertTrue(len(data) <= limit)
|
|
139 |
# else:
|
|
140 |
# exp_content_type = self.contentTypes[format]
|
|
141 |
# self.assertEqual(headers['content_type'].find(exp_content_type), 0)
|
|
142 |
# #self.assert_extended(data, format, entity, limit)
|
|
143 |
# if format == 'json':
|
|
144 |
# data = json.loads(data) if data else []
|
|
145 |
# elif format == 'xml':
|
|
146 |
# data = minidom.parseString(data)
|
|
147 |
# return status, headers, data
|
|
148 |
|
199 |
149 |
def assert_headers(self, headers, type, **exp_meta):
|
200 |
150 |
prefix = 'x-%s-meta-' %type
|
201 |
151 |
system_headers = [h for h in headers if not h.startswith(prefix)]
|
... | ... | |
205 |
155 |
elif exp_meta:
|
206 |
156 |
k = k.split(prefix)[-1]
|
207 |
157 |
self.assertEqual(v, exp_meta[k])
|
208 |
|
|
|
158 |
|
209 |
159 |
#def assert_extended(self, data, format, type, size):
|
210 |
160 |
# if format == 'xml':
|
211 |
161 |
# self._assert_xml(data, type, size)
|
212 |
162 |
# elif format == 'json':
|
213 |
163 |
# self._assert_json(data, type, size)
|
214 |
|
#
|
|
164 |
|
215 |
165 |
#def _assert_json(self, data, type, size):
|
216 |
166 |
# print '#', data
|
217 |
167 |
# convert = lambda s: s.lower()
|
... | ... | |
223 |
173 |
# if 'subdir' in i.keys():
|
224 |
174 |
# continue
|
225 |
175 |
# self.assertTrue(item in i.keys())
|
226 |
|
#
|
|
176 |
|
227 |
177 |
#def _assert_xml(self, data, type, size):
|
228 |
178 |
# print '#', data
|
229 |
179 |
# convert = lambda s: s.lower()
|
... | ... | |
250 |
200 |
except Fault, f:
|
251 |
201 |
self.failUnless(f.status == status)
|
252 |
202 |
|
|
203 |
def assert_container_exists(self, container):
|
|
204 |
"""
|
|
205 |
asserts the existence of a container
|
|
206 |
"""
|
|
207 |
try:
|
|
208 |
self.client.retrieve_container_metadata(container)
|
|
209 |
except Fault, f:
|
|
210 |
self.failIf(f.status == 404)
|
|
211 |
|
253 |
212 |
def assert_object_exists(self, container, object):
|
254 |
213 |
"""
|
255 |
214 |
asserts the existence of an object
|
... | ... | |
265 |
224 |
"""
|
266 |
225 |
self.assert_raises_fault(404, self.client.retrieve_object_metadata,
|
267 |
226 |
container, object)
|
268 |
|
|
|
227 |
|
269 |
228 |
def upload_random_data(self, container, name, length=1024, type=None,
|
270 |
229 |
enc=None, **meta):
|
271 |
230 |
data = get_random_data(length)
|
272 |
231 |
return self.upload_data(container, name, data, type, enc, **meta)
|
273 |
|
|
|
232 |
|
274 |
233 |
def upload_data(self, container, name, data, type=None, enc=None, etag=None,
|
275 |
234 |
**meta):
|
276 |
235 |
obj = {}
|
... | ... | |
279 |
238 |
obj['data'] = data
|
280 |
239 |
obj['hash'] = compute_md5_hash(obj['data'])
|
281 |
240 |
|
282 |
|
headers = {}
|
283 |
|
for k,v in meta.items():
|
284 |
|
key = 'x-object-meta-%s' % k
|
285 |
|
headers[key] = v
|
286 |
|
headers['etag'] = etag if etag else obj['hash']
|
|
241 |
args = {}
|
|
242 |
args['etag'] = etag if etag else obj['hash']
|
|
243 |
|
287 |
244 |
guess = mimetypes.guess_type(name)
|
288 |
245 |
type = type if type else guess[0]
|
289 |
246 |
enc = enc if enc else guess[1]
|
290 |
|
headers['content-type'] = type if type else 'plain/text'
|
291 |
|
headers['content-encoding'] = enc if enc else None
|
292 |
|
obj['meta'] = headers
|
|
247 |
args['content_type'] = type if type else 'plain/text'
|
|
248 |
args['content_encoding'] = enc if enc else None
|
|
249 |
|
|
250 |
obj['meta'] = args
|
293 |
251 |
|
294 |
252 |
path = '/%s/%s' % (container, name)
|
295 |
|
status, headers, data = self.client.put(path, obj['data'],
|
296 |
|
headers=headers)
|
297 |
|
if status == 201:
|
298 |
|
self.assertTrue('etag' in headers)
|
299 |
|
self.assertEqual(obj['hash'], headers['etag'])
|
300 |
|
return obj
|
|
253 |
self.client.create_object(container, name, StringIO(obj['data']),
|
|
254 |
meta, **args)
|
|
255 |
|
|
256 |
return obj
|
301 |
257 |
except IOError:
|
302 |
258 |
return
|
303 |
259 |
|
... | ... | |
307 |
263 |
self.account = 'test'
|
308 |
264 |
self.containers = ['apples', 'bananas', 'kiwis', 'oranges', 'pears']
|
309 |
265 |
for item in self.containers:
|
310 |
|
self.create_container(item)
|
311 |
|
|
312 |
|
def tearDown(self):
|
313 |
|
for c in self.list_containers()[2]:
|
314 |
|
self.client.delete_container(c)
|
315 |
|
|
|
266 |
self.client.create_container(item)
|
|
267 |
|
316 |
268 |
def test_get_account_meta(self):
|
317 |
|
headers = self.get_account_meta()[1]
|
|
269 |
meta = self.client.retrieve_account_metadata()
|
318 |
270 |
|
319 |
|
containers = self.list_containers()[2]
|
|
271 |
containers = self.client.list_containers()
|
320 |
272 |
l = str(len(containers))
|
321 |
|
self.assertEqual(headers['x-account-container-count'], l)
|
|
273 |
self.assertEqual(meta['x-account-container-count'], l)
|
322 |
274 |
size = 0
|
323 |
275 |
for c in containers:
|
324 |
|
h = self.get_container_meta(c)[1]
|
325 |
|
size = size + int(h['x-container-bytes-used'])
|
326 |
|
self.assertEqual(headers['x-account-bytes-used'], str(size))
|
327 |
|
|
|
276 |
m = self.client.retrieve_container_metadata(c)
|
|
277 |
size = size + int(m['x-container-bytes-used'])
|
|
278 |
self.assertEqual(meta['x-account-bytes-used'], str(size))
|
|
279 |
|
328 |
280 |
#def test_get_account_401(self):
|
329 |
281 |
# response = self.get_account_meta('non-existing-account')
|
330 |
282 |
# print response
|
... | ... | |
337 |
289 |
#create some containers
|
338 |
290 |
self.containers = ['apples', 'bananas', 'kiwis', 'oranges', 'pears']
|
339 |
291 |
for item in self.containers:
|
340 |
|
self.create_container(item)
|
341 |
|
|
342 |
|
def tearDown(self):
|
343 |
|
for c in self.list_containers()[2]:
|
344 |
|
for o in self.list_objects(c)[2]:
|
345 |
|
self.client.delete_object(c, o)
|
346 |
|
self.client.delete_container(c)
|
347 |
|
|
|
292 |
self.client.create_container(item)
|
|
293 |
|
348 |
294 |
def test_list(self):
|
349 |
295 |
#list containers
|
350 |
|
containers = self.list_containers()[2]
|
|
296 |
containers = self.client.list_containers()
|
351 |
297 |
self.assertEquals(self.containers, containers)
|
352 |
|
|
|
298 |
|
353 |
299 |
#def test_list_204(self):
|
354 |
300 |
# response = self.list_containers('non-existing-account')
|
355 |
301 |
# self.assertEqual(response.status_code, 204)
|
356 |
|
|
|
302 |
|
357 |
303 |
def test_list_with_limit(self):
|
358 |
304 |
limit = 2
|
359 |
|
containers = self.list_containers(limit=limit)[2]
|
|
305 |
containers = self.client.list_containers(limit=limit)
|
360 |
306 |
self.assertEquals(len(containers), limit)
|
361 |
307 |
self.assertEquals(self.containers[:2], containers)
|
362 |
|
|
|
308 |
|
363 |
309 |
def test_list_with_marker(self):
|
364 |
310 |
l = 2
|
365 |
311 |
m = 'bananas'
|
366 |
|
containers = self.list_containers(limit=l, marker=m)[2]
|
|
312 |
containers = self.client.list_containers(limit=l, marker=m)
|
367 |
313 |
i = self.containers.index(m) + 1
|
368 |
314 |
self.assertEquals(self.containers[i:(i+l)], containers)
|
369 |
315 |
|
370 |
316 |
m = 'oranges'
|
371 |
|
containers = self.list_containers(limit=l, marker=m)[2]
|
|
317 |
containers = self.client.list_containers(limit=l, marker=m)
|
372 |
318 |
i = self.containers.index(m) + 1
|
373 |
319 |
self.assertEquals(self.containers[i:(i+l)], containers)
|
374 |
|
|
|
320 |
|
375 |
321 |
#def test_extended_list(self):
|
376 |
322 |
# self.list_containers(self.account, limit=3, format='xml')
|
377 |
323 |
# self.list_containers(self.account, limit=3, format='json')
|
378 |
|
|
|
324 |
|
379 |
325 |
def test_list_json_with_marker(self):
|
380 |
326 |
l = 2
|
381 |
327 |
m = 'bananas'
|
382 |
|
status, headers, containers = self.list_containers(limit=l, marker=m,
|
383 |
|
format='json')
|
|
328 |
containers = self.client.list_containers(limit=l, marker=m, detail=True)
|
384 |
329 |
self.assertEqual(containers[0]['name'], 'kiwis')
|
385 |
330 |
self.assertEqual(containers[1]['name'], 'oranges')
|
386 |
|
|
387 |
|
def test_list_xml_with_marker(self):
|
388 |
|
l = 2
|
389 |
|
m = 'oranges'
|
390 |
|
status, headers, xml = self.list_containers(limit=l, marker=m,
|
391 |
|
format='xml')
|
392 |
|
nodes = xml.getElementsByTagName('name')
|
393 |
|
self.assertEqual(len(nodes), 1)
|
394 |
|
self.assertEqual(nodes[0].childNodes[0].data, 'pears')
|
395 |
|
|
|
331 |
|
|
332 |
#def test_list_xml_with_marker(self):
|
|
333 |
# l = 2
|
|
334 |
# m = 'oranges'
|
|
335 |
# status, headers, xml = self.list_containers(limit=l, marker=m, format='xml')
|
|
336 |
# nodes = xml.getElementsByTagName('name')
|
|
337 |
# self.assertEqual(len(nodes), 1)
|
|
338 |
# self.assertEqual(nodes[0].childNodes[0].data, 'pears')
|
|
339 |
|
396 |
340 |
def test_if_modified_since(self):
|
397 |
341 |
t = datetime.datetime.utcnow()
|
398 |
342 |
t2 = t - datetime.timedelta(minutes=10)
|
399 |
343 |
|
400 |
344 |
#add a new container
|
401 |
|
self.create_container('dummy')
|
402 |
|
|
|
345 |
self.client.create_container('dummy')
|
|
346 |
|
403 |
347 |
for f in DATE_FORMATS:
|
404 |
348 |
past = t2.strftime(f)
|
405 |
|
|
406 |
|
headers = {'if-modified-since':'%s' %past}
|
407 |
|
status, headers, data = self.list_containers(**headers)
|
408 |
|
|
409 |
|
#assert get success
|
410 |
|
self.assertEqual(status, 200)
|
411 |
|
|
|
349 |
try:
|
|
350 |
c = self.client.list_containers(if_modified_since=past)
|
|
351 |
self.assertEqual(len(c), len(self.containers) + 1)
|
|
352 |
except Fault, f:
|
|
353 |
self.failIf(f.status == 304) #fail if not modified
|
|
354 |
|
412 |
355 |
def test_if_modified_since_invalid_date(self):
|
413 |
|
headers = {'if-modified-since':''}
|
414 |
|
status, headers, data = self.list_containers(**headers)
|
415 |
|
|
416 |
|
#assert get success
|
417 |
|
self.assertEqual(status, 200)
|
418 |
|
|
|
356 |
c = self.client.list_containers(if_modified_since='')
|
|
357 |
self.assertEqual(len(c), len(self.containers))
|
|
358 |
|
419 |
359 |
def test_if_not_modified_since(self):
|
420 |
360 |
now = datetime.datetime.utcnow()
|
421 |
361 |
since = now + datetime.timedelta(1)
|
422 |
362 |
|
423 |
363 |
for f in DATE_FORMATS:
|
424 |
|
headers = {'if-modified-since':'%s' %since.strftime(f)}
|
|
364 |
args = {'if_modified_since':'%s' %since.strftime(f)}
|
|
365 |
|
425 |
366 |
#assert not modified
|
426 |
|
self.assert_raises_fault(304, self.list_containers, **headers)
|
427 |
|
|
|
367 |
self.assert_raises_fault(304, self.client.list_containers, **args)
|
|
368 |
|
428 |
369 |
def test_if_unmodified_since(self):
|
429 |
370 |
now = datetime.datetime.utcnow()
|
430 |
371 |
since = now + datetime.timedelta(1)
|
431 |
372 |
|
432 |
373 |
for f in DATE_FORMATS:
|
433 |
|
headers = {'if-unmodified-since':'%s' %since.strftime(f)}
|
434 |
|
status, headers, data = self.list_containers(**headers)
|
|
374 |
c = self.client.list_containers(if_unmodified_since=since.strftime(f))
|
435 |
375 |
|
436 |
376 |
#assert success
|
437 |
|
self.assertEqual(status, 200)
|
438 |
|
self.assertEqual(self.containers, data)
|
439 |
|
|
|
377 |
self.assertEqual(self.containers, c)
|
|
378 |
|
440 |
379 |
def test_if_unmodified_since_precondition_failed(self):
|
441 |
380 |
t = datetime.datetime.utcnow()
|
442 |
381 |
t2 = t - datetime.timedelta(minutes=10)
|
443 |
382 |
|
444 |
383 |
#add a new container
|
445 |
|
self.create_container('dummy')
|
|
384 |
self.client.create_container('dummy')
|
446 |
385 |
|
447 |
386 |
for f in DATE_FORMATS:
|
448 |
387 |
past = t2.strftime(f)
|
449 |
388 |
|
450 |
|
headers = {'if-unmodified-since':'%s' %past}
|
|
389 |
args = {'if_unmodified_since':'%s' %past}
|
|
390 |
|
451 |
391 |
#assert precondition failed
|
452 |
|
self.assert_raises_fault(412, self.list_containers, **headers)
|
453 |
|
|
|
392 |
self.assert_raises_fault(412, self.client.list_containers, **args)
|
|
393 |
|
454 |
394 |
class AccountPost(BaseTestCase):
|
455 |
395 |
def setUp(self):
|
456 |
396 |
BaseTestCase.setUp(self)
|
457 |
397 |
self.account = 'test'
|
458 |
398 |
self.containers = ['apples', 'bananas', 'kiwis', 'oranges', 'pears']
|
459 |
399 |
for item in self.containers:
|
460 |
|
self.create_container(item)
|
461 |
|
|
462 |
|
def tearDown(self):
|
463 |
|
containers = self.list_containers()[2]
|
464 |
|
for c in containers:
|
465 |
|
self.client.delete_container(c)
|
466 |
|
|
|
400 |
self.client.create_container(item)
|
|
401 |
|
467 |
402 |
def test_update_meta(self):
|
468 |
403 |
meta = {'test':'test', 'tost':'tost'}
|
469 |
|
status, headers, data = self.get_account_meta(**meta)
|
|
404 |
self.client.update_account_metadata(**meta)
|
|
405 |
self.assertEqual(meta, self.client.retrieve_account_metadata(restricted=True))
|
470 |
406 |
|
471 |
407 |
#def test_invalid_account_update_meta(self):
|
472 |
408 |
# with AssertMappingInvariant(self.get_account_meta, self.account):
|
473 |
409 |
# meta = {'HTTP_X_ACCOUNT_META_TEST':'test',
|
474 |
410 |
# 'HTTP_X_ACCOUNT_META_TOST':'tost'}
|
475 |
411 |
# response = self.update_account_meta('non-existing-account', **meta)
|
476 |
|
|
|
412 |
|
477 |
413 |
class ContainerHead(BaseTestCase):
|
478 |
414 |
def setUp(self):
|
479 |
415 |
BaseTestCase.setUp(self)
|
480 |
416 |
self.account = 'test'
|
481 |
417 |
self.container = 'apples'
|
482 |
|
status = self.create_container(self.container)[0]
|
483 |
|
|
484 |
|
def tearDown(self):
|
485 |
|
for o in self.list_objects(self.container)[2]:
|
486 |
|
self.client.delete_object(self.container, o)
|
487 |
|
self.client.delete_container(self.container)
|
488 |
|
|
|
418 |
self.client.create_container(self.container)
|
|
419 |
|
489 |
420 |
def test_get_meta(self):
|
490 |
421 |
meta = {'trash':'true'}
|
491 |
422 |
t1 = datetime.datetime.utcnow()
|
492 |
423 |
o = self.upload_random_data(self.container, o_names[0], **meta)
|
493 |
424 |
if o:
|
494 |
|
status, headers, data = self.get_container_meta(self.container)
|
|
425 |
headers = self.client.retrieve_container_metadata(self.container)
|
495 |
426 |
self.assertEqual(headers['x-container-object-count'], '1')
|
496 |
427 |
self.assertEqual(headers['x-container-bytes-used'], str(len(o['data'])))
|
497 |
428 |
t2 = datetime.datetime.strptime(headers['last-modified'], DATE_FORMATS[2])
|
... | ... | |
507 |
438 |
self.account = 'test'
|
508 |
439 |
self.container = ['pears', 'apples']
|
509 |
440 |
for c in self.container:
|
510 |
|
self.create_container(c)
|
|
441 |
self.client.create_container(c)
|
511 |
442 |
self.obj = []
|
512 |
443 |
for o in o_names[:8]:
|
513 |
444 |
self.obj.append(self.upload_random_data(self.container[0], o))
|
514 |
445 |
for o in o_names[8:]:
|
515 |
446 |
self.obj.append(self.upload_random_data(self.container[1], o))
|
516 |
|
|
517 |
|
def tearDown(self):
|
518 |
|
for c in self.container:
|
519 |
|
for obj in self.list_objects(c)[2]:
|
520 |
|
self.client.delete_object(c, obj)
|
521 |
|
self.client.delete_container(c)
|
522 |
|
|
|
447 |
|
523 |
448 |
def test_list_objects(self):
|
524 |
|
objects = self.list_objects(self.container[0])[2]
|
|
449 |
objects = self.client.list_objects(self.container[0])
|
525 |
450 |
l = [elem['name'] for elem in self.obj[:8]]
|
526 |
451 |
l.sort()
|
527 |
452 |
self.assertEqual(objects, l)
|
528 |
|
|
|
453 |
|
529 |
454 |
def test_list_objects_with_limit_marker(self):
|
530 |
|
objects = self.list_objects(self.container[0], limit=2)[2]
|
|
455 |
objects = self.client.list_objects(self.container[0], limit=2)
|
531 |
456 |
l = [elem['name'] for elem in self.obj[:8]]
|
532 |
457 |
l.sort()
|
533 |
458 |
self.assertEqual(objects, l[:2])
|
... | ... | |
536 |
461 |
'moms_birthday.jpg']
|
537 |
462 |
limit = 4
|
538 |
463 |
for m in markers:
|
539 |
|
objects = self.list_objects(self.container[0], limit=limit,
|
540 |
|
marker=m)[2]
|
|
464 |
objects = self.client.list_objects(self.container[0], limit=limit,
|
|
465 |
marker=m)
|
541 |
466 |
l = [elem['name'] for elem in self.obj[:8]]
|
542 |
467 |
l.sort()
|
543 |
468 |
start = l.index(m) + 1
|
544 |
469 |
end = start + limit
|
545 |
470 |
end = len(l) >= end and end or len(l)
|
546 |
471 |
self.assertEqual(objects, l[start:end])
|
547 |
|
|
|
472 |
|
548 |
473 |
def test_list_pseudo_hierarchical_folders(self):
|
549 |
|
objects = self.list_objects(self.container[1], prefix='photos',
|
550 |
|
delimiter='/')[2]
|
|
474 |
objects = self.client.list_objects(self.container[1], prefix='photos',
|
|
475 |
delimiter='/')
|
551 |
476 |
self.assertEquals(['photos/animals/', 'photos/me.jpg',
|
552 |
477 |
'photos/plants/'], objects)
|
553 |
478 |
|
554 |
|
objects = self.list_objects(self.container[1], prefix='photos/animals',
|
555 |
|
delimiter='/')[2]
|
|
479 |
objects = self.client.list_objects(self.container[1],
|
|
480 |
prefix='photos/animals',
|
|
481 |
delimiter='/')
|
556 |
482 |
l = ['photos/animals/cats/', 'photos/animals/dogs/']
|
557 |
483 |
self.assertEquals(l, objects)
|
558 |
484 |
|
559 |
|
objects = self.list_objects(self.container[1], path='photos')[2]
|
|
485 |
objects = self.client.list_objects(self.container[1], path='photos')
|
560 |
486 |
self.assertEquals(['photos/me.jpg'], objects)
|
561 |
|
|
|
487 |
|
562 |
488 |
def test_extended_list_json(self):
|
563 |
|
objects = self.list_objects(self.container[1],
|
564 |
|
format='json', limit=2,
|
565 |
|
prefix='photos/animals',
|
566 |
|
delimiter='/')[2]
|
|
489 |
objects = self.client.list_objects(self.container[1], detail=True,
|
|
490 |
limit=2, prefix='photos/animals',
|
|
491 |
delimiter='/')
|
567 |
492 |
self.assertEqual(objects[0]['subdir'], 'photos/animals/cats/')
|
568 |
493 |
self.assertEqual(objects[1]['subdir'], 'photos/animals/dogs/')
|
569 |
|
|
570 |
|
def test_extended_list_xml(self):
|
571 |
|
xml = self.list_objects(self.container[1], format='xml', limit=4,
|
572 |
|
prefix='photos', delimiter='/')[2]
|
573 |
|
dirs = xml.getElementsByTagName('subdir')
|
574 |
|
self.assertEqual(len(dirs), 2)
|
575 |
|
self.assertEqual(dirs[0].attributes['name'].value, 'photos/animals/')
|
576 |
|
self.assertEqual(dirs[1].attributes['name'].value, 'photos/plants/')
|
577 |
|
|
578 |
|
objects = xml.getElementsByTagName('name')
|
579 |
|
self.assertEqual(len(objects), 1)
|
580 |
|
self.assertEqual(objects[0].childNodes[0].data, 'photos/me.jpg')
|
581 |
|
|
|
494 |
|
|
495 |
#def test_extended_list_xml(self):
|
|
496 |
# xml = self.client.list_objects(self.container[1], format='xml', limit=4,
|
|
497 |
# prefix='photos', delimiter='/')
|
|
498 |
# dirs = xml.getElementsByTagName('subdir')
|
|
499 |
# self.assertEqual(len(dirs), 2)
|
|
500 |
# self.assertEqual(dirs[0].attributes['name'].value, 'photos/animals/')
|
|
501 |
# self.assertEqual(dirs[1].attributes['name'].value, 'photos/plants/')
|
|
502 |
#
|
|
503 |
# objects = xml.getElementsByTagName('name')
|
|
504 |
# self.assertEqual(len(objects), 1)
|
|
505 |
# self.assertEqual(objects[0].childNodes[0].data, 'photos/me.jpg')
|
|
506 |
|
582 |
507 |
def test_list_meta_double_matching(self):
|
583 |
508 |
meta = {'quality':'aaa', 'stock':'true'}
|
584 |
509 |
self.client.update_object_metadata(self.container[0],
|
585 |
510 |
self.obj[0]['name'], **meta)
|
586 |
|
obj = self.list_objects(self.container[0], meta='Quality,Stock')[2]
|
|
511 |
obj = self.client.list_objects(self.container[0], meta='Quality,Stock')
|
587 |
512 |
self.assertEqual(len(obj), 1)
|
588 |
513 |
self.assertTrue(obj, self.obj[0]['name'])
|
589 |
|
|
|
514 |
|
590 |
515 |
def test_list_using_meta(self):
|
591 |
516 |
meta = {'quality':'aaa'}
|
592 |
517 |
for o in self.obj[:2]:
|
... | ... | |
597 |
522 |
self.client.update_object_metadata(self.container[0], o['name'],
|
598 |
523 |
**meta)
|
599 |
524 |
|
600 |
|
status, headers, data = self.list_objects(self.container[0],
|
601 |
|
meta='Quality')
|
602 |
|
self.assertEqual(status, 200)
|
603 |
|
self.assertEqual(len(data), 2)
|
604 |
|
self.assertTrue(data, [o['name'] for o in self.obj[:2]])
|
|
525 |
obj = self.client.list_objects(self.container[0], meta='Quality')
|
|
526 |
self.assertEqual(len(obj), 2)
|
|
527 |
self.assertTrue(obj, [o['name'] for o in self.obj[:2]])
|
605 |
528 |
|
606 |
529 |
# test case insensitive
|
607 |
|
status, headers, obj = self.list_objects(self.container[0],
|
608 |
|
meta='quality')
|
609 |
|
self.assertEqual(status, 200)
|
|
530 |
obj = self.client.list_objects(self.container[0], meta='quality')
|
610 |
531 |
self.assertEqual(len(obj), 2)
|
611 |
532 |
self.assertTrue(obj, [o['name'] for o in self.obj[:2]])
|
612 |
533 |
|
613 |
534 |
# test multiple matches
|
614 |
|
status, headers, obj = self.list_objects(self.container[0],
|
615 |
|
meta='Quality,Stock')
|
616 |
|
self.assertEqual(status, 200)
|
|
535 |
obj = self.client.list_objects(self.container[0], meta='Quality,Stock')
|
617 |
536 |
self.assertEqual(len(obj), 4)
|
618 |
537 |
self.assertTrue(obj, [o['name'] for o in self.obj[:4]])
|
619 |
538 |
|
620 |
539 |
# test non 1-1 multiple match
|
621 |
|
status, headers, obj = self.list_objects(self.container[0],
|
622 |
|
meta='Quality,aaaa')
|
623 |
|
self.assertEqual(status, 200)
|
|
540 |
obj = self.client.list_objects(self.container[0], meta='Quality,aaaa')
|
624 |
541 |
self.assertEqual(len(obj), 2)
|
625 |
542 |
self.assertTrue(obj, [o['name'] for o in self.obj[:2]])
|
626 |
|
|
|
543 |
|
627 |
544 |
def test_if_modified_since(self):
|
628 |
545 |
t = datetime.datetime.utcnow()
|
629 |
546 |
t2 = t - datetime.timedelta(minutes=10)
|
630 |
547 |
|
631 |
548 |
#add a new object
|
632 |
549 |
self.upload_random_data(self.container[0], o_names[0])
|
633 |
|
|
|
550 |
|
634 |
551 |
for f in DATE_FORMATS:
|
635 |
552 |
past = t2.strftime(f)
|
636 |
|
|
637 |
|
headers = {'if-modified-since':'%s' %past}
|
638 |
|
status, headers, data = self.list_objects(self.container[0],
|
639 |
|
**headers)
|
640 |
|
|
641 |
|
#assert get success
|
642 |
|
self.assertEqual(status, 200)
|
643 |
|
|
|
553 |
try:
|
|
554 |
o = self.client.list_objects(self.container[0],
|
|
555 |
if_modified_since=past)
|
|
556 |
self.assertEqual(o,
|
|
557 |
self.client.list_objects(self.container[0]))
|
|
558 |
except Fault, f:
|
|
559 |
self.failIf(f.status == 304) #fail if not modified
|
|
560 |
|
644 |
561 |
def test_if_modified_since_invalid_date(self):
|
645 |
562 |
headers = {'if-modified-since':''}
|
646 |
|
status, headers, data = self.list_objects(self.container[0], **headers)
|
647 |
|
|
648 |
|
#assert get success
|
649 |
|
self.assertEqual(status, 200)
|
650 |
|
|
|
563 |
o = self.client.list_objects(self.container[0], if_modified_since='')
|
|
564 |
self.assertEqual(o, self.client.list_objects(self.container[0]))
|
|
565 |
|
651 |
566 |
def test_if_not_modified_since(self):
|
652 |
567 |
now = datetime.datetime.utcnow()
|
653 |
568 |
since = now + datetime.timedelta(1)
|
654 |
569 |
|
655 |
570 |
for f in DATE_FORMATS:
|
656 |
|
headers = {'if-modified-since':'%s' %since.strftime(f)}
|
|
571 |
args = {'if_modified_since':'%s' %since.strftime(f)}
|
|
572 |
|
657 |
573 |
#assert not modified
|
658 |
|
self.assert_raises_fault(304, self.list_objects, self.container[0],
|
659 |
|
**headers)
|
|
574 |
self.assert_raises_fault(304, self.client.list_objects,
|
|
575 |
self.container[0], **args)
|
660 |
576 |
|
661 |
577 |
def test_if_unmodified_since(self):
|
662 |
578 |
now = datetime.datetime.utcnow()
|
663 |
579 |
since = now + datetime.timedelta(1)
|
664 |
580 |
|
665 |
581 |
for f in DATE_FORMATS:
|
666 |
|
headers = {'if-unmodified-since':'%s' %since.strftime(f)}
|
667 |
|
status, headers, data = self.list_objects(self.container[0], **headers)
|
|
582 |
obj = self.client.list_objects(self.container[0],
|
|
583 |
if_unmodified_since=since.strftime(f))
|
668 |
584 |
|
669 |
|
#assert success
|
670 |
|
self.assertEqual(status, 200)
|
671 |
|
objlist = self.list_objects(self.container[0])[2]
|
672 |
|
self.assertEqual(data, objlist)
|
673 |
|
|
|
585 |
#assert unmodified
|
|
586 |
self.assertEqual(obj, self.client.list_objects(self.container[0]))
|
|
587 |
|
674 |
588 |
def test_if_unmodified_since_precondition_failed(self):
|
675 |
589 |
t = datetime.datetime.utcnow()
|
676 |
590 |
t2 = t - datetime.timedelta(minutes=10)
|
677 |
591 |
|
678 |
592 |
#add a new container
|
679 |
|
self.create_container('dummy')
|
680 |
|
|
|
593 |
self.client.create_container('dummy')
|
|
594 |
|
681 |
595 |
for f in DATE_FORMATS:
|
682 |
596 |
past = t2.strftime(f)
|
683 |
597 |
|
684 |
|
headers = {'if-unmodified-since':'%s' %past}
|
|
598 |
args = {'if_unmodified_since':'%s' %past}
|
|
599 |
|
685 |
600 |
#assert precondition failed
|
686 |
|
self.assert_raises_fault(412, self.list_objects, self.container[0],
|
687 |
|
**headers)
|
|
601 |
self.assert_raises_fault(412, self.client.list_objects,
|
|
602 |
self.container[0], **args)
|
688 |
603 |
|
689 |
604 |
class ContainerPut(BaseTestCase):
|
690 |
605 |
def setUp(self):
|
691 |
606 |
BaseTestCase.setUp(self)
|
692 |
607 |
self.account = 'test'
|
693 |
608 |
self.containers = ['c1', 'c2']
|
694 |
|
|
695 |
|
def tearDown(self):
|
696 |
|
for c in self.list_containers()[2]:
|
697 |
|
r = self.client.delete_container(c)
|
698 |
|
|
|
609 |
|
699 |
610 |
def test_create(self):
|
700 |
|
status = self.create_container(self.containers[0])[0]
|
701 |
|
self.assertEqual(status, 201)
|
702 |
|
|
703 |
|
containers = self.list_containers()[2]
|
|
611 |
self.client.create_container(self.containers[0])
|
|
612 |
containers = self.client.list_containers()
|
704 |
613 |
self.assertTrue(self.containers[0] in containers)
|
705 |
|
status = self.get_container_meta(self.containers[0])[0]
|
706 |
|
self.assertEqual(status, 204)
|
707 |
|
|
|
614 |
self.assert_container_exists(self.containers[0])
|
|
615 |
|
708 |
616 |
def test_create_twice(self):
|
709 |
|
status, header, data = self.create_container(self.containers[0])
|
710 |
|
if status == 201:
|
711 |
|
status, header, data = self.create_container(self.containers[0])
|
712 |
|
self.assertTrue(status, 202)
|
713 |
|
|
|
617 |
self.client.create_container(self.containers[0])
|
|
618 |
self.assertTrue(not self.client.create_container(self.containers[0]))
|
|
619 |
|
714 |
620 |
class ContainerPost(BaseTestCase):
|
715 |
621 |
def setUp(self):
|
716 |
622 |
BaseTestCase.setUp(self)
|
717 |
623 |
self.account = 'test'
|
718 |
624 |
self.container = 'apples'
|
719 |
|
self.create_container(self.container)
|
720 |
|
|
721 |
|
def tearDown(self):
|
722 |
|
for o in self.list_objects(self.container)[2]:
|
723 |
|
self.client.delete_object(self.account, self.container, o)
|
724 |
|
self.client.delete_container(self.container)
|
725 |
|
|
|
625 |
self.client.create_container(self.container)
|
|
626 |
|
726 |
627 |
def test_update_meta(self):
|
727 |
628 |
meta = {'test':'test33',
|
728 |
629 |
'tost':'tost22'}
|
729 |
630 |
self.client.update_container_metadata(self.container, **meta)
|
730 |
|
headers = self.get_container_meta(self.container)[1]
|
|
631 |
headers = self.client.retrieve_container_metadata(self.container)
|
731 |
632 |
for k,v in meta.items():
|
732 |
633 |
k = 'x-container-meta-%s' % k
|
733 |
634 |
self.assertTrue(headers[k])
|
... | ... | |
739 |
640 |
self.account = 'test'
|
740 |
641 |
self.containers = ['c1', 'c2']
|
741 |
642 |
for c in self.containers:
|
742 |
|
self.create_container(c)
|
|
643 |
self.client.create_container(c)
|
743 |
644 |
self.upload_random_data(self.containers[1], o_names[0])
|
744 |
|
|
745 |
|
def tearDown(self):
|
746 |
|
for c in self.list_containers()[2]:
|
747 |
|
for o in self.list_objects(c)[2]:
|
748 |
|
self.client.delete_object(c, o)
|
749 |
|
self.client.delete_container(c)
|
750 |
|
|
|
645 |
|
751 |
646 |
def test_delete(self):
|
752 |
647 |
status = self.client.delete_container(self.containers[0])[0]
|
753 |
648 |
self.assertEqual(status, 204)
|
754 |
|
|
|
649 |
|
755 |
650 |
def test_delete_non_empty(self):
|
756 |
651 |
self.assert_raises_fault(409, self.client.delete_container,
|
757 |
652 |
self.containers[1])
|
758 |
|
|
|
653 |
|
759 |
654 |
def test_delete_invalid(self):
|
760 |
655 |
self.assert_raises_fault(404, self.client.delete_container, 'c3')
|
761 |
656 |
|
... | ... | |
769 |
664 |
self.containers = ['c1', 'c2']
|
770 |
665 |
#create some containers
|
771 |
666 |
for c in self.containers:
|
772 |
|
self.create_container(c)
|
|
667 |
self.client.create_container(c)
|
773 |
668 |
|
774 |
669 |
#upload a file
|
775 |
670 |
names = ('obj1', 'obj2')
|
776 |
671 |
self.objects = []
|
777 |
672 |
for n in names:
|
778 |
673 |
self.objects.append(self.upload_random_data(self.containers[1], n))
|
779 |
|
|
780 |
|
def tearDown(self):
|
781 |
|
for c in self.containers:
|
782 |
|
for o in self.list_objects(c)[2]:
|
783 |
|
self.client.delete_object(c, o)
|
784 |
|
self.client.delete_container(c)
|
785 |
|
|
|
674 |
|
786 |
675 |
def test_get(self):
|
787 |
676 |
#perform get
|
788 |
|
status, headers, data = self.get_object(self.containers[1],
|
789 |
|
self.objects[0]['name'],
|
790 |
|
self.objects[0]['meta'])
|
791 |
|
#assert success
|
792 |
|
self.assertEqual(status, 200)
|
793 |
|
|
794 |
|
#assert content-type
|
795 |
|
self.assertEqual(headers['content-type'],
|
796 |
|
self.objects[0]['meta']['content-type'])
|
797 |
|
|
|
677 |
o = self.client.retrieve_object(self.containers[1],
|
|
678 |
self.objects[0]['name'],
|
|
679 |
self.objects[0]['meta'])
|
|
680 |
self.assertEqual(o, self.objects[0]['data'])
|
|
681 |
|
798 |
682 |
def test_get_invalid(self):
|
799 |
|
self.assert_raises_fault(404, self.get_object, self.containers[0],
|
800 |
|
self.objects[0]['name'])
|
801 |
|
|
|
683 |
self.assert_raises_fault(404, self.client.retrieve_object,
|
|
684 |
self.containers[0], self.objects[0]['name'])
|
|
685 |
|
802 |
686 |
def test_get_partial(self):
|
803 |
687 |
#perform get with range
|
804 |
|
headers = {'range':'bytes=0-499'}
|
805 |
|
status, headers, data = self.get_object(self.containers[1],
|
806 |
|
self.objects[0]['name'],
|
807 |
|
**headers)
|
|
688 |
status, headers, data = self.client.request_object(self.containers[1],
|
|
689 |
self.objects[0]['name'],
|
|
690 |
range='bytes=0-499')
|
808 |
691 |
|
809 |
692 |
#assert successful partial content
|
810 |
693 |
self.assertEqual(status, 206)
|
811 |
694 |
|
812 |
695 |
#assert content-type
|
813 |
696 |
self.assertEqual(headers['content-type'],
|
814 |
|
self.objects[0]['meta']['content-type'])
|
|
697 |
self.objects[0]['meta']['content_type'])
|
815 |
698 |
|
816 |
699 |
#assert content length
|
817 |
700 |
self.assertEqual(int(headers['content-length']), 500)
|
818 |
701 |
|
819 |
702 |
#assert content
|
820 |
703 |
self.assertEqual(self.objects[0]['data'][:500], data)
|
821 |
|
|
|
704 |
|
822 |
705 |
def test_get_final_500(self):
|
823 |
706 |
#perform get with range
|
824 |
707 |
headers = {'range':'bytes=-500'}
|
825 |
|
status, headers, data = self.get_object(self.containers[1],
|
826 |
|
self.objects[0]['name'],
|
827 |
|
**headers)
|
|
708 |
status, headers, data = self.client.request_object(self.containers[1],
|
|
709 |
self.objects[0]['name'],
|
|
710 |
range='bytes=-500')
|
828 |
711 |
|
829 |
712 |
#assert successful partial content
|
830 |
713 |
self.assertEqual(status, 206)
|
831 |
714 |
|
832 |
715 |
#assert content-type
|
833 |
716 |
self.assertEqual(headers['content-type'],
|
834 |
|
self.objects[0]['meta']['content-type'])
|
|
717 |
self.objects[0]['meta']['content_type'])
|
835 |
718 |
|
836 |
719 |
#assert content length
|
837 |
720 |
self.assertEqual(int(headers['content-length']), 500)
|
838 |
721 |
|
839 |
722 |
#assert content
|
840 |
723 |
self.assertTrue(self.objects[0]['data'][-500:], data)
|
841 |
|
|
|
724 |
|
842 |
725 |
def test_get_rest(self):
|
843 |
726 |
#perform get with range
|
844 |
727 |
offset = len(self.objects[0]['data']) - 500
|
845 |
|
headers = {'range':'bytes=%s-' %offset}
|
846 |
|
status, headers, data = self.get_object(self.containers[1],
|
|
728 |
status, headers, data = self.client.request_object(self.containers[1],
|
847 |
729 |
self.objects[0]['name'],
|
848 |
|
**headers)
|
|
730 |
range='bytes=%s-' %offset)
|
849 |
731 |
|
850 |
732 |
#assert successful partial content
|
851 |
733 |
self.assertEqual(status, 206)
|
852 |
734 |
|
853 |
735 |
#assert content-type
|
854 |
736 |
self.assertEqual(headers['content-type'],
|
855 |
|
self.objects[0]['meta']['content-type'])
|
|
737 |
self.objects[0]['meta']['content_type'])
|
856 |
738 |
|
857 |
739 |
#assert content length
|
858 |
740 |
self.assertEqual(int(headers['content-length']), 500)
|
859 |
741 |
|
860 |
742 |
#assert content
|
861 |
743 |
self.assertTrue(self.objects[0]['data'][-500:], data)
|
862 |
|
|
|
744 |
|
863 |
745 |
def test_get_range_not_satisfiable(self):
|
864 |
746 |
#perform get with range
|
865 |
747 |
offset = len(self.objects[0]['data']) + 1
|
866 |
|
headers = {'range':'bytes=0-%s' %offset}
|
867 |
748 |
|
868 |
749 |
#assert range not satisfiable
|
869 |
|
self.assert_raises_fault(416, self.get_object, self.containers[1],
|
870 |
|
self.objects[0]['name'], **headers)
|
871 |
|
|
|
750 |
self.assert_raises_fault(416, self.client.retrieve_object,
|
|
751 |
self.containers[1], self.objects[0]['name'],
|
|
752 |
range='bytes=0-%s' %offset)
|
|
753 |
|
872 |
754 |
def test_multiple_range(self):
|
873 |
755 |
#perform get with multiple range
|
874 |
756 |
ranges = ['0-499', '-500', '1000-']
|
875 |
|
headers = {'range' : 'bytes=%s' % ','.join(ranges)}
|
876 |
|
status, headers, data = self.get_object(self.containers[1],
|
877 |
|
self.objects[0]['name'],
|
878 |
|
**headers)
|
|
757 |
bytes = 'bytes=%s' % ','.join(ranges)
|
|
758 |
status, headers, data = self.client.request_object(self.containers[1],
|
|
759 |
self.objects[0]['name'],
|
|
760 |
range=bytes)
|
879 |
761 |
|
880 |
762 |
# assert partial content
|
881 |
763 |
self.assertEqual(status, 206)
|
... | ... | |
916 |
798 |
self.assertEqual(len(fdata), len(sdata))
|
917 |
799 |
self.assertEquals(fdata, sdata)
|
918 |
800 |
i+=1
|
919 |
|
|
|
801 |
|
920 |
802 |
def test_multiple_range_not_satisfiable(self):
|
921 |
803 |
#perform get with multiple range
|
922 |
804 |
out_of_range = len(self.objects[0]['data']) + 1
|
923 |
805 |
ranges = ['0-499', '-500', '%d-' %out_of_range]
|
924 |
|
headers = {'range' : 'bytes=%s' % ','.join(ranges)}
|
|
806 |
bytes = 'bytes=%s' % ','.join(ranges)
|
925 |
807 |
|
926 |
808 |
# assert partial content
|
927 |
|
self.assert_raises_fault(416, self.get_object, self.containers[1],
|
928 |
|
self.objects[0]['name'], **headers)
|
929 |
|
|
930 |
|
|
|
809 |
self.assert_raises_fault(416, self.client.retrieve_object,
|
|
810 |
self.containers[1],
|
|
811 |
self.objects[0]['name'], range=bytes)
|
|
812 |
|
931 |
813 |
def test_get_with_if_match(self):
|
932 |
814 |
#perform get with If-Match
|
933 |
|
headers = {'if-match':self.objects[0]['hash']}
|
934 |
|
status, headers, data = self.get_object(self.containers[1],
|
935 |
|
self.objects[0]['name'],
|
936 |
|
**headers)
|
|
815 |
etag = self.objects[0]['hash']
|
|
816 |
status, headers, data = self.client.request_object(self.containers[1],
|
|
817 |
self.objects[0]['name'],
|
|
818 |
if_match=etag)
|
937 |
819 |
#assert get success
|
938 |
820 |
self.assertEqual(status, 200)
|
939 |
821 |
|
940 |
822 |
#assert content-type
|
941 |
823 |
self.assertEqual(headers['content-type'],
|
942 |
|
self.objects[0]['meta']['content-type'])
|
|
824 |
self.objects[0]['meta']['content_type'])
|
943 |
825 |
|
944 |
826 |
#assert response content
|
945 |
827 |
self.assertEqual(self.objects[0]['data'], data)
|
946 |
|
|
|
828 |
|
947 |
829 |
def test_get_with_if_match_star(self):
|
948 |
830 |
#perform get with If-Match *
|
949 |
831 |
headers = {'if-match':'*'}
|
950 |
|
status, headers, data = self.get_object(self.containers[1],
|
|
832 |
status, headers, data = self.client.request_object(self.containers[1],
|
951 |
833 |
self.objects[0]['name'],
|
952 |
834 |
**headers)
|
953 |
835 |
#assert get success
|
... | ... | |
955 |
837 |
|
956 |
838 |
#assert content-type
|
957 |
839 |
self.assertEqual(headers['content-type'],
|
958 |
|
self.objects[0]['meta']['content-type'])
|
|
840 |
self.objects[0]['meta']['content_type'])
|
959 |
841 |
|
960 |
842 |
#assert response content
|
961 |
843 |
self.assertEqual(self.objects[0]['data'], data)
|
962 |
|
|
|
844 |
|
963 |
845 |
def test_get_with_multiple_if_match(self):
|
964 |
846 |
#perform get with If-Match
|
965 |
847 |
etags = [i['hash'] for i in self.objects if i]
|
966 |
848 |
etags = ','.join('"%s"' % etag for etag in etags)
|
967 |
|
headers = {'if-match':etags}
|
968 |
|
status, headers, data = self.get_object(self.containers[1],
|
969 |
|
self.objects[0]['name'],
|
970 |
|
**headers)
|
|
849 |
status, headers, data = self.client.request_object(self.containers[1],
|
|
850 |
self.objects[0]['name'],
|
|
851 |
if_match=etags)
|
971 |
852 |
#assert get success
|
972 |
853 |
self.assertEqual(status, 200)
|
973 |
854 |
|
974 |
855 |
#assert content-type
|
975 |
856 |
self.assertEqual(headers['content-type'],
|
976 |
|
self.objects[0]['meta']['content-type'])
|
|
857 |
self.objects[0]['meta']['content_type'])
|
977 |
858 |
|
978 |
859 |
#assert content-type
|
979 |
860 |
self.assertEqual(headers['content-type'],
|
980 |
|
self.objects[0]['meta']['content-type'])
|
|
861 |
self.objects[0]['meta']['content_type'])
|
981 |
862 |
|
982 |
863 |
#assert response content
|
983 |
864 |
self.assertEqual(self.objects[0]['data'], data)
|
984 |
|
|
|
865 |
|
985 |
866 |
def test_if_match_precondition_failed(self):
|
986 |
|
#perform get with If-Match
|
987 |
|
headers = {'if-match':'123'}
|
988 |
|
|
989 |
867 |
#assert precondition failed
|
990 |
|
self.assert_raises_fault(412, self.get_object, self.containers[1],
|
991 |
|
self.objects[0]['name'], **headers)
|
992 |
|
|
993 |
|
|
|
868 |
self.assert_raises_fault(412, self.client.retrieve_object,
|
|
869 |
self.containers[1],
|
|
870 |
self.objects[0]['name'], if_match='123')
|
|
871 |
|
994 |
872 |
def test_if_none_match(self):
|
995 |
873 |
#perform get with If-None-Match
|
996 |
|
headers = {'if-none-match':'123'}
|
997 |
|
status, headers, data = self.get_object(self.containers[1],
|
998 |
|
self.objects[0]['name'],
|
999 |
|
**headers)
|
|
874 |
status, headers, data = self.client.request_object(self.containers[1],
|
|
875 |
self.objects[0]['name'],
|
|
876 |
if_none_match='123')
|
1000 |
877 |
|
1001 |
878 |
#assert get success
|
1002 |
879 |
self.assertEqual(status, 200)
|
1003 |
880 |
|
1004 |
881 |
#assert content-type
|
1005 |
|
self.assertEqual(headers['content-type'],
|
1006 |
|
self.objects[0]['meta']['content-type'])
|
1007 |
|
|
|
882 |
self.assertEqual(headers['content_type'],
|
|
883 |
self.objects[0]['meta']['content_type'])
|
|
884 |
|
1008 |
885 |
def test_if_none_match(self):
|
1009 |
|
#perform get with If-None-Match *
|
1010 |
|
headers = {'if-none-match':'*'}
|
1011 |
|
|
1012 |
|
#assert not modified
|
1013 |
|
self.assert_raises_fault(304, self.get_object, self.containers[1],
|
1014 |
|
self.objects[0]['name'],
|
1015 |
|
**headers)
|
1016 |
|
|
|
886 |
#perform get with If-None-Match * and assert not modified
|
|
887 |
self.assert_raises_fault(304, self.client.retrieve_object,
|
|
888 |
self.containers[1],
|
|
889 |
self.objects[0]['name'],
|
|
890 |
if_none_match='*')
|
|
891 |
|
1017 |
892 |
def test_if_none_match_not_modified(self):
|
1018 |
|
#perform get with If-None-Match
|
1019 |
|
headers = {'if-none-match':'%s' %self.objects[0]['hash']}
|
1020 |
|
|
1021 |
|
#assert not modified
|
1022 |
|
self.assert_raises_fault(304, self.get_object, self.containers[1],
|
1023 |
|
self.objects[0]['name'],
|
1024 |
|
**headers)
|
1025 |
|
|
1026 |
|
headers = self.get_object(self.containers[1],
|
1027 |
|
self.objects[0]['name'])[1]
|
1028 |
|
self.assertEqual(headers['etag'], self.objects[0]['hash'])
|
1029 |
|
|
|
893 |
#perform get with If-None-Match and assert not modified
|
|
894 |
self.assert_raises_fault(304, self.client.retrieve_object,
|
|
895 |
self.containers[1],
|
|
896 |
self.objects[0]['name'],
|
|
897 |
if_none_match=self.objects[0]['hash'])
|
|
898 |
|
|
899 |
meta = self.client.retrieve_object_metadata(self.containers[1],
|
|
900 |
self.objects[0]['name'])
|
|
901 |
self.assertEqual(meta['etag'], self.objects[0]['hash'])
|
|
902 |
|
1030 |
903 |
def test_if_modified_since(self):
|
1031 |
904 |
t = datetime.datetime.utcnow()
|
1032 |
905 |
t2 = t - datetime.timedelta(minutes=10)
|
... | ... | |
1040 |
913 |
past = t2.strftime(f)
|
1041 |
914 |
|
1042 |
915 |
headers = {'if-modified-since':'%s' %past}
|
1043 |
|
status, headers, data = self.get_object(self.containers[1],
|
1044 |
|
self.objects[0]['name'],
|
1045 |
|
**headers)
|
1046 |
|
|
1047 |
|
#assert get success
|
1048 |
|
self.assertEqual(status, 200)
|
1049 |
|
|
1050 |
|
#assert content-type
|
1051 |
|
self.assertEqual(headers['content-type'],
|
1052 |
|
self.objects[0]['meta']['content-type'])
|
1053 |
|
|
1054 |
|
def test_if_modified_since_invalid_date(self):
|
1055 |
|
headers = {'if-modified-since':''}
|
1056 |
|
status, headers, data = self.get_object(self.containers[1],
|
|
916 |
try:
|
|
917 |
o = self.client.retrieve_object(self.containers[1],
|
1057 |
918 |
self.objects[0]['name'],
|
1058 |
|
**headers)
|
1059 |
|
|
1060 |
|
#assert get success
|
1061 |
|
self.assertEqual(status, 200)
|
1062 |
|
|
1063 |
|
#assert content-type
|
1064 |
|
self.assertEqual(headers['content-type'],
|
1065 |
|
self.objects[0]['meta']['content-type'])
|
1066 |
|
|
|
919 |
if_modified_since=past)
|
|
920 |
self.assertEqual(o,
|
|
921 |
self.client.retrieve_object(self.containers[1],
|
|
922 |
self.objects[0]['name']))
|
|
923 |
except Fault, f:
|
|
924 |
self.failIf(f.status == 304)
|
|
925 |
|
|
926 |
def test_if_modified_since_invalid_date(self):
|
|
927 |
o = self.client.retrieve_object(self.containers[1],
|
|
928 |
self.objects[0]['name'],
|
|
929 |
if_modified_since='')
|
|
930 |
self.assertEqual(o, self.client.retrieve_object(self.containers[1],
|
|
931 |
self.objects[0]['name']))
|
|
932 |
|
1067 |
933 |
def test_if_not_modified_since(self):
|
1068 |
934 |
now = datetime.datetime.utcnow()
|
1069 |
935 |
since = now + datetime.timedelta(1)
|
1070 |
936 |
|
1071 |
937 |
for f in DATE_FORMATS:
|
1072 |
|
headers = {'if-modified-since':'%s' %since.strftime(f)}
|
1073 |
|
|
1074 |
938 |
#assert not modified
|
1075 |
|
self.assert_raises_fault(304, self.get_object, self.containers[1],
|
1076 |
|
self.objects[0]['name'], **headers)
|
1077 |
|
|
1078 |
|
|
|
939 |
self.assert_raises_fault(304, self.client.retrieve_object,
|
|
940 |
self.containers[1], self.objects[0]['name'],
|
|
941 |
if_modified_since=since.strftime(f))
|
|
942 |
|
1079 |
943 |
def test_if_unmodified_since(self):
|
1080 |
944 |
now = datetime.datetime.utcnow()
|
1081 |
945 |
since = now + datetime.timedelta(1)
|
1082 |
946 |
|
1083 |
947 |
for f in DATE_FORMATS:
|
1084 |
|
headers = {'if-unmodified-since':'%s' %since.strftime(f)}
|
1085 |
|
status, headers, data = self.get_object(self.containers[1],
|
1086 |
|
self.objects[0]['name'],
|
1087 |
|
**headers)
|
|
948 |
t = since.strftime(f)
|
|
949 |
status, headers, data = self.client.request_object(self.containers[1],
|
|
950 |
self.objects[0]['name'],
|
|
951 |
if_unmodified_since=t)
|
1088 |
952 |
#assert success
|
1089 |
953 |
self.assertEqual(status, 200)
|
1090 |
954 |
self.assertEqual(self.objects[0]['data'], data)
|
1091 |
955 |
|
1092 |
956 |
#assert content-type
|
1093 |
957 |
self.assertEqual(headers['content-type'],
|
1094 |
|
self.objects[0]['meta']['content-type'])
|
1095 |
|
|
|
958 |
self.objects[0]['meta']['content_type'])
|
|
959 |
|
1096 |
960 |
def test_if_unmodified_since_precondition_failed(self):
|
1097 |
961 |
t = datetime.datetime.utcnow()
|
1098 |
962 |
t2 = t - datetime.timedelta(minutes=10)
|
... | ... | |
1104 |
968 |
|
1105 |
969 |
for f in DATE_FORMATS:
|
1106 |
970 |
past = t2.strftime(f)
|
1107 |
|
|
1108 |
|
headers = {'if-unmodified-since':'%s' %past}
|
1109 |
|
|
1110 |
971 |
#assert precondition failed
|
1111 |
|
self.assert_raises_fault(412, self.get_object, self.containers[1],
|
1112 |
|
self.objects[0]['name'], **headers)
|
1113 |
|
|
1114 |
|
|
|
972 |
self.assert_raises_fault(412, self.client.retrieve_object,
|
|
973 |
self.containers[1], self.objects[0]['name'],
|
|
974 |
if_unmodified_since=past)
|
|
975 |
|
1115 |
976 |
def test_hashes(self):
|
1116 |
977 |
l = 8388609
|
1117 |
978 |
fname = 'largefile'
|
1118 |
979 |
o = self.upload_random_data(self.containers[1], fname, l)
|
1119 |
980 |
if o:
|
1120 |
|
data = self.get_object(self.containers[1],
|
1121 |
|
fname,
|
1122 |
|
'json')[2]
|
|
981 |
data = self.client.retrieve_object(self.containers[1], fname, detail=True)
|
1123 |
982 |
body = json.loads(data)
|
1124 |
983 |
hashes = body['hashes']
|
1125 |
984 |
block_size = body['block_size']
|
... | ... | |
1139 |
998 |
BaseTestCase.setUp(self)
|
1140 |
999 |
self.account = 'test'
|
1141 |
1000 |
self.container = 'c1'
|
1142 |
|
self.create_container(self.container)
|
|
1001 |
self.client.create_container(self.container)
|
1143 |
1002 |
|
1144 |
|
def tearDown(self):
|
1145 |
|
objects = self.list_objects(self.container)[2]
|
1146 |
|
for o in objects:
|
1147 |
|
self.client.delete_object(self.container, o)
|
1148 |
|
self.client.delete_container(self.container)
|
1149 |
|
|
1150 |
1003 |
def test_upload(self):
|
1151 |
1004 |
name = o_names[0]
|
1152 |
1005 |
meta = {'test':'test1'}
|
... | ... | |
1159 |
1012 |
self.assertEqual(headers['test'], meta['test'])
|
1160 |
1013 |
|
1161 |
1014 |
#assert uploaded content
|
1162 |
|
status, headers, content = self.get_object(self.container, name)
|
1163 |
|
self.assertEqual(len(o['data']), int(headers['content-length']))
|
1164 |
|
self.assertEqual(o['data'], content)
|
1165 |
|
|
|
1015 |
status, h, data = self.client.request_object(self.container, name)
|
|
1016 |
self.assertEqual(len(o['data']), int(h['content-length']))
|
|
1017 |
self.assertEqual(o['data'], data)
|
|
1018 |
|
|
1019 |
#assert content-type
|
|
1020 |
self.assertEqual(h['content-type'], o['meta']['content_type'])
|
|
1021 |
|
1166 |
1022 |
def test_upload_unprocessable_entity(self):
|
1167 |
1023 |
meta={'etag':'123', 'test':'test1'}
|
1168 |
1024 |
|
1169 |
1025 |
#assert unprocessable entity
|
1170 |
|
self.assert_raises_fault(422, self.upload_random_data,self.container,
|
|
1026 |
self.assert_raises_fault(422, self.upload_random_data, self.container,
|
1171 |
1027 |
o_names[0], **meta)
|
1172 |
|
|
|
1028 |
|
1173 |
1029 |
def test_chucked_transfer(self):
|
1174 |
|
fname = './api/tests.py'
|
1175 |
|
objname = os.path.split(fname)[-1:][0]
|
1176 |
|
f = open(fname, 'r')
|
1177 |
|
status = self.client.create_object(self.container,
|
1178 |
|
objname,
|
1179 |
|
f,
|
1180 |
|
chunked=True)[0]
|
1181 |
|
self.assertEqual(status, 201)
|
|
1030 |
data = get_random_data()
|
|
1031 |
objname = 'object'
|
|
1032 |
self.client.create_object_using_chunks(self.container, objname,
|
|
1033 |
StringIO(data))
|
1182 |
1034 |
|
1183 |
|
uploaded_data = self.get_object(self.container,
|
1184 |
|
objname)[2]
|
1185 |
|
f = open(fname, 'r')
|
1186 |
|
actual_data = f.read()
|
1187 |
|
self.assertEqual(actual_data, uploaded_data)
|
|
1035 |
uploaded_data = self.client.retrieve_object(self.container, objname)
|
|
1036 |
self.assertEqual(data, uploaded_data)
|
1188 |
1037 |
|
1189 |
1038 |
class ObjectCopy(BaseTestCase):
|
1190 |
1039 |
def setUp(self):
|
... | ... | |
1192 |
1041 |
self.account = 'test'
|
1193 |
1042 |
self.containers = ['c1', 'c2']
|
1194 |
1043 |
for c in self.containers:
|
1195 |
|
self.create_container(c)
|
|
1044 |
self.client.create_container(c)
|
1196 |
1045 |
self.obj = self.upload_random_data(self.containers[0], o_names[0])
|
1197 |
|
|
1198 |
|
def tearDown(self):
|
1199 |
|
for c in self.containers:
|
1200 |
|
for o in self.list_objects(c)[2]:
|
1201 |
|
self.client.delete_object(c, o)
|
1202 |
|
self.client.delete_container(c)
|
1203 |
|
|
|
1046 |
|
1204 |
1047 |
def test_copy(self):
|
1205 |
1048 |
with AssertMappingInvariant(self.client.retrieve_object_metadata,
|
1206 |
1049 |
self.containers[0], self.obj['name']):
|
... | ... | |
1226 |
1069 |
|
1227 |
1070 |
#assert src object still exists
|
1228 |
1071 |
self.assert_object_exists(self.containers[0], self.obj['name'])
|
1229 |
|
|
|
1072 |
|
1230 |
1073 |
def test_copy_from_different_container(self):
|
1231 |
1074 |
with AssertMappingInvariant(self.client.retrieve_object_metadata,
|
1232 |
1075 |
self.containers[0], self.obj['name']):
|
... | ... | |
1247 |
1090 |
|
1248 |
1091 |
#assert src object still exists
|
1249 |
1092 |
self.assert_object_exists(self.containers[0], self.obj['name'])
|
1250 |
|
|
|
1093 |
|
1251 |
1094 |
def test_copy_invalid(self):
|
1252 |
1095 |
#copy from invalid object
|
1253 |
1096 |
meta = {'test':'testcopy'}
|
... | ... | |
1290 |
1133 |
self.account = 'test'
|
1291 |
1134 |
self.containers = ['c1', 'c2']
|
1292 |
1135 |
for c in self.containers:
|
1293 |
|
self.create_container(c)
|
|
1136 |
self.client.create_container(c)
|
1294 |
1137 |
self.obj = self.upload_random_data(self.containers[0], o_names[0])
|
1295 |
|
|
1296 |
|
def tearDown(self):
|
1297 |
|
for c in self.containers:
|
1298 |
|
for o in self.list_objects(c)[2]:
|
1299 |
|
self.client.delete_object(c, o)
|
1300 |
|
self.client.delete_container(c)
|
1301 |
|
|
|
1138 |
|
1302 |
1139 |
def test_update_meta(self):
|
1303 |
1140 |
#perform update metadata
|
1304 |
1141 |
more = {'foo':'foo', 'bar':'bar'}
|
... | ... | |
1316 |
1153 |
for k,v in more.items():
|
1317 |
1154 |
self.assertTrue(k in headers.keys())
|
1318 |
1155 |
self.assertTrue(headers[k], v)
|
1319 |
|
|
|
1156 |
|
1320 |
1157 |
def test_update_object(self,
|
1321 |
1158 |
first_byte_pos=0,
|
1322 |
1159 |
last_byte_pos=499,
|
... | ... | |
1329 |
1166 |
length)
|
1330 |
1167 |
partial = last_byte_pos - first_byte_pos + 1
|
1331 |
1168 |
data = get_random_data(partial)
|
1332 |
|
headers = {'content-range':range,
|
1333 |
|
'content-type':'application/octet-stream'}
|
|
1169 |
args = {'content_type':'application/octet-stream',
|
|
1170 |
'content_range':'%s' %range}
|
1334 |
1171 |
if content_length:
|
1335 |
|
headers.update({'content-length':'%s' % content_length})
|
1336 |
|
|
1337 |
|
status = self.client.update_object_data(self.containers[0],
|
1338 |
|
self.obj['name'],
|
1339 |
|
data,
|
1340 |
|
headers)[0]
|
1341 |
|
|
|
1172 |
args['content_length'] = content_length
|
|
1173 |
status = self.client.update_object(self.containers[0], self.obj['name'],
|
|
1174 |
StringIO(data), **args)[0]
|
1342 |
1175 |
|
1343 |
1176 |
if partial < 0 or (instance_length and l <= last_byte_pos):
|
1344 |
1177 |
self.assertEqual(status, 202)
|
1345 |
1178 |
else:
|
1346 |
|
self.assertEqual(status, 204)
|
1347 |
|
|
|
1179 |
self.assertEqual(status, 204)
|
1348 |
1180 |
#check modified object
|
1349 |
|
content = self.get_object(self.containers[0], self.obj['name'])[2]
|
|
1181 |
content = self.client.retrieve_object(self.containers[0],
|
|
1182 |
self.obj['name'])
|
1350 |
1183 |
self.assertEqual(content[0:partial], data)
|
1351 |
1184 |
self.assertEqual(content[partial:l], self.obj['data'][partial:l])
|
1352 |
|
|
|
1185 |
|
1353 |
1186 |
def test_update_object_no_content_length(self):
|
1354 |
1187 |
self.test_update_object(content_length = None)
|
1355 |
|
|
1356 |
|
|
1357 |
|
#fails if the server resets the content-legth
|
1358 |
|
#def test_update_object_invalid_content_length(self):
|
1359 |
|
# with AssertContentInvariant(self.get_object, self.containers[0],
|
1360 |
|
# self.obj['name']):
|
1361 |
|
# self.test_update_object(content_length = 1000)
|
1362 |
|
|
1363 |
|
def test_update_object_with_unknown_instance_length(self):
|
1364 |
|
self.test_update_object(instance_length = False)
|
1365 |
|
|
|
1188 |
|
|
1189 |
def test_update_object_invalid_content_length(self):
|
|
1190 |
with AssertContentInvariant(self.client.retrieve_object,
|
|
1191 |
self.containers[0], self.obj['name']):
|
|
1192 |
self.assert_raises_fault(400, self.test_update_object,
|
|
1193 |
content_length = 1000)
|
|
1194 |
|
1366 |
1195 |
def test_update_object_invalid_range(self):
|