Copy proxy unit test from OpenStack Swift
This is a copy of the proxy unit test from OpenStack Swift. The file has minor changes to make it compatible with Gluster For Swift. Change-Id: I64a0f8d274461eb2a2c38524c6282e0d3d3d1457 Signed-off-by: Luis Pabon <lpabon@redhat.com> Reviewed-on: http://review.gluster.org/5113 Reviewed-by: Peter Portante <pportant@redhat.com> Tested-by: Peter Portante <pportant@redhat.com>
This commit is contained in:
parent
31a2ef1935
commit
40c313378e
|
@ -30,9 +30,7 @@ from gluster.swift.common import Glusterfs
|
|||
DATADIR = 'containers'
|
||||
|
||||
# Create a dummy db_file in Glusterfs.RUN_DIR
|
||||
_db_file = os.path.join(Glusterfs.RUN_DIR, 'db_file.db')
|
||||
if not os.path.exists(_db_file):
|
||||
file(_db_file, 'w+')
|
||||
_db_file = ""
|
||||
|
||||
|
||||
def _read_metadata(dd):
|
||||
|
@ -224,6 +222,12 @@ class DiskDir(DiskCommon):
|
|||
self.container_info = None
|
||||
self.uid = int(uid)
|
||||
self.gid = int(gid)
|
||||
# Create a dummy db_file in Glusterfs.RUN_DIR
|
||||
global _db_file
|
||||
if not _db_file:
|
||||
_db_file = os.path.join(Glusterfs.RUN_DIR, 'db_file.db')
|
||||
if not os.path.exists(_db_file):
|
||||
file(_db_file, 'w+')
|
||||
self.db_file = _db_file
|
||||
self.dir_exists = os_path.exists(self.datadir)
|
||||
if self.dir_exists:
|
||||
|
@ -468,6 +472,10 @@ class DiskAccount(DiskDir):
|
|||
super(DiskAccount, self).__init__(root, drive, account, None, logger)
|
||||
assert self.dir_exists
|
||||
|
||||
def is_status_deleted(self):
|
||||
"""Only returns true if the status field is set to DELETED."""
|
||||
return False
|
||||
|
||||
def initialize(self, timestamp):
|
||||
"""
|
||||
Create and write metatdata to directory/account.
|
||||
|
|
|
@ -112,6 +112,7 @@ class Gluster_DiskFile(DiskFile):
|
|||
self.keep_cache = False
|
||||
self.uid = int(uid)
|
||||
self.gid = int(gid)
|
||||
self.suppress_file_closing = False
|
||||
|
||||
# Don't store a value for data_file until we know it exists.
|
||||
self.data_file = None
|
||||
|
|
|
@ -21,7 +21,7 @@ import gluster.swift.common.constraints # noqa
|
|||
from swift.proxy import server
|
||||
|
||||
|
||||
def app_factory(global_conf, **local_conf):
|
||||
def app_factory(global_conf, **local_conf): # noqa
|
||||
"""paste.deploy app factory for creating WSGI proxy apps."""
|
||||
conf = global_conf.copy()
|
||||
conf.update(local_conf)
|
||||
|
|
|
@ -1,9 +1,110 @@
|
|||
""" Gluster Swift Unit Tests """
|
||||
""" Swift tests """
|
||||
|
||||
import sys
|
||||
import os
|
||||
import copy
|
||||
import logging
|
||||
import errno
|
||||
from sys import exc_info
|
||||
from contextlib import contextmanager
|
||||
from collections import defaultdict
|
||||
from tempfile import NamedTemporaryFile
|
||||
from eventlet.green import socket
|
||||
from tempfile import mkdtemp
|
||||
from shutil import rmtree
|
||||
from test import get_config
|
||||
from swift.common.utils import TRUE_VALUES
|
||||
from ConfigParser import MissingSectionHeaderError
|
||||
from StringIO import StringIO
|
||||
from swift.common.utils import readconf, config_true_value
|
||||
from logging import Handler
|
||||
from hashlib import md5
|
||||
from eventlet import sleep, spawn, Timeout
|
||||
import logging.handlers
|
||||
|
||||
|
||||
def readuntil2crlfs(fd):
|
||||
rv = ''
|
||||
lc = ''
|
||||
crlfs = 0
|
||||
while crlfs < 2:
|
||||
c = fd.read(1)
|
||||
rv = rv + c
|
||||
if c == '\r' and lc != '\n':
|
||||
crlfs = 0
|
||||
if lc == '\r' and c == '\n':
|
||||
crlfs += 1
|
||||
lc = c
|
||||
return rv
|
||||
|
||||
|
||||
def connect_tcp(hostport):
|
||||
rv = socket.socket()
|
||||
rv.connect(hostport)
|
||||
return rv
|
||||
|
||||
|
||||
@contextmanager
|
||||
def tmpfile(content):
|
||||
with NamedTemporaryFile('w', delete=False) as f:
|
||||
file_name = f.name
|
||||
f.write(str(content))
|
||||
try:
|
||||
yield file_name
|
||||
finally:
|
||||
os.unlink(file_name)
|
||||
|
||||
xattr_data = {}
|
||||
|
||||
|
||||
def _get_inode(fd):
|
||||
if not isinstance(fd, int):
|
||||
try:
|
||||
fd = fd.fileno()
|
||||
except AttributeError:
|
||||
return os.stat(fd).st_ino
|
||||
return os.fstat(fd).st_ino
|
||||
|
||||
|
||||
def _setxattr(fd, k, v):
|
||||
inode = _get_inode(fd)
|
||||
data = xattr_data.get(inode, {})
|
||||
data[k] = v
|
||||
xattr_data[inode] = data
|
||||
|
||||
|
||||
def _getxattr(fd, k):
|
||||
inode = _get_inode(fd)
|
||||
data = xattr_data.get(inode, {}).get(k)
|
||||
if not data:
|
||||
e = IOError("Fake IOError")
|
||||
e.errno = errno.ENODATA
|
||||
raise e
|
||||
return data
|
||||
|
||||
import xattr
|
||||
xattr.setxattr = _setxattr
|
||||
xattr.getxattr = _getxattr
|
||||
|
||||
|
||||
@contextmanager
|
||||
def temptree(files, contents=''):
|
||||
# generate enough contents to fill the files
|
||||
c = len(files)
|
||||
contents = (list(contents) + [''] * c)[:c]
|
||||
tempdir = mkdtemp()
|
||||
for path, content in zip(files, contents):
|
||||
if os.path.isabs(path):
|
||||
path = '.' + path
|
||||
new_path = os.path.join(tempdir, path)
|
||||
subdir = os.path.dirname(new_path)
|
||||
if not os.path.exists(subdir):
|
||||
os.makedirs(subdir)
|
||||
with open(new_path, 'w') as f:
|
||||
f.write(str(content))
|
||||
try:
|
||||
yield tempdir
|
||||
finally:
|
||||
rmtree(tempdir)
|
||||
|
||||
|
||||
class NullLoggingHandler(logging.Handler):
|
||||
|
@ -45,6 +146,17 @@ class FakeLogger(object):
|
|||
update_stats = _store_in('update_stats')
|
||||
set_statsd_prefix = _store_in('set_statsd_prefix')
|
||||
|
||||
def get_increments(self):
|
||||
return [call[0][0] for call in self.log_dict['increment']]
|
||||
|
||||
def get_increment_counts(self):
|
||||
counts = {}
|
||||
for metric in self.get_increments():
|
||||
if metric not in counts:
|
||||
counts[metric] = 0
|
||||
counts[metric] += 1
|
||||
return counts
|
||||
|
||||
def setFormatter(self, obj):
|
||||
self.formatter = obj
|
||||
|
||||
|
@ -91,5 +203,196 @@ def fake_syslog_handler():
|
|||
logging.handlers.SysLogHandler = FakeLogger
|
||||
|
||||
|
||||
if get_config('unit_test').get('fake_syslog', 'False').lower() in TRUE_VALUES:
|
||||
if config_true_value(get_config('unit_test').get('fake_syslog', 'False')):
|
||||
fake_syslog_handler()
|
||||
|
||||
|
||||
class MockTrue(object):
|
||||
"""
|
||||
Instances of MockTrue evaluate like True
|
||||
Any attr accessed on an instance of MockTrue will return a MockTrue
|
||||
instance. Any method called on an instance of MockTrue will return
|
||||
a MockTrue instance.
|
||||
|
||||
>>> thing = MockTrue()
|
||||
>>> thing
|
||||
True
|
||||
>>> thing == True # True == True
|
||||
True
|
||||
>>> thing == False # True == False
|
||||
False
|
||||
>>> thing != True # True != True
|
||||
False
|
||||
>>> thing != False # True != False
|
||||
True
|
||||
>>> thing.attribute
|
||||
True
|
||||
>>> thing.method()
|
||||
True
|
||||
>>> thing.attribute.method()
|
||||
True
|
||||
>>> thing.method().attribute
|
||||
True
|
||||
|
||||
"""
|
||||
|
||||
def __getattribute__(self, *args, **kwargs):
|
||||
return self
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
return self
|
||||
|
||||
def __repr__(*args, **kwargs):
|
||||
return repr(True)
|
||||
|
||||
def __eq__(self, other):
|
||||
return other is True
|
||||
|
||||
def __ne__(self, other):
|
||||
return other is not True
|
||||
|
||||
|
||||
@contextmanager
|
||||
def mock(update):
|
||||
returns = []
|
||||
deletes = []
|
||||
for key, value in update.items():
|
||||
imports = key.split('.')
|
||||
attr = imports.pop(-1)
|
||||
module = __import__(imports[0], fromlist=imports[1:])
|
||||
for modname in imports[1:]:
|
||||
module = getattr(module, modname)
|
||||
if hasattr(module, attr):
|
||||
returns.append((module, attr, getattr(module, attr)))
|
||||
else:
|
||||
deletes.append((module, attr))
|
||||
setattr(module, attr, value)
|
||||
yield True
|
||||
for module, attr, value in returns:
|
||||
setattr(module, attr, value)
|
||||
for module, attr in deletes:
|
||||
delattr(module, attr)
|
||||
|
||||
|
||||
def fake_http_connect(*code_iter, **kwargs):
|
||||
|
||||
class FakeConn(object):
|
||||
|
||||
def __init__(self, status, etag=None, body='', timestamp='1',
|
||||
expect_status=None):
|
||||
self.status = status
|
||||
if expect_status is None:
|
||||
self.expect_status = self.status
|
||||
else:
|
||||
self.expect_status = expect_status
|
||||
self.reason = 'Fake'
|
||||
self.host = '1.2.3.4'
|
||||
self.port = '1234'
|
||||
self.sent = 0
|
||||
self.received = 0
|
||||
self.etag = etag
|
||||
self.body = body
|
||||
self.timestamp = timestamp
|
||||
|
||||
def getresponse(self):
|
||||
if kwargs.get('raise_exc'):
|
||||
raise Exception('test')
|
||||
if kwargs.get('raise_timeout_exc'):
|
||||
raise Timeout()
|
||||
return self
|
||||
|
||||
def getexpect(self):
|
||||
if self.expect_status == -2:
|
||||
raise HTTPException()
|
||||
if self.expect_status == -3:
|
||||
return FakeConn(507)
|
||||
if self.expect_status == -4:
|
||||
return FakeConn(201)
|
||||
return FakeConn(100)
|
||||
|
||||
def getheaders(self):
|
||||
etag = self.etag
|
||||
if not etag:
|
||||
if isinstance(self.body, str):
|
||||
etag = '"' + md5(self.body).hexdigest() + '"'
|
||||
else:
|
||||
etag = '"68b329da9893e34099c7d8ad5cb9c940"'
|
||||
|
||||
headers = {'content-length': len(self.body),
|
||||
'content-type': 'x-application/test',
|
||||
'x-timestamp': self.timestamp,
|
||||
'last-modified': self.timestamp,
|
||||
'x-object-meta-test': 'testing',
|
||||
'etag': etag,
|
||||
'x-works': 'yes',
|
||||
'x-account-container-count': kwargs.get('count', 12345)}
|
||||
if not self.timestamp:
|
||||
del headers['x-timestamp']
|
||||
try:
|
||||
if container_ts_iter.next() is False:
|
||||
headers['x-container-timestamp'] = '1'
|
||||
except StopIteration:
|
||||
pass
|
||||
if 'slow' in kwargs:
|
||||
headers['content-length'] = '4'
|
||||
if 'headers' in kwargs:
|
||||
headers.update(kwargs['headers'])
|
||||
return headers.items()
|
||||
|
||||
def read(self, amt=None):
|
||||
if 'slow' in kwargs:
|
||||
if self.sent < 4:
|
||||
self.sent += 1
|
||||
sleep(0.1)
|
||||
return ' '
|
||||
rv = self.body[:amt]
|
||||
self.body = self.body[amt:]
|
||||
return rv
|
||||
|
||||
def send(self, amt=None):
|
||||
if 'slow' in kwargs:
|
||||
if self.received < 4:
|
||||
self.received += 1
|
||||
sleep(0.1)
|
||||
|
||||
def getheader(self, name, default=None):
|
||||
return dict(self.getheaders()).get(name.lower(), default)
|
||||
|
||||
timestamps_iter = iter(kwargs.get('timestamps') or ['1'] * len(code_iter))
|
||||
etag_iter = iter(kwargs.get('etags') or [None] * len(code_iter))
|
||||
x = kwargs.get('missing_container', [False] * len(code_iter))
|
||||
if not isinstance(x, (tuple, list)):
|
||||
x = [x] * len(code_iter)
|
||||
container_ts_iter = iter(x)
|
||||
code_iter = iter(code_iter)
|
||||
static_body = kwargs.get('body', None)
|
||||
body_iter = kwargs.get('body_iter', None)
|
||||
if body_iter:
|
||||
body_iter = iter(body_iter)
|
||||
|
||||
def connect(*args, **ckwargs):
|
||||
if 'give_content_type' in kwargs:
|
||||
if len(args) >= 7 and 'Content-Type' in args[6]:
|
||||
kwargs['give_content_type'](args[6]['Content-Type'])
|
||||
else:
|
||||
kwargs['give_content_type']('')
|
||||
if 'give_connect' in kwargs:
|
||||
kwargs['give_connect'](*args, **ckwargs)
|
||||
status = code_iter.next()
|
||||
if isinstance(status, tuple):
|
||||
status, expect_status = status
|
||||
else:
|
||||
expect_status = status
|
||||
etag = etag_iter.next()
|
||||
timestamp = timestamps_iter.next()
|
||||
|
||||
if status <= 0:
|
||||
raise HTTPException()
|
||||
if body_iter is None:
|
||||
body = static_body or ''
|
||||
else:
|
||||
body = body_iter.next()
|
||||
return FakeConn(status, etag, body=body, timestamp=timestamp,
|
||||
expect_status=expect_status)
|
||||
|
||||
return connect
|
||||
|
|
|
@ -43,15 +43,17 @@ def setup():
|
|||
if e.errno != errno.EEXIST:
|
||||
raise
|
||||
|
||||
|
||||
import gluster.swift.common.DiskDir as dd
|
||||
|
||||
|
||||
def teardown():
|
||||
dd._db_file = ""
|
||||
shutil.rmtree(gluster.swift.common.Glusterfs.RUN_DIR)
|
||||
gluster.swift.common.Glusterfs.RUN_DIR = _saved_RUN_DIR
|
||||
gluster.swift.common.Glusterfs._do_getsize = _saved_do_getsize
|
||||
|
||||
|
||||
import gluster.swift.common.DiskDir as dd
|
||||
|
||||
|
||||
def timestamp_in_range(ts, base):
|
||||
low = normalize_timestamp(base - 5)
|
||||
high = normalize_timestamp(base + 5)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue