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
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)
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)
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 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 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
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()
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()
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)
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 })
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 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
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
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
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
def setUp(self): self.app = proxy_server.Application(None, FakeMemcache(), account_ring=FakeRing(), container_ring=FakeRing())
def test_GETorHEAD_base(self): base = Controller(self.app) req = Request.blank('/v1/a/c/o/with/slashes') ring = FakeRing() nodes = list(ring.get_part_nodes(0)) + list(ring.get_more_nodes(0)) with patch('swift.proxy.controllers.base.' 'http_connect', fake_http_connect(200)): resp = base.GETorHEAD_base(req, 'object', iter(nodes), 'part', '/a/c/o/with/slashes') self.assertTrue('swift.object/a/c/o/with/slashes' in resp.environ) self.assertEqual( resp.environ['swift.object/a/c/o/with/slashes']['status'], 200) req = Request.blank('/v1/a/c/o') with patch('swift.proxy.controllers.base.' 'http_connect', fake_http_connect(200)): resp = base.GETorHEAD_base(req, 'object', iter(nodes), 'part', '/a/c/o') self.assertTrue('swift.object/a/c/o' in resp.environ) self.assertEqual(resp.environ['swift.object/a/c/o']['status'], 200) req = Request.blank('/v1/a/c') with patch('swift.proxy.controllers.base.' 'http_connect', fake_http_connect(200)): resp = base.GETorHEAD_base(req, 'container', iter(nodes), 'part', '/a/c') self.assertTrue('swift.container/a/c' in resp.environ) self.assertEqual(resp.environ['swift.container/a/c']['status'], 200) req = Request.blank('/v1/a') with patch('swift.proxy.controllers.base.' 'http_connect', fake_http_connect(200)): resp = base.GETorHEAD_base(req, 'account', iter(nodes), 'part', '/a') self.assertTrue('swift.account/a' in resp.environ) self.assertEqual(resp.environ['swift.account/a']['status'], 200) # 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)
[(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)
def setUp(self): self.app = proxy_server.Application( None, account_ring=FakeRing(replicas=4), container_ring=FakeRing(replicas=4))
class InternalClient(object): container_ring = FakeRing()
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]))
""" 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))
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)
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'
""" 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)