summaryrefslogtreecommitdiffstats
path: root/test/functional/swift_test_client.py
diff options
context:
space:
mode:
Diffstat (limited to 'test/functional/swift_test_client.py')
-rw-r--r--test/functional/swift_test_client.py148
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