Example #1
0
    def test_GETorHEAD_base(self):
        base = Controller(self.app)
        req = Request.blank('/v1/a/c/o/with/slashes')
        with patch('swift.proxy.controllers.base.'
                   'http_connect', fake_http_connect(200)):
            resp = base.GETorHEAD_base(req, 'object', FakeRing(), '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', FakeRing(), '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', FakeRing(), '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', FakeRing(), 'part',
                                       '/a')
        self.assertTrue('swift.account/a' in resp.environ)
        self.assertEqual(resp.environ['swift.account/a']['status'], 200)
Example #2
0
    def setUp(self):
        # setup fake rings with handoffs
        self.obj_ring = FakeRing(max_more_nodes=3)
        for policy in POLICIES:
            policy.object_ring = self.obj_ring

        logger = debug_logger('proxy-server')
        logger.thread_locals = ('txn1', '127.0.0.2')
        self.app = PatchedObjControllerApp(None,
                                           FakeMemcache(),
                                           account_ring=FakeRing(),
                                           container_ring=FakeRing(),
                                           logger=logger)

        class FakeContainerInfoObjController(proxy_server.ObjectController):
            def container_info(controller, *args, **kwargs):
                patch_path = 'swift.proxy.controllers.base.get_info'
                with mock.patch(patch_path) as mock_get_info:
                    mock_get_info.return_value = dict(self.container_info)
                    return super(FakeContainerInfoObjController,
                                 controller).container_info(*args, **kwargs)

        # this is taking advantage of the fact that self.app is a
        # PachedObjControllerApp, so handle_response will route into an
        # instance of our FakeContainerInfoObjController just by
        # overriding the class attribute for object_controller
        self.app.object_controller = FakeContainerInfoObjController
Example #3
0
    def test_validate_ring(self):
        test_policies = [
            ECStoragePolicy(0,
                            'ec8-2',
                            ec_type='jerasure_rs_vand',
                            ec_ndata=8,
                            ec_nparity=2,
                            object_ring=FakeRing(replicas=8),
                            is_default=True),
            ECStoragePolicy(1,
                            'ec10-4',
                            ec_type='jerasure_rs_vand',
                            ec_ndata=10,
                            ec_nparity=4,
                            object_ring=FakeRing(replicas=10)),
            ECStoragePolicy(2,
                            'ec4-2',
                            ec_type='jerasure_rs_vand',
                            ec_ndata=4,
                            ec_nparity=2,
                            object_ring=FakeRing(replicas=7)),
        ]
        policies = StoragePolicyCollection(test_policies)

        for policy in policies:
            msg = 'EC ring for policy %s needs to be configured with ' \
                  'exactly %d nodes.' % \
                  (policy.name, policy.ec_ndata + policy.ec_nparity)
            self.assertRaisesWithMessage(RingValidationError, msg,
                                         policy._validate_ring)
Example #4
0
    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)
Example #5
0
    def setUp(self):
        skip_if_no_xattrs()
        self.app = proxy.Application(None,
                                     FakeMemcache(),
                                     logger=debug_logger('proxy-ut'),
                                     account_ring=FakeRing(replicas=1),
                                     container_ring=FakeRing(replicas=1))
        self.copy_app = ServerSideCopyMiddleware(self.app, {})
        monkey_patch_mimetools()
        self.tmpdir = mkdtemp()
        self.testdir = os.path.join(self.tmpdir,
                                    'tmp_test_object_server_ObjectController')
        mkdirs(os.path.join(self.testdir, 'sda', 'tmp'))
        conf = {'devices': self.testdir, 'mount_check': 'false'}
        self.obj_ctlr = object_server.ObjectController(
            conf, logger=debug_logger('obj-ut'))

        http_connect = get_http_connect(fake_http_connect(200),
                                        fake_http_connect(200),
                                        FakeServerConnection(self.obj_ctlr))

        self.orig_base_http_connect = swift.proxy.controllers.base.http_connect
        self.orig_obj_http_connect = swift.proxy.controllers.obj.http_connect
        swift.proxy.controllers.base.http_connect = http_connect
        swift.proxy.controllers.obj.http_connect = http_connect
Example #6
0
    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)
Example #7
0
 def setUp(self):
     self.app = proxy_server.Application(None,
                                         FakeMemcache(),
                                         account_ring=FakeRing(),
                                         container_ring=FakeRing(),
                                         logger=debug_logger())
     self.app.request_node_count = lambda ring: 10000000
     self.app.sort_nodes = lambda l: l  # stop shuffling the primary nodes
Example #8
0
 def setUp(self):
     self.app = proxy_server.Application(
         None,
         FakeMemcache(),
         account_ring=FakeRing(),
         container_ring=FakeRing(),
         object_ring=FakeRing(max_more_nodes=9))
     self.app.request_node_count = lambda replicas: 10000000
     self.app.sort_nodes = lambda l: l  # stop shuffling the primary nodes
Example #9
0
 def __init__(self):
     self._calls = []
     self.req_method_paths = []
     self.swift_sources = []
     self.uploaded = {}
     # mapping of (method, path) --> (response class, headers, body)
     self._responses = {}
     self.logger = FakeLogger('fake-swift')
     self.account_ring = FakeRing()
     self.container_ring = FakeRing()
     self.get_object_ring = lambda policy_index: FakeRing()
Example #10
0
 def __init__(self):
     self._calls = []
     self.req_bodies = []
     self._unclosed_req_keys = defaultdict(int)
     self._unread_req_paths = defaultdict(int)
     self.req_method_paths = []
     self.swift_sources = []
     self.txn_ids = []
     self.uploaded = {}
     # mapping of (method, path) --> (response class, headers, body)
     self._responses = {}
     self.logger = debug_logger('fake-swift')
     self.account_ring = FakeRing()
     self.container_ring = FakeRing()
     self.get_object_ring = lambda policy_index: FakeRing()
Example #11
0
    def setUp(self):
        # setup fake rings with handoffs
        self.obj_ring = FakeRing(max_more_nodes=3)
        for policy in POLICIES:
            policy.object_ring = self.obj_ring

        logger = debug_logger('proxy-server')
        logger.thread_locals = ('txn1', '127.0.0.2')
        self.app = PatchedObjControllerApp(
            None, FakeMemcache(), account_ring=FakeRing(),
            container_ring=FakeRing(), logger=logger)

        class FakeContainerInfoObjController(proxy_server.ObjectController):

            def container_info(controller, *args, **kwargs):
                patch_path = 'swift.proxy.controllers.base.get_info'
                with mock.patch(patch_path) as mock_get_info:
                    mock_get_info.return_value = dict(self.container_info)
                    return super(FakeContainerInfoObjController,
                                 controller).container_info(*args, **kwargs)

        # this is taking advantage of the fact that self.app is a
        # PachedObjControllerApp, so handle_response will route into an
        # instance of our FakeContainerInfoObjController just by
        # overriding the class attribute for object_controller
        self.app.object_controller = FakeContainerInfoObjController
Example #12
0
 def test_quorum_size_replication(self):
     expected_sizes = {1: 1,
                       2: 2,
                       3: 2,
                       4: 3,
                       5: 3}
     for n, expected in expected_sizes.items():
         policy = StoragePolicy(0, 'zero',
                                object_ring=FakeRing(replicas=n))
         self.assertEqual(policy.quorum, expected)
Example #13
0
 def setUp(self):
     logger = debug_logger('proxy-server')
     logger.thread_locals = ('txn1', '127.0.0.2')
     self.app = proxy_server.Application(None,
                                         FakeMemcache(),
                                         account_ring=FakeRing(),
                                         container_ring=FakeRing(),
                                         object_ring=FakeRing(),
                                         logger=logger)
     self.controller = proxy_server.ObjectController(
         self.app, 'a', 'c', 'o')
     self.controller.container_info = mock.MagicMock(
         return_value={
             'partition':
             1,
             'nodes': [
                 {
                     'ip': '127.0.0.1',
                     'port': '1',
                     'device': 'sda'
                 },
                 {
                     'ip': '127.0.0.1',
                     'port': '2',
                     'device': 'sda'
                 },
                 {
                     'ip': '127.0.0.1',
                     'port': '3',
                     'device': 'sda'
                 },
             ],
             'write_acl':
             None,
             'read_acl':
             None,
             'sync_key':
             None,
             'versions':
             None
         })
Example #14
0
    def setUp(self):
        # setup fake rings with handoffs
        self.obj_ring = FakeRing(max_more_nodes=3)
        for policy in POLICIES:
            policy.object_ring = self.obj_ring

        logger = debug_logger('proxy-server')
        logger.thread_locals = ('txn1', '127.0.0.2')
        self.app = PatchedObjControllerApp(None,
                                           FakeMemcache(),
                                           account_ring=FakeRing(),
                                           container_ring=FakeRing(),
                                           logger=logger)

        class FakeContainerInfoObjController(proxy_server.ObjectController):
            def container_info(controller, *args, **kwargs):
                patch_path = 'swift.proxy.controllers.base.get_info'
                with mock.patch(patch_path) as mock_get_info:
                    mock_get_info.return_value = dict(self.container_info)
                    return super(FakeContainerInfoObjController,
                                 controller).container_info(*args, **kwargs)

        self.app.object_controller = FakeContainerInfoObjController
Example #15
0
    def setUp(self):
        TestRingBase.setUp(self)
        self.logger = debug_logger()
        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(),
                                            container_ring=self.container_ring)

        self.account_info = {
            'status': 200,
            'container_count': '10',
            'total_object_count': '100',
            'bytes': '1000',
            'meta': {},
            'sysmeta': {},
        }

        class FakeAccountInfoContainerController(
                proxy_server.ContainerController):
            def account_info(controller, *args, **kwargs):
                patch_path = 'swift.proxy.controllers.base.get_info'
                with mock.patch(patch_path) as mock_get_info:
                    mock_get_info.return_value = dict(self.account_info)
                    return super(FakeAccountInfoContainerController,
                                 controller).account_info(*args, **kwargs)

        _orig_get_controller = self.app.get_controller

        def wrapped_get_controller(*args, **kwargs):
            with mock.patch('swift.proxy.server.ContainerController',
                            new=FakeAccountInfoContainerController):
                return _orig_get_controller(*args, **kwargs)

        self.app.get_controller = wrapped_get_controller
Example #16
0
class FakeInternalClient(object):
    container_ring = FakeRing()

    def __init__(self, aco_dict):
        """
        :param aco_dict: A dict of account ,container, object that
            FakeInternalClient can return when each method called. Each account
            has container name dict, and each container dict has a list of
            objects in the container.
            e.g. {'account1': {
                      'container1: ['obj1', 'obj2', {'name': 'obj3'}],
                      'container2: [],
                      },
                  'account2': {},
                 }
            N.B. the objects entries should be the container-server JSON style
            db rows, but this fake will dynamically detect when names are given
            and wrap them for convenience.
        """
        self.aco_dict = defaultdict(dict)
        self.aco_dict.update(aco_dict)

    def get_account_info(self, account):
        acc_dict = self.aco_dict[account]
        container_count = len(acc_dict)
        obj_count = sum(len(objs) for objs in acc_dict.values())
        return container_count, obj_count

    def iter_containers(self, account, prefix=''):
        acc_dict = self.aco_dict[account]
        return [{
            'name': six.text_type(container)
        } for container in sorted(acc_dict) if container.startswith(prefix)]

    def delete_container(*a, **kw):
        pass

    def iter_objects(self, account, container):
        acc_dict = self.aco_dict[account]
        obj_iter = acc_dict.get(container, [])
        resp = []
        for obj in obj_iter:
            if not isinstance(obj, dict):
                obj = {'name': six.text_type(obj)}
            resp.append(obj)
        return resp

    def delete_object(*a, **kw):
        pass
Example #17
0
        class InternalClient(object):

            container_ring = FakeRing()

            def get_account_info(*a, **kw):
                return 1, 2

            def iter_containers(*a, **kw):
                return [{'name': u'1234'}]

            def iter_objects(*a, **kw):
                return [{'name': u'1234-troms\xf8'}]

            def make_request(*a, **kw):
                pass

            def delete_container(*a, **kw):
                pass
Example #18
0
class FakeInternalClient(object):
    container_ring = FakeRing()

    def __init__(self, aco_dict):
        """
        :param aco_dict: A dict of account ,container, object that
            FakeInternalClient can return when each method called. Each account
            has container name dict, and each container dict has object name
            list in the container.
            e.g. {'account1': {
                      'container1: ['obj1', 'obj2', 'obj3'],
                      'container2: [],
                      },
                  'account2': {},
                 }
        """
        self.aco_dict = defaultdict(dict)
        self.aco_dict.update(aco_dict)

    def get_account_info(self, account):
        acc_dict = self.aco_dict[account]
        container_count = len(acc_dict)
        obj_count = sum(len(objs) for objs in acc_dict.values())
        return container_count, obj_count

    def iter_containers(self, account, prefix=''):
        acc_dict = self.aco_dict[account]
        return [{
            'name': six.text_type(container)
        } for container in acc_dict if container.startswith(prefix)]

    def delete_container(*a, **kw):
        pass

    def iter_objects(self, account, container):
        acc_dict = self.aco_dict[account]
        obj_iter = acc_dict.get(container, [])
        return [{'name': six.text_type(obj)} for obj in obj_iter]

    def make_request(*a, **kw):
        pass
Example #19
0
    def setUp(self):
        # setup fake rings with handoffs
        self.obj_ring = FakeRing(max_more_nodes=3)
        for policy in POLICIES:
            policy.object_ring = self.obj_ring

        logger = debug_logger('proxy-server')
        logger.thread_locals = ('txn1', '127.0.0.2')
        self.app = PatchedObjControllerApp(
            None, FakeMemcache(), account_ring=FakeRing(),
            container_ring=FakeRing(), logger=logger)

        class FakeContainerInfoObjController(proxy_server.ObjectController):

            def container_info(controller, *args, **kwargs):
                patch_path = 'swift.proxy.controllers.base.get_info'
                with mock.patch(patch_path) as mock_get_info:
                    mock_get_info.return_value = dict(self.container_info)
                    return super(FakeContainerInfoObjController,
                                 controller).container_info(*args, **kwargs)

        self.app.object_controller = FakeContainerInfoObjController
Example #20
0
 def setUp(self):
     self.app = proxy_server.Application(None,
                                         FakeMemcache(),
                                         account_ring=FakeRing(),
                                         container_ring=FakeRing())
Example #21
0
                       [(k, v) for k, v in response.headers.items()])
        return iter(response.body)


class FakeCache(FakeMemcache):
    def __init__(self, stub=None, **pre_cached):
        super(FakeCache, self).__init__()
        if pre_cached:
            self.store.update(pre_cached)
        self.stub = stub

    def get(self, key):
        return self.stub or self.store.get(key)


@patch_policies([StoragePolicy(0, 'zero', True, object_ring=FakeRing())])
class TestFuncs(unittest.TestCase):
    def setUp(self):
        self.app = proxy_server.Application(None,
                                            FakeMemcache(),
                                            account_ring=FakeRing(),
                                            container_ring=FakeRing())

    def test_get_info(self):
        app = FakeApp()
        # Do a non cached call to account
        env = {}
        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)
Example #22
0
    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)

        # Run the above tests again, but this time with concurrent_reads
        # turned on
        policy = next(iter(POLICIES))
        concurrent_get_threads = policy.object_ring.replica_count
        for concurrency_timeout in (0, 2):
            self.app.concurrency_timeout = concurrency_timeout
            req = Request.blank('/v1/a/c/o/with/slashes')
            # NOTE: We are using slow_connect of fake_http_connect as using
            # a concurrency of 0 when mocking the connection is a little too
            # fast for eventlet. Network i/o will make this fine, but mocking
            # it seems is too instantaneous.
            with patch('swift.proxy.controllers.base.http_connect',
                       fake_http_connect(200, slow_connect=True)):
                resp = base.GETorHEAD_base(req,
                                           'object',
                                           iter(nodes),
                                           'part',
                                           '/a/c/o/with/slashes',
                                           concurrency=concurrent_get_threads)
            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, slow_connect=True)):
                resp = base.GETorHEAD_base(req,
                                           'object',
                                           iter(nodes),
                                           'part',
                                           '/a/c/o',
                                           concurrency=concurrent_get_threads)
            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, slow_connect=True)):
                resp = base.GETorHEAD_base(req,
                                           'container',
                                           iter(nodes),
                                           'part',
                                           '/a/c',
                                           concurrency=concurrent_get_threads)
            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, slow_connect=True)):
                resp = base.GETorHEAD_base(req,
                                           'account',
                                           iter(nodes),
                                           'part',
                                           '/a',
                                           concurrency=concurrent_get_threads)
            self.assertTrue('swift.account/a' in resp.environ)
            self.assertEqual(resp.environ['swift.account/a']['status'], 200)
Example #23
0
 class InternalClient(object):
     container_ring = FakeRing()
Example #24
0
class TestObjController(unittest.TestCase):
    container_info = {
        'partition': 1,
        'nodes': [
            {'ip': '127.0.0.1', 'port': '1', 'device': 'sda'},
            {'ip': '127.0.0.1', 'port': '2', 'device': 'sda'},
            {'ip': '127.0.0.1', 'port': '3', 'device': 'sda'},
        ],
        'write_acl': None,
        'read_acl': None,
        'storage_policy': None,
        'sync_key': None,
        'versions': None,
    }

    def setUp(self):
        # setup fake rings with handoffs
        self.obj_ring = FakeRing(max_more_nodes=3)
        for policy in POLICIES:
            policy.object_ring = self.obj_ring

        logger = debug_logger('proxy-server')
        logger.thread_locals = ('txn1', '127.0.0.2')
        self.app = PatchedObjControllerApp(
            None, FakeMemcache(), account_ring=FakeRing(),
            container_ring=FakeRing(), logger=logger)

        class FakeContainerInfoObjController(proxy_server.ObjectController):

            def container_info(controller, *args, **kwargs):
                patch_path = 'swift.proxy.controllers.base.get_info'
                with mock.patch(patch_path) as mock_get_info:
                    mock_get_info.return_value = dict(self.container_info)
                    return super(FakeContainerInfoObjController,
                                 controller).container_info(*args, **kwargs)

        self.app.object_controller = FakeContainerInfoObjController

    def test_PUT_simple(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='PUT')
        req.headers['content-length'] = '0'
        with set_http_connect(201, 201, 201):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 201)

    def test_PUT_if_none_match(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='PUT')
        req.headers['if-none-match'] = '*'
        req.headers['content-length'] = '0'
        with set_http_connect(201, 201, 201):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 201)

    def test_PUT_if_none_match_denied(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='PUT')
        req.headers['if-none-match'] = '*'
        req.headers['content-length'] = '0'
        with set_http_connect(201, 412, 201):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 412)

    def test_PUT_if_none_match_not_star(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='PUT')
        req.headers['if-none-match'] = 'somethingelse'
        req.headers['content-length'] = '0'
        with set_http_connect():
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 400)

    def test_GET_simple(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o')
        with set_http_connect(200):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 200)

    def test_GET_error(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o')
        with set_http_connect(503, 200):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 200)

    def test_GET_handoff(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o')
        codes = [503] * self.obj_ring.replicas + [200]
        with set_http_connect(*codes):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 200)

    def test_GET_not_found(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o')
        codes = [404] * (self.obj_ring.replicas +
                         self.obj_ring.max_more_nodes)
        with set_http_connect(*codes):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 404)

    def test_DELETE_simple(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='DELETE')
        with set_http_connect(204, 204, 204):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 204)

    def test_DELETE_missing_one(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='DELETE')
        with set_http_connect(404, 204, 204):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 204)

    def test_DELETE_half_not_found_statuses(self):
        self.obj_ring.set_replicas(4)

        req = swift.common.swob.Request.blank('/v1/a/c/o', method='DELETE')
        with set_http_connect(404, 204, 404, 204):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 204)

    def test_DELETE_half_not_found_headers_and_body(self):
        # Transformed responses have bogus bodies and headers, so make sure we
        # send the client headers and body from a real node's response.
        self.obj_ring.set_replicas(4)

        status_codes = (404, 404, 204, 204)
        bodies = ('not found', 'not found', '', '')
        headers = [{}, {}, {'Pick-Me': 'yes'}, {'Pick-Me': 'yes'}]

        req = swift.common.swob.Request.blank('/v1/a/c/o', method='DELETE')
        with set_http_connect(*status_codes, body_iter=bodies,
                              headers=headers):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 204)
        self.assertEquals(resp.headers.get('Pick-Me'), 'yes')
        self.assertEquals(resp.body, '')

    def test_DELETE_not_found(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='DELETE')
        with set_http_connect(404, 404, 204):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 404)

    def test_DELETE_handoff(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='DELETE')
        codes = [204] * self.obj_ring.replicas
        with set_http_connect(507, *codes):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 204)

    def test_POST_as_COPY_simple(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='POST')
        head_resp = [200] * self.obj_ring.replicas + \
            [404] * self.obj_ring.max_more_nodes
        put_resp = [201] * self.obj_ring.replicas
        codes = head_resp + put_resp
        with set_http_connect(*codes):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 202)

    def test_POST_delete_at(self):
        t = str(int(time.time() + 100))
        req = swob.Request.blank('/v1/a/c/o', method='POST',
                                 headers={'Content-Type': 'foo/bar',
                                          'X-Delete-At': t})
        post_headers = []

        def capture_headers(ip, port, device, part, method, path, headers,
                            **kwargs):
            if method == 'POST':
                post_headers.append(headers)
        x_newest_responses = [200] * self.obj_ring.replicas + \
            [404] * self.obj_ring.max_more_nodes
        post_resp = [200] * self.obj_ring.replicas
        codes = x_newest_responses + post_resp
        with set_http_connect(*codes, give_connect=capture_headers):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 200)
        for given_headers in post_headers:
            self.assertEquals(given_headers.get('X-Delete-At'), t)
            self.assertTrue('X-Delete-At-Host' in given_headers)
            self.assertTrue('X-Delete-At-Device' in given_headers)
            self.assertTrue('X-Delete-At-Partition' in given_headers)
            self.assertTrue('X-Delete-At-Container' in given_headers)

    def test_POST_non_int_delete_after(self):
        t = str(int(time.time() + 100)) + '.1'
        req = swob.Request.blank('/v1/a/c/o', method='POST',
                                 headers={'Content-Type': 'foo/bar',
                                          'X-Delete-After': t})
        resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 400)
        self.assertEqual('Non-integer X-Delete-After', resp.body)

    def test_POST_negative_delete_after(self):
        req = swob.Request.blank('/v1/a/c/o', method='POST',
                                 headers={'Content-Type': 'foo/bar',
                                          'X-Delete-After': '-60'})
        resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 400)
        self.assertEqual('X-Delete-After in past', resp.body)

    def test_POST_delete_at_non_integer(self):
        t = str(int(time.time() + 100)) + '.1'
        req = swob.Request.blank('/v1/a/c/o', method='POST',
                                 headers={'Content-Type': 'foo/bar',
                                          'X-Delete-At': t})
        resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 400)
        self.assertEqual('Non-integer X-Delete-At', resp.body)

    def test_POST_delete_at_in_past(self):
        t = str(int(time.time() - 100))
        req = swob.Request.blank('/v1/a/c/o', method='POST',
                                 headers={'Content-Type': 'foo/bar',
                                          'X-Delete-At': t})
        resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 400)
        self.assertEqual('X-Delete-At in past', resp.body)

    def test_PUT_converts_delete_after_to_delete_at(self):
        req = swob.Request.blank('/v1/a/c/o', method='PUT', body='',
                                 headers={'Content-Type': 'foo/bar',
                                          'X-Delete-After': '60'})
        put_headers = []

        def capture_headers(ip, port, device, part, method, path, headers,
                            **kwargs):
            if method == 'PUT':
                put_headers.append(headers)
        codes = [201] * self.obj_ring.replicas
        t = time.time()
        with set_http_connect(*codes, give_connect=capture_headers):
            with mock.patch('time.time', lambda: t):
                resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 201)
        expected_delete_at = str(int(t) + 60)
        for given_headers in put_headers:
            self.assertEquals(given_headers.get('X-Delete-At'),
                              expected_delete_at)
            self.assertTrue('X-Delete-At-Host' in given_headers)
            self.assertTrue('X-Delete-At-Device' in given_headers)
            self.assertTrue('X-Delete-At-Partition' in given_headers)
            self.assertTrue('X-Delete-At-Container' in given_headers)

    def test_PUT_non_int_delete_after(self):
        t = str(int(time.time() + 100)) + '.1'
        req = swob.Request.blank('/v1/a/c/o', method='PUT', body='',
                                 headers={'Content-Type': 'foo/bar',
                                          'X-Delete-After': t})
        with set_http_connect():
            resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 400)
        self.assertEqual('Non-integer X-Delete-After', resp.body)

    def test_PUT_negative_delete_after(self):
        req = swob.Request.blank('/v1/a/c/o', method='PUT', body='',
                                 headers={'Content-Type': 'foo/bar',
                                          'X-Delete-After': '-60'})
        with set_http_connect():
            resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 400)
        self.assertEqual('X-Delete-After in past', resp.body)

    def test_PUT_delete_at(self):
        t = str(int(time.time() + 100))
        req = swob.Request.blank('/v1/a/c/o', method='PUT', body='',
                                 headers={'Content-Type': 'foo/bar',
                                          'X-Delete-At': t})
        put_headers = []

        def capture_headers(ip, port, device, part, method, path, headers,
                            **kwargs):
            if method == 'PUT':
                put_headers.append(headers)
        codes = [201] * self.obj_ring.replicas
        with set_http_connect(*codes, give_connect=capture_headers):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 201)
        for given_headers in put_headers:
            self.assertEquals(given_headers.get('X-Delete-At'), t)
            self.assertTrue('X-Delete-At-Host' in given_headers)
            self.assertTrue('X-Delete-At-Device' in given_headers)
            self.assertTrue('X-Delete-At-Partition' in given_headers)
            self.assertTrue('X-Delete-At-Container' in given_headers)

    def test_PUT_delete_at_non_integer(self):
        t = str(int(time.time() - 100)) + '.1'
        req = swob.Request.blank('/v1/a/c/o', method='PUT', body='',
                                 headers={'Content-Type': 'foo/bar',
                                          'X-Delete-At': t})
        with set_http_connect():
            resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 400)
        self.assertEqual('Non-integer X-Delete-At', resp.body)

    def test_PUT_delete_at_in_past(self):
        t = str(int(time.time() - 100))
        req = swob.Request.blank('/v1/a/c/o', method='PUT', body='',
                                 headers={'Content-Type': 'foo/bar',
                                          'X-Delete-At': t})
        with set_http_connect():
            resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 400)
        self.assertEqual('X-Delete-At in past', resp.body)

    def test_container_sync_put_x_timestamp_not_found(self):
        test_indexes = [None] + [int(p) for p in POLICIES]
        for policy_index in test_indexes:
            self.container_info['storage_policy'] = policy_index
            put_timestamp = utils.Timestamp(time.time()).normal
            req = swob.Request.blank(
                '/v1/a/c/o', method='PUT', headers={
                    'Content-Length': 0,
                    'X-Timestamp': put_timestamp})
            ts_iter = itertools.repeat(put_timestamp)
            head_resp = [404] * self.obj_ring.replicas + \
                [404] * self.obj_ring.max_more_nodes
            put_resp = [201] * self.obj_ring.replicas
            codes = head_resp + put_resp
            with set_http_connect(*codes, timestamps=ts_iter):
                resp = req.get_response(self.app)
            self.assertEqual(resp.status_int, 201)

    def test_container_sync_put_x_timestamp_match(self):
        test_indexes = [None] + [int(p) for p in POLICIES]
        for policy_index in test_indexes:
            self.container_info['storage_policy'] = policy_index
            put_timestamp = utils.Timestamp(time.time()).normal
            req = swob.Request.blank(
                '/v1/a/c/o', method='PUT', headers={
                    'Content-Length': 0,
                    'X-Timestamp': put_timestamp})
            ts_iter = itertools.repeat(put_timestamp)
            head_resp = [200] * self.obj_ring.replicas + \
                [404] * self.obj_ring.max_more_nodes
            codes = head_resp
            with set_http_connect(*codes, timestamps=ts_iter):
                resp = req.get_response(self.app)
            self.assertEqual(resp.status_int, 202)

    def test_container_sync_put_x_timestamp_older(self):
        ts = (utils.Timestamp(t) for t in itertools.count(int(time.time())))
        test_indexes = [None] + [int(p) for p in POLICIES]
        for policy_index in test_indexes:
            self.container_info['storage_policy'] = policy_index
            req = swob.Request.blank(
                '/v1/a/c/o', method='PUT', headers={
                    'Content-Length': 0,
                    'X-Timestamp': ts.next().internal})
            ts_iter = itertools.repeat(ts.next().internal)
            head_resp = [200] * self.obj_ring.replicas + \
                [404] * self.obj_ring.max_more_nodes
            codes = head_resp
            with set_http_connect(*codes, timestamps=ts_iter):
                resp = req.get_response(self.app)
            self.assertEqual(resp.status_int, 202)

    def test_container_sync_put_x_timestamp_newer(self):
        ts = (utils.Timestamp(t) for t in itertools.count(int(time.time())))
        test_indexes = [None] + [int(p) for p in POLICIES]
        for policy_index in test_indexes:
            orig_timestamp = ts.next().internal
            req = swob.Request.blank(
                '/v1/a/c/o', method='PUT', headers={
                    'Content-Length': 0,
                    'X-Timestamp': ts.next().internal})
            ts_iter = itertools.repeat(orig_timestamp)
            head_resp = [200] * self.obj_ring.replicas + \
                [404] * self.obj_ring.max_more_nodes
            put_resp = [201] * self.obj_ring.replicas
            codes = head_resp + put_resp
            with set_http_connect(*codes, timestamps=ts_iter):
                resp = req.get_response(self.app)
            self.assertEqual(resp.status_int, 201)

    def test_container_sync_delete(self):
        ts = (utils.Timestamp(t) for t in itertools.count(int(time.time())))
        test_indexes = [None] + [int(p) for p in POLICIES]
        for policy_index in test_indexes:
            req = swob.Request.blank(
                '/v1/a/c/o', method='DELETE', headers={
                    'X-Timestamp': ts.next().internal})
            codes = [409] * self.obj_ring.replicas
            ts_iter = itertools.repeat(ts.next().internal)
            with set_http_connect(*codes, timestamps=ts_iter):
                resp = req.get_response(self.app)
            self.assertEqual(resp.status_int, 409)

    def test_put_x_timestamp_conflict(self):
        ts = (utils.Timestamp(t) for t in itertools.count(int(time.time())))
        req = swob.Request.blank(
            '/v1/a/c/o', method='PUT', headers={
                'Content-Length': 0,
                'X-Timestamp': ts.next().internal})
        head_resp = [404] * self.obj_ring.replicas + \
            [404] * self.obj_ring.max_more_nodes
        put_resp = [409] + [201] * self.obj_ring.replicas
        codes = head_resp + put_resp
        with set_http_connect(*codes):
            resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 201)

    def test_COPY_simple(self):
        req = swift.common.swob.Request.blank(
            '/v1/a/c/o', method='COPY',
            headers={'Content-Length': 0,
                     'Destination': 'c/o-copy'})
        head_resp = [200] * self.obj_ring.replicas + \
            [404] * self.obj_ring.max_more_nodes
        put_resp = [201] * self.obj_ring.replicas
        codes = head_resp + put_resp
        with set_http_connect(*codes):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 201)

    def test_HEAD_simple(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='HEAD')
        with set_http_connect(200):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 200)

    def test_HEAD_x_newest(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='HEAD',
                                              headers={'X-Newest': 'true'})
        with set_http_connect(200, 200, 200):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 200)

    def test_PUT_log_info(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='PUT')
        req.headers['x-copy-from'] = 'some/where'
        req.headers['Content-Length'] = 0
        # override FakeConn default resp headers to keep log_info clean
        resp_headers = {'x-delete-at': None}
        head_resp = [200] * self.obj_ring.replicas + \
            [404] * self.obj_ring.max_more_nodes
        put_resp = [201] * self.obj_ring.replicas
        codes = head_resp + put_resp
        with set_http_connect(*codes, headers=resp_headers):
            resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 201)
        self.assertEquals(
            req.environ.get('swift.log_info'), ['x-copy-from:some/where'])
        # and then check that we don't do that for originating POSTs
        req = swift.common.swob.Request.blank('/v1/a/c/o')
        req.method = 'POST'
        req.headers['x-copy-from'] = 'else/where'
        with set_http_connect(*codes, headers=resp_headers):
            resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 202)
        self.assertEquals(req.environ.get('swift.log_info'), None)
Example #25
0
            func = account_func
        resp = func(ipaddr,
                    port,
                    device,
                    partition,
                    method,
                    path,
                    headers=headers,
                    query_string=query_string)
        return resp

    return http_connect


@patch_policies(
    [StoragePolicy(0, 'zero', True, object_ring=FakeRing(replicas=1))])
class TestObjectSysmeta(unittest.TestCase):
    '''Tests object sysmeta is correctly handled by combination
    of proxy server and object server.
    '''
    def _assertStatus(self, resp, expected):
        self.assertEqual(resp.status_int, expected,
                         'Expected %d, got %s' % (expected, resp.status))

    def _assertInHeaders(self, resp, expected):
        for key, val in expected.items():
            self.assertTrue(key in resp.headers,
                            'Header %s missing from %s' % (key, resp.headers))
            self.assertEqual(
                val, resp.headers[key], 'Expected header %s:%s, got %s:%s' %
                (key, val, key, resp.headers[key]))
Example #26
0
 def setUp(self):
     self.app = proxy_server.Application(
         None,
         account_ring=FakeRing(replicas=4),
         container_ring=FakeRing(replicas=4))
Example #27
0
    """
    This patch is just a hook over handle_request to ensure that when
    get_controller is called the ObjectController class is patched to
    return a (possibly stubbed) ObjectController class.
    """

    object_controller = proxy_server.ObjectController

    def handle_request(self, req):
        with mock.patch('swift.proxy.server.ObjectController',
                        new=self.object_controller):
            return super(PatchedObjControllerApp, self).handle_request(req)


@patch_policies([StoragePolicy(0, 'zero', True,
                               object_ring=FakeRing(max_more_nodes=9))])
class TestObjControllerWriteAffinity(unittest.TestCase):
    def setUp(self):
        self.app = proxy_server.Application(
            None, FakeMemcache(), account_ring=FakeRing(),
            container_ring=FakeRing(), logger=debug_logger())
        self.app.request_node_count = lambda ring: 10000000
        self.app.sort_nodes = lambda l: l  # stop shuffling the primary nodes

    def test_iter_nodes_local_first_noops_when_no_affinity(self):
        controller = proxy_server.ObjectController(self.app, 'a', 'c', 'o')
        self.app.write_affinity_is_local_fn = None
        object_ring = self.app.get_object_ring(None)
        all_nodes = object_ring.get_part_nodes(1)
        all_nodes.extend(object_ring.get_more_nodes(1))
Example #28
0
class TestObjController(unittest.TestCase):
    container_info = {
        'partition':
        1,
        'nodes': [
            {
                'ip': '127.0.0.1',
                'port': '1',
                'device': 'sda'
            },
            {
                'ip': '127.0.0.1',
                'port': '2',
                'device': 'sda'
            },
            {
                'ip': '127.0.0.1',
                'port': '3',
                'device': 'sda'
            },
        ],
        'write_acl':
        None,
        'read_acl':
        None,
        'storage_policy':
        None,
        'sync_key':
        None,
        'versions':
        None,
    }

    def setUp(self):
        # setup fake rings with handoffs
        self.obj_ring = FakeRing(max_more_nodes=3)
        for policy in POLICIES:
            policy.object_ring = self.obj_ring

        logger = debug_logger('proxy-server')
        logger.thread_locals = ('txn1', '127.0.0.2')
        self.app = PatchedObjControllerApp(None,
                                           FakeMemcache(),
                                           account_ring=FakeRing(),
                                           container_ring=FakeRing(),
                                           logger=logger)

        class FakeContainerInfoObjController(proxy_server.ObjectController):
            def container_info(controller, *args, **kwargs):
                patch_path = 'swift.proxy.controllers.base.get_info'
                with mock.patch(patch_path) as mock_get_info:
                    mock_get_info.return_value = dict(self.container_info)
                    return super(FakeContainerInfoObjController,
                                 controller).container_info(*args, **kwargs)

        self.app.object_controller = FakeContainerInfoObjController

    def test_PUT_simple(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='PUT')
        req.headers['content-length'] = '0'
        with set_http_connect(201, 201, 201):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 201)

    def test_PUT_if_none_match(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='PUT')
        req.headers['if-none-match'] = '*'
        req.headers['content-length'] = '0'
        with set_http_connect(201, 201, 201):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 201)

    def test_PUT_if_none_match_denied(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='PUT')
        req.headers['if-none-match'] = '*'
        req.headers['content-length'] = '0'
        with set_http_connect(201, 412, 201):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 412)

    def test_PUT_if_none_match_not_star(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='PUT')
        req.headers['if-none-match'] = 'somethingelse'
        req.headers['content-length'] = '0'
        with set_http_connect():
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 400)

    def test_GET_simple(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o')
        with set_http_connect(200):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 200)

    def test_GET_error(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o')
        with set_http_connect(503, 200):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 200)

    def test_GET_handoff(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o')
        codes = [503] * self.obj_ring.replicas + [200]
        with set_http_connect(*codes):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 200)

    def test_GET_not_found(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o')
        codes = [404] * (self.obj_ring.replicas + self.obj_ring.max_more_nodes)
        with set_http_connect(*codes):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 404)

    def test_DELETE_simple(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='DELETE')
        with set_http_connect(204, 204, 204):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 204)

    def test_DELETE_missing_one(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='DELETE')
        with set_http_connect(404, 204, 204):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 204)

    def test_DELETE_half_not_found_statuses(self):
        self.obj_ring.set_replicas(4)

        req = swift.common.swob.Request.blank('/v1/a/c/o', method='DELETE')
        with set_http_connect(404, 204, 404, 204):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 204)

    def test_DELETE_half_not_found_headers_and_body(self):
        # Transformed responses have bogus bodies and headers, so make sure we
        # send the client headers and body from a real node's response.
        self.obj_ring.set_replicas(4)

        status_codes = (404, 404, 204, 204)
        bodies = ('not found', 'not found', '', '')
        headers = [{}, {}, {'Pick-Me': 'yes'}, {'Pick-Me': 'yes'}]

        req = swift.common.swob.Request.blank('/v1/a/c/o', method='DELETE')
        with set_http_connect(*status_codes, body_iter=bodies,
                              headers=headers):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 204)
        self.assertEquals(resp.headers.get('Pick-Me'), 'yes')
        self.assertEquals(resp.body, '')

    def test_DELETE_not_found(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='DELETE')
        with set_http_connect(404, 404, 204):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 404)

    def test_DELETE_handoff(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='DELETE')
        codes = [204] * self.obj_ring.replicas
        with set_http_connect(507, *codes):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 204)

    def test_POST_as_COPY_simple(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='POST')
        head_resp = [200] * self.obj_ring.replicas + \
            [404] * self.obj_ring.max_more_nodes
        put_resp = [201] * self.obj_ring.replicas
        codes = head_resp + put_resp
        with set_http_connect(*codes):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 202)

    def test_POST_delete_at(self):
        t = str(int(time.time() + 100))
        req = swob.Request.blank('/v1/a/c/o',
                                 method='POST',
                                 headers={
                                     'Content-Type': 'foo/bar',
                                     'X-Delete-At': t
                                 })
        post_headers = []

        def capture_headers(ip, port, device, part, method, path, headers,
                            **kwargs):
            if method == 'POST':
                post_headers.append(headers)
        x_newest_responses = [200] * self.obj_ring.replicas + \
            [404] * self.obj_ring.max_more_nodes
        post_resp = [200] * self.obj_ring.replicas
        codes = x_newest_responses + post_resp
        with set_http_connect(*codes, give_connect=capture_headers):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 200)
        for given_headers in post_headers:
            self.assertEquals(given_headers.get('X-Delete-At'), t)
            self.assertTrue('X-Delete-At-Host' in given_headers)
            self.assertTrue('X-Delete-At-Device' in given_headers)
            self.assertTrue('X-Delete-At-Partition' in given_headers)
            self.assertTrue('X-Delete-At-Container' in given_headers)

    def test_POST_non_int_delete_after(self):
        t = str(int(time.time() + 100)) + '.1'
        req = swob.Request.blank('/v1/a/c/o',
                                 method='POST',
                                 headers={
                                     'Content-Type': 'foo/bar',
                                     'X-Delete-After': t
                                 })
        resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 400)
        self.assertEqual('Non-integer X-Delete-After', resp.body)

    def test_POST_negative_delete_after(self):
        req = swob.Request.blank('/v1/a/c/o',
                                 method='POST',
                                 headers={
                                     'Content-Type': 'foo/bar',
                                     'X-Delete-After': '-60'
                                 })
        resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 400)
        self.assertEqual('X-Delete-After in past', resp.body)

    def test_POST_delete_at_non_integer(self):
        t = str(int(time.time() + 100)) + '.1'
        req = swob.Request.blank('/v1/a/c/o',
                                 method='POST',
                                 headers={
                                     'Content-Type': 'foo/bar',
                                     'X-Delete-At': t
                                 })
        resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 400)
        self.assertEqual('Non-integer X-Delete-At', resp.body)

    def test_POST_delete_at_in_past(self):
        t = str(int(time.time() - 100))
        req = swob.Request.blank('/v1/a/c/o',
                                 method='POST',
                                 headers={
                                     'Content-Type': 'foo/bar',
                                     'X-Delete-At': t
                                 })
        resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 400)
        self.assertEqual('X-Delete-At in past', resp.body)

    def test_PUT_converts_delete_after_to_delete_at(self):
        req = swob.Request.blank('/v1/a/c/o',
                                 method='PUT',
                                 body='',
                                 headers={
                                     'Content-Type': 'foo/bar',
                                     'X-Delete-After': '60'
                                 })
        put_headers = []

        def capture_headers(ip, port, device, part, method, path, headers,
                            **kwargs):
            if method == 'PUT':
                put_headers.append(headers)

        codes = [201] * self.obj_ring.replicas
        t = time.time()
        with set_http_connect(*codes, give_connect=capture_headers):
            with mock.patch('time.time', lambda: t):
                resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 201)
        expected_delete_at = str(int(t) + 60)
        for given_headers in put_headers:
            self.assertEquals(given_headers.get('X-Delete-At'),
                              expected_delete_at)
            self.assertTrue('X-Delete-At-Host' in given_headers)
            self.assertTrue('X-Delete-At-Device' in given_headers)
            self.assertTrue('X-Delete-At-Partition' in given_headers)
            self.assertTrue('X-Delete-At-Container' in given_headers)

    def test_PUT_non_int_delete_after(self):
        t = str(int(time.time() + 100)) + '.1'
        req = swob.Request.blank('/v1/a/c/o',
                                 method='PUT',
                                 body='',
                                 headers={
                                     'Content-Type': 'foo/bar',
                                     'X-Delete-After': t
                                 })
        with set_http_connect():
            resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 400)
        self.assertEqual('Non-integer X-Delete-After', resp.body)

    def test_PUT_negative_delete_after(self):
        req = swob.Request.blank('/v1/a/c/o',
                                 method='PUT',
                                 body='',
                                 headers={
                                     'Content-Type': 'foo/bar',
                                     'X-Delete-After': '-60'
                                 })
        with set_http_connect():
            resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 400)
        self.assertEqual('X-Delete-After in past', resp.body)

    def test_PUT_delete_at(self):
        t = str(int(time.time() + 100))
        req = swob.Request.blank('/v1/a/c/o',
                                 method='PUT',
                                 body='',
                                 headers={
                                     'Content-Type': 'foo/bar',
                                     'X-Delete-At': t
                                 })
        put_headers = []

        def capture_headers(ip, port, device, part, method, path, headers,
                            **kwargs):
            if method == 'PUT':
                put_headers.append(headers)

        codes = [201] * self.obj_ring.replicas
        with set_http_connect(*codes, give_connect=capture_headers):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 201)
        for given_headers in put_headers:
            self.assertEquals(given_headers.get('X-Delete-At'), t)
            self.assertTrue('X-Delete-At-Host' in given_headers)
            self.assertTrue('X-Delete-At-Device' in given_headers)
            self.assertTrue('X-Delete-At-Partition' in given_headers)
            self.assertTrue('X-Delete-At-Container' in given_headers)

    def test_PUT_delete_at_non_integer(self):
        t = str(int(time.time() - 100)) + '.1'
        req = swob.Request.blank('/v1/a/c/o',
                                 method='PUT',
                                 body='',
                                 headers={
                                     'Content-Type': 'foo/bar',
                                     'X-Delete-At': t
                                 })
        with set_http_connect():
            resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 400)
        self.assertEqual('Non-integer X-Delete-At', resp.body)

    def test_PUT_delete_at_in_past(self):
        t = str(int(time.time() - 100))
        req = swob.Request.blank('/v1/a/c/o',
                                 method='PUT',
                                 body='',
                                 headers={
                                     'Content-Type': 'foo/bar',
                                     'X-Delete-At': t
                                 })
        with set_http_connect():
            resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 400)
        self.assertEqual('X-Delete-At in past', resp.body)

    def test_container_sync_put_x_timestamp_not_found(self):
        test_indexes = [None] + [int(p) for p in POLICIES]
        for policy_index in test_indexes:
            self.container_info['storage_policy'] = policy_index
            put_timestamp = utils.Timestamp(time.time()).normal
            req = swob.Request.blank('/v1/a/c/o',
                                     method='PUT',
                                     headers={
                                         'Content-Length': 0,
                                         'X-Timestamp': put_timestamp
                                     })
            ts_iter = itertools.repeat(put_timestamp)
            head_resp = [404] * self.obj_ring.replicas + \
                [404] * self.obj_ring.max_more_nodes
            put_resp = [201] * self.obj_ring.replicas
            codes = head_resp + put_resp
            with set_http_connect(*codes, timestamps=ts_iter):
                resp = req.get_response(self.app)
            self.assertEqual(resp.status_int, 201)

    def test_container_sync_put_x_timestamp_match(self):
        test_indexes = [None] + [int(p) for p in POLICIES]
        for policy_index in test_indexes:
            self.container_info['storage_policy'] = policy_index
            put_timestamp = utils.Timestamp(time.time()).normal
            req = swob.Request.blank('/v1/a/c/o',
                                     method='PUT',
                                     headers={
                                         'Content-Length': 0,
                                         'X-Timestamp': put_timestamp
                                     })
            ts_iter = itertools.repeat(put_timestamp)
            head_resp = [200] * self.obj_ring.replicas + \
                [404] * self.obj_ring.max_more_nodes
            codes = head_resp
            with set_http_connect(*codes, timestamps=ts_iter):
                resp = req.get_response(self.app)
            self.assertEqual(resp.status_int, 202)

    def test_container_sync_put_x_timestamp_older(self):
        ts = (utils.Timestamp(t) for t in itertools.count(int(time.time())))
        test_indexes = [None] + [int(p) for p in POLICIES]
        for policy_index in test_indexes:
            self.container_info['storage_policy'] = policy_index
            req = swob.Request.blank('/v1/a/c/o',
                                     method='PUT',
                                     headers={
                                         'Content-Length': 0,
                                         'X-Timestamp': ts.next().internal
                                     })
            ts_iter = itertools.repeat(ts.next().internal)
            head_resp = [200] * self.obj_ring.replicas + \
                [404] * self.obj_ring.max_more_nodes
            codes = head_resp
            with set_http_connect(*codes, timestamps=ts_iter):
                resp = req.get_response(self.app)
            self.assertEqual(resp.status_int, 202)

    def test_container_sync_put_x_timestamp_newer(self):
        ts = (utils.Timestamp(t) for t in itertools.count(int(time.time())))
        test_indexes = [None] + [int(p) for p in POLICIES]
        for policy_index in test_indexes:
            orig_timestamp = ts.next().internal
            req = swob.Request.blank('/v1/a/c/o',
                                     method='PUT',
                                     headers={
                                         'Content-Length': 0,
                                         'X-Timestamp': ts.next().internal
                                     })
            ts_iter = itertools.repeat(orig_timestamp)
            head_resp = [200] * self.obj_ring.replicas + \
                [404] * self.obj_ring.max_more_nodes
            put_resp = [201] * self.obj_ring.replicas
            codes = head_resp + put_resp
            with set_http_connect(*codes, timestamps=ts_iter):
                resp = req.get_response(self.app)
            self.assertEqual(resp.status_int, 201)

    def test_container_sync_delete(self):
        ts = (utils.Timestamp(t) for t in itertools.count(int(time.time())))
        test_indexes = [None] + [int(p) for p in POLICIES]
        for policy_index in test_indexes:
            req = swob.Request.blank(
                '/v1/a/c/o',
                method='DELETE',
                headers={'X-Timestamp': ts.next().internal})
            codes = [409] * self.obj_ring.replicas
            ts_iter = itertools.repeat(ts.next().internal)
            with set_http_connect(*codes, timestamps=ts_iter):
                resp = req.get_response(self.app)
            self.assertEqual(resp.status_int, 409)

    def test_put_x_timestamp_conflict(self):
        ts = (utils.Timestamp(t) for t in itertools.count(int(time.time())))
        req = swob.Request.blank('/v1/a/c/o',
                                 method='PUT',
                                 headers={
                                     'Content-Length': 0,
                                     'X-Timestamp': ts.next().internal
                                 })
        head_resp = [404] * self.obj_ring.replicas + \
            [404] * self.obj_ring.max_more_nodes
        put_resp = [409] + [201] * self.obj_ring.replicas
        codes = head_resp + put_resp
        with set_http_connect(*codes):
            resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 201)

    def test_COPY_simple(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o',
                                              method='COPY',
                                              headers={
                                                  'Content-Length': 0,
                                                  'Destination': 'c/o-copy'
                                              })
        head_resp = [200] * self.obj_ring.replicas + \
            [404] * self.obj_ring.max_more_nodes
        put_resp = [201] * self.obj_ring.replicas
        codes = head_resp + put_resp
        with set_http_connect(*codes):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 201)

    def test_HEAD_simple(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='HEAD')
        with set_http_connect(200):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 200)

    def test_HEAD_x_newest(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o',
                                              method='HEAD',
                                              headers={'X-Newest': 'true'})
        with set_http_connect(200, 200, 200):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 200)

    def test_PUT_log_info(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='PUT')
        req.headers['x-copy-from'] = 'some/where'
        req.headers['Content-Length'] = 0
        # override FakeConn default resp headers to keep log_info clean
        resp_headers = {'x-delete-at': None}
        head_resp = [200] * self.obj_ring.replicas + \
            [404] * self.obj_ring.max_more_nodes
        put_resp = [201] * self.obj_ring.replicas
        codes = head_resp + put_resp
        with set_http_connect(*codes, headers=resp_headers):
            resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 201)
        self.assertEquals(req.environ.get('swift.log_info'),
                          ['x-copy-from:some/where'])
        # and then check that we don't do that for originating POSTs
        req = swift.common.swob.Request.blank('/v1/a/c/o')
        req.method = 'POST'
        req.headers['x-copy-from'] = 'else/where'
        with set_http_connect(*codes, headers=resp_headers):
            resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 202)
        self.assertEquals(req.environ.get('swift.log_info'), None)
Example #29
0
        a, c, o = split_path(path, 1, 3, True)
        if o:
            func = object_func
        elif c:
            func = container_func
        else:
            func = account_func
        resp = func(ipaddr, port, device, partition, method, path,
                    headers=headers, query_string=query_string)
        return resp

    return http_connect


@patch_policies([StoragePolicy(0, 'zero', True,
                               object_ring=FakeRing(replicas=1))])
class TestObjectSysmeta(unittest.TestCase):
    '''Tests object sysmeta is correctly handled by combination
    of proxy server and object server.
    '''
    def _assertStatus(self, resp, expected):
        self.assertEqual(resp.status_int, expected,
                         'Expected %d, got %s'
                         % (expected, resp.status))

    def _assertInHeaders(self, resp, expected):
        for key, val in expected.iteritems():
            self.assertTrue(key in resp.headers,
                            'Header %s missing from %s' % (key, resp.headers))
            self.assertEqual(val, resp.headers[key],
                             'Expected header %s:%s, got %s:%s'
Example #30
0
    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)

        # Run the above tests again, but this time with concurrent_reads
        # turned on
        policy = next(iter(POLICIES))
        concurrent_get_threads = policy.object_ring.replica_count
        for concurrency_timeout in (0, 2):
            self.app.concurrency_timeout = concurrency_timeout
            req = Request.blank('/v1/a/c/o/with/slashes')
            # NOTE: We are using slow_connect of fake_http_connect as using
            # a concurrency of 0 when mocking the connection is a little too
            # fast for eventlet. Network i/o will make this fine, but mocking
            # it seems is too instantaneous.
            with patch('swift.proxy.controllers.base.http_connect',
                       fake_http_connect(200, slow_connect=True)):
                resp = base.GETorHEAD_base(
                    req, 'object', iter(nodes), 'part', '/a/c/o/with/slashes',
                    concurrency=concurrent_get_threads)
            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, slow_connect=True)):
                resp = base.GETorHEAD_base(
                    req, 'object', iter(nodes), 'part', '/a/c/o',
                    concurrency=concurrent_get_threads)
            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, slow_connect=True)):
                resp = base.GETorHEAD_base(
                    req, 'container', iter(nodes), 'part', '/a/c',
                    concurrency=concurrent_get_threads)
            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, slow_connect=True)):
                resp = base.GETorHEAD_base(
                    req, 'account', iter(nodes), 'part', '/a',
                    concurrency=concurrent_get_threads)
            self.assertTrue('swift.account/a' in resp.environ)
            self.assertEqual(resp.environ['swift.account/a']['status'], 200)
Example #31
0
class TestObjController(unittest.TestCase):
    container_info = {
        'partition': 1,
        'nodes': [
            {'ip': '127.0.0.1', 'port': '1', 'device': 'sda'},
            {'ip': '127.0.0.1', 'port': '2', 'device': 'sda'},
            {'ip': '127.0.0.1', 'port': '3', 'device': 'sda'},
        ],
        'write_acl': None,
        'read_acl': None,
        'storage_policy': None,
        'sync_key': None,
        'versions': None,
    }

    def setUp(self):
        # setup fake rings with handoffs
        self.obj_ring = FakeRing(max_more_nodes=3)
        for policy in POLICIES:
            policy.object_ring = self.obj_ring

        logger = debug_logger('proxy-server')
        logger.thread_locals = ('txn1', '127.0.0.2')
        self.app = PatchedObjControllerApp(
            None, FakeMemcache(), account_ring=FakeRing(),
            container_ring=FakeRing(), logger=logger)

        class FakeContainerInfoObjController(proxy_server.ObjectController):

            def container_info(controller, *args, **kwargs):
                patch_path = 'swift.proxy.controllers.base.get_info'
                with mock.patch(patch_path) as mock_get_info:
                    mock_get_info.return_value = dict(self.container_info)
                    return super(FakeContainerInfoObjController,
                                 controller).container_info(*args, **kwargs)

        # this is taking advantage of the fact that self.app is a
        # PachedObjControllerApp, so handle_response will route into an
        # instance of our FakeContainerInfoObjController just by
        # overriding the class attribute for object_controller
        self.app.object_controller = FakeContainerInfoObjController

    def test_PUT_simple(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='PUT')
        req.headers['content-length'] = '0'
        with set_http_connect(201, 201, 201):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 201)

    def test_PUT_if_none_match(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='PUT')
        req.headers['if-none-match'] = '*'
        req.headers['content-length'] = '0'
        with set_http_connect(201, 201, 201):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 201)

    def test_PUT_if_none_match_denied(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='PUT')
        req.headers['if-none-match'] = '*'
        req.headers['content-length'] = '0'
        with set_http_connect(201, 412, 201):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 412)

    def test_PUT_if_none_match_not_star(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='PUT')
        req.headers['if-none-match'] = 'somethingelse'
        req.headers['content-length'] = '0'
        with set_http_connect():
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 400)

    def test_PUT_connect_exceptions(self):
        object_ring = self.app.get_object_ring(None)
        self.app.sort_nodes = lambda n: n  # disable shuffle

        def test_status_map(statuses, expected):
            self.app._error_limiting = {}
            req = swob.Request.blank('/v1/a/c/o.jpg', method='PUT',
                                     body='test body')
            with set_http_connect(*statuses):
                resp = req.get_response(self.app)
            self.assertEqual(resp.status_int, expected)

        base_status = [201] * 3
        # test happy path
        test_status_map(list(base_status), 201)
        for i in range(3):
            self.assertEqual(node_error_count(
                self.app, object_ring.devs[i]), 0)
        # single node errors and test isolation
        for i in range(3):
            status_list = list(base_status)
            status_list[i] = 503
            test_status_map(status_list, 201)
            for j in range(3):
                self.assertEqual(node_error_count(
                    self.app, object_ring.devs[j]), 1 if j == i else 0)
        # connect errors
        test_status_map((201, Timeout(), 201, 201), 201)
        self.assertEqual(node_error_count(
            self.app, object_ring.devs[1]), 1)
        test_status_map((Exception('kaboom!'), 201, 201, 201), 201)
        self.assertEqual(node_error_count(
            self.app, object_ring.devs[0]), 1)
        # expect errors
        test_status_map((201, 201, (503, None), 201), 201)
        self.assertEqual(node_error_count(
            self.app, object_ring.devs[2]), 1)
        test_status_map(((507, None), 201, 201, 201), 201)
        self.assertEqual(
            node_error_count(self.app, object_ring.devs[0]),
            self.app.error_suppression_limit + 1)
        # response errors
        test_status_map(((100, Timeout()), 201, 201), 201)
        self.assertEqual(
            node_error_count(self.app, object_ring.devs[0]), 1)
        test_status_map((201, 201, (100, Exception())), 201)
        self.assertEqual(
            node_error_count(self.app, object_ring.devs[2]), 1)
        test_status_map((201, (100, 507), 201), 201)
        self.assertEqual(
            node_error_count(self.app, object_ring.devs[1]),
            self.app.error_suppression_limit + 1)

    def test_GET_simple(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o')
        with set_http_connect(200):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 200)

    def test_GET_error(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o')
        with set_http_connect(503, 200):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 200)

    def test_GET_handoff(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o')
        codes = [503] * self.obj_ring.replicas + [200]
        with set_http_connect(*codes):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 200)

    def test_GET_not_found(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o')
        codes = [404] * (self.obj_ring.replicas +
                         self.obj_ring.max_more_nodes)
        with set_http_connect(*codes):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 404)

    def test_DELETE_simple(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='DELETE')
        with set_http_connect(204, 204, 204):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 204)

    def test_DELETE_missing_one(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='DELETE')
        with set_http_connect(404, 204, 204):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 204)

    def test_DELETE_half_not_found_statuses(self):
        self.obj_ring.set_replicas(4)

        req = swift.common.swob.Request.blank('/v1/a/c/o', method='DELETE')
        with set_http_connect(404, 204, 404, 204):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 204)

    def test_DELETE_half_not_found_headers_and_body(self):
        # Transformed responses have bogus bodies and headers, so make sure we
        # send the client headers and body from a real node's response.
        self.obj_ring.set_replicas(4)

        status_codes = (404, 404, 204, 204)
        bodies = ('not found', 'not found', '', '')
        headers = [{}, {}, {'Pick-Me': 'yes'}, {'Pick-Me': 'yes'}]

        req = swift.common.swob.Request.blank('/v1/a/c/o', method='DELETE')
        with set_http_connect(*status_codes, body_iter=bodies,
                              headers=headers):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 204)
        self.assertEquals(resp.headers.get('Pick-Me'), 'yes')
        self.assertEquals(resp.body, '')

    def test_DELETE_not_found(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='DELETE')
        with set_http_connect(404, 404, 204):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 404)

    def test_DELETE_handoff(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='DELETE')
        codes = [204] * self.obj_ring.replicas
        with set_http_connect(507, *codes):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 204)

    def test_POST_as_COPY_simple(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='POST')
        head_resp = [200] * self.obj_ring.replicas + \
            [404] * self.obj_ring.max_more_nodes
        put_resp = [201] * self.obj_ring.replicas
        codes = head_resp + put_resp
        with set_http_connect(*codes):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 202)

    def test_POST_delete_at(self):
        t = str(int(time.time() + 100))
        req = swob.Request.blank('/v1/a/c/o', method='POST',
                                 headers={'Content-Type': 'foo/bar',
                                          'X-Delete-At': t})
        post_headers = []

        def capture_headers(ip, port, device, part, method, path, headers,
                            **kwargs):
            if method == 'POST':
                post_headers.append(headers)
        x_newest_responses = [200] * self.obj_ring.replicas + \
            [404] * self.obj_ring.max_more_nodes
        post_resp = [200] * self.obj_ring.replicas
        codes = x_newest_responses + post_resp
        with set_http_connect(*codes, give_connect=capture_headers):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 200)
        for given_headers in post_headers:
            self.assertEquals(given_headers.get('X-Delete-At'), t)
            self.assertTrue('X-Delete-At-Host' in given_headers)
            self.assertTrue('X-Delete-At-Device' in given_headers)
            self.assertTrue('X-Delete-At-Partition' in given_headers)
            self.assertTrue('X-Delete-At-Container' in given_headers)

    def test_POST_non_int_delete_after(self):
        t = str(int(time.time() + 100)) + '.1'
        req = swob.Request.blank('/v1/a/c/o', method='POST',
                                 headers={'Content-Type': 'foo/bar',
                                          'X-Delete-After': t})
        resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 400)
        self.assertEqual('Non-integer X-Delete-After', resp.body)

    def test_POST_negative_delete_after(self):
        req = swob.Request.blank('/v1/a/c/o', method='POST',
                                 headers={'Content-Type': 'foo/bar',
                                          'X-Delete-After': '-60'})
        resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 400)
        self.assertEqual('X-Delete-After in past', resp.body)

    def test_POST_delete_at_non_integer(self):
        t = str(int(time.time() + 100)) + '.1'
        req = swob.Request.blank('/v1/a/c/o', method='POST',
                                 headers={'Content-Type': 'foo/bar',
                                          'X-Delete-At': t})
        resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 400)
        self.assertEqual('Non-integer X-Delete-At', resp.body)

    def test_POST_delete_at_in_past(self):
        t = str(int(time.time() - 100))
        req = swob.Request.blank('/v1/a/c/o', method='POST',
                                 headers={'Content-Type': 'foo/bar',
                                          'X-Delete-At': t})
        resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 400)
        self.assertEqual('X-Delete-At in past', resp.body)

    def test_PUT_converts_delete_after_to_delete_at(self):
        req = swob.Request.blank('/v1/a/c/o', method='PUT', body='',
                                 headers={'Content-Type': 'foo/bar',
                                          'X-Delete-After': '60'})
        put_headers = []

        def capture_headers(ip, port, device, part, method, path, headers,
                            **kwargs):
            if method == 'PUT':
                put_headers.append(headers)
        codes = [201] * self.obj_ring.replicas
        t = time.time()
        with set_http_connect(*codes, give_connect=capture_headers):
            with mock.patch('time.time', lambda: t):
                resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 201)
        expected_delete_at = str(int(t) + 60)
        for given_headers in put_headers:
            self.assertEquals(given_headers.get('X-Delete-At'),
                              expected_delete_at)
            self.assertTrue('X-Delete-At-Host' in given_headers)
            self.assertTrue('X-Delete-At-Device' in given_headers)
            self.assertTrue('X-Delete-At-Partition' in given_headers)
            self.assertTrue('X-Delete-At-Container' in given_headers)

    def test_PUT_non_int_delete_after(self):
        t = str(int(time.time() + 100)) + '.1'
        req = swob.Request.blank('/v1/a/c/o', method='PUT', body='',
                                 headers={'Content-Type': 'foo/bar',
                                          'X-Delete-After': t})
        with set_http_connect():
            resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 400)
        self.assertEqual('Non-integer X-Delete-After', resp.body)

    def test_PUT_negative_delete_after(self):
        req = swob.Request.blank('/v1/a/c/o', method='PUT', body='',
                                 headers={'Content-Type': 'foo/bar',
                                          'X-Delete-After': '-60'})
        with set_http_connect():
            resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 400)
        self.assertEqual('X-Delete-After in past', resp.body)

    def test_PUT_delete_at(self):
        t = str(int(time.time() + 100))
        req = swob.Request.blank('/v1/a/c/o', method='PUT', body='',
                                 headers={'Content-Type': 'foo/bar',
                                          'X-Delete-At': t})
        put_headers = []

        def capture_headers(ip, port, device, part, method, path, headers,
                            **kwargs):
            if method == 'PUT':
                put_headers.append(headers)
        codes = [201] * self.obj_ring.replicas
        with set_http_connect(*codes, give_connect=capture_headers):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 201)
        for given_headers in put_headers:
            self.assertEquals(given_headers.get('X-Delete-At'), t)
            self.assertTrue('X-Delete-At-Host' in given_headers)
            self.assertTrue('X-Delete-At-Device' in given_headers)
            self.assertTrue('X-Delete-At-Partition' in given_headers)
            self.assertTrue('X-Delete-At-Container' in given_headers)

    def test_PUT_delete_at_non_integer(self):
        t = str(int(time.time() - 100)) + '.1'
        req = swob.Request.blank('/v1/a/c/o', method='PUT', body='',
                                 headers={'Content-Type': 'foo/bar',
                                          'X-Delete-At': t})
        with set_http_connect():
            resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 400)
        self.assertEqual('Non-integer X-Delete-At', resp.body)

    def test_PUT_delete_at_in_past(self):
        t = str(int(time.time() - 100))
        req = swob.Request.blank('/v1/a/c/o', method='PUT', body='',
                                 headers={'Content-Type': 'foo/bar',
                                          'X-Delete-At': t})
        with set_http_connect():
            resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 400)
        self.assertEqual('X-Delete-At in past', resp.body)

    def test_container_sync_put_x_timestamp_not_found(self):
        test_indexes = [None] + [int(p) for p in POLICIES]
        for policy_index in test_indexes:
            self.container_info['storage_policy'] = policy_index
            put_timestamp = utils.Timestamp(time.time()).normal
            req = swob.Request.blank(
                '/v1/a/c/o', method='PUT', headers={
                    'Content-Length': 0,
                    'X-Timestamp': put_timestamp})
            codes = [201] * self.obj_ring.replicas
            with set_http_connect(*codes):
                resp = req.get_response(self.app)
            self.assertEqual(resp.status_int, 201)

    def test_container_sync_put_x_timestamp_match(self):
        test_indexes = [None] + [int(p) for p in POLICIES]
        for policy_index in test_indexes:
            self.container_info['storage_policy'] = policy_index
            put_timestamp = utils.Timestamp(time.time()).normal
            req = swob.Request.blank(
                '/v1/a/c/o', method='PUT', headers={
                    'Content-Length': 0,
                    'X-Timestamp': put_timestamp})
            ts_iter = itertools.repeat(put_timestamp)
            codes = [409] * self.obj_ring.replicas
            with set_http_connect(*codes, timestamps=ts_iter):
                resp = req.get_response(self.app)
            self.assertEqual(resp.status_int, 202)

    def test_container_sync_put_x_timestamp_older(self):
        ts = (utils.Timestamp(t) for t in itertools.count(int(time.time())))
        test_indexes = [None] + [int(p) for p in POLICIES]
        for policy_index in test_indexes:
            self.container_info['storage_policy'] = policy_index
            req = swob.Request.blank(
                '/v1/a/c/o', method='PUT', headers={
                    'Content-Length': 0,
                    'X-Timestamp': ts.next().internal})
            ts_iter = itertools.repeat(ts.next().internal)
            codes = [409] * self.obj_ring.replicas
            with set_http_connect(*codes, timestamps=ts_iter):
                resp = req.get_response(self.app)
            self.assertEqual(resp.status_int, 202)

    def test_container_sync_put_x_timestamp_newer(self):
        ts = (utils.Timestamp(t) for t in itertools.count(int(time.time())))
        test_indexes = [None] + [int(p) for p in POLICIES]
        for policy_index in test_indexes:
            orig_timestamp = ts.next().internal
            req = swob.Request.blank(
                '/v1/a/c/o', method='PUT', headers={
                    'Content-Length': 0,
                    'X-Timestamp': ts.next().internal})
            ts_iter = itertools.repeat(orig_timestamp)
            codes = [201] * self.obj_ring.replicas
            with set_http_connect(*codes, timestamps=ts_iter):
                resp = req.get_response(self.app)
            self.assertEqual(resp.status_int, 201)

    def test_container_sync_delete(self):
        ts = (utils.Timestamp(t) for t in itertools.count(int(time.time())))
        test_indexes = [None] + [int(p) for p in POLICIES]
        for policy_index in test_indexes:
            req = swob.Request.blank(
                '/v1/a/c/o', method='DELETE', headers={
                    'X-Timestamp': ts.next().internal})
            codes = [409] * self.obj_ring.replicas
            ts_iter = itertools.repeat(ts.next().internal)
            with set_http_connect(*codes, timestamps=ts_iter):
                resp = req.get_response(self.app)
            self.assertEqual(resp.status_int, 409)

    def test_put_x_timestamp_conflict(self):
        ts = (utils.Timestamp(t) for t in itertools.count(int(time.time())))
        req = swob.Request.blank(
            '/v1/a/c/o', method='PUT', headers={
                'Content-Length': 0,
                'X-Timestamp': ts.next().internal})
        ts_iter = iter([ts.next().internal, None, None])
        codes = [409] + [201] * (self.obj_ring.replicas - 1)
        with set_http_connect(*codes, timestamps=ts_iter):
            resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 202)

    def test_container_sync_put_x_timestamp_race(self):
        ts = (utils.Timestamp(t) for t in itertools.count(int(time.time())))
        test_indexes = [None] + [int(p) for p in POLICIES]
        for policy_index in test_indexes:
            put_timestamp = ts.next().internal
            req = swob.Request.blank(
                '/v1/a/c/o', method='PUT', headers={
                    'Content-Length': 0,
                    'X-Timestamp': put_timestamp})

            # object nodes they respond 409 because another in-flight request
            # finished and now the on disk timestamp is equal to the request.
            put_ts = [put_timestamp] * self.obj_ring.replicas
            codes = [409] * self.obj_ring.replicas

            ts_iter = iter(put_ts)
            with set_http_connect(*codes, timestamps=ts_iter):
                resp = req.get_response(self.app)
            self.assertEqual(resp.status_int, 202)

    def test_container_sync_put_x_timestamp_unsynced_race(self):
        ts = (utils.Timestamp(t) for t in itertools.count(int(time.time())))
        test_indexes = [None] + [int(p) for p in POLICIES]
        for policy_index in test_indexes:
            put_timestamp = ts.next().internal
            req = swob.Request.blank(
                '/v1/a/c/o', method='PUT', headers={
                    'Content-Length': 0,
                    'X-Timestamp': put_timestamp})

            # only one in-flight request finished
            put_ts = [None] * (self.obj_ring.replicas - 1)
            put_resp = [201] * (self.obj_ring.replicas - 1)
            put_ts += [put_timestamp]
            put_resp += [409]

            ts_iter = iter(put_ts)
            codes = put_resp
            with set_http_connect(*codes, timestamps=ts_iter):
                resp = req.get_response(self.app)
            self.assertEqual(resp.status_int, 202)

    def test_COPY_simple(self):
        req = swift.common.swob.Request.blank(
            '/v1/a/c/o', method='COPY',
            headers={'Content-Length': 0,
                     'Destination': 'c/o-copy'})
        head_resp = [200] * self.obj_ring.replicas + \
            [404] * self.obj_ring.max_more_nodes
        put_resp = [201] * self.obj_ring.replicas
        codes = head_resp + put_resp
        with set_http_connect(*codes):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 201)

    def test_HEAD_simple(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='HEAD')
        with set_http_connect(200):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 200)

    def test_HEAD_x_newest(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='HEAD',
                                              headers={'X-Newest': 'true'})
        with set_http_connect(200, 200, 200):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 200)

    def test_HEAD_x_newest_different_timestamps(self):
        req = swob.Request.blank('/v1/a/c/o', method='HEAD',
                                 headers={'X-Newest': 'true'})
        ts = (utils.Timestamp(t) for t in itertools.count(int(time.time())))
        timestamps = [next(ts) for i in range(3)]
        newest_timestamp = timestamps[-1]
        random.shuffle(timestamps)
        backend_response_headers = [{
            'X-Backend-Timestamp': t.internal,
            'X-Timestamp': t.normal
        } for t in timestamps]
        with set_http_connect(200, 200, 200,
                              headers=backend_response_headers):
            resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 200)
        self.assertEqual(resp.headers['x-timestamp'], newest_timestamp.normal)

    def test_HEAD_x_newest_with_two_vector_timestamps(self):
        req = swob.Request.blank('/v1/a/c/o', method='HEAD',
                                 headers={'X-Newest': 'true'})
        ts = (utils.Timestamp(time.time(), offset=offset)
              for offset in itertools.count())
        timestamps = [next(ts) for i in range(3)]
        newest_timestamp = timestamps[-1]
        random.shuffle(timestamps)
        backend_response_headers = [{
            'X-Backend-Timestamp': t.internal,
            'X-Timestamp': t.normal
        } for t in timestamps]
        with set_http_connect(200, 200, 200,
                              headers=backend_response_headers):
            resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 200)
        self.assertEqual(resp.headers['x-backend-timestamp'],
                         newest_timestamp.internal)

    def test_HEAD_x_newest_with_some_missing(self):
        req = swob.Request.blank('/v1/a/c/o', method='HEAD',
                                 headers={'X-Newest': 'true'})
        ts = (utils.Timestamp(t) for t in itertools.count(int(time.time())))
        request_count = self.app.request_node_count(self.obj_ring.replicas)
        backend_response_headers = [{
            'x-timestamp': next(ts).normal,
        } for i in range(request_count)]
        responses = [404] * (request_count - 1)
        responses.append(200)
        request_log = []

        def capture_requests(ip, port, device, part, method, path,
                             headers=None, **kwargs):
            req = {
                'ip': ip,
                'port': port,
                'device': device,
                'part': part,
                'method': method,
                'path': path,
                'headers': headers,
            }
            request_log.append(req)
        with set_http_connect(*responses,
                              headers=backend_response_headers,
                              give_connect=capture_requests):
            resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 200)
        for req in request_log:
            self.assertEqual(req['method'], 'HEAD')
            self.assertEqual(req['path'], '/a/c/o')

    def test_PUT_log_info(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='PUT')
        req.headers['x-copy-from'] = 'some/where'
        req.headers['Content-Length'] = 0
        # override FakeConn default resp headers to keep log_info clean
        resp_headers = {'x-delete-at': None}
        head_resp = [200] * self.obj_ring.replicas + \
            [404] * self.obj_ring.max_more_nodes
        put_resp = [201] * self.obj_ring.replicas
        codes = head_resp + put_resp
        with set_http_connect(*codes, headers=resp_headers):
            resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 201)
        self.assertEquals(
            req.environ.get('swift.log_info'), ['x-copy-from:some/where'])
        # and then check that we don't do that for originating POSTs
        req = swift.common.swob.Request.blank('/v1/a/c/o')
        req.method = 'POST'
        req.headers['x-copy-from'] = 'else/where'
        with set_http_connect(*codes, headers=resp_headers):
            resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 202)
        self.assertEquals(req.environ.get('swift.log_info'), None)
Example #32
0
    def test_multiple_names_EC(self):
        # checking duplicate names on insert
        test_policies_ec = [
            ECStoragePolicy(
                0, 'ec8-2',
                aliases='zeus, jupiter',
                ec_type=DEFAULT_TEST_EC_TYPE,
                ec_ndata=8, ec_nparity=2,
                object_ring=FakeRing(replicas=8),
                is_default=True),
            ECStoragePolicy(
                1, 'ec10-4',
                aliases='ec8-2',
                ec_type=DEFAULT_TEST_EC_TYPE,
                ec_ndata=10, ec_nparity=4,
                object_ring=FakeRing(replicas=10))]

        self.assertRaises(PolicyError, StoragePolicyCollection,
                          test_policies_ec)

        # checking correct retrival using other names
        good_test_policies_EC = [
            ECStoragePolicy(0, 'ec8-2', aliases='zeus, jupiter',
                            ec_type=DEFAULT_TEST_EC_TYPE,
                            ec_ndata=8, ec_nparity=2,
                            object_ring=FakeRing(replicas=8),
                            is_default=True),
            ECStoragePolicy(1, 'ec10-4', aliases='athena, minerva',
                            ec_type=DEFAULT_TEST_EC_TYPE,
                            ec_ndata=10, ec_nparity=4,
                            object_ring=FakeRing(replicas=10)),
            ECStoragePolicy(2, 'ec4-2', aliases='poseidon, neptune',
                            ec_type=DEFAULT_TEST_EC_TYPE,
                            ec_ndata=4, ec_nparity=2,
                            object_ring=FakeRing(replicas=7)),
        ]
        ec_policies = StoragePolicyCollection(good_test_policies_EC)

        for name in ('ec8-2', 'zeus', 'jupiter'):
            self.assertEqual(ec_policies.get_by_name(name), ec_policies[0])
        for name in ('ec10-4', 'athena', 'minerva'):
            self.assertEqual(ec_policies.get_by_name(name), ec_policies[1])

        # Testing parsing of conf files/text
        good_ec_conf = self._conf("""
        [storage-policy:0]
        name = ec8-2
        aliases = zeus, jupiter
        policy_type = erasure_coding
        ec_type = %(ec_type)s
        default = yes
        ec_num_data_fragments = 8
        ec_num_parity_fragments = 2
        [storage-policy:1]
        name = ec10-4
        aliases = poseidon, neptune
        policy_type = erasure_coding
        ec_type = %(ec_type)s
        ec_num_data_fragments = 10
        ec_num_parity_fragments = 4
        """ % {'ec_type': DEFAULT_TEST_EC_TYPE})

        ec_policies = parse_storage_policies(good_ec_conf)
        self.assertEqual(ec_policies.get_by_name('ec8-2'),
                         ec_policies[0])
        self.assertEqual(ec_policies.get_by_name('ec10-4'),
                         ec_policies.get_by_name('poseidon'))

        name_repeat_ec_conf = self._conf("""
        [storage-policy:0]
        name = ec8-2
        aliases = ec8-2
        policy_type = erasure_coding
        ec_type = %(ec_type)s
        default = yes
        ec_num_data_fragments = 8
        ec_num_parity_fragments = 2
        """ % {'ec_type': DEFAULT_TEST_EC_TYPE})
        # Test on line below should not generate errors. Repeat of main
        # name under aliases is permitted during construction
        # but only because automated testing requires it.
        ec_policies = parse_storage_policies(name_repeat_ec_conf)

        bad_ec_conf = self._conf("""
        [storage-policy:0]
        name = ec8-2
        aliases = zeus, zeus
        policy_type = erasure_coding
        ec_type = %(ec_type)s
        default = yes
        ec_num_data_fragments = 8
        ec_num_parity_fragments = 2
        """ % {'ec_type': DEFAULT_TEST_EC_TYPE})
        self.assertRaisesWithMessage(PolicyError,
                                     'is already assigned to this policy',
                                     parse_storage_policies, bad_ec_conf)
Example #33
0
class TestObjController(unittest.TestCase):
    container_info = {
        'partition':
        1,
        'nodes': [
            {
                'ip': '127.0.0.1',
                'port': '1',
                'device': 'sda'
            },
            {
                'ip': '127.0.0.1',
                'port': '2',
                'device': 'sda'
            },
            {
                'ip': '127.0.0.1',
                'port': '3',
                'device': 'sda'
            },
        ],
        'write_acl':
        None,
        'read_acl':
        None,
        'storage_policy':
        None,
        'sync_key':
        None,
        'versions':
        None,
    }

    def setUp(self):
        # setup fake rings with handoffs
        self.obj_ring = FakeRing(max_more_nodes=3)
        for policy in POLICIES:
            policy.object_ring = self.obj_ring

        logger = debug_logger('proxy-server')
        logger.thread_locals = ('txn1', '127.0.0.2')
        self.app = PatchedObjControllerApp(None,
                                           FakeMemcache(),
                                           account_ring=FakeRing(),
                                           container_ring=FakeRing(),
                                           logger=logger)

        class FakeContainerInfoObjController(proxy_server.ObjectController):
            def container_info(controller, *args, **kwargs):
                patch_path = 'swift.proxy.controllers.base.get_info'
                with mock.patch(patch_path) as mock_get_info:
                    mock_get_info.return_value = dict(self.container_info)
                    return super(FakeContainerInfoObjController,
                                 controller).container_info(*args, **kwargs)

        # this is taking advantage of the fact that self.app is a
        # PachedObjControllerApp, so handle_response will route into an
        # instance of our FakeContainerInfoObjController just by
        # overriding the class attribute for object_controller
        self.app.object_controller = FakeContainerInfoObjController

    def test_PUT_simple(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='PUT')
        req.headers['content-length'] = '0'
        with set_http_connect(201, 201, 201):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 201)

    def test_PUT_if_none_match(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='PUT')
        req.headers['if-none-match'] = '*'
        req.headers['content-length'] = '0'
        with set_http_connect(201, 201, 201):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 201)

    def test_PUT_if_none_match_denied(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='PUT')
        req.headers['if-none-match'] = '*'
        req.headers['content-length'] = '0'
        with set_http_connect(201, 412, 201):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 412)

    def test_PUT_if_none_match_not_star(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='PUT')
        req.headers['if-none-match'] = 'somethingelse'
        req.headers['content-length'] = '0'
        with set_http_connect():
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 400)

    def test_PUT_connect_exceptions(self):
        object_ring = self.app.get_object_ring(None)
        self.app.sort_nodes = lambda n: n  # disable shuffle

        def test_status_map(statuses, expected):
            self.app._error_limiting = {}
            req = swob.Request.blank('/v1/a/c/o.jpg',
                                     method='PUT',
                                     body='test body')
            with set_http_connect(*statuses):
                resp = req.get_response(self.app)
            self.assertEqual(resp.status_int, expected)

        base_status = [201] * 3
        # test happy path
        test_status_map(list(base_status), 201)
        for i in range(3):
            self.assertEqual(node_error_count(self.app, object_ring.devs[i]),
                             0)
        # single node errors and test isolation
        for i in range(3):
            status_list = list(base_status)
            status_list[i] = 503
            test_status_map(status_list, 201)
            for j in range(3):
                self.assertEqual(
                    node_error_count(self.app, object_ring.devs[j]),
                    1 if j == i else 0)
        # connect errors
        test_status_map((201, Timeout(), 201, 201), 201)
        self.assertEqual(node_error_count(self.app, object_ring.devs[1]), 1)
        test_status_map((Exception('kaboom!'), 201, 201, 201), 201)
        self.assertEqual(node_error_count(self.app, object_ring.devs[0]), 1)
        # expect errors
        test_status_map((201, 201, (503, None), 201), 201)
        self.assertEqual(node_error_count(self.app, object_ring.devs[2]), 1)
        test_status_map(((507, None), 201, 201, 201), 201)
        self.assertEqual(node_error_count(self.app, object_ring.devs[0]),
                         self.app.error_suppression_limit + 1)
        # response errors
        test_status_map(((100, Timeout()), 201, 201), 201)
        self.assertEqual(node_error_count(self.app, object_ring.devs[0]), 1)
        test_status_map((201, 201, (100, Exception())), 201)
        self.assertEqual(node_error_count(self.app, object_ring.devs[2]), 1)
        test_status_map((201, (100, 507), 201), 201)
        self.assertEqual(node_error_count(self.app, object_ring.devs[1]),
                         self.app.error_suppression_limit + 1)

    def test_GET_simple(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o')
        with set_http_connect(200):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 200)

    def test_GET_error(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o')
        with set_http_connect(503, 200):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 200)

    def test_GET_handoff(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o')
        codes = [503] * self.obj_ring.replicas + [200]
        with set_http_connect(*codes):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 200)

    def test_GET_not_found(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o')
        codes = [404] * (self.obj_ring.replicas + self.obj_ring.max_more_nodes)
        with set_http_connect(*codes):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 404)

    def test_DELETE_simple(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='DELETE')
        with set_http_connect(204, 204, 204):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 204)

    def test_DELETE_missing_one(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='DELETE')
        with set_http_connect(404, 204, 204):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 204)

    def test_DELETE_half_not_found_statuses(self):
        self.obj_ring.set_replicas(4)

        req = swift.common.swob.Request.blank('/v1/a/c/o', method='DELETE')
        with set_http_connect(404, 204, 404, 204):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 204)

    def test_DELETE_half_not_found_headers_and_body(self):
        # Transformed responses have bogus bodies and headers, so make sure we
        # send the client headers and body from a real node's response.
        self.obj_ring.set_replicas(4)

        status_codes = (404, 404, 204, 204)
        bodies = ('not found', 'not found', '', '')
        headers = [{}, {}, {'Pick-Me': 'yes'}, {'Pick-Me': 'yes'}]

        req = swift.common.swob.Request.blank('/v1/a/c/o', method='DELETE')
        with set_http_connect(*status_codes, body_iter=bodies,
                              headers=headers):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 204)
        self.assertEquals(resp.headers.get('Pick-Me'), 'yes')
        self.assertEquals(resp.body, '')

    def test_DELETE_not_found(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='DELETE')
        with set_http_connect(404, 404, 204):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 404)

    def test_DELETE_handoff(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='DELETE')
        codes = [204] * self.obj_ring.replicas
        with set_http_connect(507, *codes):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 204)

    def test_POST_as_COPY_simple(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='POST')
        head_resp = [200] * self.obj_ring.replicas + \
            [404] * self.obj_ring.max_more_nodes
        put_resp = [201] * self.obj_ring.replicas
        codes = head_resp + put_resp
        with set_http_connect(*codes):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 202)

    def test_POST_delete_at(self):
        t = str(int(time.time() + 100))
        req = swob.Request.blank('/v1/a/c/o',
                                 method='POST',
                                 headers={
                                     'Content-Type': 'foo/bar',
                                     'X-Delete-At': t
                                 })
        post_headers = []

        def capture_headers(ip, port, device, part, method, path, headers,
                            **kwargs):
            if method == 'POST':
                post_headers.append(headers)
        x_newest_responses = [200] * self.obj_ring.replicas + \
            [404] * self.obj_ring.max_more_nodes
        post_resp = [200] * self.obj_ring.replicas
        codes = x_newest_responses + post_resp
        with set_http_connect(*codes, give_connect=capture_headers):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 200)
        for given_headers in post_headers:
            self.assertEquals(given_headers.get('X-Delete-At'), t)
            self.assertTrue('X-Delete-At-Host' in given_headers)
            self.assertTrue('X-Delete-At-Device' in given_headers)
            self.assertTrue('X-Delete-At-Partition' in given_headers)
            self.assertTrue('X-Delete-At-Container' in given_headers)

    def test_POST_non_int_delete_after(self):
        t = str(int(time.time() + 100)) + '.1'
        req = swob.Request.blank('/v1/a/c/o',
                                 method='POST',
                                 headers={
                                     'Content-Type': 'foo/bar',
                                     'X-Delete-After': t
                                 })
        resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 400)
        self.assertEqual('Non-integer X-Delete-After', resp.body)

    def test_POST_negative_delete_after(self):
        req = swob.Request.blank('/v1/a/c/o',
                                 method='POST',
                                 headers={
                                     'Content-Type': 'foo/bar',
                                     'X-Delete-After': '-60'
                                 })
        resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 400)
        self.assertEqual('X-Delete-After in past', resp.body)

    def test_POST_delete_at_non_integer(self):
        t = str(int(time.time() + 100)) + '.1'
        req = swob.Request.blank('/v1/a/c/o',
                                 method='POST',
                                 headers={
                                     'Content-Type': 'foo/bar',
                                     'X-Delete-At': t
                                 })
        resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 400)
        self.assertEqual('Non-integer X-Delete-At', resp.body)

    def test_POST_delete_at_in_past(self):
        t = str(int(time.time() - 100))
        req = swob.Request.blank('/v1/a/c/o',
                                 method='POST',
                                 headers={
                                     'Content-Type': 'foo/bar',
                                     'X-Delete-At': t
                                 })
        resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 400)
        self.assertEqual('X-Delete-At in past', resp.body)

    def test_PUT_converts_delete_after_to_delete_at(self):
        req = swob.Request.blank('/v1/a/c/o',
                                 method='PUT',
                                 body='',
                                 headers={
                                     'Content-Type': 'foo/bar',
                                     'X-Delete-After': '60'
                                 })
        put_headers = []

        def capture_headers(ip, port, device, part, method, path, headers,
                            **kwargs):
            if method == 'PUT':
                put_headers.append(headers)

        codes = [201] * self.obj_ring.replicas
        t = time.time()
        with set_http_connect(*codes, give_connect=capture_headers):
            with mock.patch('time.time', lambda: t):
                resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 201)
        expected_delete_at = str(int(t) + 60)
        for given_headers in put_headers:
            self.assertEquals(given_headers.get('X-Delete-At'),
                              expected_delete_at)
            self.assertTrue('X-Delete-At-Host' in given_headers)
            self.assertTrue('X-Delete-At-Device' in given_headers)
            self.assertTrue('X-Delete-At-Partition' in given_headers)
            self.assertTrue('X-Delete-At-Container' in given_headers)

    def test_PUT_non_int_delete_after(self):
        t = str(int(time.time() + 100)) + '.1'
        req = swob.Request.blank('/v1/a/c/o',
                                 method='PUT',
                                 body='',
                                 headers={
                                     'Content-Type': 'foo/bar',
                                     'X-Delete-After': t
                                 })
        with set_http_connect():
            resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 400)
        self.assertEqual('Non-integer X-Delete-After', resp.body)

    def test_PUT_negative_delete_after(self):
        req = swob.Request.blank('/v1/a/c/o',
                                 method='PUT',
                                 body='',
                                 headers={
                                     'Content-Type': 'foo/bar',
                                     'X-Delete-After': '-60'
                                 })
        with set_http_connect():
            resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 400)
        self.assertEqual('X-Delete-After in past', resp.body)

    def test_PUT_delete_at(self):
        t = str(int(time.time() + 100))
        req = swob.Request.blank('/v1/a/c/o',
                                 method='PUT',
                                 body='',
                                 headers={
                                     'Content-Type': 'foo/bar',
                                     'X-Delete-At': t
                                 })
        put_headers = []

        def capture_headers(ip, port, device, part, method, path, headers,
                            **kwargs):
            if method == 'PUT':
                put_headers.append(headers)

        codes = [201] * self.obj_ring.replicas
        with set_http_connect(*codes, give_connect=capture_headers):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 201)
        for given_headers in put_headers:
            self.assertEquals(given_headers.get('X-Delete-At'), t)
            self.assertTrue('X-Delete-At-Host' in given_headers)
            self.assertTrue('X-Delete-At-Device' in given_headers)
            self.assertTrue('X-Delete-At-Partition' in given_headers)
            self.assertTrue('X-Delete-At-Container' in given_headers)

    def test_PUT_delete_at_non_integer(self):
        t = str(int(time.time() - 100)) + '.1'
        req = swob.Request.blank('/v1/a/c/o',
                                 method='PUT',
                                 body='',
                                 headers={
                                     'Content-Type': 'foo/bar',
                                     'X-Delete-At': t
                                 })
        with set_http_connect():
            resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 400)
        self.assertEqual('Non-integer X-Delete-At', resp.body)

    def test_PUT_delete_at_in_past(self):
        t = str(int(time.time() - 100))
        req = swob.Request.blank('/v1/a/c/o',
                                 method='PUT',
                                 body='',
                                 headers={
                                     'Content-Type': 'foo/bar',
                                     'X-Delete-At': t
                                 })
        with set_http_connect():
            resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 400)
        self.assertEqual('X-Delete-At in past', resp.body)

    def test_container_sync_put_x_timestamp_not_found(self):
        test_indexes = [None] + [int(p) for p in POLICIES]
        for policy_index in test_indexes:
            self.container_info['storage_policy'] = policy_index
            put_timestamp = utils.Timestamp(time.time()).normal
            req = swob.Request.blank('/v1/a/c/o',
                                     method='PUT',
                                     headers={
                                         'Content-Length': 0,
                                         'X-Timestamp': put_timestamp
                                     })
            codes = [201] * self.obj_ring.replicas
            with set_http_connect(*codes):
                resp = req.get_response(self.app)
            self.assertEqual(resp.status_int, 201)

    def test_container_sync_put_x_timestamp_match(self):
        test_indexes = [None] + [int(p) for p in POLICIES]
        for policy_index in test_indexes:
            self.container_info['storage_policy'] = policy_index
            put_timestamp = utils.Timestamp(time.time()).normal
            req = swob.Request.blank('/v1/a/c/o',
                                     method='PUT',
                                     headers={
                                         'Content-Length': 0,
                                         'X-Timestamp': put_timestamp
                                     })
            ts_iter = itertools.repeat(put_timestamp)
            codes = [409] * self.obj_ring.replicas
            with set_http_connect(*codes, timestamps=ts_iter):
                resp = req.get_response(self.app)
            self.assertEqual(resp.status_int, 202)

    def test_container_sync_put_x_timestamp_older(self):
        ts = (utils.Timestamp(t) for t in itertools.count(int(time.time())))
        test_indexes = [None] + [int(p) for p in POLICIES]
        for policy_index in test_indexes:
            self.container_info['storage_policy'] = policy_index
            req = swob.Request.blank('/v1/a/c/o',
                                     method='PUT',
                                     headers={
                                         'Content-Length': 0,
                                         'X-Timestamp': ts.next().internal
                                     })
            ts_iter = itertools.repeat(ts.next().internal)
            codes = [409] * self.obj_ring.replicas
            with set_http_connect(*codes, timestamps=ts_iter):
                resp = req.get_response(self.app)
            self.assertEqual(resp.status_int, 202)

    def test_container_sync_put_x_timestamp_newer(self):
        ts = (utils.Timestamp(t) for t in itertools.count(int(time.time())))
        test_indexes = [None] + [int(p) for p in POLICIES]
        for policy_index in test_indexes:
            orig_timestamp = ts.next().internal
            req = swob.Request.blank('/v1/a/c/o',
                                     method='PUT',
                                     headers={
                                         'Content-Length': 0,
                                         'X-Timestamp': ts.next().internal
                                     })
            ts_iter = itertools.repeat(orig_timestamp)
            codes = [201] * self.obj_ring.replicas
            with set_http_connect(*codes, timestamps=ts_iter):
                resp = req.get_response(self.app)
            self.assertEqual(resp.status_int, 201)

    def test_container_sync_delete(self):
        ts = (utils.Timestamp(t) for t in itertools.count(int(time.time())))
        test_indexes = [None] + [int(p) for p in POLICIES]
        for policy_index in test_indexes:
            req = swob.Request.blank(
                '/v1/a/c/o',
                method='DELETE',
                headers={'X-Timestamp': ts.next().internal})
            codes = [409] * self.obj_ring.replicas
            ts_iter = itertools.repeat(ts.next().internal)
            with set_http_connect(*codes, timestamps=ts_iter):
                resp = req.get_response(self.app)
            self.assertEqual(resp.status_int, 409)

    def test_put_x_timestamp_conflict(self):
        ts = (utils.Timestamp(t) for t in itertools.count(int(time.time())))
        req = swob.Request.blank('/v1/a/c/o',
                                 method='PUT',
                                 headers={
                                     'Content-Length': 0,
                                     'X-Timestamp': ts.next().internal
                                 })
        ts_iter = iter([ts.next().internal, None, None])
        codes = [409] + [201] * (self.obj_ring.replicas - 1)
        with set_http_connect(*codes, timestamps=ts_iter):
            resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 202)

    def test_container_sync_put_x_timestamp_race(self):
        ts = (utils.Timestamp(t) for t in itertools.count(int(time.time())))
        test_indexes = [None] + [int(p) for p in POLICIES]
        for policy_index in test_indexes:
            put_timestamp = ts.next().internal
            req = swob.Request.blank('/v1/a/c/o',
                                     method='PUT',
                                     headers={
                                         'Content-Length': 0,
                                         'X-Timestamp': put_timestamp
                                     })

            # object nodes they respond 409 because another in-flight request
            # finished and now the on disk timestamp is equal to the request.
            put_ts = [put_timestamp] * self.obj_ring.replicas
            codes = [409] * self.obj_ring.replicas

            ts_iter = iter(put_ts)
            with set_http_connect(*codes, timestamps=ts_iter):
                resp = req.get_response(self.app)
            self.assertEqual(resp.status_int, 202)

    def test_container_sync_put_x_timestamp_unsynced_race(self):
        ts = (utils.Timestamp(t) for t in itertools.count(int(time.time())))
        test_indexes = [None] + [int(p) for p in POLICIES]
        for policy_index in test_indexes:
            put_timestamp = ts.next().internal
            req = swob.Request.blank('/v1/a/c/o',
                                     method='PUT',
                                     headers={
                                         'Content-Length': 0,
                                         'X-Timestamp': put_timestamp
                                     })

            # only one in-flight request finished
            put_ts = [None] * (self.obj_ring.replicas - 1)
            put_resp = [201] * (self.obj_ring.replicas - 1)
            put_ts += [put_timestamp]
            put_resp += [409]

            ts_iter = iter(put_ts)
            codes = put_resp
            with set_http_connect(*codes, timestamps=ts_iter):
                resp = req.get_response(self.app)
            self.assertEqual(resp.status_int, 202)

    def test_COPY_simple(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o',
                                              method='COPY',
                                              headers={
                                                  'Content-Length': 0,
                                                  'Destination': 'c/o-copy'
                                              })
        head_resp = [200] * self.obj_ring.replicas + \
            [404] * self.obj_ring.max_more_nodes
        put_resp = [201] * self.obj_ring.replicas
        codes = head_resp + put_resp
        with set_http_connect(*codes):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 201)

    def test_HEAD_simple(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='HEAD')
        with set_http_connect(200):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 200)

    def test_HEAD_x_newest(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o',
                                              method='HEAD',
                                              headers={'X-Newest': 'true'})
        with set_http_connect(200, 200, 200):
            resp = req.get_response(self.app)
        self.assertEquals(resp.status_int, 200)

    def test_HEAD_x_newest_different_timestamps(self):
        req = swob.Request.blank('/v1/a/c/o',
                                 method='HEAD',
                                 headers={'X-Newest': 'true'})
        ts = (utils.Timestamp(t) for t in itertools.count(int(time.time())))
        timestamps = [next(ts) for i in range(3)]
        newest_timestamp = timestamps[-1]
        random.shuffle(timestamps)
        backend_response_headers = [{
            'X-Backend-Timestamp': t.internal,
            'X-Timestamp': t.normal
        } for t in timestamps]
        with set_http_connect(200, 200, 200, headers=backend_response_headers):
            resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 200)
        self.assertEqual(resp.headers['x-timestamp'], newest_timestamp.normal)

    def test_HEAD_x_newest_with_two_vector_timestamps(self):
        req = swob.Request.blank('/v1/a/c/o',
                                 method='HEAD',
                                 headers={'X-Newest': 'true'})
        ts = (utils.Timestamp(time.time(), offset=offset)
              for offset in itertools.count())
        timestamps = [next(ts) for i in range(3)]
        newest_timestamp = timestamps[-1]
        random.shuffle(timestamps)
        backend_response_headers = [{
            'X-Backend-Timestamp': t.internal,
            'X-Timestamp': t.normal
        } for t in timestamps]
        with set_http_connect(200, 200, 200, headers=backend_response_headers):
            resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 200)
        self.assertEqual(resp.headers['x-backend-timestamp'],
                         newest_timestamp.internal)

    def test_HEAD_x_newest_with_some_missing(self):
        req = swob.Request.blank('/v1/a/c/o',
                                 method='HEAD',
                                 headers={'X-Newest': 'true'})
        ts = (utils.Timestamp(t) for t in itertools.count(int(time.time())))
        request_count = self.app.request_node_count(self.obj_ring.replicas)
        backend_response_headers = [{
            'x-timestamp': next(ts).normal,
        } for i in range(request_count)]
        responses = [404] * (request_count - 1)
        responses.append(200)
        request_log = []

        def capture_requests(ip,
                             port,
                             device,
                             part,
                             method,
                             path,
                             headers=None,
                             **kwargs):
            req = {
                'ip': ip,
                'port': port,
                'device': device,
                'part': part,
                'method': method,
                'path': path,
                'headers': headers,
            }
            request_log.append(req)

        with set_http_connect(*responses,
                              headers=backend_response_headers,
                              give_connect=capture_requests):
            resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 200)
        for req in request_log:
            self.assertEqual(req['method'], 'HEAD')
            self.assertEqual(req['path'], '/a/c/o')

    def test_PUT_log_info(self):
        req = swift.common.swob.Request.blank('/v1/a/c/o', method='PUT')
        req.headers['x-copy-from'] = 'some/where'
        req.headers['Content-Length'] = 0
        # override FakeConn default resp headers to keep log_info clean
        resp_headers = {'x-delete-at': None}
        head_resp = [200] * self.obj_ring.replicas + \
            [404] * self.obj_ring.max_more_nodes
        put_resp = [201] * self.obj_ring.replicas
        codes = head_resp + put_resp
        with set_http_connect(*codes, headers=resp_headers):
            resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 201)
        self.assertEquals(req.environ.get('swift.log_info'),
                          ['x-copy-from:some/where'])
        # and then check that we don't do that for originating POSTs
        req = swift.common.swob.Request.blank('/v1/a/c/o')
        req.method = 'POST'
        req.headers['x-copy-from'] = 'else/where'
        with set_http_connect(*codes, headers=resp_headers):
            resp = req.get_response(self.app)
        self.assertEqual(resp.status_int, 202)
        self.assertEquals(req.environ.get('swift.log_info'), None)
Example #34
0
    """
    This patch is just a hook over handle_request to ensure that when
    get_controller is called the ObjectController class is patched to
    return a (possibly stubbed) ObjectController class.
    """

    object_controller = proxy_server.ObjectController

    def handle_request(self, req):
        with mock.patch('swift.proxy.server.ObjectController',
                        new=self.object_controller):
            return super(PatchedObjControllerApp, self).handle_request(req)


@patch_policies(
    [StoragePolicy(0, 'zero', True, object_ring=FakeRing(max_more_nodes=9))])
class TestObjControllerWriteAffinity(unittest.TestCase):
    def setUp(self):
        self.app = proxy_server.Application(None,
                                            FakeMemcache(),
                                            account_ring=FakeRing(),
                                            container_ring=FakeRing(),
                                            logger=debug_logger())
        self.app.request_node_count = lambda ring: 10000000
        self.app.sort_nodes = lambda l: l  # stop shuffling the primary nodes

    def test_iter_nodes_local_first_noops_when_no_affinity(self):
        controller = proxy_server.ObjectController(self.app, 'a', 'c', 'o')
        self.app.write_affinity_is_local_fn = None
        object_ring = self.app.get_object_ring(None)
        all_nodes = object_ring.get_part_nodes(1)