summaryrefslogtreecommitdiffstats
path: root/test/unit
diff options
context:
space:
mode:
authorvenkata edara <redara@redhat.com>2017-05-10 13:27:38 +0530
committerPrashanth Pai <ppai@redhat.com>2017-05-11 05:48:27 +0000
commit513988915aa1af13a989d062b021fe1562cbf18d (patch)
tree1c281911e3a9bfa97f8a7285f20691cb77c45c1d /test/unit
parente9c2c5eb55e1012ccce0ce51ac48bed0c0f1d4b7 (diff)
Rebase to Swift 2.10.1 (newton)
Change-Id: I53a962c9a301089c8aed0b43c50f944c30225944 Signed-off-by: venkata edara <redara@redhat.com> Reviewed-on: https://review.gluster.org/16653 Reviewed-by: Prashanth Pai <ppai@redhat.com> Tested-by: Prashanth Pai <ppai@redhat.com>
Diffstat (limited to 'test/unit')
-rw-r--r--test/unit/__init__.py296
-rw-r--r--test/unit/obj/test_diskfile.py2
-rw-r--r--test/unit/obj/test_expirer.py162
-rw-r--r--test/unit/proxy/controllers/test_account.py218
-rw-r--r--test/unit/proxy/controllers/test_base.py741
-rw-r--r--test/unit/proxy/controllers/test_container.py190
-rw-r--r--test/unit/proxy/test_server.py20
7 files changed, 1184 insertions, 445 deletions
diff --git a/test/unit/__init__.py b/test/unit/__init__.py
index 372fb58..ee2a262 100644
--- a/test/unit/__init__.py
+++ b/test/unit/__init__.py
@@ -15,10 +15,12 @@
""" Swift tests """
+from __future__ import print_function
import os
import copy
import logging
import errno
+from six.moves import range
import sys
from contextlib import contextmanager, closing
from collections import defaultdict, Iterable
@@ -30,20 +32,28 @@ import eventlet
from eventlet.green import socket
from tempfile import mkdtemp
from shutil import rmtree
-from swift.common.utils import Timestamp
+import signal
+import json
+
+
+from swift.common.utils import Timestamp, NOTICE
from test import get_config
-from swift.common import swob, utils
+from swift.common import utils
+from swift.common.header_key_dict import HeaderKeyDict
from swift.common.ring import Ring, RingData
from hashlib import md5
import logging.handlers
-from httplib import HTTPException
+
+from six.moves.http_client import HTTPException
from swift.common import storage_policy
-from swift.common.storage_policy import StoragePolicy, ECStoragePolicy
+from swift.common.storage_policy import (StoragePolicy, ECStoragePolicy,
+ VALID_EC_TYPES)
import functools
-import cPickle as pickle
+import six.moves.cPickle as pickle
from gzip import GzipFile
import mock as mocklib
import inspect
+from nose import SkipTest
EMPTY_ETAG = md5().hexdigest()
@@ -53,6 +63,22 @@ if not os.path.basename(sys.argv[0]).startswith('swift'):
utils.HASH_PATH_SUFFIX = 'endcap'
+EC_TYPE_PREFERENCE = [
+ 'liberasurecode_rs_vand',
+ 'jerasure_rs_vand',
+]
+for eclib_name in EC_TYPE_PREFERENCE:
+ if eclib_name in VALID_EC_TYPES:
+ break
+else:
+ raise SystemExit('ERROR: unable to find suitable PyECLib type'
+ ' (none of %r found in %r)' % (
+ EC_TYPE_PREFERENCE,
+ VALID_EC_TYPES,
+ ))
+DEFAULT_TEST_EC_TYPE = eclib_name
+
+
def patch_policies(thing_or_policies=None, legacy_only=False,
with_ec_default=False, fake_ring_args=None):
if isinstance(thing_or_policies, (
@@ -67,7 +93,7 @@ def patch_policies(thing_or_policies=None, legacy_only=False,
elif with_ec_default:
default_policies = [
ECStoragePolicy(0, name='ec', is_default=True,
- ec_type='jerasure_rs_vand', ec_ndata=10,
+ ec_type=DEFAULT_TEST_EC_TYPE, ec_ndata=10,
ec_nparity=4, ec_segment_size=4096),
StoragePolicy(1, name='unu'),
]
@@ -183,13 +209,6 @@ class FakeRing(Ring):
def __init__(self, replicas=3, max_more_nodes=0, part_power=0,
base_port=1000):
- """
- :param part_power: make part calculation based on the path
-
- If you set a part_power when you setup your FakeRing the parts you get
- out of ring methods will actually be based on the path - otherwise we
- exercise the real ring code, but ignore the result and return 1.
- """
self._base_port = base_port
self.max_more_nodes = max_more_nodes
self._part_shift = 32 - part_power
@@ -207,7 +226,8 @@ class FakeRing(Ring):
for x in range(self.replicas):
ip = '10.0.0.%s' % x
port = self._base_port + x
- self._devs.append({
+ # round trip through json to ensure unicode like real rings
+ self._devs.append(json.loads(json.dumps({
'ip': ip,
'replication_ip': ip,
'port': port,
@@ -216,7 +236,7 @@ class FakeRing(Ring):
'zone': x % 3,
'region': x % 2,
'id': x,
- })
+ })))
@property
def replica_count(self):
@@ -226,9 +246,7 @@ class FakeRing(Ring):
return [dict(node, index=i) for i, node in enumerate(list(self._devs))]
def get_more_nodes(self, part):
- # replicas^2 is the true cap
- for x in xrange(self.replicas, min(self.replicas + self.max_more_nodes,
- self.replicas * self.replicas)):
+ for x in range(self.replicas, (self.replicas + self.max_more_nodes)):
yield {'ip': '10.0.0.%s' % x,
'replication_ip': '10.0.0.%s' % x,
'port': self._base_port + x,
@@ -244,9 +262,9 @@ def write_fake_ring(path, *devs):
Pretty much just a two node, two replica, 2 part power ring...
"""
dev1 = {'id': 0, 'zone': 0, 'device': 'sda1', 'ip': '127.0.0.1',
- 'port': 6000}
+ 'port': 6200}
dev2 = {'id': 0, 'zone': 0, 'device': 'sdb1', 'ip': '127.0.0.1',
- 'port': 6000}
+ 'port': 6200}
dev1_updates, dev2_updates = devs or ({}, {})
@@ -266,7 +284,7 @@ class FabricatedRing(Ring):
your tests needs.
"""
- def __init__(self, replicas=6, devices=8, nodes=4, port=6000,
+ def __init__(self, replicas=6, devices=8, nodes=4, port=6200,
part_power=4):
self.devices = devices
self.nodes = nodes
@@ -459,6 +477,12 @@ class UnmockTimeModule(object):
logging.time = UnmockTimeModule()
+class WARN_DEPRECATED(Exception):
+ def __init__(self, msg):
+ self.msg = msg
+ print(self.msg)
+
+
class FakeLogger(logging.Logger, object):
# a thread safe fake logger
@@ -478,8 +502,21 @@ class FakeLogger(logging.Logger, object):
logging.INFO: 'info',
logging.DEBUG: 'debug',
logging.CRITICAL: 'critical',
+ NOTICE: 'notice',
}
+ def warn(self, *args, **kwargs):
+ raise WARN_DEPRECATED("Deprecated Method warn use warning instead")
+
+ def notice(self, msg, *args, **kwargs):
+ """
+ Convenience function for syslog priority LOG_NOTICE. The python
+ logging lvl is set to 25, just above info. SysLogHandler is
+ monkey patched to map this log lvl to the LOG_NOTICE syslog
+ priority.
+ """
+ self.log(NOTICE, msg, *args, **kwargs)
+
def _log(self, level, msg, *args, **kwargs):
store_name = self.store_in[level]
cargs = [msg]
@@ -495,7 +532,9 @@ class FakeLogger(logging.Logger, object):
def _clear(self):
self.log_dict = defaultdict(list)
self.lines_dict = {'critical': [], 'error': [], 'info': [],
- 'warning': [], 'debug': []}
+ 'warning': [], 'debug': [], 'notice': []}
+
+ clear = _clear # this is a public interface
def get_lines_for_level(self, level):
if level not in self.lines_dict:
@@ -560,8 +599,8 @@ class FakeLogger(logging.Logger, object):
try:
line = record.getMessage()
except TypeError:
- print 'WARNING: unable to format log message %r %% %r' % (
- record.msg, record.args)
+ print('WARNING: unable to format log message %r %% %r' % (
+ record.msg, record.args))
raise
self.lines_dict[record.levelname.lower()].append(line)
@@ -575,17 +614,24 @@ class FakeLogger(logging.Logger, object):
pass
+class DebugSwiftLogFormatter(utils.SwiftLogFormatter):
+
+ def format(self, record):
+ msg = super(DebugSwiftLogFormatter, self).format(record)
+ return msg.replace('#012', '\n')
+
+
class DebugLogger(FakeLogger):
"""A simple stdout logging version of FakeLogger"""
def __init__(self, *args, **kwargs):
FakeLogger.__init__(self, *args, **kwargs)
- self.formatter = logging.Formatter(
+ self.formatter = DebugSwiftLogFormatter(
"%(server)s %(levelname)s: %(message)s")
def handle(self, record):
self._handle(record)
- print self.formatter.format(record)
+ print(self.formatter.format(record))
class DebugLogAdapter(utils.LogAdapter):
@@ -704,6 +750,74 @@ def mock(update):
delattr(module, attr)
+class FakeStatus(object):
+ """
+ This will work with our fake_http_connect, if you hand in one of these
+ instead of a status int or status int tuple to the "codes" iter you can
+ add some eventlet sleep to the expect and response stages of the
+ connection.
+ """
+
+ def __init__(self, status, expect_sleep=None, response_sleep=None):
+ """
+ :param status: the response status int, or a tuple of
+ ([expect_status, ...], response_status)
+ :param expect_sleep: float, time to eventlet sleep during expect, can
+ be a iter of floats
+ :param response_sleep: float, time to eventlet sleep during response
+ """
+ # connect exception
+ if isinstance(status, (Exception, eventlet.Timeout)):
+ raise status
+ if isinstance(status, tuple):
+ self.expect_status = list(status[:-1])
+ self.status = status[-1]
+ self.explicit_expect_list = True
+ else:
+ self.expect_status, self.status = ([], status)
+ self.explicit_expect_list = False
+ if not self.expect_status:
+ # when a swift backend service returns a status before reading
+ # from the body (mostly an error response) eventlet.wsgi will
+ # respond with that status line immediately instead of 100
+ # Continue, even if the client sent the Expect 100 header.
+ # BufferedHttp and the proxy both see these error statuses
+ # when they call getexpect, so our FakeConn tries to act like
+ # our backend services and return certain types of responses
+ # as expect statuses just like a real backend server would do.
+ if self.status in (507, 412, 409):
+ self.expect_status = [status]
+ else:
+ self.expect_status = [100, 100]
+
+ # setup sleep attributes
+ if not isinstance(expect_sleep, (list, tuple)):
+ expect_sleep = [expect_sleep] * len(self.expect_status)
+ self.expect_sleep_list = list(expect_sleep)
+ while len(self.expect_sleep_list) < len(self.expect_status):
+ self.expect_sleep_list.append(None)
+ self.response_sleep = response_sleep
+
+ def get_response_status(self):
+ if self.response_sleep is not None:
+ eventlet.sleep(self.response_sleep)
+ if self.expect_status and self.explicit_expect_list:
+ raise Exception('Test did not consume all fake '
+ 'expect status: %r' % (self.expect_status,))
+ if isinstance(self.status, (Exception, eventlet.Timeout)):
+ raise self.status
+ return self.status
+
+ def get_expect_status(self):
+ expect_sleep = self.expect_sleep_list.pop(0)
+ if expect_sleep is not None:
+ eventlet.sleep(expect_sleep)
+ expect_status = self.expect_status.pop(0)
+ if isinstance(expect_status, (Exception, eventlet.Timeout)):
+ raise expect_status
+ return expect_status
+
+
class SlowBody(object):
"""
This will work with our fake_http_connect, if you hand in these
@@ -740,30 +854,10 @@ def fake_http_connect(*code_iter, **kwargs):
def __init__(self, status, etag=None, body='', timestamp='1',
headers=None, expect_headers=None, connection_id=None,
- give_send=None):
- # connect exception
- if isinstance(status, (Exception, eventlet.Timeout)):
- raise status
- if isinstance(status, tuple):
- self.expect_status = list(status[:-1])
- self.status = status[-1]
- self.explicit_expect_list = True
- else:
- self.expect_status, self.status = ([], status)
- self.explicit_expect_list = False
- if not self.expect_status:
- # when a swift backend service returns a status before reading
- # from the body (mostly an error response) eventlet.wsgi will
- # respond with that status line immediately instead of 100
- # Continue, even if the client sent the Expect 100 header.
- # BufferedHttp and the proxy both see these error statuses
- # when they call getexpect, so our FakeConn tries to act like
- # our backend services and return certain types of responses
- # as expect statuses just like a real backend server would do.
- if self.status in (507, 412, 409):
- self.expect_status = [status]
- else:
- self.expect_status = [100, 100]
+ give_send=None, give_expect=None):
+ if not isinstance(status, FakeStatus):
+ status = FakeStatus(status)
+ self._status = status
self.reason = 'Fake'
self.host = '1.2.3.4'
self.port = '1234'
@@ -776,6 +870,8 @@ def fake_http_connect(*code_iter, **kwargs):
self.timestamp = timestamp
self.connection_id = connection_id
self.give_send = give_send
+ self.give_expect = give_expect
+ self.closed = False
if 'slow' in kwargs and isinstance(kwargs['slow'], list):
try:
self._next_sleep = kwargs['slow'].pop(0)
@@ -785,11 +881,6 @@ def fake_http_connect(*code_iter, **kwargs):
eventlet.sleep()
def getresponse(self):
- if self.expect_status and self.explicit_expect_list:
- raise Exception('Test did not consume all fake '
- 'expect status: %r' % (self.expect_status,))
- if isinstance(self.status, (Exception, eventlet.Timeout)):
- raise self.status
exc = kwargs.get('raise_exc')
if exc:
if isinstance(exc, (Exception, eventlet.Timeout)):
@@ -797,16 +888,21 @@ def fake_http_connect(*code_iter, **kwargs):
raise Exception('test')
if kwargs.get('raise_timeout_exc'):
raise eventlet.Timeout()
+ self.status = self._status.get_response_status()
return self
def getexpect(self):
- expect_status = self.expect_status.pop(0)
- if isinstance(self.expect_status, (Exception, eventlet.Timeout)):
- raise self.expect_status
+ if self.give_expect:
+ self.give_expect(self)
+ expect_status = self._status.get_expect_status()
headers = dict(self.expect_headers)
if expect_status == 409:
headers['X-Backend-Timestamp'] = self.timestamp
- return FakeConn(expect_status, headers=headers)
+ response = FakeConn(expect_status,
+ timestamp=self.timestamp,
+ headers=headers)
+ response.status = expect_status
+ return response
def getheaders(self):
etag = self.etag
@@ -816,7 +912,7 @@ def fake_http_connect(*code_iter, **kwargs):
else:
etag = '"68b329da9893e34099c7d8ad5cb9c940"'
- headers = swob.HeaderKeyDict({
+ headers = HeaderKeyDict({
'content-length': len(self.body),
'content-type': 'x-application/test',
'x-timestamp': self.timestamp,
@@ -834,7 +930,7 @@ def fake_http_connect(*code_iter, **kwargs):
# when timestamp is None, HeaderKeyDict raises KeyError
headers.pop('x-timestamp', None)
try:
- if container_ts_iter.next() is False:
+ if next(container_ts_iter) is False:
headers['x-container-timestamp'] = '1'
except StopIteration:
pass
@@ -865,9 +961,9 @@ def fake_http_connect(*code_iter, **kwargs):
self.body = self.body[amt:]
return rv
- def send(self, amt=None):
+ def send(self, data=None):
if self.give_send:
- self.give_send(self.connection_id, amt)
+ self.give_send(self, data)
am_slow, value = self.get_slow()
if am_slow:
if self.received < 4:
@@ -875,10 +971,10 @@ def fake_http_connect(*code_iter, **kwargs):
eventlet.sleep(value)
def getheader(self, name, default=None):
- return swob.HeaderKeyDict(self.getheaders()).get(name, default)
+ return HeaderKeyDict(self.getheaders()).get(name, default)
def close(self):
- pass
+ self.closed = True
timestamps_iter = iter(kwargs.get('timestamps') or ['1'] * len(code_iter))
etag_iter = iter(kwargs.get('etags') or [None] * len(code_iter))
@@ -911,27 +1007,28 @@ def fake_http_connect(*code_iter, **kwargs):
kwargs['give_content_type'](args[6]['Content-Type'])
else:
kwargs['give_content_type']('')
- i, status = conn_id_and_code_iter.next()
+ i, status = next(conn_id_and_code_iter)
if 'give_connect' in kwargs:
give_conn_fn = kwargs['give_connect']
argspec = inspect.getargspec(give_conn_fn)
if argspec.keywords or 'connection_id' in argspec.args:
ckwargs['connection_id'] = i
give_conn_fn(*args, **ckwargs)
- etag = etag_iter.next()
- headers = headers_iter.next()
- expect_headers = expect_headers_iter.next()
- timestamp = timestamps_iter.next()
+ etag = next(etag_iter)
+ headers = next(headers_iter)
+ expect_headers = next(expect_headers_iter)
+ timestamp = next(timestamps_iter)
if status <= 0:
raise HTTPException()
if body_iter is None:
body = static_body or ''
else:
- body = body_iter.next()
+ body = next(body_iter)
return FakeConn(status, etag, body=body, timestamp=timestamp,
headers=headers, expect_headers=expect_headers,
- connection_id=i, give_send=kwargs.get('give_send'))
+ connection_id=i, give_send=kwargs.get('give_send'),
+ give_expect=kwargs.get('give_expect'))
connect.code_iter = code_iter
@@ -966,3 +1063,58 @@ def mocked_http_conn(*args, **kwargs):
def make_timestamp_iter():
return iter(Timestamp(t) for t in itertools.count(int(time.time())))
+
+
+class Timeout(object):
+ def __init__(self, seconds):
+ self.seconds = seconds
+
+ def __enter__(self):
+ signal.signal(signal.SIGALRM, self._exit)
+ signal.alarm(self.seconds)
+
+ def __exit__(self, type, value, traceback):
+ signal.alarm(0)
+
+ def _exit(self, signum, frame):
+ class TimeoutException(Exception):
+ pass
+ raise TimeoutException
+
+
+def requires_o_tmpfile_support(func):
+ @functools.wraps(func)
+ def wrapper(*args, **kwargs):
+ if not utils.o_tmpfile_supported():
+ raise SkipTest('Requires O_TMPFILE support')
+ return func(*args, **kwargs)
+ return wrapper
+
+
+def encode_frag_archive_bodies(policy, body):
+ """
+ Given a stub body produce a list of complete frag_archive bodies as
+ strings in frag_index order.
+
+ :param policy: a StoragePolicy instance, with policy_type EC_POLICY
+ :param body: a string, the body to encode into frag archives
+
+ :returns: list of strings, the complete frag_archive bodies for the given
+ plaintext
+ """
+ segment_size = policy.ec_segment_size
+ # split up the body into buffers
+ chunks = [body[x:x + segment_size]
+ for x in range(0, len(body), segment_size)]
+ # encode the buffers into fragment payloads
+ fragment_payloads = []
+ for chunk in chunks:
+ fragments = policy.pyeclib_driver.encode(chunk)
+ if not fragments:
+ break
+ fragment_payloads.append(fragments)
+
+ # join up the fragment payloads per node
+ ec_archive_bodies = [''.join(frags)
+ for frags in zip(*fragment_payloads)]
+ return ec_archive_bodies
diff --git a/test/unit/obj/test_diskfile.py b/test/unit/obj/test_diskfile.py
index 9701f44..2aed737 100644
--- a/test/unit/obj/test_diskfile.py
+++ b/test/unit/obj/test_diskfile.py
@@ -31,7 +31,7 @@ from gluster.swift.common.exceptions import AlreadyExistsAsDir, \
AlreadyExistsAsFile
from swift.common.exceptions import DiskFileNoSpace, DiskFileNotOpen, \
DiskFileNotExist, DiskFileExpired
-from swift.common.utils import ThreadPool
+from gluster.swift.common.utils import ThreadPool
import gluster.swift.common.utils
from gluster.swift.common.utils import normalize_timestamp
diff --git a/test/unit/obj/test_expirer.py b/test/unit/obj/test_expirer.py
index 9701027..4830a90 100644
--- a/test/unit/obj/test_expirer.py
+++ b/test/unit/obj/test_expirer.py
@@ -13,7 +13,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import urllib
from time import time
from unittest import main, TestCase
from test.unit import FakeRing, mocked_http_conn, debug_logger
@@ -22,8 +21,10 @@ from tempfile import mkdtemp
from shutil import rmtree
import mock
+import six
+from six.moves import urllib
-from swift.common import internal_client, utils
+from swift.common import internal_client, utils, swob
from swift.obj import expirer
@@ -54,7 +55,7 @@ class TestObjectExpirer(TestCase):
self.rcache = mkdtemp()
self.conf = {'recon_cache_path': self.rcache}
- self.logger = debug_logger('test-recon')
+ self.logger = debug_logger('test-expirer')
def tearDown(self):
rmtree(self.rcache)
@@ -88,10 +89,16 @@ class TestObjectExpirer(TestCase):
}
# from config
x = expirer.ObjectExpirer(vals)
- self.assertRaises(ValueError, x.get_process_values, {})
+ expected_msg = 'process must be an integer greater' \
+ ' than or equal to 0'
+ with self.assertRaises(ValueError) as ctx:
+ x.get_process_values({})
+ self.assertEqual(str(ctx.exception), expected_msg)
# from kwargs
x = expirer.ObjectExpirer({})
- self.assertRaises(ValueError, x.get_process_values, vals)
+ with self.assertRaises(ValueError) as ctx:
+ x.get_process_values(vals)
+ self.assertEqual(str(ctx.exception), expected_msg)
def test_get_process_values_negative_processes(self):
vals = {
@@ -100,10 +107,16 @@ class TestObjectExpirer(TestCase):
}
# from config
x = expirer.ObjectExpirer(vals)
- self.assertRaises(ValueError, x.get_process_values, {})
+ expected_msg = 'processes must be an integer greater' \
+ ' than or equal to 0'
+ with self.assertRaises(ValueError) as ctx:
+ x.get_process_values({})
+ self.assertEqual(str(ctx.exception), expected_msg)
# from kwargs
x = expirer.ObjectExpirer({})
- self.assertRaises(ValueError, x.get_process_values, vals)
+ with self.assertRaises(ValueError) as ctx:
+ x.get_process_values(vals)
+ self.assertEqual(str(ctx.exception), expected_msg)
def test_get_process_values_process_greater_than_processes(self):
vals = {
@@ -112,10 +125,32 @@ class TestObjectExpirer(TestCase):
}
# from config
x = expirer.ObjectExpirer(vals)
- self.assertRaises(ValueError, x.get_process_values, {})
+ expected_msg = 'process must be less than processes'
+ with self.assertRaises(ValueError) as ctx:
+ x.get_process_values({})
+ self.assertEqual(str(ctx.exception), expected_msg)
# from kwargs
x = expirer.ObjectExpirer({})
- self.assertRaises(ValueError, x.get_process_values, vals)
+ with self.assertRaises(ValueError) as ctx:
+ x.get_process_values(vals)
+ self.assertEqual(str(ctx.exception), expected_msg)
+
+ def test_get_process_values_process_equal_to_processes(self):
+ vals = {
+ 'processes': 5,
+ 'process': 5,
+ }
+ # from config
+ x = expirer.ObjectExpirer(vals)
+ expected_msg = 'process must be less than processes'
+ with self.assertRaises(ValueError) as ctx:
+ x.get_process_values({})
+ self.assertEqual(str(ctx.exception), expected_msg)
+ # from kwargs
+ x = expirer.ObjectExpirer({})
+ with self.assertRaises(ValueError) as ctx:
+ x.get_process_values(vals)
+ self.assertEqual(str(ctx.exception), expected_msg)
def test_init_concurrency_too_small(self):
conf = {
@@ -153,10 +188,11 @@ class TestObjectExpirer(TestCase):
sum([len(self.containers[x]) for x in self.containers])
def iter_containers(self, *a, **kw):
- return [{'name': unicode(x)} for x in self.containers.keys()]
+ return [{'name': six.text_type(x)}
+ for x in self.containers.keys()]
def iter_objects(self, account, container):
- return [{'name': unicode(x)}
+ return [{'name': six.text_type(x)}
for x in self.containers[container]]
def delete_container(*a, **kw):
@@ -172,7 +208,7 @@ class TestObjectExpirer(TestCase):
x.swift = InternalClient(containers)
deleted_objects = {}
- for i in xrange(3):
+ for i in range(3):
x.process = i
x.run_once()
self.assertNotEqual(deleted_objects, x.deleted_objects)
@@ -183,52 +219,55 @@ class TestObjectExpirer(TestCase):
self.assertEqual(len(set(x.obj_containers_in_order[:4])), 4)
def test_delete_object(self):
- class InternalClient(object):
-
- container_ring = None
-
- def __init__(self, test, account, container, obj):
- self.test = test
- self.account = account
- self.container = container
- self.obj = obj
- self.delete_object_called = False
-
- class DeleteActualObject(object):
- def __init__(self, test, actual_obj, timestamp):
- self.test = test
- self.actual_obj = actual_obj
- self.timestamp = timestamp
- self.called = False
-
- def __call__(self, actual_obj, timestamp):
- self.test.assertEqual(self.actual_obj, actual_obj)
- self.test.assertEqual(self.timestamp, timestamp)
- self.called = True
-
+ x = expirer.ObjectExpirer({}, logger=self.logger)
+ actual_obj = 'actual_obj'
+ timestamp = int(time())
+ reclaim_ts = timestamp - x.reclaim_age
container = 'container'
obj = 'obj'
- actual_obj = 'actual_obj'
- timestamp = 'timestamp'
-
- x = expirer.ObjectExpirer({}, logger=self.logger)
- x.swift = \
- InternalClient(self, x.expiring_objects_account, container, obj)
- x.delete_actual_object = \
- DeleteActualObject(self, actual_obj, timestamp)
- delete_object_called = []
-
- def pop_queue(c, o):
- self.assertEqual(container, c)
- self.assertEqual(obj, o)
- delete_object_called[:] = [True]
-
- x.pop_queue = pop_queue
-
- x.delete_object(actual_obj, timestamp, container, obj)
- self.assertTrue(delete_object_called)
- self.assertTrue(x.delete_actual_object.called)
+ http_exc = {
+ resp_code:
+ internal_client.UnexpectedResponse(
+ str(resp_code), swob.HTTPException(status=resp_code))
+ for resp_code in {404, 412, 500}
+ }
+ exc_other = Exception()
+
+ def check_call_to_delete_object(exc, ts, should_pop):
+ x.logger.clear()
+ start_reports = x.report_objects
+ with mock.patch.object(x, 'delete_actual_object',
+ side_effect=exc) as delete_actual:
+ with mock.patch.object(x, 'pop_queue') as pop_queue:
+ x.delete_object(actual_obj, ts, container, obj)
+
+ delete_actual.assert_called_once_with(actual_obj, ts)
+ log_lines = x.logger.get_lines_for_level('error')
+ if should_pop:
+ pop_queue.assert_called_once_with(container, obj)
+ self.assertEqual(start_reports + 1, x.report_objects)
+ self.assertFalse(log_lines)
+ else:
+ self.assertFalse(pop_queue.called)
+ self.assertEqual(start_reports, x.report_objects)
+ self.assertEqual(1, len(log_lines))
+ self.assertIn('Exception while deleting object container obj',
+ log_lines[0])
+
+ # verify pop_queue logic on exceptions
+ for exc, ts, should_pop in [(None, timestamp, True),
+ (http_exc[404], timestamp, False),
+ (http_exc[412], timestamp, False),
+ (http_exc[500], reclaim_ts, False),
+ (exc_other, reclaim_ts, False),
+ (http_exc[404], reclaim_ts, True),
+ (http_exc[412], reclaim_ts, True)]:
+
+ try:
+ check_call_to_delete_object(exc, ts, should_pop)
+ except AssertionError as err:
+ self.fail("Failed on %r at %f: %s" % (exc, ts, err))
def test_report(self):
x = expirer.ObjectExpirer({}, logger=self.logger)
@@ -525,7 +564,7 @@ class TestObjectExpirer(TestCase):
got_unicode = [False]
def delete_actual_object_test_for_unicode(actual_obj, timestamp):
- if isinstance(actual_obj, unicode):
+ if isinstance(actual_obj, six.text_type):
got_unicode[0] = True
fake_swift = InternalClient(
@@ -673,6 +712,8 @@ class TestObjectExpirer(TestCase):
ts = '1234'
x.delete_actual_object('/path/to/object', ts)
self.assertEqual(got_env[0]['HTTP_X_IF_DELETE_AT'], ts)
+ self.assertEqual(got_env[0]['HTTP_X_TIMESTAMP'],
+ got_env[0]['HTTP_X_IF_DELETE_AT'])
def test_delete_actual_object_nourlquoting(self):
# delete_actual_object should not do its own url quoting because
@@ -690,6 +731,8 @@ class TestObjectExpirer(TestCase):
ts = '1234'
x.delete_actual_object('/path/to/object name', ts)
self.assertEqual(got_env[0]['HTTP_X_IF_DELETE_AT'], ts)
+ self.assertEqual(got_env[0]['HTTP_X_TIMESTAMP'],
+ got_env[0]['HTTP_X_IF_DELETE_AT'])
self.assertEqual(got_env[0]['PATH_INFO'], '/v1/path/to/object name')
def test_delete_actual_object_raises_404(self):
@@ -704,7 +747,7 @@ class TestObjectExpirer(TestCase):
self.assertRaises(internal_client.UnexpectedResponse,
x.delete_actual_object, '/path/to/object', '1234')
- def test_delete_actual_object_handles_412(self):
+ def test_delete_actual_object_raises_412(self):
def fake_app(env, start_response):
start_response('412 Precondition Failed',
@@ -714,7 +757,8 @@ class TestObjectExpirer(TestCase):
internal_client.loadapp = lambda *a, **kw: fake_app
x = expirer.ObjectExpirer({})
- x.delete_actual_object('/path/to/object', '1234')
+ self.assertRaises(internal_client.UnexpectedResponse,
+ x.delete_actual_object, '/path/to/object', '1234')
def test_delete_actual_object_does_not_handle_odd_stuff(self):
@@ -744,7 +788,7 @@ class TestObjectExpirer(TestCase):
x.delete_actual_object(name, timestamp)
self.assertEqual(x.swift.make_request.call_count, 1)
self.assertEqual(x.swift.make_request.call_args[0][1],
- '/v1/' + urllib.quote(name))
+ '/v1/' + urllib.parse.quote(name))
def test_pop_queue(self):
class InternalClient(object):
diff --git a/test/unit/proxy/controllers/test_account.py b/test/unit/proxy/controllers/test_account.py
index 23ad0a1..a46dcc9 100644
--- a/test/unit/proxy/controllers/test_account.py
+++ b/test/unit/proxy/controllers/test_account.py
@@ -25,6 +25,7 @@ from test.unit import fake_http_connect, FakeRing, FakeMemcache
from swift.common.storage_policy import StoragePolicy
from swift.common.request_helpers import get_sys_meta_prefix
import swift.proxy.controllers.base
+from swift.proxy.controllers.base import get_account_info
from test.unit import patch_policies
@@ -36,6 +37,31 @@ class TestAccountController(unittest.TestCase):
None, FakeMemcache(),
account_ring=FakeRing(), container_ring=FakeRing())
+ def _make_callback_func(self, context):
+ def callback(ipaddr, port, device, partition, method, path,
+ headers=None, query_string=None, ssl=False):
+ context['method'] = method
+ context['path'] = path
+ context['headers'] = headers or {}
+ return callback
+
+ def _assert_responses(self, method, test_cases):
+ if method in ('PUT', 'DELETE'):
+ self.app.allow_account_management = True
+ controller = proxy_server.AccountController(self.app, 'AUTH_bob')
+
+ for responses, expected in test_cases:
+ with mock.patch(
+ 'swift.proxy.controllers.base.http_connect',
+ fake_http_connect(*responses)):
+ req = Request.blank('/v1/AUTH_bob')
+ resp = getattr(controller, method)(req)
+
+ self.assertEqual(expected,
+ resp.status_int,
+ 'Expected %s but got %s. Failed case: %s' %
+ (expected, resp.status_int, str(responses)))
+
def test_account_info_in_response_env(self):
controller = proxy_server.AccountController(self.app, 'AUTH_bob')
with mock.patch('swift.proxy.controllers.base.http_connect',
@@ -43,9 +69,10 @@ class TestAccountController(unittest.TestCase):
req = Request.blank('/v1/AUTH_bob', {'PATH_INFO': '/v1/AUTH_bob'})
resp = controller.HEAD(req)
self.assertEqual(2, resp.status_int // 100)
- self.assertTrue('swift.account/AUTH_bob' in resp.environ)
- self.assertEqual(headers_to_account_info(resp.headers),
- resp.environ['swift.account/AUTH_bob'])
+ self.assertIn('account/AUTH_bob', resp.environ['swift.infocache'])
+ self.assertEqual(
+ headers_to_account_info(resp.headers),
+ resp.environ['swift.infocache']['account/AUTH_bob'])
def test_swift_owner(self):
owner_headers = {
@@ -57,17 +84,17 @@ class TestAccountController(unittest.TestCase):
with mock.patch('swift.proxy.controllers.base.http_connect',
fake_http_connect(200, headers=owner_headers)):
resp = controller.HEAD(req)
- self.assertEquals(2, resp.status_int // 100)
+ self.assertEqual(2, resp.status_int // 100)
for key in owner_headers:
- self.assertTrue(key not in resp.headers)
+ self.assertNotIn(key, resp.headers)
req = Request.blank('/v1/a', environ={'swift_owner': True})
with mock.patch('swift.proxy.controllers.base.http_connect',
fake_http_connect(200, headers=owner_headers)):
resp = controller.HEAD(req)
- self.assertEquals(2, resp.status_int // 100)
+ self.assertEqual(2, resp.status_int // 100)
for key in owner_headers:
- self.assertTrue(key in resp.headers)
+ self.assertIn(key, resp.headers)
def test_get_deleted_account(self):
resp_headers = {
@@ -79,7 +106,7 @@ class TestAccountController(unittest.TestCase):
with mock.patch('swift.proxy.controllers.base.http_connect',
fake_http_connect(404, headers=resp_headers)):
resp = controller.HEAD(req)
- self.assertEquals(410, resp.status_int)
+ self.assertEqual(410, resp.status_int)
def test_long_acct_names(self):
long_acct_name = '%sLongAccountName' % (
@@ -90,25 +117,17 @@ class TestAccountController(unittest.TestCase):
with mock.patch('swift.proxy.controllers.base.http_connect',
fake_http_connect(200)):
resp = controller.HEAD(req)
- self.assertEquals(400, resp.status_int)
+ self.assertEqual(400, resp.status_int)
with mock.patch('swift.proxy.controllers.base.http_connect',
fake_http_connect(200)):
resp = controller.GET(req)
- self.assertEquals(400, resp.status_int)
+ self.assertEqual(400, resp.status_int)
with mock.patch('swift.proxy.controllers.base.http_connect',
fake_http_connect(200)):
resp = controller.POST(req)
- self.assertEquals(400, resp.status_int)
-
- def _make_callback_func(self, context):
- def callback(ipaddr, port, device, partition, method, path,
- headers=None, query_string=None, ssl=False):
- context['method'] = method
- context['path'] = path
- context['headers'] = headers or {}
- return callback
+ self.assertEqual(400, resp.status_int)
def test_sys_meta_headers_PUT(self):
# check that headers in sys meta namespace make it through
@@ -129,9 +148,9 @@ class TestAccountController(unittest.TestCase):
fake_http_connect(200, 200, give_connect=callback)):
controller.PUT(req)
self.assertEqual(context['method'], 'PUT')
- self.assertTrue(sys_meta_key in context['headers'])
+ self.assertIn(sys_meta_key, context['headers'])
self.assertEqual(context['headers'][sys_meta_key], 'foo')
- self.assertTrue(user_meta_key in context['headers'])
+ self.assertIn(user_meta_key, context['headers'])
self.assertEqual(context['headers'][user_meta_key], 'bar')
self.assertNotEqual(context['headers']['x-timestamp'], '1.0')
@@ -152,9 +171,9 @@ class TestAccountController(unittest.TestCase):
fake_http_connect(200, 200, give_connect=callback)):
controller.POST(req)
self.assertEqual(context['method'], 'POST')
- self.assertTrue(sys_meta_key in context['headers'])
+ self.assertIn(sys_meta_key, context['headers'])
self.assertEqual(context['headers'][sys_meta_key], 'foo')
- self.assertTrue(user_meta_key in context['headers'])
+ self.assertIn(user_meta_key, context['headers'])
self.assertEqual(context['headers'][user_meta_key], 'bar')
self.assertNotEqual(context['headers']['x-timestamp'], '1.0')
@@ -193,7 +212,7 @@ class TestAccountController(unittest.TestCase):
self.assertEqual(resp.headers.get(header), value)
else:
# blank ACLs should result in no header
- self.assert_(header not in resp.headers)
+ self.assertNotIn(header, resp.headers)
def test_add_acls_impossible_cases(self):
# For test coverage: verify that defensive coding does defend, in cases
@@ -208,19 +227,25 @@ class TestAccountController(unittest.TestCase):
self.assertEqual(1, len(resp.headers)) # we always get Content-Type
self.assertEqual(2, len(resp.environ))
- def test_memcache_key_impossible_cases(self):
+ def test_cache_key_impossible_cases(self):
# For test coverage: verify that defensive coding does defend, in cases
# that shouldn't arise naturally
- self.assertRaises(
- ValueError,
- lambda: swift.proxy.controllers.base.get_container_memcache_key(
- '/a', None))
+ with self.assertRaises(ValueError):
+ # Container needs account
+ swift.proxy.controllers.base.get_cache_key(None, 'c')
+
+ with self.assertRaises(ValueError):
+ # Object needs account
+ swift.proxy.controllers.base.get_cache_key(None, 'c', 'o')
+
+ with self.assertRaises(ValueError):
+ # Object needs container
+ swift.proxy.controllers.base.get_cache_key('a', None, 'o')
def test_stripping_swift_admin_headers(self):
# Verify that a GET/HEAD which receives privileged headers from the
# account server will strip those headers for non-swift_owners
- hdrs_ext, hdrs_int = self._make_user_and_sys_acl_headers_data()
headers = {
'x-account-meta-harmless': 'hi mom',
'x-account-meta-temp-url-key': 's3kr1t',
@@ -243,6 +268,139 @@ class TestAccountController(unittest.TestCase):
'x-account-meta-temp-url-key' in resp.headers)
self.assertEqual(privileged_header_present, env['swift_owner'])
+ def test_response_code_for_PUT(self):
+ PUT_TEST_CASES = [
+ ((201, 201, 201), 201),
+ ((201, 201, 404), 201),
+ ((201, 201, 503), 201),
+ ((201, 404, 404), 404),
+ ((201, 404, 503), 503),
+ ((201, 503, 503), 503),
+ ((404, 404, 404), 404),
+ ((404, 404, 503), 404),
+ ((404, 503, 503), 503),
+ ((503, 503, 503), 503)
+ ]
+ self._assert_responses('PUT', PUT_TEST_CASES)
+
+ def test_response_code_for_DELETE(self):
+ DELETE_TEST_CASES = [
+ ((204, 204, 204), 204),
+ ((204, 204, 404), 204),
+ ((204, 204, 503), 204),
+ ((204, 404, 404), 404),
+ ((204, 404, 503), 503),
+ ((204, 503, 503), 503),
+ ((404, 404, 404), 404),
+ ((404, 404, 503), 404),
+ ((404, 503, 503), 503),
+ ((503, 503, 503), 503)
+ ]
+ self._assert_responses('DELETE', DELETE_TEST_CASES)
+
+ def test_response_code_for_POST(self):
+ POST_TEST_CASES = [
+ ((204, 204, 204), 204),
+ ((204, 204, 404), 204),
+ ((204, 204, 503), 204),
+ ((204, 404, 404), 404),
+ ((204, 404, 503), 503),
+ ((204, 503, 503), 503),
+ ((404, 404, 404), 404),
+ ((404, 404, 503), 404),
+ ((404, 503, 503), 503),
+ ((503, 503, 503), 503)
+ ]
+ self._assert_responses('POST', POST_TEST_CASES)
+
+
+@patch_policies(
+ [StoragePolicy(0, 'zero', True, object_ring=FakeRing(replicas=4))])
+class TestAccountController4Replicas(TestAccountController):
+ def setUp(self):
+ self.app = proxy_server.Application(
+ None,
+ FakeMemcache(),
+ account_ring=FakeRing(replicas=4),
+ container_ring=FakeRing(replicas=4))
+
+ def test_response_code_for_PUT(self):
+ PUT_TEST_CASES = [
+ ((201, 201, 201, 201), 201),
+ ((201, 201, 201, 404), 201),
+ ((201, 201, 201, 503), 201),
+ ((201, 201, 404, 404), 201),
+ ((201, 201, 404, 503), 201),
+ ((201, 201, 503, 503), 201),
+ ((201, 404, 404, 404), 404),
+ ((201, 404, 404, 503), 404),
+ ((201, 404, 503, 503), 503),
+ ((201, 503, 503, 503), 503),
+ ((404, 404, 404, 404), 404),
+ ((404, 404, 404, 503), 404),
+ ((404, 404, 503, 503), 404),
+ ((404, 503, 503, 503), 503),
+ ((503, 503, 503, 503), 503)
+ ]
+ self._assert_responses('PUT', PUT_TEST_CASES)
+
+ def test_response_code_for_DELETE(self):
+ DELETE_TEST_CASES = [
+ ((204, 204, 204, 204), 204),
+ ((204, 204, 204, 404), 204),
+ ((204, 204, 204, 503), 204),
+ ((204, 204, 404, 404), 204),
+ ((204, 204, 404, 503), 204),
+ ((204, 204, 503, 503), 204),
+ ((204, 404, 404, 404), 404),
+ ((204, 404, 404, 503), 404),
+ ((204, 404, 503, 503), 503),
+ ((204, 503, 503, 503), 503),
+ ((404, 404, 404, 404), 404),
+ ((404, 404, 404, 503), 404),
+ ((404, 404, 503, 503), 404),
+ ((404, 503, 503, 503), 503),
+ ((503, 503, 503, 503), 503)
+ ]
+ self._assert_responses('DELETE', DELETE_TEST_CASES)
+
+ def test_response_code_for_POST(self):
+ POST_TEST_CASES = [
+ ((204, 204, 204, 204), 204),
+ ((204, 204, 204, 404), 204),
+ ((204, 204, 204, 503), 204),
+ ((204, 204, 404, 404), 204),
+ ((204, 204, 404, 503), 204),
+ ((204, 204, 503, 503), 204),
+ ((204, 404, 404, 404), 404),
+ ((204, 404, 404, 503), 404),
+ ((204, 404, 503, 503), 503),
+ ((204, 503, 503, 503), 503),
+ ((404, 404, 404, 404), 404),
+ ((404, 404, 404, 503), 404),
+ ((404, 404, 503, 503), 404),
+ ((404, 503, 503, 503), 503),
+ ((503, 503, 503, 503), 503)
+ ]
+ self._assert_responses('POST', POST_TEST_CASES)
+
+
+@patch_policies([StoragePolicy(0, 'zero', True, object_ring=FakeRing())])
+class TestGetAccountInfo(unittest.TestCase):
+ def setUp(self):
+ self.app = proxy_server.Application(
+ None, FakeMemcache(),
+ account_ring=FakeRing(), container_ring=FakeRing())
+
+ def test_get_deleted_account_410(self):
+ resp_headers = {'x-account-status': 'deleted'}
+
+ req = Request.blank('/v1/a')
+ with mock.patch('swift.proxy.controllers.base.http_connect',
+ fake_http_connect(404, headers=resp_headers)):
+ info = get_account_info(req.environ, self.app)
+ self.assertEqual(410, info.get('status'))
+
if __name__ == '__main__':
unittest.main()
diff --git a/test/unit/proxy/controllers/test_base.py b/test/unit/proxy/controllers/test_base.py
index 037e28b..1ab0037 100644
--- a/test/unit/proxy/controllers/test_base.py
+++ b/test/unit/proxy/controllers/test_base.py
@@ -16,22 +16,22 @@
import itertools
from collections import defaultdict
import unittest
-from mock import patch
+import mock
from swift.proxy.controllers.base import headers_to_container_info, \
headers_to_account_info, headers_to_object_info, get_container_info, \
- get_container_memcache_key, get_account_info, get_account_memcache_key, \
- get_object_env_key, get_info, get_object_info, \
- Controller, GetOrHeadHandler, _set_info_cache, _set_object_info_cache, \
- bytes_to_skip
-from swift.common.swob import Request, HTTPException, HeaderKeyDict, \
- RESPONSE_REASONS
+ get_cache_key, get_account_info, get_info, get_object_info, \
+ Controller, GetOrHeadHandler, bytes_to_skip
+from swift.common.swob import Request, HTTPException, RESPONSE_REASONS
from swift.common import exceptions
from swift.common.utils import split_path
+from swift.common.header_key_dict import HeaderKeyDict
from swift.common.http import is_success
from swift.common.storage_policy import StoragePolicy
from test.unit import fake_http_connect, FakeRing, FakeMemcache
from swift.proxy import server as proxy_server
-from swift.common.request_helpers import get_sys_meta_prefix
+from swift.common.request_helpers import (
+ get_sys_meta_prefix, get_object_transient_sysmeta
+)
from test.unit import patch_policies
@@ -95,7 +95,7 @@ class DynamicResponseFactory(object):
def _get_response(self, type_):
self.stats[type_] += 1
class_ = self.response_type[type_]
- return class_(self.statuses.next())
+ return class_(next(self.statuses))
def get_response(self, environ):
(version, account, container, obj) = split_path(
@@ -112,6 +112,31 @@ class DynamicResponseFactory(object):
return resp
+class ZeroCacheAccountResponse(FakeResponse):
+ base_headers = {
+ 'X-Backend-Recheck-Account-Existence': '0',
+ 'x-account-container-count': 333,
+ 'x-account-object-count': 1000,
+ 'x-account-bytes-used': 6666,
+ }
+
+
+class ZeroCacheContainerResponse(FakeResponse):
+ base_headers = {
+ 'X-Backend-Recheck-Container-Existence': '0',
+ 'x-container-object-count': 1000,
+ 'x-container-bytes-used': 6666,
+ }
+
+
+class ZeroCacheDynamicResponseFactory(DynamicResponseFactory):
+ response_type = {
+ 'obj': ObjectResponse,
+ 'container': ZeroCacheContainerResponse,
+ 'account': ZeroCacheAccountResponse,
+ }
+
+
class FakeApp(object):
recheck_container_existence = 30
@@ -120,23 +145,14 @@ class FakeApp(object):
def __init__(self, response_factory=None, statuses=None):
self.responses = response_factory or \
DynamicResponseFactory(*statuses or [])
- self.sources = []
+ self.captured_envs = []
def __call__(self, environ, start_response):
- self.sources.append(environ.get('swift.source'))
+ self.captured_envs.append(environ)
response = self.responses.get_response(environ)
reason = RESPONSE_REASONS[response.status_int][0]
start_response('%d %s' % (response.status_int, reason),
[(k, v) for k, v in response.headers.items()])
- # It's a bit strnage, but the get_info cache stuff relies on the
- # app setting some keys in the environment as it makes requests
- # (in particular GETorHEAD_base) - so our fake does the same
- _set_info_cache(self, environ, response.account,
- response.container, response)
- if response.obj:
- _set_object_info_cache(self, environ, response.account,
- response.container, response.obj,
- response)
return iter(response.body)
@@ -158,40 +174,80 @@ class TestFuncs(unittest.TestCase):
account_ring=FakeRing(),
container_ring=FakeRing())
- def test_GETorHEAD_base(self):
- base = Controller(self.app)
- req = Request.blank('/v1/a/c/o/with/slashes')
- ring = FakeRing()
- nodes = list(ring.get_part_nodes(0)) + list(ring.get_more_nodes(0))
- with patch('swift.proxy.controllers.base.'
- 'http_connect', fake_http_connect(200)):
- resp = base.GETorHEAD_base(req, 'object', iter(nodes), 'part',
- '/a/c/o/with/slashes')
- self.assertTrue('swift.object/a/c/o/with/slashes' in resp.environ)
- self.assertEqual(
- resp.environ['swift.object/a/c/o/with/slashes']['status'], 200)
- req = Request.blank('/v1/a/c/o')
- with patch('swift.proxy.controllers.base.'
- 'http_connect', fake_http_connect(200)):
- resp = base.GETorHEAD_base(req, 'object', iter(nodes), 'part',
- '/a/c/o')
- self.assertTrue('swift.object/a/c/o' in resp.environ)
- self.assertEqual(resp.environ['swift.object/a/c/o']['status'], 200)
- req = Request.blank('/v1/a/c')
- with patch('swift.proxy.controllers.base.'
- 'http_connect', fake_http_connect(200)):
- resp = base.GETorHEAD_base(req, 'container', iter(nodes), 'part',
- '/a/c')
- self.assertTrue('swift.container/a/c' in resp.environ)
- self.assertEqual(resp.environ['swift.container/a/c']['status'], 200)
-
- req = Request.blank('/v1/a')
- with patch('swift.proxy.controllers.base.'
- 'http_connect', fake_http_connect(200)):
- resp = base.GETorHEAD_base(req, 'account', iter(nodes), 'part',
- '/a')
- self.assertTrue('swift.account/a' in resp.environ)
- self.assertEqual(resp.environ['swift.account/a']['status'], 200)
+ def test_get_info_zero_recheck(self):
+ mock_cache = mock.Mock()
+ mock_cache.get.return_value = None
+ app = FakeApp(ZeroCacheDynamicResponseFactory())
+ env = {'swift.cache': mock_cache}
+ info_a = get_info(app, env, 'a')
+ # Check that you got proper info
+ self.assertEqual(info_a['status'], 200)
+ self.assertEqual(info_a['bytes'], 6666)
+ self.assertEqual(info_a['total_object_count'], 1000)
+ self.assertEqual(info_a['container_count'], 333)
+ # Make sure the env cache is set
+ exp_cached_info_a = {
+ k: str(v) if k in (
+ 'bytes', 'container_count', 'total_object_count') else v
+ for k, v in info_a.items()}
+ self.assertEqual(env['swift.infocache'].get('account/a'),
+ exp_cached_info_a)
+ # Make sure the app was called
+ self.assertEqual(app.responses.stats['account'], 1)
+ self.assertEqual(app.responses.stats['container'], 0)
+ # Make sure memcache was called
+ self.assertEqual(mock_cache.mock_calls, [
+ mock.call.get('account/a'),
+ mock.call.set('account/a', exp_cached_info_a, time=0),
+ ])
+
+ mock_cache.reset_mock()
+ info_c = get_info(app, env, 'a', 'c')
+ # Check that you got proper info
+ self.assertEqual(info_c['status'], 200)
+ self.assertEqual(info_c['bytes'], 6666)
+ self.assertEqual(info_c['object_count'], 1000)
+ # Make sure the env cache is set
+ exp_cached_info_c = {
+ k: str(v) if k in ('bytes', 'object_count') else v
+ for k, v in info_c.items()}
+ self.assertEqual(env['swift.infocache'].get('account/a'),
+ exp_cached_info_a)
+ self.assertEqual(env['swift.infocache'].get('container/a/c'),
+ exp_cached_info_c)
+ # Check app call for container, but no new calls for account
+ self.assertEqual(app.responses.stats['account'], 1)
+ self.assertEqual(app.responses.stats['container'], 1)
+ # Make sure container info was cached
+ self.assertEqual(mock_cache.mock_calls, [
+ mock.call.get('container/a/c'),
+ mock.call.set('container/a/c', exp_cached_info_c, time=0),
+ ])
+
+ # reset call counts
+ app = FakeApp(ZeroCacheDynamicResponseFactory())
+ env = {'swift.cache': mock_cache}
+ mock_cache.reset_mock()
+ info_c = get_info(app, env, 'a', 'c')
+ # Check that you got proper info
+ self.assertEqual(info_c['status'], 200)
+ self.assertEqual(info_c['bytes'], 6666)
+ self.assertEqual(info_c['object_count'], 1000)
+ # Make sure the env cache is set
+ self.assertEqual(env['swift.infocache'].get('account/a'),
+ exp_cached_info_a)
+ self.assertEqual(env['swift.infocache'].get('container/a/c'),
+ exp_cached_info_c)
+ # check app calls both account and container
+ self.assertEqual(app.responses.stats['account'], 1)
+ self.assertEqual(app.responses.stats['container'], 1)
+ # Make sure account info was cached but container was not
+ self.assertEqual(mock_cache.mock_calls, [
+ mock.call.get('container/a/c'),
+ mock.call.get('account/a'),
+ mock.call.set('account/a', exp_cached_info_a, time=0),
+ mock.call.set('container/a/c', exp_cached_info_c, time=0),
+ ])
def test_get_info(self):
app = FakeApp()
@@ -199,196 +255,177 @@ class TestFuncs(unittest.TestCase):
env = {}
info_a = get_info(app, env, 'a')
# Check that you got proper info
- self.assertEquals(info_a['status'], 200)
- self.assertEquals(info_a['bytes'], 6666)
- self.assertEquals(info_a['total_object_count'], 1000)
- # Make sure the env cache is set
- self.assertEquals(env.get('swift.account/a'), info_a)
+ self.assertEqual(info_a['status'], 200)
+ self.assertEqual(info_a['bytes'], 6666)
+ self.assertEqual(info_a['total_object_count'], 1000)
+
# Make sure the app was called
self.assertEqual(app.responses.stats['account'], 1)
+ # Make sure the return value matches get_account_info
+ account_info = get_account_info({'PATH_INFO': '/v1/a'}, app)
+ self.assertEqual(info_a, account_info)
+
# Do an env cached call to account
+ app.responses.stats['account'] = 0
+ app.responses.stats['container'] = 0
+
info_a = get_info(app, env, 'a')
# Check that you got proper info
- self.assertEquals(info_a['status'], 200)
- self.assertEquals(info_a['bytes'], 6666)
- self.assertEquals(info_a['total_object_count'], 1000)
- # Make sure the env cache is set
- self.assertEquals(env.get('swift.account/a'), info_a)
+ self.assertEqual(info_a['status'], 200)
+ self.assertEqual(info_a['bytes'], 6666)
+ self.assertEqual(info_a['total_object_count'], 1000)
+
# Make sure the app was NOT called AGAIN
- self.assertEqual(app.responses.stats['account'], 1)
+ self.assertEqual(app.responses.stats['account'], 0)
# This time do env cached call to account and non cached to container
+ app.responses.stats['account'] = 0
+ app.responses.stats['container'] = 0
+
info_c = get_info(app, env, 'a', 'c')
# Check that you got proper info
- self.assertEquals(info_c['status'], 200)
- self.assertEquals(info_c['bytes'], 6666)
- self.assertEquals(info_c['object_count'], 1000)
- # Make sure the env cache is set
- self.assertEquals(env.get('swift.account/a'), info_a)
- self.assertEquals(env.get('swift.container/a/c'), info_c)
- # Make sure the app was called for container
+ self.assertEqual(info_c['status'], 200)
+ self.assertEqual(info_c['bytes'], 6666)
+ self.assertEqual(info_c['object_count'], 1000)
+ # Make sure the app was called for container but not account
+ self.assertEqual(app.responses.stats['account'], 0)
self.assertEqual(app.responses.stats['container'], 1)
- # This time do a non cached call to account than non cached to
+ # This time do a non-cached call to account then non-cached to
# container
+ app.responses.stats['account'] = 0
+ app.responses.stats['container'] = 0
app = FakeApp()
env = {} # abandon previous call to env
info_c = get_info(app, env, 'a', 'c')
# Check that you got proper info
- self.assertEquals(info_c['status'], 200)
- self.assertEquals(info_c['bytes'], 6666)
- self.assertEquals(info_c['object_count'], 1000)
- # Make sure the env cache is set
- self.assertEquals(env.get('swift.account/a'), info_a)
- self.assertEquals(env.get('swift.container/a/c'), info_c)
+ self.assertEqual(info_c['status'], 200)
+ self.assertEqual(info_c['bytes'], 6666)
+ self.assertEqual(info_c['object_count'], 1000)
# check app calls both account and container
self.assertEqual(app.responses.stats['account'], 1)
self.assertEqual(app.responses.stats['container'], 1)
- # This time do an env cached call to container while account is not
+ # This time do an env-cached call to container while account is not
# cached
- del(env['swift.account/a'])
+ app.responses.stats['account'] = 0
+ app.responses.stats['container'] = 0
info_c = get_info(app, env, 'a', 'c')
# Check that you got proper info
- self.assertEquals(info_a['status'], 200)
- self.assertEquals(info_c['bytes'], 6666)
- self.assertEquals(info_c['object_count'], 1000)
- # Make sure the env cache is set and account still not cached
- self.assertEquals(env.get('swift.container/a/c'), info_c)
- # no additional calls were made
- self.assertEqual(app.responses.stats['account'], 1)
- self.assertEqual(app.responses.stats['container'], 1)
-
- # Do a non cached call to account not found with ret_not_found
- app = FakeApp(statuses=(404,))
- env = {}
- info_a = get_info(app, env, 'a', ret_not_found=True)
- # Check that you got proper info
- self.assertEquals(info_a['status'], 404)
- self.assertEquals(info_a['bytes'], None)
- self.assertEquals(info_a['total_object_count'], None)
- # Make sure the env cache is set
- self.assertEquals(env.get('swift.account/a'), info_a)
- # and account was called
- self.assertEqual(app.responses.stats['account'], 1)
+ self.assertEqual(info_a['status'], 200)
+ self.assertEqual(info_c['bytes'], 6666)
+ self.assertEqual(info_c['object_count'], 1000)
- # Do a cached call to account not found with ret_not_found
- info_a = get_info(app, env, 'a', ret_not_found=True)
- # Check that you got proper info
- self.assertEquals(info_a['status'], 404)
- self.assertEquals(info_a['bytes'], None)
- self.assertEquals(info_a['total_object_count'], None)
- # Make sure the env cache is set
- self.assertEquals(env.get('swift.account/a'), info_a)
- # add account was NOT called AGAIN
- self.assertEqual(app.responses.stats['account'], 1)
-
- # Do a non cached call to account not found without ret_not_found
- app = FakeApp(statuses=(404,))
- env = {}
- info_a = get_info(app, env, 'a')
- # Check that you got proper info
- self.assertEquals(info_a, None)
- self.assertEquals(env['swift.account/a']['status'], 404)
- # and account was called
- self.assertEqual(app.responses.stats['account'], 1)
-
- # Do a cached call to account not found without ret_not_found
- info_a = get_info(None, env, 'a')
- # Check that you got proper info
- self.assertEquals(info_a, None)
- self.assertEquals(env['swift.account/a']['status'], 404)
- # add account was NOT called AGAIN
- self.assertEqual(app.responses.stats['account'], 1)
+ # no additional calls were made
+ self.assertEqual(app.responses.stats['account'], 0)
+ self.assertEqual(app.responses.stats['container'], 0)
def test_get_container_info_swift_source(self):
app = FakeApp()
req = Request.blank("/v1/a/c", environ={'swift.cache': FakeCache()})
get_container_info(req.environ, app, swift_source='MC')
- self.assertEqual(app.sources, ['GET_INFO', 'MC'])
+ self.assertEqual([e['swift.source'] for e in app.captured_envs],
+ ['MC', 'MC'])
def test_get_object_info_swift_source(self):
app = FakeApp()
req = Request.blank("/v1/a/c/o",
environ={'swift.cache': FakeCache()})
get_object_info(req.environ, app, swift_source='LU')
- self.assertEqual(app.sources, ['LU'])
+ self.assertEqual([e['swift.source'] for e in app.captured_envs],
+ ['LU'])
def test_get_container_info_no_cache(self):
req = Request.blank("/v1/AUTH_account/cont",
environ={'swift.cache': FakeCache({})})
resp = get_container_info(req.environ, FakeApp())
- self.assertEquals(resp['storage_policy'], '0')
- self.assertEquals(resp['bytes'], 6666)
- self.assertEquals(resp['object_count'], 1000)
+ self.assertEqual(resp['storage_policy'], '0')
+ self.assertEqual(resp['bytes'], 6666)
+ self.assertEqual(resp['object_count'], 1000)
def test_get_container_info_no_account(self):
- responses = DynamicResponseFactory(404, 200)
- app = FakeApp(responses)
+ app = FakeApp(statuses=[404, 200])
req = Request.blank("/v1/AUTH_does_not_exist/cont")
info = get_container_info(req.environ, app)
self.assertEqual(info['status'], 0)
def test_get_container_info_no_auto_account(self):
- responses = DynamicResponseFactory(404, 200)
- app = FakeApp(responses)
+ app = FakeApp(statuses=[200])
req = Request.blank("/v1/.system_account/cont")
info = get_container_info(req.environ, app)
self.assertEqual(info['status'], 200)
- self.assertEquals(info['bytes'], 6666)
- self.assertEquals(info['object_count'], 1000)
+ self.assertEqual(info['bytes'], 6666)
+ self.assertEqual(info['object_count'], 1000)
def test_get_container_info_cache(self):
cache_stub = {
'status': 404, 'bytes': 3333, 'object_count': 10,
- # simplejson sometimes hands back strings, sometimes unicodes
'versions': u"\u1F4A9"}
req = Request.blank("/v1/account/cont",
environ={'swift.cache': FakeCache(cache_stub)})
resp = get_container_info(req.environ, FakeApp())
- self.assertEquals(resp['storage_policy'], '0')
- self.assertEquals(resp['bytes'], 3333)
- self.assertEquals(resp['object_count'], 10)
- self.assertEquals(resp['status'], 404)
- self.assertEquals(resp['versions'], "\xe1\xbd\x8a\x39")
+ self.assertEqual(resp['storage_policy'], '0')
+ self.assertEqual(resp['bytes'], 3333)
+ self.assertEqual(resp['object_count'], 10)
+ self.assertEqual(resp['status'], 404)
+ self.assertEqual(resp['versions'], "\xe1\xbd\x8a\x39")
def test_get_container_info_env(self):
- cache_key = get_container_memcache_key("account", "cont")
- env_key = 'swift.%s' % cache_key
- req = Request.blank("/v1/account/cont",
- environ={env_key: {'bytes': 3867},
- 'swift.cache': FakeCache({})})
+ cache_key = get_cache_key("account", "cont")
+ req = Request.blank(
+ "/v1/account/cont",
+ environ={'swift.infocache': {cache_key: {'bytes': 3867}},
+ 'swift.cache': FakeCache({})})
resp = get_container_info(req.environ, 'xxx')
- self.assertEquals(resp['bytes'], 3867)
+ self.assertEqual(resp['bytes'], 3867)
def test_get_account_info_swift_source(self):
app = FakeApp()
req = Request.blank("/v1/a", environ={'swift.cache': FakeCache()})
get_account_info(req.environ, app, swift_source='MC')
- self.assertEqual(app.sources, ['MC'])
+ self.assertEqual([e['swift.source'] for e in app.captured_envs],
+ ['MC'])
+
+ def test_get_account_info_swift_owner(self):
+ app = FakeApp()
+ req = Request.blank("/v1/a", environ={'swift.cache': FakeCache()})
+ get_account_info(req.environ, app)
+ self.assertEqual([e['swift_owner'] for e in app.captured_envs],
+ [True])
+
+ def test_get_account_info_infocache(self):
+ app = FakeApp()
+ ic = {}
+ req = Request.blank("/v1/a", environ={'swift.cache': FakeCache(),
+ 'swift.infocache': ic})
+ get_account_info(req.environ, app)
+ got_infocaches = [e['swift.infocache'] for e in app.captured_envs]
+ self.assertEqual(1, len(got_infocaches))
+ self.assertIs(ic, got_infocaches[0])
def test_get_account_info_no_cache(self):
app = FakeApp()
req = Request.blank("/v1/AUTH_account",
environ={'swift.cache': FakeCache({})})
resp = get_account_info(req.environ, app)
- self.assertEquals(resp['bytes'], 6666)
- self.assertEquals(resp['total_object_count'], 1000)
+ self.assertEqual(resp['bytes'], 6666)
+ self.assertEqual(resp['total_object_count'], 1000)
def test_get_account_info_cache(self):
- # The original test that we prefer to preserve
+ # Works with fake apps that return ints in the headers
cached = {'status': 404,
'bytes': 3333,
'total_object_count': 10}
req = Request.blank("/v1/account/cont",
environ={'swift.cache': FakeCache(cached)})
resp = get_account_info(req.environ, FakeApp())
- self.assertEquals(resp['bytes'], 3333)
- self.assertEquals(resp['total_object_count'], 10)
- self.assertEquals(resp['status'], 404)
+ self.assertEqual(resp['bytes'], 3333)
+ self.assertEqual(resp['total_object_count'], 10)
+ self.assertEqual(resp['status'], 404)
- # Here is a more realistic test
+ # Works with strings too, like you get when parsing HTTP headers
+ # that came in through a socket from the account server
cached = {'status': 404,
'bytes': '3333',
'container_count': '234',
@@ -397,33 +434,34 @@ class TestFuncs(unittest.TestCase):
req = Request.blank("/v1/account/cont",
environ={'swift.cache': FakeCache(cached)})
resp = get_account_info(req.environ, FakeApp())
- self.assertEquals(resp['status'], 404)
- self.assertEquals(resp['bytes'], '3333')
- self.assertEquals(resp['container_count'], 234)
- self.assertEquals(resp['meta'], {})
- self.assertEquals(resp['total_object_count'], '10')
+ self.assertEqual(resp['status'], 404)
+ self.assertEqual(resp['bytes'], 3333)
+ self.assertEqual(resp['container_count'], 234)
+ self.assertEqual(resp['meta'], {})
+ self.assertEqual(resp['total_object_count'], 10)
def test_get_account_info_env(self):
- cache_key = get_account_memcache_key("account")
- env_key = 'swift.%s' % cache_key
- req = Request.blank("/v1/account",
- environ={env_key: {'bytes': 3867},
- 'swift.cache': FakeCache({})})
+ cache_key = get_cache_key("account")
+ req = Request.blank(
+ "/v1/account",
+ environ={'swift.infocache': {cache_key: {'bytes': 3867}},
+ 'swift.cache': FakeCache({})})
resp = get_account_info(req.environ, 'xxx')
- self.assertEquals(resp['bytes'], 3867)
+ self.assertEqual(resp['bytes'], 3867)
def test_get_object_info_env(self):
cached = {'status': 200,
'length': 3333,
'type': 'application/json',
'meta': {}}
- env_key = get_object_env_key("account", "cont", "obj")
- req = Request.blank("/v1/account/cont/obj",
- environ={env_key: cached,
- 'swift.cache': FakeCache({})})
+ cache_key = get_cache_key("account", "cont", "obj")
+ req = Request.blank(
+ "/v1/account/cont/obj",
+ environ={'swift.infocache': {cache_key: cached},
+ 'swift.cache': FakeCache({})})
resp = get_object_info(req.environ, 'xxx')
- self.assertEquals(resp['length'], 3333)
- self.assertEquals(resp['type'], 'application/json')
+ self.assertEqual(resp['length'], 3333)
+ self.assertEqual(resp['type'], 'application/json')
def test_get_object_info_no_env(self):
app = FakeApp()
@@ -433,31 +471,84 @@ class TestFuncs(unittest.TestCase):
self.assertEqual(app.responses.stats['account'], 0)
self.assertEqual(app.responses.stats['container'], 0)
self.assertEqual(app.responses.stats['obj'], 1)
- self.assertEquals(resp['length'], 5555)
- self.assertEquals(resp['type'], 'text/plain')
+ self.assertEqual(resp['length'], 5555)
+ self.assertEqual(resp['type'], 'text/plain')
+
+ def test_options(self):
+ base = Controller(self.app)
+ base.account_name = 'a'
+ base.container_name = 'c'
+ origin = 'http://m.com'
+ self.app.cors_allow_origin = [origin]
+ req = Request.blank('/v1/a/c/o',
+ environ={'swift.cache': FakeCache()},
+ headers={'Origin': origin,
+ 'Access-Control-Request-Method': 'GET'})
+
+ with mock.patch('swift.proxy.controllers.base.'
+ 'http_connect', fake_http_connect(200)):
+ resp = base.OPTIONS(req)
+ self.assertEqual(resp.status_int, 200)
+
+ def test_options_with_null_allow_origin(self):
+ base = Controller(self.app)
+ base.account_name = 'a'
+ base.container_name = 'c'
+
+ def my_container_info(*args):
+ return {
+ 'cors': {
+ 'allow_origin': '*',
+ }
+ }
+ base.container_info = my_container_info
+ req = Request.blank('/v1/a/c/o',
+ environ={'swift.cache': FakeCache()},
+ headers={'Origin': '*',
+ 'Access-Control-Request-Method': 'GET'})
+
+ with mock.patch('swift.proxy.controllers.base.'
+ 'http_connect', fake_http_connect(200)):
+ resp = base.OPTIONS(req)
+ self.assertEqual(resp.status_int, 200)
+
+ def test_options_unauthorized(self):
+ base = Controller(self.app)
+ base.account_name = 'a'
+ base.container_name = 'c'
+ self.app.cors_allow_origin = ['http://NOT_IT']
+ req = Request.blank('/v1/a/c/o',
+ environ={'swift.cache': FakeCache()},
+ headers={'Origin': 'http://m.com',
+ 'Access-Control-Request-Method': 'GET'})
+
+ with mock.patch('swift.proxy.controllers.base.'
+ 'http_connect', fake_http_connect(200)):
+ resp = base.OPTIONS(req)
+ self.assertEqual(resp.status_int, 401)
def test_headers_to_container_info_missing(self):
resp = headers_to_container_info({}, 404)
- self.assertEquals(resp['status'], 404)
- self.assertEquals(resp['read_acl'], None)
- self.assertEquals(resp['write_acl'], None)
+ self.assertEqual(resp['status'], 404)
+ self.assertIsNone(resp['read_acl'])
+ self.assertIsNone(resp['write_acl'])
def test_headers_to_container_info_meta(self):
headers = {'X-Container-Meta-Whatevs': 14,
'x-container-meta-somethingelse': 0}
resp = headers_to_container_info(headers.items(), 200)
- self.assertEquals(len(resp['meta']), 2)
- self.assertEquals(resp['meta']['whatevs'], 14)
- self.assertEquals(resp['meta']['somethingelse'], 0)
+ self.assertEqual(len(resp['meta']), 2)
+ self.assertEqual(resp['meta']['whatevs'], 14)
+ self.assertEqual(resp['meta']['somethingelse'], 0)
def test_headers_to_container_info_sys_meta(self):
prefix = get_sys_meta_prefix('container')
headers = {'%sWhatevs' % prefix: 14,
'%ssomethingelse' % prefix: 0}
resp = headers_to_container_info(headers.items(), 200)
- self.assertEquals(len(resp['sysmeta']), 2)
- self.assertEquals(resp['sysmeta']['whatevs'], 14)
- self.assertEquals(resp['sysmeta']['somethingelse'], 0)
+ self.assertEqual(len(resp['sysmeta']), 2)
+ self.assertEqual(resp['sysmeta']['whatevs'], 14)
+ self.assertEqual(resp['sysmeta']['somethingelse'], 0)
def test_headers_to_container_info_values(self):
headers = {
@@ -467,37 +558,47 @@ class TestFuncs(unittest.TestCase):
'x-container-meta-access-control-allow-origin': 'here',
}
resp = headers_to_container_info(headers.items(), 200)
- self.assertEquals(resp['read_acl'], 'readvalue')
- self.assertEquals(resp['write_acl'], 'writevalue')
- self.assertEquals(resp['cors']['allow_origin'], 'here')
+ self.assertEqual(resp['read_acl'], 'readvalue')
+ self.assertEqual(resp['write_acl'], 'writevalue')
+ self.assertEqual(resp['cors']['allow_origin'], 'here')
headers['x-unused-header'] = 'blahblahblah'
- self.assertEquals(
+ self.assertEqual(
resp,
headers_to_container_info(headers.items(), 200))
+ def test_container_info_without_req(self):
+ base = Controller(self.app)
+ base.account_name = 'a'
+ base.container_name = 'c'
+
+ container_info = \
+ base.container_info(base.account_name,
+ base.container_name)
+ self.assertEqual(container_info['status'], 0)
+
def test_headers_to_account_info_missing(self):
resp = headers_to_account_info({}, 404)
- self.assertEquals(resp['status'], 404)
- self.assertEquals(resp['bytes'], None)
- self.assertEquals(resp['container_count'], None)
+ self.assertEqual(resp['status'], 404)
+ self.assertIsNone(resp['bytes'])
+ self.assertIsNone(resp['container_count'])
def test_headers_to_account_info_meta(self):
headers = {'X-Account-Meta-Whatevs': 14,
'x-account-meta-somethingelse': 0}
resp = headers_to_account_info(headers.items(), 200)
- self.assertEquals(len(resp['meta']), 2)
- self.assertEquals(resp['meta']['whatevs'], 14)
- self.assertEquals(resp['meta']['somethingelse'], 0)
+ self.assertEqual(len(resp['meta']), 2)
+ self.assertEqual(resp['meta']['whatevs'], 14)
+ self.assertEqual(resp['meta']['somethingelse'], 0)
def test_headers_to_account_info_sys_meta(self):
prefix = get_sys_meta_prefix('account')
headers = {'%sWhatevs' % prefix: 14,
'%ssomethingelse' % prefix: 0}
resp = headers_to_account_info(headers.items(), 200)
- self.assertEquals(len(resp['sysmeta']), 2)
- self.assertEquals(resp['sysmeta']['whatevs'], 14)
- self.assertEquals(resp['sysmeta']['somethingelse'], 0)
+ self.assertEqual(len(resp['sysmeta']), 2)
+ self.assertEqual(resp['sysmeta']['whatevs'], 14)
+ self.assertEqual(resp['sysmeta']['somethingelse'], 0)
def test_headers_to_account_info_values(self):
headers = {
@@ -505,36 +606,44 @@ class TestFuncs(unittest.TestCase):
'x-account-container-count': '20',
}
resp = headers_to_account_info(headers.items(), 200)
- self.assertEquals(resp['total_object_count'], '10')
- self.assertEquals(resp['container_count'], '20')
+ self.assertEqual(resp['total_object_count'], '10')
+ self.assertEqual(resp['container_count'], '20')
headers['x-unused-header'] = 'blahblahblah'
- self.assertEquals(
+ self.assertEqual(
resp,
headers_to_account_info(headers.items(), 200))
def test_headers_to_object_info_missing(self):
resp = headers_to_object_info({}, 404)
- self.assertEquals(resp['status'], 404)
- self.assertEquals(resp['length'], None)
- self.assertEquals(resp['etag'], None)
+ self.assertEqual(resp['status'], 404)
+ self.assertIsNone(resp['length'])
+ self.assertIsNone(resp['etag'])
def test_headers_to_object_info_meta(self):
headers = {'X-Object-Meta-Whatevs': 14,
'x-object-meta-somethingelse': 0}
resp = headers_to_object_info(headers.items(), 200)
- self.assertEquals(len(resp['meta']), 2)
- self.assertEquals(resp['meta']['whatevs'], 14)
- self.assertEquals(resp['meta']['somethingelse'], 0)
+ self.assertEqual(len(resp['meta']), 2)
+ self.assertEqual(resp['meta']['whatevs'], 14)
+ self.assertEqual(resp['meta']['somethingelse'], 0)
def test_headers_to_object_info_sys_meta(self):
prefix = get_sys_meta_prefix('object')
headers = {'%sWhatevs' % prefix: 14,
'%ssomethingelse' % prefix: 0}
resp = headers_to_object_info(headers.items(), 200)
- self.assertEquals(len(resp['sysmeta']), 2)
- self.assertEquals(resp['sysmeta']['whatevs'], 14)
- self.assertEquals(resp['sysmeta']['somethingelse'], 0)
+ self.assertEqual(len(resp['sysmeta']), 2)
+ self.assertEqual(resp['sysmeta']['whatevs'], 14)
+ self.assertEqual(resp['sysmeta']['somethingelse'], 0)
+
+ def test_headers_to_object_info_transient_sysmeta(self):
+ headers = {get_object_transient_sysmeta('Whatevs'): 14,
+ get_object_transient_sysmeta('somethingelse'): 0}
+ resp = headers_to_object_info(headers.items(), 200)
+ self.assertEqual(len(resp['transient_sysmeta']), 2)
+ self.assertEqual(resp['transient_sysmeta']['whatevs'], 14)
+ self.assertEqual(resp['transient_sysmeta']['somethingelse'], 0)
def test_headers_to_object_info_values(self):
headers = {
@@ -542,26 +651,29 @@ class TestFuncs(unittest.TestCase):
'content-type': 'application/json',
}
resp = headers_to_object_info(headers.items(), 200)
- self.assertEquals(resp['length'], '1024')
- self.assertEquals(resp['type'], 'application/json')
+ self.assertEqual(resp['length'], '1024')
+ self.assertEqual(resp['type'], 'application/json')
headers['x-unused-header'] = 'blahblahblah'
- self.assertEquals(
+ self.assertEqual(
resp,
headers_to_object_info(headers.items(), 200))
def test_base_have_quorum(self):
base = Controller(self.app)
# just throw a bunch of test cases at it
- self.assertEqual(base.have_quorum([201, 404], 3), False)
- self.assertEqual(base.have_quorum([201, 201], 4), False)
- self.assertEqual(base.have_quorum([201, 201, 404, 404], 4), False)
- self.assertEqual(base.have_quorum([201, 503, 503, 201], 4), False)
- self.assertEqual(base.have_quorum([201, 201], 3), True)
- self.assertEqual(base.have_quorum([404, 404], 3), True)
- self.assertEqual(base.have_quorum([201, 201], 2), True)
- self.assertEqual(base.have_quorum([404, 404], 2), True)
- self.assertEqual(base.have_quorum([201, 404, 201, 201], 4), True)
+ self.assertFalse(base.have_quorum([201, 404], 3))
+ self.assertTrue(base.have_quorum([201, 201], 4))
+ self.assertFalse(base.have_quorum([201], 4))
+ self.assertTrue(base.have_quorum([201, 201, 404, 404], 4))
+ self.assertFalse(base.have_quorum([201, 302, 418, 503], 4))
+ self.assertTrue(base.have_quorum([201, 503, 503, 201], 4))
+ self.assertTrue(base.have_quorum([201, 201], 3))
+ self.assertTrue(base.have_quorum([404, 404], 3))
+ self.assertTrue(base.have_quorum([201, 201], 2))
+ self.assertTrue(base.have_quorum([201, 404], 2))
+ self.assertTrue(base.have_quorum([404, 404], 2))
+ self.assertTrue(base.have_quorum([201, 404, 201, 201], 4))
def test_best_response_overrides(self):
base = Controller(self.app)
@@ -579,7 +691,7 @@ class TestFuncs(unittest.TestCase):
overrides = {302: 204, 100: 204}
resp = base.best_response(req, statuses, reasons, bodies, server_type,
headers=headers, overrides=overrides)
- self.assertEqual(resp.status, '503 Internal Server Error')
+ self.assertEqual(resp.status, '503 Service Unavailable')
# next make a 404 quorum and make sure the last delete (real) 404
# status is the one returned.
@@ -593,24 +705,61 @@ class TestFuncs(unittest.TestCase):
req = Request.blank('/')
handler = GetOrHeadHandler(None, req, None, None, None, None, {})
handler.fast_forward(50)
- self.assertEquals(handler.backend_headers['Range'], 'bytes=50-')
+ self.assertEqual(handler.backend_headers['Range'], 'bytes=50-')
handler = GetOrHeadHandler(None, req, None, None, None, None,
{'Range': 'bytes=23-50'})
handler.fast_forward(20)
- self.assertEquals(handler.backend_headers['Range'], 'bytes=43-50')
+ self.assertEqual(handler.backend_headers['Range'], 'bytes=43-50')
self.assertRaises(HTTPException,
handler.fast_forward, 80)
+ self.assertRaises(exceptions.RangeAlreadyComplete,
+ handler.fast_forward, 8)
handler = GetOrHeadHandler(None, req, None, None, None, None,
{'Range': 'bytes=23-'})
handler.fast_forward(20)
- self.assertEquals(handler.backend_headers['Range'], 'bytes=43-')
+ self.assertEqual(handler.backend_headers['Range'], 'bytes=43-')
handler = GetOrHeadHandler(None, req, None, None, None, None,
{'Range': 'bytes=-100'})
handler.fast_forward(20)
- self.assertEquals(handler.backend_headers['Range'], 'bytes=-80')
+ self.assertEqual(handler.backend_headers['Range'], 'bytes=-80')
+ self.assertRaises(HTTPException,
+ handler.fast_forward, 100)
+ self.assertRaises(exceptions.RangeAlreadyComplete,
+ handler.fast_forward, 80)
+
+ handler = GetOrHeadHandler(None, req, None, None, None, None,
+ {'Range': 'bytes=0-0'})
+ self.assertRaises(exceptions.RangeAlreadyComplete,
+ handler.fast_forward, 1)
+
+ def test_range_fast_forward_after_data_timeout(self):
+ req = Request.blank('/')
+
+ # We get a 200 and learn that it's a 1000-byte object, but receive 0
+ # bytes of data, so then we get a new node, fast_forward(0), and
+ # send out a new request. That new request must be for all 1000
+ # bytes.
+ handler = GetOrHeadHandler(None, req, None, None, None, None, {})
+ handler.learn_size_from_content_range(0, 999, 1000)
+ handler.fast_forward(0)
+ self.assertEqual(handler.backend_headers['Range'], 'bytes=0-999')
+
+ # Same story as above, but a 1-byte object so we can have our byte
+ # indices be 0.
+ handler = GetOrHeadHandler(None, req, None, None, None, None, {})
+ handler.learn_size_from_content_range(0, 0, 1)
+ handler.fast_forward(0)
+ self.assertEqual(handler.backend_headers['Range'], 'bytes=0-0')
+
+ # last 100 bytes
+ handler = GetOrHeadHandler(None, req, None, None, None, None,
+ {'Range': 'bytes=-100'})
+ handler.learn_size_from_content_range(900, 999, 1000)
+ handler.fast_forward(0)
+ self.assertEqual(handler.backend_headers['Range'], 'bytes=900-999')
def test_transfer_headers_with_sysmeta(self):
base = Controller(self.app)
@@ -633,10 +782,10 @@ class TestFuncs(unittest.TestCase):
expected_headers = {'x-base-meta-owner': '',
'x-base-meta-size': '151M',
'connection': 'close'}
- for k, v in expected_headers.iteritems():
- self.assertTrue(k in dst_headers)
+ for k, v in expected_headers.items():
+ self.assertIn(k, dst_headers)
self.assertEqual(v, dst_headers[k])
- self.assertFalse('new-owner' in dst_headers)
+ self.assertNotIn('new-owner', dst_headers)
def test_generate_request_headers_with_sysmeta(self):
base = Controller(self.app)
@@ -647,17 +796,32 @@ class TestFuncs(unittest.TestCase):
hdrs.update(bad_hdrs)
req = Request.blank('/v1/a/c/o', headers=hdrs)
dst_headers = base.generate_request_headers(req, transfer=True)
- for k, v in good_hdrs.iteritems():
- self.assertTrue(k.lower() in dst_headers)
+ for k, v in good_hdrs.items():
+ self.assertIn(k.lower(), dst_headers)
self.assertEqual(v, dst_headers[k.lower()])
- for k, v in bad_hdrs.iteritems():
- self.assertFalse(k.lower() in dst_headers)
+ for k, v in bad_hdrs.items():
+ self.assertNotIn(k.lower(), dst_headers)
+
+ def test_generate_request_headers_with_no_orig_req(self):
+ base = Controller(self.app)
+ src_headers = {'x-remove-base-meta-owner': 'x',
+ 'x-base-meta-size': '151M',
+ 'new-owner': 'Kun'}
+ dst_headers = base.generate_request_headers(None,
+ additional=src_headers)
+ expected_headers = {'x-base-meta-size': '151M',
+ 'connection': 'close'}
+ for k, v in expected_headers.items():
+ self.assertIn(k, dst_headers)
+ self.assertEqual(v, dst_headers[k])
+ self.assertEqual('', dst_headers['Referer'])
def test_client_chunk_size(self):
class TestSource(object):
def __init__(self, chunks):
self.chunks = list(chunks)
+ self.status = 200
def read(self, _read_size):
if self.chunks:
@@ -665,6 +829,13 @@ class TestFuncs(unittest.TestCase):
else:
return ''
+ def getheader(self, header):
+ if header.lower() == "content-length":
+ return str(sum(len(c) for c in self.chunks))
+
+ def getheaders(self):
+ return [('content-length', self.getheader('content-length'))]
+
source = TestSource((
'abcd', '1234', 'abc', 'd1', '234abcd1234abcd1', '2'))
req = Request.blank('/v1/a/c/o')
@@ -682,6 +853,7 @@ class TestFuncs(unittest.TestCase):
class TestSource(object):
def __init__(self, chunks):
self.chunks = list(chunks)
+ self.status = 200
def read(self, _read_size):
if self.chunks:
@@ -693,7 +865,15 @@ class TestFuncs(unittest.TestCase):
else:
return ''
- node = {'ip': '1.2.3.4', 'port': 6000, 'device': 'sda'}
+ def getheader(self, header):
+ if header.lower() == "content-length":
+ return str(sum(len(c) for c in self.chunks
+ if c is not None))
+
+ def getheaders(self):
+ return [('content-length', self.getheader('content-length'))]
+
+ node = {'ip': '1.2.3.4', 'port': 6200, 'device': 'sda'}
source1 = TestSource(['abcd', '1234', 'abc', None])
source2 = TestSource(['efgh5678'])
@@ -703,11 +883,88 @@ class TestFuncs(unittest.TestCase):
client_chunk_size=8)
app_iter = handler._make_app_iter(req, node, source1)
- with patch.object(handler, '_get_source_and_node',
- lambda: (source2, node)):
+ with mock.patch.object(handler, '_get_source_and_node',
+ lambda: (source2, node)):
+ client_chunks = list(app_iter)
+ self.assertEqual(client_chunks, ['abcd1234', 'efgh5678'])
+
+ def test_client_chunk_size_resuming_chunked(self):
+
+ class TestChunkedSource(object):
+ def __init__(self, chunks):
+ self.chunks = list(chunks)
+ self.status = 200
+ self.headers = {'transfer-encoding': 'chunked',
+ 'content-type': 'text/plain'}
+
+ def read(self, _read_size):
+ if self.chunks:
+ chunk = self.chunks.pop(0)
+ if chunk is None:
+ raise exceptions.ChunkReadTimeout()
+ else:
+ return chunk
+ else:
+ return ''
+
+ def getheader(self, header):
+ return self.headers.get(header.lower())
+
+ def getheaders(self):
+ return self.headers
+
+ node = {'ip': '1.2.3.4', 'port': 6200, 'device': 'sda'}
+
+ source1 = TestChunkedSource(['abcd', '1234', 'abc', None])
+ source2 = TestChunkedSource(['efgh5678'])
+ req = Request.blank('/v1/a/c/o')
+ handler = GetOrHeadHandler(
+ self.app, req, 'Object', None, None, None, {},
+ client_chunk_size=8)
+
+ app_iter = handler._make_app_iter(req, node, source1)
+ with mock.patch.object(handler, '_get_source_and_node',
+ lambda: (source2, node)):
client_chunks = list(app_iter)
self.assertEqual(client_chunks, ['abcd1234', 'efgh5678'])
- self.assertEqual(handler.backend_headers['Range'], 'bytes=8-')
+
+ def test_disconnected_warning(self):
+ self.app.logger = mock.Mock()
+ req = Request.blank('/v1/a/c/o')
+
+ class TestSource(object):
+ def __init__(self):
+ self.headers = {'content-type': 'text/plain',
+ 'content-length': len(self.read(-1))}
+ self.status = 200
+
+ def read(self, _read_size):
+ return 'the cake is a lie'
+
+ def getheader(self, header):
+ return self.headers.get(header.lower())
+
+ def getheaders(self):
+ return self.headers
+
+ source = TestSource()
+
+ node = {'ip': '1.2.3.4', 'port': 6200, 'device': 'sda'}
+ handler = GetOrHeadHandler(
+ self.app, req, 'Object', None, None, None, {})
+ app_iter = handler._make_app_iter(req, node, source)
+ app_iter.close()
+ self.app.logger.warning.assert_called_once_with(
+ 'Client disconnected on read')
+
+ self.app.logger = mock.Mock()
+ node = {'ip': '1.2.3.4', 'port': 6200, 'device': 'sda'}
+ handler = GetOrHeadHandler(
+ self.app, req, 'Object', None, None, None, {})
+ app_iter = handler._make_app_iter(req, node, source)
+ next(app_iter)
+ app_iter.close()
+ self.app.logger.warning.assert_not_called()
def test_bytes_to_skip(self):
# if you start at the beginning, skip nothing
diff --git a/test/unit/proxy/controllers/test_container.py b/test/unit/proxy/controllers/test_container.py
index 715cd94..b5367aa 100644
--- a/test/unit/proxy/controllers/test_container.py
+++ b/test/unit/proxy/controllers/test_container.py
@@ -24,22 +24,22 @@ from swift.proxy.controllers.base import headers_to_container_info
from test.unit import fake_http_connect, FakeRing, FakeMemcache
from swift.common.storage_policy import StoragePolicy
from swift.common.request_helpers import get_sys_meta_prefix
-from swift.common import utils
from test.unit import patch_policies, mocked_http_conn, debug_logger
+#from test.unit.common.ring.test_ring import TestRingBase
from test.unit.proxy.test_server import node_error_count
@patch_policies([StoragePolicy(0, 'zero', True, object_ring=FakeRing())])
class TestContainerController(unittest.TestCase):
+
+ CONTAINER_REPLICAS = 3
+
def setUp(self):
- # SOF
- self._orig_hash_suffix = utils.HASH_PATH_SUFFIX
- self._orig_hash_prefix = utils.HASH_PATH_PREFIX
- utils.HASH_PATH_SUFFIX = 'endcap'
- utils.HASH_PATH_PREFIX = ''
+ TestRingBase.setUp(self)
self.logger = debug_logger()
- self.container_ring = FakeRing(max_more_nodes=9)
+ self.container_ring = FakeRing(replicas=self.CONTAINER_REPLICAS,
+ max_more_nodes=9)
self.app = proxy_server.Application(None, FakeMemcache(),
logger=self.logger,
account_ring=FakeRing(),
@@ -58,7 +58,7 @@ class TestContainerController(unittest.TestCase):
proxy_server.ContainerController):
def account_info(controller, *args, **kwargs):
- patch_path = 'swift.proxy.controllers.base.get_info'
+ patch_path = 'swift.proxy.controllers.base.get_account_info'
with mock.patch(patch_path) as mock_get_info:
mock_get_info.return_value = dict(self.account_info)
return super(FakeAccountInfoContainerController,
@@ -72,16 +72,43 @@ class TestContainerController(unittest.TestCase):
return _orig_get_controller(*args, **kwargs)
self.app.get_controller = wrapped_get_controller
- def test_container_info_in_response_env(self):
+ def _make_callback_func(self, context):
+ def callback(ipaddr, port, device, partition, method, path,
+ headers=None, query_string=None, ssl=False):
+ context['method'] = method
+ context['path'] = path
+ context['headers'] = headers or {}
+ return callback
+
+ def _assert_responses(self, method, test_cases):
+ controller = proxy_server.ContainerController(self.app, 'a', 'c')
+
+ for responses, expected in test_cases:
+ with mock.patch(
+ 'swift.proxy.controllers.base.http_connect',
+ fake_http_connect(*responses)):
+ req = Request.blank('/v1/a/c')
+ resp = getattr(controller, method)(req)
+
+ self.assertEqual(expected,
+ resp.status_int,
+ 'Expected %s but got %s. Failed case: %s' %
+ (expected, resp.status_int, str(responses)))
+
+ def test_container_info_got_cached(self):
controller = proxy_server.ContainerController(self.app, 'a', 'c')
with mock.patch('swift.proxy.controllers.base.http_connect',
fake_http_connect(200, 200, body='')):
req = Request.blank('/v1/a/c', {'PATH_INFO': '/v1/a/c'})
resp = controller.HEAD(req)
self.assertEqual(2, resp.status_int // 100)
- self.assertTrue("swift.container/a/c" in resp.environ)
- self.assertEqual(headers_to_container_info(resp.headers),
- resp.environ['swift.container/a/c'])
+ # Make sure it's in both swift.infocache and memcache
+ self.assertIn("container/a/c", resp.environ['swift.infocache'])
+ self.assertEqual(
+ headers_to_container_info(resp.headers),
+ resp.environ['swift.infocache']['container/a/c'])
+ from_memcache = self.app.memcache.get('container/a/c')
+ self.assertTrue(from_memcache)
def test_swift_owner(self):
owner_headers = {
@@ -93,25 +120,17 @@ class TestContainerController(unittest.TestCase):
with mock.patch('swift.proxy.controllers.base.http_connect',
fake_http_connect(200, 200, headers=owner_headers)):
resp = controller.HEAD(req)
- self.assertEquals(2, resp.status_int // 100)
+ self.assertEqual(2, resp.status_int // 100)
for key in owner_headers:
- self.assertTrue(key not in resp.headers)
+ self.assertNotIn(key, resp.headers)
req = Request.blank('/v1/a/c', environ={'swift_owner': True})
with mock.patch('swift.proxy.controllers.base.http_connect',
fake_http_connect(200, 200, headers=owner_headers)):
resp = controller.HEAD(req)
- self.assertEquals(2, resp.status_int // 100)
+ self.assertEqual(2, resp.status_int // 100)
for key in owner_headers:
- self.assertTrue(key in resp.headers)
-
- def _make_callback_func(self, context):
- def callback(ipaddr, port, device, partition, method, path,
- headers=None, query_string=None, ssl=False):
- context['method'] = method
- context['path'] = path
- context['headers'] = headers or {}
- return callback
+ self.assertIn(key, resp.headers)
def test_sys_meta_headers_PUT(self):
# check that headers in sys meta namespace make it through
@@ -131,9 +150,9 @@ class TestContainerController(unittest.TestCase):
fake_http_connect(200, 200, give_connect=callback)):
controller.PUT(req)
self.assertEqual(context['method'], 'PUT')
- self.assertTrue(sys_meta_key in context['headers'])
+ self.assertIn(sys_meta_key, context['headers'])
self.assertEqual(context['headers'][sys_meta_key], 'foo')
- self.assertTrue(user_meta_key in context['headers'])
+ self.assertIn(user_meta_key, context['headers'])
self.assertEqual(context['headers'][user_meta_key], 'bar')
self.assertNotEqual(context['headers']['x-timestamp'], '1.0')
@@ -154,9 +173,9 @@ class TestContainerController(unittest.TestCase):
fake_http_connect(200, 200, give_connect=callback)):
controller.POST(req)
self.assertEqual(context['method'], 'POST')
- self.assertTrue(sys_meta_key in context['headers'])
+ self.assertIn(sys_meta_key, context['headers'])
self.assertEqual(context['headers'][sys_meta_key], 'foo')
- self.assertTrue(user_meta_key in context['headers'])
+ self.assertIn(user_meta_key, context['headers'])
self.assertEqual(context['headers'][user_meta_key], 'bar')
self.assertNotEqual(context['headers']['x-timestamp'], '1.0')
@@ -168,12 +187,11 @@ class TestContainerController(unittest.TestCase):
self.app._error_limiting = {}
req = Request.blank('/v1/a/c', method=method)
with mocked_http_conn(*statuses) as fake_conn:
- print 'a' * 50
resp = req.get_response(self.app)
self.assertEqual(resp.status_int, expected)
for req in fake_conn.requests:
self.assertEqual(req['method'], method)
- self.assert_(req['path'].endswith('/a/c'))
+ self.assertTrue(req['path'].endswith('/a/c'))
base_status = [201] * 3
# test happy path
@@ -207,6 +225,118 @@ class TestContainerController(unittest.TestCase):
self.app, self.container_ring.devs[2]),
self.app.error_suppression_limit + 1)
+ def test_response_code_for_PUT(self):
+ PUT_TEST_CASES = [
+ ((201, 201, 201), 201),
+ ((201, 201, 404), 201),
+ ((201, 201, 503), 201),
+ ((201, 404, 404), 404),
+ ((201, 404, 503), 503),
+ ((201, 503, 503), 503),
+ ((404, 404, 404), 404),
+ ((404, 404, 503), 404),
+ ((404, 503, 503), 503),
+ ((503, 503, 503), 503)
+ ]
+ self._assert_responses('PUT', PUT_TEST_CASES)
+
+ def test_response_code_for_DELETE(self):
+ DELETE_TEST_CASES = [
+ ((204, 204, 204), 204),
+ ((204, 204, 404), 204),
+ ((204, 204, 503), 204),
+ ((204, 404, 404), 404),
+ ((204, 404, 503), 503),
+ ((204, 503, 503), 503),
+ ((404, 404, 404), 404),
+ ((404, 404, 503), 404),
+ ((404, 503, 503), 503),
+ ((503, 503, 503), 503)
+ ]
+ self._assert_responses('DELETE', DELETE_TEST_CASES)
+
+ def test_response_code_for_POST(self):
+ POST_TEST_CASES = [
+ ((204, 204, 204), 204),
+ ((204, 204, 404), 204),
+ ((204, 204, 503), 204),
+ ((204, 404, 404), 404),
+ ((204, 404, 503), 503),
+ ((204, 503, 503), 503),
+ ((404, 404, 404), 404),
+ ((404, 404, 503), 404),
+ ((404, 503, 503), 503),
+ ((503, 503, 503), 503)
+ ]
+ self._assert_responses('POST', POST_TEST_CASES)
+
+
+@patch_policies(
+ [StoragePolicy(0, 'zero', True, object_ring=FakeRing(replicas=4))])
+class TestContainerController4Replicas(TestContainerController):
+
+ CONTAINER_REPLICAS = 4
+
+ def test_response_code_for_PUT(self):
+ PUT_TEST_CASES = [
+ ((201, 201, 201, 201), 201),
+ ((201, 201, 201, 404), 201),
+ ((201, 201, 201, 503), 201),
+ ((201, 201, 404, 404), 201),
+ ((201, 201, 404, 503), 201),
+ ((201, 201, 503, 503), 201),
+ ((201, 404, 404, 404), 404),
+ ((201, 404, 404, 503), 404),
+ ((201, 404, 503, 503), 503),
+ ((201, 503, 503, 503), 503),
+ ((404, 404, 404, 404), 404),
+ ((404, 404, 404, 503), 404),
+ ((404, 404, 503, 503), 404),
+ ((404, 503, 503, 503), 503),
+ ((503, 503, 503, 503), 503)
+ ]
+ self._assert_responses('PUT', PUT_TEST_CASES)
+
+ def test_response_code_for_DELETE(self):
+ DELETE_TEST_CASES = [
+ ((204, 204, 204, 204), 204),
+ ((204, 204, 204, 404), 204),
+ ((204, 204, 204, 503), 204),
+ ((204, 204, 404, 404), 204),
+ ((204, 204, 404, 503), 204),
+ ((204, 204, 503, 503), 204),
+ ((204, 404, 404, 404), 404),
+ ((204, 404, 404, 503), 404),
+ ((204, 404, 503, 503), 503),
+ ((204, 503, 503, 503), 503),
+ ((404, 404, 404, 404), 404),
+ ((404, 404, 404, 503), 404),
+ ((404, 404, 503, 503), 404),
+ ((404, 503, 503, 503), 503),
+ ((503, 503, 503, 503), 503)
+ ]
+ self._assert_responses('DELETE', DELETE_TEST_CASES)
+
+ def test_response_code_for_POST(self):
+ POST_TEST_CASES = [
+ ((204, 204, 204, 204), 204),
+ ((204, 204, 204, 404), 204),
+ ((204, 204, 204, 503), 204),
+ ((204, 204, 404, 404), 204),
+ ((204, 204, 404, 503), 204),
+ ((204, 204, 503, 503), 204),
+ ((204, 404, 404, 404), 404),
+ ((204, 404, 404, 503), 404),
+ ((204, 404, 503, 503), 503),
+ ((204, 503, 503, 503), 503),
+ ((404, 404, 404, 404), 404),
+ ((404, 404, 404, 503), 404),
+ ((404, 404, 503, 503), 404),
+ ((404, 503, 503, 503), 503),
+ ((503, 503, 503, 503), 503)
+ ]
+ self._assert_responses('POST', POST_TEST_CASES)
+
if __name__ == '__main__':
unittest.main()
diff --git a/test/unit/proxy/test_server.py b/test/unit/proxy/test_server.py
index bdce41f..64c5825 100644
--- a/test/unit/proxy/test_server.py
+++ b/test/unit/proxy/test_server.py
@@ -66,8 +66,7 @@ from swift.common.ring import RingData
from swift.common.utils import mkdirs, normalize_timestamp, NullLogger
from swift.common.wsgi import monkey_patch_mimetools, loadapp
from swift.proxy.controllers import base as proxy_base
-from swift.proxy.controllers.base import get_container_memcache_key, \
- get_account_memcache_key, cors_validation
+from swift.proxy.controllers.base import get_cache_key,cors_validation
import swift.proxy.controllers
import swift.proxy.controllers.obj
from swift.common.swob import Request, Response, HTTPUnauthorized, \
@@ -474,14 +473,14 @@ class TestController(unittest.TestCase):
self.controller.account_info(self.account)
self.assertEquals(count, 123)
with save_globals():
- cache_key = get_account_memcache_key(self.account)
+ cache_key = get_cache_key(self.account)
account_info = {'status': 200, 'container_count': 1234}
self.memcache.set(cache_key, account_info)
partition, nodes, count = \
self.controller.account_info(self.account)
self.assertEquals(count, 1234)
with save_globals():
- cache_key = get_account_memcache_key(self.account)
+ cache_key = get_cache_key(self.account)
account_info = {'status': 200, 'container_count': '1234'}
self.memcache.set(cache_key, account_info)
partition, nodes, count = \
@@ -509,7 +508,7 @@ class TestController(unittest.TestCase):
# Test the internal representation in memcache
# 'container_count' changed from int to str
- cache_key = get_account_memcache_key(self.account)
+ cache_key = get_cache_key(self.account)
container_info = {'status': 200,
'container_count': '12345',
'total_object_count': None,
@@ -536,7 +535,7 @@ class TestController(unittest.TestCase):
# Test the internal representation in memcache
# 'container_count' changed from 0 to None
- cache_key = get_account_memcache_key(self.account)
+ cache_key = get_cache_key(self.account)
account_info = {'status': 404,
'container_count': None, # internally keep None
'total_object_count': None,
@@ -613,8 +612,7 @@ class TestController(unittest.TestCase):
self.account, self.container, self.request)
self.check_container_info_return(ret)
- cache_key = get_container_memcache_key(self.account,
- self.container)
+ cache_key = get_cache_key(self.account,self.container)
cache_value = self.memcache.get(cache_key)
self.assertTrue(isinstance(cache_value, dict))
self.assertEquals(200, cache_value.get('status'))
@@ -636,8 +634,8 @@ class TestController(unittest.TestCase):
self.account, self.container, self.request)
self.check_container_info_return(ret, True)
- cache_key = get_container_memcache_key(self.account,
- self.container)
+ cache_key = get_cache_key(self.account,
+ self.container)
cache_value = self.memcache.get(cache_key)
self.assertTrue(isinstance(cache_value, dict))
self.assertEquals(404, cache_value.get('status'))
@@ -652,7 +650,7 @@ class TestController(unittest.TestCase):
self.account, self.container, self.request)
self.check_container_info_return(ret, True)
- cache_key = get_container_memcache_key(self.account,
+ cache_key = get_cache_key(self.account,
self.container)
cache_value = self.memcache.get(cache_key)
self.assertTrue(isinstance(cache_value, dict))