Merge "Refactor and add tests for db_replicator"
This commit is contained in:
commit
bbaf490887
@ -22,10 +22,13 @@ import math
|
|||||||
from mock import patch
|
from mock import patch
|
||||||
from shutil import rmtree
|
from shutil import rmtree
|
||||||
from tempfile import mkdtemp, NamedTemporaryFile
|
from tempfile import mkdtemp, NamedTemporaryFile
|
||||||
|
import mock
|
||||||
|
import simplejson
|
||||||
|
|
||||||
from swift.common import db_replicator
|
from swift.common import db_replicator
|
||||||
from swift.common.utils import normalize_timestamp
|
from swift.common.utils import normalize_timestamp
|
||||||
from swift.container import server as container_server
|
from swift.container import server as container_server
|
||||||
|
from swift.common.exceptions import DriveNotMounted
|
||||||
|
|
||||||
from test.unit import FakeLogger
|
from test.unit import FakeLogger
|
||||||
|
|
||||||
@ -74,6 +77,12 @@ class FakeRingWithNodes:
|
|||||||
meta=''
|
meta=''
|
||||||
), dict(
|
), dict(
|
||||||
id=4, weight=10.0, zone=4, ip='1.1.1.4', port=6000, device='sdb',
|
id=4, weight=10.0, zone=4, ip='1.1.1.4', port=6000, device='sdb',
|
||||||
|
meta=''
|
||||||
|
), dict(
|
||||||
|
id=5, weight=10.0, zone=5, ip='1.1.1.5', port=6000, device='sdb',
|
||||||
|
meta=''
|
||||||
|
), dict(
|
||||||
|
id=6, weight=10.0, zone=6, ip='1.1.1.6', port=6000, device='sdb',
|
||||||
meta='')]
|
meta='')]
|
||||||
|
|
||||||
def __init__(self, path, reload_time=15, ring_name=None):
|
def __init__(self, path, reload_time=15, ring_name=None):
|
||||||
@ -118,8 +127,9 @@ def _mock_process(*args):
|
|||||||
|
|
||||||
|
|
||||||
class ReplHttp:
|
class ReplHttp:
|
||||||
def __init__(self, response=None):
|
def __init__(self, response=None, set_status=200):
|
||||||
self.response = response
|
self.response = response
|
||||||
|
self.set_status = set_status
|
||||||
replicated = False
|
replicated = False
|
||||||
host = 'localhost'
|
host = 'localhost'
|
||||||
|
|
||||||
@ -127,7 +137,7 @@ class ReplHttp:
|
|||||||
self.replicated = True
|
self.replicated = True
|
||||||
|
|
||||||
class Response:
|
class Response:
|
||||||
status = 200
|
status = self.set_status
|
||||||
data = self.response
|
data = self.response
|
||||||
|
|
||||||
def read(innerself):
|
def read(innerself):
|
||||||
@ -381,7 +391,7 @@ class TestDBReplicator(unittest.TestCase):
|
|||||||
def test_in_sync(self):
|
def test_in_sync(self):
|
||||||
replicator = TestReplicator({})
|
replicator = TestReplicator({})
|
||||||
self.assertEquals(replicator._in_sync(
|
self.assertEquals(replicator._in_sync(
|
||||||
{'id': 'a', 'point': -1, 'max_row': 0, 'hash': 'b'},
|
{'id': 'a', 'point': 0, 'max_row': 0, 'hash': 'b'},
|
||||||
{'id': 'a', 'point': -1, 'max_row': 0, 'hash': 'b'},
|
{'id': 'a', 'point': -1, 'max_row': 0, 'hash': 'b'},
|
||||||
FakeBroker(), -1), True)
|
FakeBroker(), -1), True)
|
||||||
self.assertEquals(replicator._in_sync(
|
self.assertEquals(replicator._in_sync(
|
||||||
@ -402,25 +412,12 @@ class TestDBReplicator(unittest.TestCase):
|
|||||||
replicator = TestReplicator({})
|
replicator = TestReplicator({})
|
||||||
replicator._usync_db(0, FakeBroker(), fake_http, '12345', '67890')
|
replicator._usync_db(0, FakeBroker(), fake_http, '12345', '67890')
|
||||||
|
|
||||||
def test_repl_to_node(self):
|
|
||||||
replicator = TestReplicator({})
|
|
||||||
fake_node = {'ip': '127.0.0.1', 'device': 'sda1', 'port': 1000}
|
|
||||||
fake_info = {'id': 'a', 'point': -1, 'max_row': 0, 'hash': 'b',
|
|
||||||
'created_at': 100, 'put_timestamp': 0,
|
|
||||||
'delete_timestamp': 0,
|
|
||||||
'metadata': {'Test': ('Value', normalize_timestamp(1))}}
|
|
||||||
replicator._http_connect = lambda *args: ReplHttp(
|
|
||||||
'{"id": 3, "point": -1}')
|
|
||||||
self.assertEquals(replicator._repl_to_node(
|
|
||||||
fake_node, FakeBroker(), '0', fake_info), True)
|
|
||||||
|
|
||||||
def test_stats(self):
|
def test_stats(self):
|
||||||
# I'm not sure how to test that this logs the right thing,
|
# I'm not sure how to test that this logs the right thing,
|
||||||
# but we can at least make sure it gets covered.
|
# but we can at least make sure it gets covered.
|
||||||
replicator = TestReplicator({})
|
replicator = TestReplicator({})
|
||||||
replicator._zero_stats()
|
replicator._zero_stats()
|
||||||
replicator._report_stats()
|
replicator._report_stats()
|
||||||
|
|
||||||
def test_replicate_object(self):
|
def test_replicate_object(self):
|
||||||
db_replicator.ring = FakeRingWithNodes()
|
db_replicator.ring = FakeRingWithNodes()
|
||||||
replicator = TestReplicator({})
|
replicator = TestReplicator({})
|
||||||
@ -503,6 +500,7 @@ class TestDBReplicator(unittest.TestCase):
|
|||||||
[(('Found /path/to/file for /a%20c%20t/c%20o%20n when it should '
|
[(('Found /path/to/file for /a%20c%20t/c%20o%20n when it should '
|
||||||
'be on partition 0; will replicate out and remove.',), {})])
|
'be on partition 0; will replicate out and remove.',), {})])
|
||||||
|
|
||||||
|
|
||||||
def test_delete_db(self):
|
def test_delete_db(self):
|
||||||
db_replicator.lock_parent_directory = lock_parent_directory
|
db_replicator.lock_parent_directory = lock_parent_directory
|
||||||
replicator = TestReplicator({})
|
replicator = TestReplicator({})
|
||||||
@ -753,6 +751,105 @@ class TestDBReplicator(unittest.TestCase):
|
|||||||
db_replicator.os.path.exists = orig_exists
|
db_replicator.os.path.exists = orig_exists
|
||||||
db_replicator.random.shuffle = orig_shuffle
|
db_replicator.random.shuffle = orig_shuffle
|
||||||
|
|
||||||
|
@mock.patch("swift.common.db_replicator.ReplConnection", mock.Mock())
|
||||||
|
def test_http_connect(self):
|
||||||
|
node = "node"
|
||||||
|
partition = "partition"
|
||||||
|
db_file = __file__
|
||||||
|
replicator = TestReplicator({})
|
||||||
|
replicator._http_connect(node, partition, db_file)
|
||||||
|
db_replicator.ReplConnection.assert_has_calls(
|
||||||
|
mock.call(node, partition,
|
||||||
|
os.path.basename(db_file).split('.', 1)[0],
|
||||||
|
replicator.logger))
|
||||||
|
|
||||||
|
|
||||||
|
class TestReplToNode(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
db_replicator.ring = FakeRing()
|
||||||
|
self.delete_db_calls = []
|
||||||
|
self.broker = FakeBroker()
|
||||||
|
self.replicator = TestReplicator({})
|
||||||
|
self.fake_node = {'ip': '127.0.0.1', 'device': 'sda1', 'port': 1000}
|
||||||
|
self.fake_info = {'id': 'a', 'point': -1, 'max_row': 10, 'hash': 'b',
|
||||||
|
'created_at': 100, 'put_timestamp': 0,
|
||||||
|
'delete_timestamp': 0, 'count': 0,
|
||||||
|
'metadata': {'Test': ('Value', normalize_timestamp(1))}}
|
||||||
|
self.replicator.logger= mock.Mock()
|
||||||
|
self.replicator._rsync_db = mock.Mock(return_value=True)
|
||||||
|
self.replicator._usync_db = mock.Mock(return_value=True)
|
||||||
|
self.http = ReplHttp('{"id": 3, "point": -1}')
|
||||||
|
self.replicator._http_connect = lambda *args: self.http
|
||||||
|
|
||||||
|
|
||||||
|
def test_repl_to_node_usync_success(self):
|
||||||
|
rinfo = {"id": 3, "point": -1, "max_row": 5, "hash": "c"}
|
||||||
|
self.http = ReplHttp(simplejson.dumps(rinfo))
|
||||||
|
local_sync = self.broker.get_sync()
|
||||||
|
self.assertEquals(self.replicator._repl_to_node(
|
||||||
|
self.fake_node, self.broker, '0', self.fake_info), True)
|
||||||
|
self.replicator._usync_db.assert_has_calls([
|
||||||
|
mock.call(max(rinfo['point'], local_sync), self.broker,
|
||||||
|
self.http, rinfo['id'], self.fake_info['id'])
|
||||||
|
])
|
||||||
|
|
||||||
|
def test_repl_to_node_rsync_success(self):
|
||||||
|
rinfo = {"id": 3, "point": -1, "max_row": 4, "hash": "c"}
|
||||||
|
self.http = ReplHttp(simplejson.dumps(rinfo))
|
||||||
|
local_sync = self.broker.get_sync()
|
||||||
|
self.assertEquals(self.replicator._repl_to_node(
|
||||||
|
self.fake_node, self.broker, '0', self.fake_info), True)
|
||||||
|
self.replicator.logger.increment.assert_has_calls([
|
||||||
|
mock.call.increment('remote_merges')
|
||||||
|
])
|
||||||
|
self.replicator._rsync_db.assert_has_calls([
|
||||||
|
mock.call(self.broker, self.fake_node, self.http, self.fake_info['id'],
|
||||||
|
replicate_method='rsync_then_merge',
|
||||||
|
replicate_timeout=(self.fake_info['count'] / 2000))
|
||||||
|
])
|
||||||
|
|
||||||
|
def test_repl_to_node_already_in_sync(self):
|
||||||
|
rinfo = {"id": 3, "point": -1, "max_row": 10, "hash": "b"}
|
||||||
|
self.http = ReplHttp(simplejson.dumps(rinfo))
|
||||||
|
local_sync = self.broker.get_sync()
|
||||||
|
self.assertEquals(self.replicator._repl_to_node(
|
||||||
|
self.fake_node, self.broker, '0', self.fake_info), True)
|
||||||
|
self.assertEquals(self.replicator._rsync_db.call_count, 0)
|
||||||
|
self.assertEquals(self.replicator._usync_db.call_count, 0)
|
||||||
|
|
||||||
|
def test_repl_to_node_not_found(self):
|
||||||
|
self.http = ReplHttp('{"id": 3, "point": -1}', set_status=404)
|
||||||
|
self.assertEquals(self.replicator._repl_to_node(
|
||||||
|
self.fake_node, self.broker, '0', self.fake_info), True)
|
||||||
|
self.replicator.logger.increment.assert_has_calls([
|
||||||
|
mock.call.increment('rsyncs')
|
||||||
|
])
|
||||||
|
self.replicator._rsync_db.assert_has_calls([
|
||||||
|
mock.call(self.broker, self.fake_node, self.http, self.fake_info['id'])
|
||||||
|
])
|
||||||
|
|
||||||
|
def test_repl_to_node_drive_not_mounted(self):
|
||||||
|
self.http = ReplHttp('{"id": 3, "point": -1}', set_status=507)
|
||||||
|
|
||||||
|
self.assertRaises(DriveNotMounted, self.replicator._repl_to_node,
|
||||||
|
self.fake_node, FakeBroker(), '0', self.fake_info)
|
||||||
|
|
||||||
|
def test_repl_to_node_300_status(self):
|
||||||
|
self.http = ReplHttp('{"id": 3, "point": -1}', set_status=300)
|
||||||
|
|
||||||
|
self.assertEquals(self.replicator._repl_to_node(
|
||||||
|
self.fake_node, FakeBroker(), '0', self.fake_info), None)
|
||||||
|
|
||||||
|
def test_repl_to_node_http_connect_fails(self):
|
||||||
|
self.replicator._http_connect = lambda *args: None
|
||||||
|
self.assertEquals(self.replicator._repl_to_node(
|
||||||
|
self.fake_node, FakeBroker(), '0', self.fake_info), False)
|
||||||
|
|
||||||
|
def test_repl_to_node_not_response(self):
|
||||||
|
self.http = mock.Mock(replicate=mock.Mock(return_value=None))
|
||||||
|
self.assertEquals(self.replicator._repl_to_node(
|
||||||
|
self.fake_node, FakeBroker(), '0', self.fake_info), False)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
Loading…
Reference in New Issue
Block a user