import json
import logging
from .connection import HTTPConnectionError
-from .connection.request import HTTPRequest
-#from .connection.kamakicon import KamakiHTTPConnection
+#from .connection.request import HTTPRequest
+from .connection.kamakicon import KamakiHTTPConnection
sendlog = logging.getLogger('clients.send')
recvlog = logging.getLogger('clients.recv')
class Client(object):
- def __init__(self, base_url, token, http_client=HTTPRequest()):
+ def __init__(self, base_url, token, http_client=KamakiHTTPConnection()):
self.base_url = base_url
self.token = token
self.headers = {}
#kwargs.setdefault('verify', False) # Disable certificate verification
self.http_client.url = self.base_url + path
- r = self.http_client.perform_request(method=method, data=data, binary=binary)
+ r = self.http_client.perform_request(method=method, data=data)
#r = requests.request(method, url, headers=self.headers, data=data, **kwargs)
req = self.http_client
- sendlog.info('%s %s', req.method, req.url)
+ sendlog.info('%s %s', method, req.url)
for key, val in req.headers.items():
sendlog.info('%s: %s', key, val)
sendlog.info('')
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
-from .pool import ObjectPool
-
-POOL_SIZE=8
-
-class HTTPResponsePool(ObjectPool):
-
- def __init__(self, netloc, size=POOL_SIZE):
- super(HTTPResponsePool, self).__init__(size=size)
- self.netloc = netloc
-
- def _pool_create(self):
- resp = HTTPResponse()
- resp._pool = self
- return resp
-
- def _pool_cleanup(self, resp):
- resp._get_response()
- return True
-
class HTTPResponse(object):
def __init__(self, request=None, prefetched=False):
self.request=request
- if prefetched:
- self = request.response
self.prefetched = prefetched
def _get_response(self):
from .pool.http import get_http_connection
from . import HTTPConnection, HTTPResponse, HTTPConnectionError
+from json import loads
from time import sleep
from httplib import ResponseNotReady
class KamakiHTTPResponse(HTTPResponse):
def _get_response(self):
- print('KamakiHTTPResponse:should I get response?')
if self.prefetched:
- print('\tKamakiHTTPResponse: no, I have already done that before')
return
- print('\tKamakiHTTPResponse: yes, pls')
- r = self.request.getresponse()
+
+ ready = False
+ while not ready:
+ try:
+ r = self.request.getresponse()
+ except ResponseNotReady:
+ sleep(0.2)
+ continue
+ break
self.prefetched = True
headers = {}
for k,v in r.getheaders():
headers.update({k:v})
self.headers = headers
- self.content = r.read(r.length)
+ self.content = r.read()
self.status_code = r.status
self.status = r.reason
- print('KamakiHTTPResponse: Niiiiice')
+ self.request.close()
@property
def text(self):
- _get_response()
+ self._get_response()
return self._content
@text.setter
def test(self, v):
@property
def json(self):
- _get_response()
- from json import loads
+ self._get_response()
try:
return loads(self._content)
except ValueError as err:
def json(self, v):
pass
-class KamakiHTTPConnection(HTTPConnection):
-
- url = None
- scheme = None
- netloc = None
- method = None
- data = None
- headers = None
+ def release(self):
+ if not self.prefetched:
+ self.request.close()
- scheme_ports = {
- 'http': '80',
- 'https': '443',
- }
- def _load_connection_settings(self, url=None, scheme=None, params=None, headers=None, host=None,
- port=None, method=None):
- if params is not None:
- self.params = params
- if headers is not None:
- self.headers = headers
-
- if url is None:
- url = self.url
- if host is None or scheme is None:
- p = urlparse(url)
- netloc = p.netloc
- if not netloc:
- netloc = 'localhost'
- scheme = p.scheme
- if not scheme:
- scheme = 'http'
- param_str = ''
- for i,(key, val) in enumerate(self.params.items()):
- param_str = ('?' if i == 0 else '&') + unicode(key)
- if val is not None:
- param_str+= '='+unicode(val)
- url = p.path + param_str
- else:
- host = host
- port = port if port is not None else self.scheme_ports[scheme]
- #NOTE: we force host:port as canonical form,
- # lest we have a cache miss 'host' vs 'host:80'
- netloc = "%s%s" % (host, port)
+class KamakiHTTPConnection(HTTPConnection):
- self.netloc = netloc
- self.url = url #if url in (None, '') or url[0] != '/' else url[1:]
- self.scheme = scheme
+ def _retrieve_connection_info(self):
+ """ return (scheme, netloc, url?with¶ms) """
+ url = self.url
+ for i,(key, val) in enumerate(self.params.items()):
+ param_str = ('?' if i == 0 else '&') + unicode(key)
+ if val is not None:
+ param_str+= '='+unicode(val)
+ url += param_str
- if method is not None:
- self.method = method
+ parsed = urlparse(self.url)
+ self.url = url
+ return (parsed.scheme, parsed.netloc)
- def perform_request(self, url=None, params=None, headers=None, method=None, host=None,
- port=None, data=None):
- self._load_connection_settings(url=url, params=params, headers=headers, host=host,
- port=port, method=method)
- print('---> %s %s %s %s %s'%(self.method, self.scheme, self.netloc, self.url, self.headers))
- conn = get_http_connection(netloc=self.netloc, scheme=self.scheme)
+ def perform_request(self, method=None, data=None):
+ (scheme, netloc) = self._retrieve_connection_info()
+ #get connection from pool
+ conn = get_http_connection(netloc=netloc, scheme=scheme)
try:
- conn.request(self.method, self.url, headers=self.headers, body=data)
+ conn.request(method = method.upper(), url=self.url, headers=self.headers, body=data)
except:
conn.close()
raise
def main():
#cpool = HTTPConnectionPool('https', 'pithos.okeanos.io/v1', size=8)
+ headers={'X-Auth-Token':'0TpoyAXqJSPxLdDuZHiLOA=='}
c = get_http_connection('pithos.okeanos.io', 'https')
+ c.request(method='get', url='https://pithos.okeanos.io/v1/saxtouri@admin.grnet.gr?format=json',
+ headers=headers)
+ r = c.getresponse()
+ print('HEADERS:'+unicode(r.getheaders()))
+ print('BODY:'+unicode(r.read()))
if __name__ == '__main__':
# or implied, of GRNET S.A.
import requests
-from . import HTTPConnection, HTTPResponse, HTTPConnectionError, HTTPResponsePool
+from . import HTTPConnection, HTTPResponse, HTTPConnectionError
from .pool import ObjectPool
from urlparse import urlparse
class HTTPRequestsResponse(HTTPResponse):
- _get_content_only=False
+ def __init__(self, request=None, prefetched=False):
+ super(HTTPRequestsResponse, self).__init__(request=request, prefetched=prefetched)
+ if prefetched:
+ self = request.response
def _get_response(self):
if self.prefetched:
self.status = r.status
self.status_code = r.status_code
self.content = r.content if hasattr(r, 'content') else None
- self.text = None if self._get_content_only else r.text
- self.json = None if self._get_content_only else r.json
+ from json import loads
+ try:
+ self.json = loads(r.content)#None if self._get_content_only else r.json
+ except ValueError:
+ self.json = None
+ self.text = r.content#None if self._get_content_only else r.text
self.exception = r.exception if hasattr(r, 'exception') else None
except requests.ConnectionError as err:
raise HTTPConnectionError('Connection error', status=651, details=err.message)
if hasattr(self, '_pool'):
self._pool.pool_put(self)
-class HTTPRequestsResponsePool(HTTPResponsePool):
+POOL_SIZE=8
+class HTTPRequestsResponsePool(ObjectPool):
+ def __init__(self, netloc, size=POOL_SIZE):
+ super(ObjectPool, self).__init__(size=size)
+ self.netloc = netloc
+
+ def _pool_cleanup(self, resp):
+ resp._get_response()
+ return True
@classmethod
def key(self, full_url):
respool = self._pools[pool_key]
return respool.pool_get()
- def perform_request(self, method=None, url=None, params=None, headers=None, data=None,
- binary=False):
+ def perform_request(self, method=None, url=None, params=None, headers=None, data=None):
"""perform a request
Example: method='PUT' url='https://my.server:8080/path/to/service'
params={'update':None, 'format':'json'} headers={'X-Auth-Token':'s0m3t0k3n=='}
self._response_object = requests.request(self.method, self.url, headers=self.headers, data=data,
verify=self.verify, prefetch = False)
res.request = self._response_object.request
- if binary:
- res._get_content_only = True
return res
import hashlib, os, gevent.pool
from time import time
+from datetime import datetime
from .storage import StorageClient, ClientError
from .utils import path4url, prefix_keys, filter_in, filter_out, list2str
return self.delete(path, *args, success=success, **kwargs)
def purge_container(self):
- self.container_delete(until=unicode(time()))
+ r = self.container_delete(until=unicode(time()))
+ r.release()
def upload_object_unchunked(self, obj, f, withHashFile = False, size=None, etag=None,
content_encoding=None, content_disposition=None, content_type=None, sharing=None,
from StringIO import StringIO
f = StringIO(data)
data = f.read(size) if size is not None else f.read()
- self.object_put(obj, data=data, etag=etag, content_encoding=content_encoding,
+ r = self.object_put(obj, data=data, etag=etag, content_encoding=content_encoding,
content_disposition=content_disposition, content_type=content_type, permitions=sharing,
public=public, success=201)
+ r.release()
def put_block_async(self, data, hash):
class SilentGreenlet(gevent.Greenlet):
content_disposition=None, content_type=None, sharing=None, public=None):
self.assert_container()
obj_content_type = 'application/octet-stream' if content_type is None else content_type
- self.object_put(obj, content_length=0, etag=etag, content_encoding=content_encoding,
+ r = self.object_put(obj, content_length=0, etag=etag, content_encoding=content_encoding,
content_disposition=content_disposition, content_type=content_type, permitions=sharing,
public=public, manifest='%s/%s'%(self.container,obj))
+ r.release()
def upload_object(self, object, f, size=None, hash_cb=None, upload_cb=None, etag=None,
content_encoding=None, content_disposition=None, content_type=None, sharing=None,
size = size if size is not None else os.fstat(f.fileno()).st_size
nblocks = 1 + (size - 1) // blocksize
hashes = []
- map = {}
+ hmap = {}
offset = 0
bytes = len(block)
hash = pithos_hash(block, blockhash)
hashes.append(hash)
- map[hash] = (offset, bytes)
+ hmap[hash] = (offset, bytes)
offset += bytes
if hash_cb:
hash_gen.next()
if upload_cb:
upload_gen = upload_cb(len(missing))
upload_gen.next()
+ r .release()
flying = []
- r .release()
for hash in missing:
- offset, bytes = map[hash]
+ offset, bytes = hmap[hash]
f.seek(offset)
data = f.read(bytes)
r = self.put_block_async(data, hash)
flying = [r for r in flying if not r.ready()]
gevent.joinall(flying)
- self.object_put(object, format='json', hashmap=True, content_type=obj_content_type,
+ r = self.object_put(object, format='json', hashmap=True, content_type=obj_content_type,
json=hashmap, success=201)
+ r.release()
def download_object(self, obj, f, download_cb=None, version=None, overide=False,
range=None, if_match=None, if_none_match=None, if_modified_since=None,
download_gen.next()
#load local file existing hashmap
+ hash_dict = {}
if islocalfile:
- hash_dict = {}
from os import path
if path.exists(f.name):
from binascii import hexlify
status=600)
#download and save/print
+ flying = []
for i, h in enumerate(map):
#if not islocalfile and h in hash_dict:
if h in hash_dict:
if range is not None and end > custom_end:
end = custom_end
data_range = 'bytes=%s-%s'%(start, end)
- r = self.object_get(obj, data_range=data_range, success=(200, 206), version=version,
- if_etag_match=if_match, if_etag_not_match=if_none_match, binary=True,
- if_modified_since=if_modified_since, if_unmodified_since=if_unmodified_since)
+ result_array = []
if islocalfile:
- f.seek(start)
- f.write(r.content)
- f.flush()
- r.release()
- #f.write(data.text.encode('utf-8'))
-
- if overide and not islocalfile:
+ handler = self._get_block_async(obj, data_range=data_range, version=version,
+ if_etag_match=if_match, if_etag_not_match=if_none_match,
+ if_modified_since=if_modified_since, if_unmodified_since=if_unmodified_since)
+ flying.append({'handler':handler, 'start':start})
+ newflying = []
+ for v in flying:
+ h = v['handler']
+ if h.ready():
+ if h.exception:
+ h.release()
+ raise h.exception
+ f.seek(v['start'])
+ f.write(h.value.content)
+ f.flush()
+ h.value.release()
+ else:
+ newflying.append(v)
+ flying = newflying
+ else:
+ r = self._get_block(obj, data_range=data_range, version=version,
+ if_etag_match=if_match, if_etag_not_match=if_none_match,
+ if_modified_since=if_modified_since, if_unmodified_since=if_unmodified_since)
+ f.write(r.content)
+ f.flush()
+ r.release()
+
+ #write the last results and exit
+ if islocalfile:
+ from time import sleep
+ while len(flying) > 0:
+ result_array=[]
+ newflying = []
+ for v in flying:
+ h = v['handler']
+ if h.ready():
+ if h.exception:
+ h.release()
+ raise h.exception
+ f.seek(v['start'])
+ f.write(h.value.content)
+ f.flush()
+ h.value.release()
+ else:
+ sleep(.2)
+ newflying.append(v)
+ flying = newflying
f.truncate(total_size)
+ def _get_block(self, obj, **kwargs):
+ r = self.object_get(obj, success=(200, 206), binary=True, **kwargs)
+ return r
+
+ def _get_block_async(self, obj, **kwargs):
+ class SilentGreenlet(gevent.Greenlet):
+ def _report_error(self, exc_info):
+ _stderr = sys._stderr
+ try:
+ sys.stderr = StringIO()
+ gevent.Greenlet._report_error(self, exc_info)
+ finally:
+ sys.stderr = _stderr
+ POOL_SIZE = 5
+ if self.async_pool is None:
+ self.async_pool = gevent.pool.Pool(size=POOL_SIZE)
+ g = SilentGreenlet(self._get_block, obj, **kwargs)
+ self.async_pool.start(g)
+ return g
def get_object_hashmap(self, obj, version=None, if_match=None, if_none_match=None,
if_modified_since=None, if_unmodified_since=None):
if_etag_not_match=if_none_match, if_modified_since=if_modified_since,
if_unmodified_since=if_unmodified_since)
except ClientError as err:
+ r.release()
if err.status == 304 or err.status == 412:
return {}
raise
return result
def set_account_group(self, group, usernames):
- self.account_post(update=True, groups = {group:usernames})
+ r = self.account_post(update=True, groups = {group:usernames})
+ r.release()
def del_account_group(self, group):
- return self.account_post(update=True, groups={group:[]})
+ r = self.account_post(update=True, groups={group:[]})
+ r.release()
def get_account_info(self, until=None):
- from datetime import datetime
r = self.account_head(until=until)
if r.status_code == 401:
+ r.release()
raise ClientError("No authorization")
- return r.headers
+ reply = r.headers
+ r.release()
+ return reply
def get_account_quota(self):
return filter_in(self.get_account_info(), 'X-Account-Policy-Quota', exactMatch = True)
def set_account_meta(self, metapairs):
assert(type(metapairs) is dict)
- self.account_post(update=True, metadata=metapairs)
+ r = self.account_post(update=True, metadata=metapairs)
+ r.release()
def del_account_meta(self, metakey):
- self.account_post(update=True, metadata={metakey:''})
+ r = self.account_post(update=True, metadata={metakey:''})
+ r.release()
def set_account_quota(self, quota):
- self.account_post(update=True, quota=quota)
+ r = self.account_post(update=True, quota=quota)
+ r.release()
def set_account_versioning(self, versioning):
- self.account_post(update=True, versioning = versioning)
+ r = self.account_post(update=True, versioning = versioning)
+ r.release()
def list_containers(self):
r = self.account_get()
- return r.json
+ reply = r.json
+ r.release()
+ return reply
def del_container(self, until=None, delimiter=None):
self.assert_container()
r = self.container_delete(until=until, delimiter=delimiter, success=(204, 404, 409))
if r.status_code == 404:
+ r.release()
raise ClientError('Container "%s" does not exist'%self.container, r.status_code)
elif r.status_code == 409:
+ r.release()
raise ClientError('Container "%s" is not empty'%self.container, r.status_code)
+ r.release()
def get_container_versioning(self, container):
self.container = container
def get_container_info(self, until = None):
r = self.container_head(until=until)
+ reply = r.headers
+ r.release()
return r.headers
def get_container_meta(self, until = None):
def set_container_meta(self, metapairs):
assert(type(metapairs) is dict)
- self.container_post(update=True, metadata=metapairs)
+ r = self.container_post(update=True, metadata=metapairs)
+ r.release()
def del_container_meta(self, metakey):
- self.container_post(update=True, metadata={metakey:''})
+ r = self.container_post(update=True, metadata={metakey:''})
+ r.release()
def set_container_quota(self, quota):
- self.container_post(update=True, quota=quota)
+ r = self.container_post(update=True, quota=quota)
+ r.release()
def set_container_versioning(self, versioning):
- self.container_post(update=True, versioning=versioning)
+ r = self.container_post(update=True, versioning=versioning)
+ r.release()
def del_object(self, obj, until=None, delimiter=None):
self.assert_container()
- self.object_delete(obj, until=until, delimiter=delimiter)
+ r = self.object_delete(obj, until=until, delimiter=delimiter)
+ r.release()
def set_object_meta(self, object, metapairs):
assert(type(metapairs) is dict)
- self.object_post(object, update=True, metadata=metapairs)
+ r = self.object_post(object, update=True, metadata=metapairs)
+ r.release()
def del_object_meta(self, metakey, object):
- self.object_post(object, update=True, metadata={metakey:''})
+ r = self.object_post(object, update=True, metadata={metakey:''})
+ r.release()
def publish_object(self, object):
- self.object_post(object, update=True, public=True)
+ r = self.object_post(object, update=True, public=True)
+ r.release()
def unpublish_object(self, object):
- self.object_post(object, update=True, public=False)
+ r = self.object_post(object, update=True, public=False)
+ r.release()
def get_object_info(self, obj, version=None):
r = self.object_head(obj, version=version)
- return r.headers
+ reply = r.headers
+ r.release()
+ return reply
def get_object_meta(self, obj, version=None):
return filter_in(self.get_object_info(obj, version=version), 'X-Object-Meta')
perms = {}
perms['read'] = read_permition if isinstance(read_permition, list) else ''
perms['write'] = write_permition if isinstance(write_permition, list) else ''
- self.object_post(object, update=True, permitions=perms)
+ r = self.object_post(object, update=True, permitions=perms)
+ r.release()
def del_object_sharing(self, object):
self.set_object_sharing(object)
for i in range(nblocks):
block = source_file.read(min(blocksize, filesize - offset))
offset += len(block)
- self.object_post(object, update=True, content_range='bytes */*',
+ r = self.object_post(object, update=True, content_range='bytes */*',
content_type='application/octet-stream', content_length=len(block), data=block)
+ r.release()
if upload_cb is not None:
upload_gen.next()
def truncate_object(self, object, upto_bytes):
- self.object_post(object, update=True, content_range='bytes 0-%s/*'%upto_bytes,
+ r = self.object_post(object, update=True, content_range='bytes 0-%s/*'%upto_bytes,
content_type='application/octet-stream', object_bytes=upto_bytes,
source_object=path4url(self.container, object))
+ r.release()
def overwrite_object(self, object, start, end, source_file, upload_cb=None):
"""Overwrite a part of an object with given source file
for i in range(nblocks):
block = source_file.read(min(blocksize, filesize - offset, datasize - offset))
offset += len(block)
- self.object_post(object, update=True, content_type='application/octet-stream',
+ r = self.object_post(object, update=True, content_type='application/octet-stream',
content_length=len(block), content_range='bytes %s-%s/*'%(start,end), data=block)
+ r.release()
if upload_cb is not None:
upload_gen.next()
self.container = dst_container
dst_object = dst_object or src_object
src_path = path4url(src_container, src_object)
- self.object_put(dst_object, success=201, copy_from=src_path, content_length=0,
+ r = self.object_put(dst_object, success=201, copy_from=src_path, content_length=0,
source_version=source_version, public=public, content_type=content_type,
delimiter=delimiter)
+ r.release()
def move_object(self, src_container, src_object, dst_container, dst_object=False,
source_version = None, public=False, content_type=None, delimiter=None):
self.container = dst_container
dst_object = dst_object or src_object
src_path = path4url(src_container, src_object)
- self.object_put(dst_object, success=201, move_from=src_path, content_length=0,
+ r = self.object_put(dst_object, success=201, move_from=src_path, content_length=0,
source_version=source_version, public=public, content_type=content_type,
delimiter=delimiter)
+ r.release()
from . import Client, ClientError
from .utils import filter_in, filter_out, prefix_keys, path4url
-from .connection.kamakicon import KamakiHTTPConnection
+#from .connection.kamakicon import KamakiHTTPConnection
class StorageClient(Client):
"""OpenStack Object Storage API 1.0 client"""
path = path4url(self.account)
r = self.head(path, success=(204, 401))
if r.status_code == 401:
+ r.release()
raise ClientError("No authorization")
- return r.headers
+ reply = r.headers
+ r.release()
+ return reply
def replace_account_meta(self, metapairs):
self.assert_account()
path = path4url(self.account)
for key, val in metapairs:
self.set_header('X-Account-Meta-'+key, val)
- self.post(path, success=202)
+ r = self.post(path, success=202)
+ r.release()
def del_account_meta(self, metakey):
headers = self.get_account_info()
if len(self.headers) == len(headers):
raise ClientError('X-Account-Meta-%s not found' % metakey, 404)
path = path4url(self.account)
- self.post(path, success = 202)
+ r = self.post(path, success = 202)
+ r.release()
def create_container(self, container):
self.assert_account()
path = path4url(self.account, container)
r = self.put(path, success=(201, 202))
if r.status_code == 202:
+ r.release()
raise ClientError("Container already exists", r.status_code)
+ r.release()
def get_container_info(self, container):
self.assert_account()
path = path4url(self.account, container)
r = self.head(path, success=(204, 404))
if r.status_code == 404:
+ r.release()
raise ClientError("Container does not exist", r.status_code)
- return r.headers
+ reply = r.headers
+ r.release()
+ return reply
def delete_container(self, container):
self.assert_account()
path = path4url(self.account, container)
r = self.delete(path, success=(204, 404, 409))
if r.status_code == 404:
+ r.release()
raise ClientError("Container does not exist", r.status_code)
elif r.status_code == 409:
+ r.release()
raise ClientError("Container is not empty", r.status_code)
+ r.release()
def list_containers(self):
self.assert_account()
self.set_param('format', 'json')
path = path4url(self.account)
r = self.get(path, success = (200, 204))
- return r.json
+ reply = r.json
+ r.release()
+ return reply
def upload_object(self, object, f, size=None):
# This is a naive implementation, it loads the whole file in memory
self.assert_container()
path = path4url(self.account, self.container, object)
data = f.read(size) if size is not None else f.read()
- self.put(path, data=data, success=201)
+ r = self.put(path, data=data, success=201)
+ r.release()
def create_directory(self, object):
self.assert_container()
path = path4url(self.account, self.container, object)
self.set_header('Content-Type', 'application/directory')
self.set_header('Content-length', '0')
- self.put(path, success=201)
+ r = self.put(path, success=201)
+ r.release()
def get_object_info(self, object):
self.assert_container()
path = path4url(self.account, self.container, object)
r = self.head(path, success=200)
- return r.headers
+ reply = r.headers
+ r.release()
+ return reply
def get_object_meta(self, object):
r = filter_in(self.get_object_info(object), 'X-Object-Meta-')
self.assert_container()
self.set_header('X-Object-Meta-'+metakey, '')
path = path4url(self.account, self.container, object)
- self.post(path, success = 202)
+ r = self.post(path, success = 202)
+ r.release()
def replace_object_meta(self, metapairs):
self.assert_container()
path=path4url(self.account, self.container)
for key, val in metapairs:
self.set_header('X-Object-Meta-'+key, val)
- self.post(path, success=202)
+ r = self.post(path, success=202)
+ r.release()
def get_object(self, object):
self.assert_container()
path = path4url(self.account, self.container, object)
r = self.get(path, success=200)
size = int(r.headers['content-length'])
- return r.content, size
+ cnt = r.content
+ r.release()
+ return cnt, size
def copy_object(self, src_container, src_object, dst_container, dst_object=False):
self.assert_account()
dst_path = path4url(self.account, dst_container, dst_object)
self.set_header('X-Copy-From', path4url(src_container, src_object))
self.set_header('Content-Length', 0)
- self.put(dst_path, success=201)
+ r = self.put(dst_path, success=201)
+ r.release()
def move_object(self, src_container, src_object, dst_container, dst_object=False):
self.assert_account()
dst_path = path4url(self.account, dst_container, dst_object)
self.set_header('X-Move-From', path4url(src_container, src_object))
self.set_header('Content-Length', 0)
- self.put(dst_path, success=201)
+ r = self.put(dst_path, success=201)
+ r.release()
def delete_object(self, object):
self.assert_container()
path = path4url(self.account, self.container, object)
r = self.delete(path, success=(204, 404))
if r.status_code == 404:
+ r.release()
raise ClientError("Object %s not found" %object, r.status_code)
+ r.release()
def list_objects(self):
self.assert_container()
self.set_param('format', 'json')
r = self.get(path, success=(200, 204, 304, 404), )
if r.status_code == 404:
+ r.release()
raise ClientError("Incorrect account (%s) for that container"%self.account, r.status_code)
elif r.status_code == 304:
+ r.release()
return []
- return r.json
+ reply = r.json
+ r.release()
+ return reply
def list_objects_in_path(self, path_prefix):
self.assert_container()
self.set_param('path', 'path_prefix')
r = self.get(path, success=(200, 204, 404))
if r.status_code == 404:
+ r.release()
raise ClientError("Incorrect account (%s) for that container"%self.account, r.status_code)
- return r.json
+ reply = r.json
+ r.release()
+ return reply
token = 'C/yBXmz3XjTFBnujc2biAg=='
token = 'ac0yH8cQMEZu3M3Mp1MWGA=='
account = 'admin@adminland.com'
- """
+
url='https://pithos.okeanos.grnet.gr/v1'
token='MI6PT0yrXJ9Ji/x8l9Wmig=='
account='saxtouri@gmail.com'
+ """
+
+ url='https://pithos.okeanos.io/v1'
+ token='0TpoyAXqJSPxLdDuZHiLOA=='
+ account='saxtouri@admin.grnet.gr'
self.fname = None
self.makeNewObject(self.c2, 'test1')
"""Prepare an object to be shared - also its container"""
self.client.container = self.c1
- self.client.object_post('test', update=True, permitions={'read':'someUser'})
+ r = self.client.object_post('test', update=True, permitions={'read':'someUser'})
+ r.release()
self.makeNewObject(self.c1, 'another.test')
def makeNewObject(self, container, obj):
self.client.container = container
- self.client.object_put(obj, content_type='application/octet-stream',
+ r = self.client.object_put(obj, content_type='application/octet-stream',
data= 'file '+obj+' that lives in '+container,
metadata={'incontainer':container})
+ r.release()
def forceDeleteContainer(self, container):
self.client.container = container
r = self.client.list_objects()
for obj in r:
name = obj['name']
- self.client.object_delete(name)
- self.client.container_delete()
+ self.client.del_object(name)
+ r = self.client.container_delete()
self.container = ''
+ r.release()
def tearDown(self):
"""Destroy test cases"""
"""Test account_HEAD"""
r = self.client.account_head()
self.assertEqual(r.status_code, 204)
+ r.release()
r = self.client.account_head(until='1000000000')
self.assertEqual(r.status_code, 204)
+ r.release()
datestring = unicode(r.headers['x-account-until-timestamp'])
self.assertEqual(u'Sun, 09 Sep 2001 01:46:40 GMT', datestring)
for format in self.client.DATE_FORMATS:
now_formated = self.now_unformated.strftime(format)
r1 = self.client.account_head(if_modified_since=now_formated, success=(204, 304, 412))
+ sc1 = r1.status_code
+ r1.release()
r2 = self.client.account_head(if_unmodified_since=now_formated, success=(204, 304, 412))
- self.assertNotEqual(r1.status_code, r2.status_code)
+ sc2 = r2.status_code
+ r2.release()
+ self.assertNotEqual(sc1, sc2)
def test_account_get(self):
"""Test account_GET"""
self.assertEqual(r.status_code, 200)
fullLen = len(r.json)
self.assertTrue(fullLen > 2)
+ r.release()
r = self.client.account_get(limit=1)
self.assertEqual(len(r.json), 1)
+ r.release()
r = self.client.account_get(marker='c2_')
temp_c0 = r.json[0]['name']
temp_c2 = r.json[2]['name']
+ r.release()
r = self.client.account_get(limit=2, marker='c2_')
conames = [container['name'] for container in r.json \
if container['name'].lower().startswith('c2_')]
self.assertTrue(temp_c0 in conames)
self.assertFalse(temp_c2 in conames)
+ r.release()
r = self.client.account_get(show_only_shared=True)
self.assertTrue(self.c1 in [c['name'] for c in r.json])
+ r.release()
r = self.client.account_get(until=1342609206)
self.assertTrue(len(r.json) <= fullLen)
+ r.release()
"""Check if(un)modified_since"""
for format in self.client.DATE_FORMATS:
now_formated = self.now_unformated.strftime(format)
r1 = self.client.account_get(if_modified_since=now_formated, success=(200, 304, 412))
+ sc1 = r1.status_code
+ r1.release()
r2 = self.client.account_get(if_unmodified_since=now_formated, success=(200, 304, 412))
- self.assertNotEqual(r1.status_code, r2.status_code)
+ sc2 = r2.status_code
+ r2.release()
+ self.assertNotEqual(sc1, sc2)
def test_account_post(self):
"""Test account_POST"""
r = self.client.account_post()
self.assertEqual(r.status_code, 202)
grpName = 'grp'+unicode(self.now)
+ r.release()
"""Method set/del_account_meta and set_account_groupcall use account_post internally
"""
r = self.client.container_head()
self.assertEqual(r.status_code, 204)
+ r.release()
"""Check until"""
r = self.client.container_head(until=1000000, success=(204, 404))
self.assertEqual(r.status_code, 404)
+ r.release()
"""Check and if(un)modified_since"""
for format in self.client.DATE_FORMATS:
now_formated = self.now_unformated.strftime(format)
r1 = self.client.container_head(if_modified_since=now_formated, success=(204, 304, 412))
+ sc1=r1.status_code
+ r1.release()
r2 = self.client.container_head(if_unmodified_since=now_formated, success=(204, 304, 412))
- self.assertNotEqual(r1.status_code, r2.status_code)
+ sc2=r2.status_code
+ r2.release()
+ self.assertNotEqual(sc1, sc2)
def test_container_get(self):
"""Test container_GET"""
r = self.client.container_get()
self.assertEqual(r.status_code, 200)
fullLen = len(r.json)
+ r.release()
r = self.client.container_get(prefix='test')
lalobjects = [obj for obj in r.json if obj['name'].startswith('test')]
self.assertTrue(len(r.json) > 1)
self.assertEqual(len(r.json), len(lalobjects))
+ r.release()
r = self.client.container_get(limit=1)
self.assertEqual(len(r.json), 1)
+ r.release()
r = self.client.container_get(marker='another')
self.assertTrue(len(r.json) > 1)
neobjects = [obj for obj in r.json if obj['name'] > 'another']
self.assertEqual(len(r.json), len(neobjects))
+ r.release()
r = self.client.container_get(prefix='another.test', delimiter='.')
self.assertTrue(fullLen > len(r.json))
+ r.release()
r = self.client.container_get(path='/')
self.assertEqual(fullLen, len(r.json))
+ r.release()
r = self.client.container_get(format='xml')
self.assertEqual(r.text.split()[4], 'name="'+self.c1+'">')
+ r.release()
r = self.client.container_get(meta=['incontainer'])
self.assertTrue(len(r.json) > 0)
+ r.release()
r = self.client.container_get(show_only_shared=True)
self.assertTrue(len(r.json) < fullLen)
+ r.release()
try:
r = self.client.container_get(until=1000000000)
datestring = unicode(r.headers['x-account-until-timestamp'])
self.assertEqual(u'Sun, 09 Sep 2001 01:46:40 GMT', datestring)
- except:#Normally, container wasn't created in that date...
+ r.release()
+ except ClientError:
+ r.release()
pass
- """Check and if(un)modified_since"""
+ """Check and if un/modified_since"""
for format in self.client.DATE_FORMATS:
now_formated = self.now_unformated.strftime(format)
r1 = self.client.container_get(if_modified_since=now_formated, success=(200, 304, 412))
+ sc1 = r1.status_code
+ r1.release()
r2 = self.client.container_get(if_unmodified_since=now_formated, success=(200, 304, 412))
- self.assertNotEqual(r1.status_code, r2.status_code)
+ sc2 = r2.status_code
+ r2.release()
+ self.assertNotEqual(sc1, sc2)
def test_container_put(self):
"""Test container_PUT"""
r = self.client.container_put()
self.assertEqual(r.status_code, 202)
+ r.release()
r = self.client.get_container_quota(self.client.container)
cquota = r.values()[0]
r = self.client.container_put(quota=newquota)
self.assertEqual(r.status_code, 202)
+ r.release()
r = self.client.get_container_quota(self.client.container)
xquota = int(r.values()[0])
self.assertEqual(newquota, xquota)
r = self.client.container_put(versioning='auto')
self.assertEqual(r.status_code, 202)
+ r.release()
r = self.client.get_container_versioning(self.client.container)
nvers = r.values()[0]
self.assertEqual('auto', nvers)
r = self.client.container_put(versioning='none')
self.assertEqual(r.status_code, 202)
+ r.release()
r = self.client.get_container_versioning(self.client.container)
nvers = r.values()[0]
self.assertEqual('none', nvers)
r = self.client.container_put(metadata={'m1':'v1', 'm2':'v2'})
self.assertEqual(r.status_code, 202)
+ r.release()
r = self.client.get_container_meta(self.client.container)
self.assertTrue(r.has_key('x-container-meta-m1'))
self.assertEqual(r['x-container-meta-m1'], 'v1')
r = self.client.container_put(metadata={'m1':'', 'm2':'v2a'})
self.assertEqual(r.status_code, 202)
+ r.release()
r = self.client.get_container_meta(self.client.container)
self.assertTrue(not r.has_key('x-container-meta-m1'))
self.assertTrue(r.has_key('x-container-meta-m2'))
"""Simple post"""
r = self.client.container_post()
self.assertEqual(r.status_code, 202)
+ r.release()
"""post meta"""
self.client.set_container_meta({'m1':'v1', 'm2':'v2'})
"""Check update=False"""
r = self.client.object_post('test', update=False, metadata={'newmeta':'newval'})
+ r.release()
r = self.client.get_object_info('test')
self.assertTrue(r.has_key('x-object-meta-newmeta'))
self.assertFalse(r.has_key('x-object-meta-incontainer'))
self.client.container = self.c2
r = self.client.container_delete(success=409)
self.assertEqual(r.status_code, 409)
+ r.release()
"""Fail to delete c3 (empty) container"""
self.client.container = self.c3
r = self.client.container_delete(until='1000000000')
self.assertEqual(r.status_code, 204)
+ r.release()
"""Delete c3 (empty) container"""
r = self.client.container_delete()
self.assertEqual(r.status_code, 204)
+ r.release()
def test_object_head(self):
"""Test object_HEAD"""
r = self.client.object_head(obj)
self.assertEqual(r.status_code, 200)
etag = r.headers['etag']
+ r.release()
r = self.client.object_head(obj, version=40)
self.assertEqual(r.headers['x-object-version'], '40')
+ r.release()
r = self.client.object_head(obj, if_etag_match=etag)
self.assertEqual(r.status_code, 200)
+ r.release()
r = self.client.object_head(obj, if_etag_not_match=etag, success=(200, 412, 304))
self.assertNotEqual(r.status_code, 200)
+ r.release()
r = self.client.object_head(obj, version=40, if_etag_match=etag, success=412)
self.assertEqual(r.status_code, 412)
+ r.release()
"""Check and if(un)modified_since"""
for format in self.client.DATE_FORMATS:
now_formated = self.now_unformated.strftime(format)
- r1 = self.client.object_head(obj, if_modified_since=now_formated, success=(200, 304, 412))
- r2 = self.client.object_head(obj, if_unmodified_since=now_formated, success=(200, 304, 412))
- self.assertNotEqual(r1.status_code, r2.status_code)
+ r1 = self.client.object_head(obj, if_modified_since=now_formated,
+ success=(200, 304, 412))
+ sc1 = r1.status_code
+ r1.release()
+ r2 = self.client.object_head(obj, if_unmodified_since=now_formated,
+ success=(200, 304, 412))
+ sc2 = r2.status_code
+ r2.release()
+ self.assertNotEqual(sc1, sc2)
def test_object_get(self):
"""Test object_GET"""
osize = int(r.headers['content-length'])
etag = r.headers['etag']
+ r.release()
r = self.client.object_get(obj, hashmap=True)
self.assertTrue(r.json.has_key('hashes') \
and r.json.has_key('block_hash') \
and r.json.has_key('block_size') \
and r.json.has_key('bytes'))
+ r.release()
r = self.client.object_get(obj, format='xml', hashmap=True)
self.assertEqual(len(r.text.split('hash>')), 3)
+ r.release()
rangestr = 'bytes=%s-%s'%(osize/3, osize/2)
r = self.client.object_get(obj, data_range=rangestr, success=(200, 206))
partsize = int(r.headers['content-length'])
self.assertTrue(0 < partsize and partsize <= 1+osize/3)
+ r.release()
rangestr = 'bytes=%s-%s'%(osize/3, osize/2)
r = self.client.object_get(obj, data_range=rangestr, if_range=True, success=(200, 206))
partsize = int(r.headers['content-length'])
self.assertTrue(0 < partsize and partsize <= 1+osize/3)
+ r.release()
r = self.client.object_get(obj, if_etag_match=etag)
self.assertEqual(r.status_code, 200)
+ r.release()
r = self.client.object_get(obj, if_etag_not_match=etag+'LALALA')
self.assertEqual(r.status_code, 200)
+ r.release()
"""Check and if(un)modified_since"""
for format in self.client.DATE_FORMATS:
now_formated = self.now_unformated.strftime(format)
- r1 = self.client.object_get(obj, if_modified_since=now_formated, success=(200, 304, 412))
+ r1 = self.client.object_get(obj, if_modified_since=now_formated,
+ success=(200, 304, 412))
+ sc1 = r1.status_code
+ r1.release()
r2 = self.client.object_get(obj, if_unmodified_since=now_formated, success=(200, 304, 412))
- self.assertNotEqual(r1.status_code, r2.status_code)
+ sc2 = r2.status_code
+ r2.release()
+ self.assertNotEqual(sc1, sc2)
def test_object_put(self):
"""Test object_PUT"""
content_disposition='attachment; filename="fname.ext"')
self.assertEqual(r.status_code, 201)
etag = r.headers['etag']
+ r.release()
"""Check content-disposition"""
r = self.client.get_object_info(obj)
"""Check public and if_etag_match"""
r = self.client.object_put(obj, if_etag_match=etag, data='b',
content_type='application/octet-stream', public=True)
+ r.release()
r = self.client.object_get(obj)
self.assertTrue(r.headers.has_key('x-object-public'))
vers2 = int(r.headers['x-object-version'])
etag = r.headers['etag']
self.assertEqual(r.text, 'b')
+ r.release()
"""Check if_etag_not_match"""
r = self.client.object_put(obj, if_etag_not_match=etag, data='c',
content_type='application/octet-stream', success=(201, 412))
self.assertEqual(r.status_code, 412)
+ r.release()
"""Check content_type and content_length"""
tmpdir = 'dir'+unicode(self.now)
r = self.client.object_put(tmpdir, content_type='application/directory',
content_length=0)
+ r.release()
r = self.client.get_object_info(tmpdir)
self.assertEqual(r['content-type'], 'application/directory')
source_account=self.client.account,
content_length=0, success=201)
self.assertEqual(r.status_code, 201)
+ r.release()
"""Check cross-container copy_from, content_encoding"""
self.client.container = self.c1
content_encoding='application/octet-stream',
source_account=self.client.account,
content_length=0, success=201)
+ r.release()
self.assertEqual(r.status_code, 201)
r = self.client.get_object_info(obj)
self.assertEqual(r['etag'], etag)
source_account='nonExistendAddress@NeverLand.com',
content_length=0, success=(201, 403))
self.assertEqual(r.status_code, 403)
+ r.release()
"""Check cross-container move_from"""
r = self.client.object_put(obj+'v0', format=None,
content_encoding='application/octet-stream',
content_length=0, success=201)
self.assertEqual(r.status_code, 201)
+ r.release()
r = self.client.get_object_info(obj+'v0')
self.assertEqual(r['etag'], etag)
source_version = vers2,
content_encoding='application/octet-stream',
content_length=0, success=201)
+ r.release()
"""Check manifest"""
mobj = 'manifest.test'
for i in range(10):
txt += '%s'%i
r = self.client.object_put('%s/%s'%(mobj, i), data='%s'%i,
- content_encoding='application/octet-stream',
- content_length=1, success=201)
- self.client.object_put(mobj, content_length=0,
+ content_encoding='application/octet-stream', content_length=1, success=201)
+ r.release()
+ r = self.client.object_put(mobj, content_length=0, content_type='application/octet-stream',
manifest='%s/%s'%(self.client.container, mobj))
+ r.release()
r = self.client.object_get(mobj)
self.assertEqual(r.text, txt)
+ r.release()
"""Some problems with transfer-encoding?"""
'read':['accX:groupA', 'u1', 'u2'],
'write':['u2', 'u3']},
content_disposition='attachment; filename="fname.ext"')
+ r.release()
r = self.client.object_copy(obj+'orig',
destination = '/'+self.client.container+'/'+obj,
ignore_content_type=False, content_type='application/json',
metadata={'mkey2':'mval2a', 'mkey3':'mval3'},
permitions={'write':['u5', 'accX:groupB']})
self.assertEqual(r.status_code, 201)
+ r.release()
"""Check content-disposition"""
r = self.client.get_object_info(obj)
content_type='application/json', destination_account='nonExistendAddress@NeverLand.com',
success=(201, 403))
self.assertEqual(r.status_code, 403)
+ r.release()
"""Check destination being another container
and also content_type and content encoding"""
content_encoding='utf8', content_type='application/json')
self.assertEqual(r.status_code, 201)
self.assertEqual(r.headers['content-type'], 'application/json; charset=UTF-8')
+ r.release()
"""Check ignore_content_type and content_type"""
r = self.client.object_get(obj)
etag = r.headers['etag']
ctype = r.headers['content-type']
self.assertEqual(ctype, 'application/json')
+ r.release()
r = self.client.object_copy(obj+'orig',
destination = '/'+self.client.container+'/'+obj+'0',
ignore_content_type=True, content_type='application/json')
self.assertEqual(r.status_code, 201)
self.assertNotEqual(r.headers['content-type'], 'application/json')
+ r.release()
"""Check if_etag_(not_)match"""
r = self.client.object_copy(obj,
destination='/'+self.client.container+'/'+obj+'1', if_etag_match=etag)
self.assertEqual(r.status_code, 201)
+ r.release()
r = self.client.object_copy(obj,
destination='/'+self.client.container+'/'+obj+'2', if_etag_not_match='lalala')
self.assertEqual(r.status_code, 201)
vers2 = r.headers['x-object-version']
+ r.release()
"""Check source_version, public and format """
r = self.client.object_copy(obj+'2', destination='/'+self.client.container+'/'+obj+'3', source_version=vers2, format='xml', public=True)
self.assertEqual(r.status_code, 201)
self.assertTrue(r.headers['content-type'].index('xml') > 0)
+ r.release()
r = self.client.get_object_info(obj+'3')
self.assertTrue(r.has_key('x-object-public'))
r = self.client.object_put(obj+'orig', content_type='application/octet-stream',
data= data, metadata={'mkey1':'mval1', 'mkey2':'mval2'},
permitions={'read':['accX:groupA', 'u1', 'u2'], 'write':['u2', 'u3']})
+ r.release()
r = self.client.object_move(obj+'orig', destination = '/'+self.client.container+'/'+obj,
ignore_content_type=False, content_type='application/json',
metadata={'mkey2':'mval2a', 'mkey3':'mval3'},
permitions={'write':['u5', 'accX:groupB']})
self.assertEqual(r.status_code, 201)
+ r.release()
"""Check Metadata"""
r = self.client.get_object_meta(obj)
content_type='application/json', destination_account='nonExistendAddress@NeverLand.com',
success=(201, 403))
self.assertEqual(r.status_code, 403)
+ r.release()
"""Check destination being another container and also
content_type, content_disposition and content encoding"""
content_disposition='attachment; filename="fname.ext"')
self.assertEqual(r.status_code, 201)
self.assertEqual(r.headers['content-type'], 'application/json; charset=UTF-8')
- r = self.client.container=self.c1
+ self.client.container=self.c1
r = self.client.get_object_info(obj)
self.assertTrue(r.has_key('content-disposition') and 'fname.ext' in r['content-disposition'])
etag = r['etag']
ignore_content_type=True, content_type='application/json')
self.assertEqual(r.status_code, 201)
self.assertNotEqual(r.headers['content-type'], 'application/json')
+ r.release()
"""Check if_etag_(not_)match"""
- r = self.client.container=self.c2
+ self.client.container=self.c2
r = self.client.object_move(obj, destination='/'+self.client.container+'/'+obj+'0',
if_etag_match=etag)
self.assertEqual(r.status_code, 201)
+ r.release()
r = self.client.object_move(obj+'0', destination='/'+self.client.container+'/'+obj+'1',
if_etag_not_match='lalala')
self.assertEqual(r.status_code, 201)
+ r.release()
"""Check public and format """
r = self.client.object_move(obj+'1', destination='/'+self.client.container+'/'+obj+'2',
format='xml', public=True)
self.assertEqual(r.status_code, 201)
self.assertTrue(r.headers['content-type'].index('xml') > 0)
+ r.release()
r = self.client.get_object_info(obj+'2')
self.assertTrue(r.has_key('x-object-public'))
r = self.client.object_put(obj, content_type='application/octet-stream',
data= 'H', metadata={'mkey1':'mval1', 'mkey2':'mval2'},
permitions={'read':['accX:groupA', 'u1', 'u2'], 'write':['u2', 'u3']})
+ r.release()
"""Append tests update, content_range, content_type, content_length"""
newf = open(obj, 'r')
self.client.append_object(obj, newf)
r = self.client.object_get(obj)
self.assertTrue(r.text.startswith('Hello!'))
+ r.release()
"""Overwrite tests update, content_type, content_length, content_range"""
newf.seek(0)
r = self.client.object_get(obj)
self.assertTrue(r.text.startswith('ello!'))
newf.close()
+ r.release()
"""Truncate tests update, content_range, content_type,
object_bytes and source_object"""
r = self.client.truncate_object(obj, 5)
r = self.client.object_get(obj)
self.assertEqual(r.text, 'ello!')
+ r.release()
"""Check metadata"""
self.client.set_object_meta(obj, {'mkey2':'mval2a', 'mkey3':'mval3'})
r = self.client.object_post(obj, update=True, public=True,
if_etag_not_match=etag, success=(412,202,204))
self.assertEqual(r.status_code, 412)
- self.client.object_post(obj, update=True, public=True,
+ r.release()
+ r = self.client.object_post(obj, update=True, public=True,
if_etag_match=etag, content_encoding='application/json')
+ r.release()
r = self.client.get_object_info(obj)
helloVersion = r['x-object-version']
self.assertTrue(r.has_key('x-object-public'))
source_account='thisAccountWillNeverExist@adminland.com',
source_version=helloVersion, data='12345', success=(403, 202, 204))
self.assertEqual(r.status_code, 403)
+ r.release()
r = self.client.object_post(obj, update=True, content_type='application/octet-srteam',
content_length=5, content_range='bytes 1-5/*', source_object='/%s/%s'%(self.c2,obj),
source_account=self.client.account, source_version=helloVersion, data='12345',
content_disposition='attachment; filename="fname.ext"')
+ r.release()
r = self.client.object_get(obj)
self.assertEqual(r.text, 'eello!')
self.assertTrue(r.headers.has_key('content-disposition')
and 'fname.ext' in r.headers['content-disposition'])
+ r.release()
"""Check manifest"""
mobj = 'manifest.test'
r = self.client.object_put('%s/%s'%(mobj, i), data='%s'%i,
content_encoding='application/octet-stream',
content_length=1, success=201)
- self.client.object_put(mobj, content_length=0)
+ r.release()
+ r = self.client.object_put(mobj, content_length=0, content_type='application/octet-stream')
+ r.release()
r = self.client.object_post(mobj, manifest='%s/%s'%(self.client.container, mobj))
+ r.release()
r = self.client.object_get(mobj)
self.assertEqual(r.text, txt)
+ r.release()
"""We need to check transfer_encoding """
r = self.client.object_put(obj, content_type='application/octet-stream',
data= 'H', metadata={'mkey1':'mval1', 'mkey2':'mval2'},
permitions={'read':['accX:groupA', 'u1', 'u2'], 'write':['u2', 'u3']})
+ r.release()
"""Check with false until"""
r = self.client.object_delete(obj, until=1000000)
+ r.release()
r = self.client.object_get(obj, success=(200, 404))
self.assertEqual(r.status_code, 200)
+ r.release()
"""Check normal case"""
r = self.client.object_delete(obj)
self.assertEqual(r.status_code, 204)
+ r.release()
r = self.client.object_get(obj, success=(200, 404))
self.assertEqual(r.status_code, 404)
+ r.release()
def create_large_file(self, size, name):
"""Create a large file at fs"""