diff options
Diffstat (limited to 'test/functional/swift_test_client.py')
-rw-r--r-- | test/functional/swift_test_client.py | 148 |
1 files changed, 104 insertions, 44 deletions
diff --git a/test/functional/swift_test_client.py b/test/functional/swift_test_client.py index 5c0ab87..d98af92 100644 --- a/test/functional/swift_test_client.py +++ b/test/functional/swift_test_client.py @@ -14,19 +14,18 @@ # limitations under the License. import hashlib -import httplib +import json import os import random import socket -import StringIO import time -import urllib -import simplejson as json - -from nose import SkipTest +from unittest2 import SkipTest from xml.dom import minidom +import six +from six.moves import http_client +from six.moves import urllib from swiftclient import get_auth from swift.common import constraints @@ -34,7 +33,7 @@ from swift.common.utils import config_true_value from test import safe_repr -httplib._MAXHEADERS = constraints.MAX_HEADER_COUNT +http_client._MAXHEADERS = constraints.MAX_HEADER_COUNT class AuthenticationFailed(Exception): @@ -71,7 +70,7 @@ class ResponseError(Exception): def listing_empty(method): - for i in xrange(6): + for i in range(6): if len(method()) == 0: return True @@ -166,10 +165,10 @@ class Connection(object): x = storage_url.split('/') if x[0] == 'http:': - self.conn_class = httplib.HTTPConnection + self.conn_class = http_client.HTTPConnection self.storage_port = 80 elif x[0] == 'https:': - self.conn_class = httplib.HTTPSConnection + self.conn_class = http_client.HTTPSConnection self.storage_port = 443 else: raise ValueError('unexpected protocol %s' % (x[0])) @@ -209,7 +208,7 @@ class Connection(object): def http_connect(self): self.connection = self.conn_class(self.storage_host, port=self.storage_port) - #self.connection.set_debuglevel(3) + # self.connection.set_debuglevel(3) def make_path(self, path=None, cfg=None): if path is None: @@ -221,7 +220,7 @@ class Connection(object): return '/' + self.storage_url.split('/')[1] if path: - quote = urllib.quote + quote = urllib.parse.quote if cfg.get('no_quote') or cfg.get('no_path_quote'): quote = lambda x: x return '%s/%s' % (self.storage_url, @@ -237,6 +236,9 @@ class Connection(object): if not cfg.get('no_auth_token'): headers['X-Auth-Token'] = self.storage_token + if cfg.get('use_token'): + headers['X-Auth-Token'] = cfg.get('use_token') + if isinstance(hdrs, dict): headers.update(hdrs) return headers @@ -258,7 +260,7 @@ class Connection(object): path = self.make_path(path, cfg=cfg) headers = self.make_headers(hdrs, cfg=cfg) if isinstance(parms, dict) and parms: - quote = urllib.quote + quote = urllib.parse.quote if cfg.get('no_quote') or cfg.get('no_parms_quote'): quote = lambda x: x query_args = ['%s=%s' % (quote(x), quote(str(y))) @@ -283,7 +285,7 @@ class Connection(object): try: self.response = try_request() - except httplib.HTTPException as e: + except http_client.HTTPException as e: fail_messages.append(safe_repr(e)) continue @@ -326,7 +328,7 @@ class Connection(object): headers.pop('Content-Length', None) if isinstance(parms, dict) and parms: - quote = urllib.quote + quote = urllib.parse.quote if cfg.get('no_quote') or cfg.get('no_parms_quote'): quote = lambda x: x query_args = ['%s=%s' % (quote(x), quote(str(y))) @@ -335,9 +337,9 @@ class Connection(object): self.connection = self.conn_class(self.storage_host, port=self.storage_port) - #self.connection.set_debuglevel(3) + # self.connection.set_debuglevel(3) self.connection.putrequest('PUT', path) - for key, value in headers.iteritems(): + for key, value in headers.items(): self.connection.putheader(key, value) self.connection.endheaders() @@ -423,7 +425,6 @@ class Account(Base): raise RequestError('Invalid format: %s' % format_type) if format_type is None and 'format' in parms: del parms['format'] - status = self.conn.make_request('GET', self.path, hdrs=hdrs, parms=parms, cfg=cfg) if status == 200: @@ -458,6 +459,7 @@ class Account(Base): def delete_containers(self): for c in listing_items(self.containers): cont = self.container(c) + cont.update_metadata(hdrs={'x-versions-location': ''}) if not cont.delete_recursive(): return False @@ -488,6 +490,9 @@ class Account(Base): class Container(Base): + # policy_specified is set in __init__.py when tests are being set up. + policy_specified = None + def __init__(self, conn, account, name): self.conn = conn self.account = str(account) @@ -500,9 +505,23 @@ class Container(Base): parms = {} if cfg is None: cfg = {} + if self.policy_specified and 'X-Storage-Policy' not in hdrs: + hdrs['X-Storage-Policy'] = self.policy_specified return self.conn.make_request('PUT', self.path, hdrs=hdrs, parms=parms, cfg=cfg) in (201, 202) + def update_metadata(self, hdrs=None, cfg=None): + if hdrs is None: + hdrs = {} + if cfg is None: + cfg = {} + + self.conn.make_request('POST', self.path, hdrs=hdrs, cfg=cfg) + if not 200 <= self.conn.response.status <= 299: + raise ResponseError(self.conn.response, 'POST', + self.conn.make_path(self.path)) + return True + def delete(self, hdrs=None, parms=None): if hdrs is None: hdrs = {} @@ -537,7 +556,6 @@ class Container(Base): raise RequestError('Invalid format: %s' % format_type) if format_type is None and 'format' in parms: del parms['format'] - status = self.conn.make_request('GET', self.path, hdrs=hdrs, parms=parms, cfg=cfg) if status == 200: @@ -545,26 +563,38 @@ class Container(Base): files = json.loads(self.conn.response.read()) for file_item in files: - file_item['name'] = file_item['name'].encode('utf-8') - file_item['content_type'] = file_item['content_type'].\ - encode('utf-8') + for key in ('name', 'subdir', 'content_type'): + if key in file_item: + file_item[key] = file_item[key].encode('utf-8') return files elif format_type == 'xml': files = [] tree = minidom.parseString(self.conn.response.read()) - for x in tree.getElementsByTagName('object'): + container = tree.getElementsByTagName('container')[0] + for x in container.childNodes: file_item = {} - for key in ['name', 'hash', 'bytes', 'content_type', - 'last_modified']: - - file_item[key] = x.getElementsByTagName(key)[0].\ - childNodes[0].nodeValue + if x.tagName == 'object': + for key in ['name', 'hash', 'bytes', 'content_type', + 'last_modified']: + file_item[key] = x.getElementsByTagName(key)[0].\ + childNodes[0].nodeValue + elif x.tagName == 'subdir': + file_item['subdir'] = x.getElementsByTagName( + 'name')[0].childNodes[0].nodeValue + else: + raise ValueError('Found unexpected element %s' + % x.tagName) files.append(file_item) for file_item in files: - file_item['name'] = file_item['name'].encode('utf-8') - file_item['content_type'] = file_item['content_type'].\ - encode('utf-8') + if 'subdir' in file_item: + file_item['subdir'] = file_item['subdir'].\ + encode('utf-8') + else: + file_item['name'] = file_item['name'].encode('utf-8') + file_item['content_type'] = file_item['content_type'].\ + encode('utf-8') + file_item['bytes'] = int(file_item['bytes']) return files else: content = self.conn.response.read() @@ -593,7 +623,8 @@ class Container(Base): if self.conn.response.status == 204: required_fields = [['bytes_used', 'x-container-bytes-used'], - ['object_count', 'x-container-object-count']] + ['object_count', 'x-container-object-count'], + ['last_modified', 'last-modified']] optional_fields = [ ['versions', 'x-versions-location'], ['tempurl_key', 'x-container-meta-temp-url-key'], @@ -618,6 +649,7 @@ class File(Base): self.chunked_write_in_progress = False self.content_type = None + self.content_range = None self.size = None self.metadata = {} @@ -633,6 +665,9 @@ class File(Base): else: headers['Content-Length'] = 0 + if cfg.get('use_token'): + headers['X-Auth-Token'] = cfg.get('use_token') + if cfg.get('no_content_type'): pass elif self.content_type: @@ -655,7 +690,7 @@ class File(Base): block_size = 4096 if isinstance(data, str): - data = StringIO.StringIO(data) + data = six.StringIO(data) checksum = hashlib.md5() buff = data.read(block_size) @@ -681,7 +716,7 @@ class File(Base): headers.update(hdrs) if 'Destination' in headers: - headers['Destination'] = urllib.quote(headers['Destination']) + headers['Destination'] = urllib.parse.quote(headers['Destination']) return self.conn.make_request('COPY', self.path, hdrs=headers, parms=parms) == 201 @@ -705,20 +740,20 @@ class File(Base): if 'Destination-Account' in headers: headers['Destination-Account'] = \ - urllib.quote(headers['Destination-Account']) + urllib.parse.quote(headers['Destination-Account']) if 'Destination' in headers: - headers['Destination'] = urllib.quote(headers['Destination']) + headers['Destination'] = urllib.parse.quote(headers['Destination']) return self.conn.make_request('COPY', self.path, hdrs=headers, parms=parms) == 201 - def delete(self, hdrs=None, parms=None): + def delete(self, hdrs=None, parms=None, cfg=None): if hdrs is None: hdrs = {} if parms is None: parms = {} if self.conn.make_request('DELETE', self.path, hdrs=hdrs, - parms=parms) != 204: + cfg=cfg, parms=parms) != 204: raise ResponseError(self.conn.response, 'DELETE', self.conn.make_path(self.path)) @@ -823,6 +858,8 @@ class File(Base): for hdr in self.conn.response.getheaders(): if hdr[0].lower() == 'content-type': self.content_type = hdr[1] + if hdr[0].lower() == 'content-range': + self.content_range = hdr[1] if hasattr(buffer, 'write'): scratch = self.conn.response.read(8192) @@ -861,7 +898,7 @@ class File(Base): finally: fobj.close() - def sync_metadata(self, metadata=None, cfg=None): + def sync_metadata(self, metadata=None, cfg=None, parms=None): if metadata is None: metadata = {} if cfg is None: @@ -877,8 +914,8 @@ class File(Base): cfg.get('set_content_length') else: headers['Content-Length'] = 0 - - self.conn.make_request('POST', self.path, hdrs=headers, cfg=cfg) + self.conn.make_request('POST', self.path, hdrs=headers, + parms=parms, cfg=cfg) if self.conn.response.status not in (201, 202): raise ResponseError(self.conn.response, 'POST', @@ -931,7 +968,7 @@ class File(Base): pass self.size = int(os.fstat(data.fileno())[6]) else: - data = StringIO.StringIO(data) + data = six.StringIO(data) self.size = data.len headers = self.make_headers(cfg=cfg) @@ -983,7 +1020,7 @@ class File(Base): if not self.write(data, hdrs=hdrs, parms=parms, cfg=cfg): raise ResponseError(self.conn.response, 'PUT', self.conn.make_path(self.path)) - self.md5 = self.compute_md5sum(StringIO.StringIO(data)) + self.md5 = self.compute_md5sum(six.StringIO(data)) return data def write_random_return_resp(self, size=None, hdrs=None, parms=None, @@ -1000,5 +1037,28 @@ class File(Base): return_resp=True) if not resp: raise ResponseError(self.conn.response) - self.md5 = self.compute_md5sum(StringIO.StringIO(data)) + self.md5 = self.compute_md5sum(six.StringIO(data)) return resp + + def post(self, hdrs=None, parms=None, cfg=None, return_resp=False): + if hdrs is None: + hdrs = {} + if parms is None: + parms = {} + if cfg is None: + cfg = {} + + headers = self.make_headers(cfg=cfg) + headers.update(hdrs) + + self.conn.make_request('POST', self.path, hdrs=headers, + parms=parms, cfg=cfg) + + if self.conn.response.status not in (201, 202): + raise ResponseError(self.conn.response, 'POST', + self.conn.make_path(self.path)) + + if return_resp: + return self.conn.response + + return True |