diff --git a/tests/test_ctl.py b/tests/test_ctl.py index e5c450c1..5d6b33d6 100644 --- a/tests/test_ctl.py +++ b/tests/test_ctl.py @@ -8,7 +8,6 @@ from click.testing import CliRunner from mock import patch, Mock from patroni.ctl import ctl, members, store_config, load_config, output_members, post_patroni, get_dcs, parse_dcs, \ wait_for_leader, get_all_members, get_any_member, get_cursor, query_member, configure, PatroniCtlException -from patroni.etcd import Etcd, Client from psycopg2 import OperationalError from test_etcd import etcd_read, requests_get, socket_getaddrinfo, MockResponse from test_ha import get_cluster_initialized_without_leader, get_cluster_initialized_with_leader, \ @@ -50,9 +49,9 @@ class TestCtl(unittest.TestCase): @patch('socket.getaddrinfo', socket_getaddrinfo) def setUp(self): self.runner = CliRunner() - with patch.object(Client, 'machines') as mock_machines: + with patch.object(etcd.Client, 'machines') as mock_machines: mock_machines.__get__ = Mock(return_value=['http://remotehost:2379']) - self.e = Etcd('foo', {'ttl': 30, 'host': 'ok:2379', 'scope': 'test'}) + self.e = get_dcs({'etcd': {'ttl': 30, 'host': 'ok:2379', 'scope': 'test'}}, 'foo') @patch('psycopg2.connect', psycopg2_connect) def test_get_cursor(self): @@ -81,29 +80,30 @@ class TestCtl(unittest.TestCase): self.assertIsNone(output_members(cluster, name='abc', fmt='json')) self.assertIsNone(output_members(cluster, name='abc', fmt='tsv')) - @patch('patroni.etcd.Etcd.get_cluster', Mock(return_value=get_cluster_initialized_with_leader())) - @patch('patroni.etcd.Etcd.get_etcd_client', Mock(return_value=None)) + @patch('patroni.ctl.get_dcs') @patch('patroni.ctl.post_patroni', Mock(return_value=MockResponse())) - def test_failover(self): - result = self.runner.invoke(ctl, ['failover', 'dummy'], input='''leader\nother\n\ny''') + def test_failover(self, mock_get_dcs): + mock_get_dcs.return_value = self.e + mock_get_dcs.return_value.get_cluster = get_cluster_initialized_with_leader + result = self.runner.invoke(ctl, ['failover', 'dummy'], input='leader\nother\n\ny') assert 'leader' in result.output - result = self.runner.invoke(ctl, ['failover', 'dummy'], input='''leader\nother\n2100-01-01T12:23:00\ny''') + result = self.runner.invoke(ctl, ['failover', 'dummy'], input='leader\nother\n2100-01-01T12:23:00\ny') assert result.exit_code == 0 - result = self.runner.invoke(ctl, ['failover', 'dummy'], input='''leader\nother\n2030-01-01T12:23:00\ny''') + result = self.runner.invoke(ctl, ['failover', 'dummy'], input='leader\nother\n2030-01-01T12:23:00\ny') assert result.exit_code == 0 # Aborting failover,as we anser NO to the confirmation - result = self.runner.invoke(ctl, ['failover', 'dummy'], input='''leader\nother\n\nN''') + result = self.runner.invoke(ctl, ['failover', 'dummy'], input='leader\nother\n\nN') assert result.exit_code == 1 # Target and source are equal - result = self.runner.invoke(ctl, ['failover', 'dummy'], input='''leader\nleader\n\ny''') + result = self.runner.invoke(ctl, ['failover', 'dummy'], input='leader\nleader\n\ny') assert result.exit_code == 1 # Reality is not part of this cluster - result = self.runner.invoke(ctl, ['failover', 'dummy'], input='''leader\nReality\n\ny''') + result = self.runner.invoke(ctl, ['failover', 'dummy'], input='leader\nReality\n\ny') assert result.exit_code == 1 result = self.runner.invoke(ctl, ['failover', 'dummy', '--force']) @@ -124,26 +124,26 @@ class TestCtl(unittest.TestCase): result = self.runner.invoke(ctl, ['failover', 'dummy'], input='dummy') assert result.exit_code == 1 - with patch('patroni.etcd.Etcd.get_cluster', Mock(return_value=get_cluster_initialized_with_only_leader())): - # No members available - result = self.runner.invoke(ctl, ['failover', 'dummy'], input='''leader\nother\n\ny''') - assert result.exit_code == 1 - - with patch('patroni.etcd.Etcd.get_cluster', Mock(return_value=get_cluster_initialized_without_leader())): - # No master available - result = self.runner.invoke(ctl, ['failover', 'dummy'], input='''leader\nother\n\ny''') - assert result.exit_code == 1 - with patch('patroni.ctl.post_patroni', Mock(side_effect=Exception)): # Non-responding patroni - result = self.runner.invoke(ctl, ['failover', 'dummy'], input='''leader\nother\n\ny''') + result = self.runner.invoke(ctl, ['failover', 'dummy'], input='leader\nother\n\ny') assert 'falling back to DCS' in result.output with patch('patroni.ctl.post_patroni') as mocked: mocked.return_value.status_code = 500 - result = self.runner.invoke(ctl, ['failover', 'dummy'], input='''leader\nother\n\ny''') + result = self.runner.invoke(ctl, ['failover', 'dummy'], input='leader\nother\n\ny') assert 'Failover failed' in result.output + # No members available + mock_get_dcs.return_value.get_cluster = get_cluster_initialized_with_only_leader + result = self.runner.invoke(ctl, ['failover', 'dummy'], input='leader\nother\n\ny') + assert result.exit_code == 1 + + # No master available + mock_get_dcs.return_value.get_cluster = get_cluster_initialized_without_leader + result = self.runner.invoke(ctl, ['failover', 'dummy'], input='leader\nother\n\ny') + assert result.exit_code == 1 + def test_get_dcs(self): self.assertRaises(PatroniCtlException, get_dcs, {'dummy': {}}, 'dummy') with patch('patroni.Patroni.get_dcs', Mock(return_value=self.e)): @@ -151,36 +151,37 @@ class TestCtl(unittest.TestCase): @patch('psycopg2.connect', psycopg2_connect) @patch('patroni.ctl.query_member', Mock(return_value=([['mock column']], None))) + @patch('patroni.ctl.get_dcs') @patch.object(etcd.Client, 'read', etcd_read) - def test_query(self): - with patch('patroni.ctl.get_dcs', Mock(return_value=self.e)): + def test_query(self, mock_get_dcs): + mock_get_dcs.return_value = self.e + # Mutually exclusive + result = self.runner.invoke(ctl, ['query', 'alpha', '--member', 'abc', '--role', 'master']) + assert result.exit_code == 1 + + with self.runner.isolated_filesystem(): + with open('dummy', 'w') as dummy_file: + dummy_file.write('SELECT 1') + # Mutually exclusive - result = self.runner.invoke(ctl, ['query', 'alpha', '--member', 'abc', '--role', 'master']) + result = self.runner.invoke(ctl, ['query', 'alpha', '--file', 'dummy', '--command', 'dummy']) assert result.exit_code == 1 - with self.runner.isolated_filesystem(): - with open('dummy', 'w') as dummy_file: - dummy_file.write('SELECT 1') + result = self.runner.invoke(ctl, ['query', 'alpha', '--file', 'dummy']) + assert result.exit_code == 0 - # Mutually exclusive - result = self.runner.invoke(ctl, ['query', 'alpha', '--file', 'dummy', '--command', 'dummy']) - assert result.exit_code == 1 + os.remove('dummy') - result = self.runner.invoke(ctl, ['query', 'alpha', '--file', 'dummy']) - assert result.exit_code == 0 + result = self.runner.invoke(ctl, ['query', 'alpha', '--command', 'SELECT 1']) + assert 'mock column' in result.output - os.remove('dummy') + # --command or --file is mandatory + result = self.runner.invoke(ctl, ['query', 'alpha']) + assert result.exit_code == 1 - result = self.runner.invoke(ctl, ['query', 'alpha', '--command', 'SELECT 1']) - assert 'mock column' in result.output - - # --command or --file is mandatory - result = self.runner.invoke(ctl, ['query', 'alpha']) - assert result.exit_code == 1 - - result = self.runner.invoke(ctl, ['query', 'alpha', '--command', 'SELECT 1', '--username', 'root', - '--password', '--dbname', 'postgres'], input='ab\nab') - assert 'mock column' in result.output + result = self.runner.invoke(ctl, ['query', 'alpha', '--command', 'SELECT 1', '--username', 'root', + '--password', '--dbname', 'postgres'], input='ab\nab') + assert 'mock column' in result.output def test_query_member(self): with patch('patroni.ctl.get_cursor', Mock(return_value=MockConnect().cursor())): @@ -203,24 +204,24 @@ class TestCtl(unittest.TestCase): with patch('patroni.ctl.get_cursor', Mock(side_effect=OperationalError('bla'))): rows = query_member(None, None, None, 'replica', 'SELECT pg_is_in_recovery()') - @patch('patroni.dcs.AbstractDCS.get_cluster', Mock(return_value=get_cluster_initialized_with_leader())) - def test_dsn(self): - with patch('patroni.ctl.get_dcs', Mock(return_value=self.e)): - result = self.runner.invoke(ctl, ['dsn', 'alpha']) - assert 'host=127.0.0.1 port=5435' in result.output + @patch('patroni.ctl.get_dcs') + def test_dsn(self, mock_get_dcs): + mock_get_dcs.return_value.get_cluster = get_cluster_initialized_with_leader + result = self.runner.invoke(ctl, ['dsn', 'alpha']) + assert 'host=127.0.0.1 port=5435' in result.output - # Mutually exclusive options - result = self.runner.invoke(ctl, ['dsn', 'alpha', '--role', 'master', '--member', 'dummy']) - assert result.exit_code == 1 + # Mutually exclusive options + result = self.runner.invoke(ctl, ['dsn', 'alpha', '--role', 'master', '--member', 'dummy']) + assert result.exit_code == 1 - # Non-existing member - result = self.runner.invoke(ctl, ['dsn', 'alpha', '--member', 'dummy']) - assert result.exit_code == 1 + # Non-existing member + result = self.runner.invoke(ctl, ['dsn', 'alpha', '--member', 'dummy']) + assert result.exit_code == 1 - @patch('patroni.etcd.Etcd.get_cluster', Mock(return_value=get_cluster_initialized_with_leader())) - @patch('patroni.etcd.Etcd.get_etcd_client', Mock(return_value=None)) @patch('requests.post', requests_get) - def test_restart_reinit(self): + @patch('patroni.ctl.get_dcs') + def test_restart_reinit(self, mock_get_dcs): + mock_get_dcs.return_value.get_cluster = get_cluster_initialized_with_leader result = self.runner.invoke(ctl, ['restart', 'alpha'], input='y') assert 'restart failed for' in result.output assert result.exit_code == 0 @@ -240,29 +241,28 @@ class TestCtl(unittest.TestCase): result = self.runner.invoke(ctl, ['restart', 'alpha'], input='y') assert result.exit_code == 0 - @patch('patroni.etcd.Etcd.get_cluster', Mock(return_value=get_cluster_initialized_with_leader())) - @patch.object(etcd.Client, 'delete', Mock(side_effect=etcd.EtcdException)) - def test_remove(self): - with patch('patroni.ctl.get_dcs', Mock(return_value=self.e)): - result = self.runner.invoke(ctl, ['remove', 'alpha'], input='alpha\nslave') - assert 'Please confirm' in result.output - assert 'You are about to remove all' in result.output - # Not typing an exact confirmation - assert result.exit_code == 1 + @patch('patroni.ctl.get_dcs') + def test_remove(self, mock_get_dcs): + mock_get_dcs.return_value.get_cluster = get_cluster_initialized_with_leader + result = self.runner.invoke(ctl, ['remove', 'alpha'], input='alpha\nslave') + assert 'Please confirm' in result.output + assert 'You are about to remove all' in result.output + # Not typing an exact confirmation + assert result.exit_code == 1 - # master specified does not match master of cluster - result = self.runner.invoke(ctl, ['remove', 'alpha'], input='''alpha\nYes I am aware\nslave''') - assert result.exit_code == 1 + # master specified does not match master of cluster + result = self.runner.invoke(ctl, ['remove', 'alpha'], input='alpha\nYes I am aware\nslave') + assert result.exit_code == 1 - # cluster specified on cmdline does not match verification prompt - result = self.runner.invoke(ctl, ['remove', 'alpha'], input='beta\nleader') - assert result.exit_code == 1 + # cluster specified on cmdline does not match verification prompt + result = self.runner.invoke(ctl, ['remove', 'alpha'], input='beta\nleader') + assert result.exit_code == 1 - result = self.runner.invoke(ctl, ['remove', 'alpha'], input='''alpha\nYes I am aware\nleader''') - assert result.exit_code == 0 + result = self.runner.invoke(ctl, ['remove', 'alpha'], input='alpha\nYes I am aware\nleader') + assert result.exit_code == 0 - @patch('patroni.etcd.Etcd.watch', Mock(return_value=None)) - @patch('patroni.etcd.Etcd.get_cluster', Mock(return_value=get_cluster_initialized_with_leader())) + @patch('patroni.dcs.AbstractDCS.watch', Mock(return_value=None)) + @patch('patroni.dcs.AbstractDCS.get_cluster', Mock(return_value=get_cluster_initialized_with_leader())) def test_wait_for_leader(self): self.assertRaises(PatroniCtlException, wait_for_leader, self.e, 0) @@ -299,9 +299,9 @@ class TestCtl(unittest.TestCase): self.assertEquals(len(list(get_all_members(get_cluster_initialized_without_leader(), role='replica'))), 2) - @patch('patroni.etcd.Etcd.get_cluster', Mock(return_value=get_cluster_initialized_with_leader())) - @patch('patroni.etcd.Etcd.get_etcd_client', Mock(return_value=None)) - def test_members(self): + @patch('patroni.ctl.get_dcs') + def test_members(self, mock_get_dcs): + mock_get_dcs.return_value.get_cluster = get_cluster_initialized_with_leader result = self.runner.invoke(members, ['alpha']) assert '127.0.0.1' in result.output assert result.exit_code == 0 diff --git a/tests/test_etcd.py b/tests/test_etcd.py index ef61f413..a6116652 100644 --- a/tests/test_etcd.py +++ b/tests/test_etcd.py @@ -240,6 +240,9 @@ class TestEtcd(unittest.TestCase): def test_delete_leader(self): self.assertFalse(self.etcd.delete_leader()) + def test_delete_cluster(self): + self.assertFalse(self.etcd.delete_cluster()) + @patch.object(etcd.Client, 'watch', etcd_watch) def test_watch(self): self.etcd.watch(0) @@ -249,6 +252,6 @@ class TestEtcd(unittest.TestCase): with patch.object(AbstractDCS, 'watch', Mock()): self.etcd.watch(9.5) - @patch('patroni.etcd.Etcd.retry', Mock(side_effect=AttributeError("foo"))) def test_other_exceptions(self): + self.etcd.retry = Mock(side_effect=AttributeError('foo')) self.assertRaises(EtcdError, self.etcd.cancel_initialization) diff --git a/tests/test_ha.py b/tests/test_ha.py index 3071ecc8..9dc512e0 100644 --- a/tests/test_ha.py +++ b/tests/test_ha.py @@ -5,10 +5,10 @@ import pytz from mock import Mock, MagicMock, patch from patroni.dcs import Cluster, Failover, Leader, Member -from patroni.etcd import Client, Etcd from patroni.exceptions import DCSError, PostgresException from patroni.ha import Ha from patroni.postgresql import Postgresql +from patroni import Patroni from test_etcd import socket_getaddrinfo, etcd_read, etcd_write, requests_get @@ -85,7 +85,7 @@ class TestHa(unittest.TestCase): @patch('socket.getaddrinfo', socket_getaddrinfo) @patch.object(etcd.Client, 'read', etcd_read) def setUp(self): - with patch.object(Client, 'machines') as mock_machines: + with patch.object(etcd.Client, 'machines') as mock_machines: mock_machines.__get__ = Mock(return_value=['http://remotehost:2379']) self.p = Postgresql({'name': 'postgresql0', 'scope': 'dummy', 'listen': '127.0.0.1:5432', 'data_dir': 'data/postgresql0', 'superuser': {}, 'admin': {}, @@ -94,7 +94,7 @@ class TestHa(unittest.TestCase): self.p.set_role('replica') self.p.check_replication_lag = true self.p.can_create_replica_without_replication_connection = MagicMock(return_value=False) - self.e = Etcd('foo', {'ttl': 30, 'host': 'ok:2379', 'scope': 'test'}) + self.e = Patroni.get_dcs('foo', {'etcd': {'ttl': 30, 'host': 'ok:2379', 'scope': 'test'}}) self.ha = Ha(MockPatroni(self.p, self.e)) self.ha._async_executor.run_async = run_async self.ha.old_cluster = self.e.get_cluster() diff --git a/tests/test_patroni.py b/tests/test_patroni.py index 6f7e67fe..3f5e913c 100644 --- a/tests/test_patroni.py +++ b/tests/test_patroni.py @@ -9,11 +9,10 @@ from mock import Mock, patch from patroni.api import RestApiServer from patroni.async_executor import AsyncExecutor from patroni.consul import Consul -from patroni.etcd import Etcd from patroni import Patroni, PatroniException, main as _main from patroni.zookeeper import ZooKeeper from six.moves import BaseHTTPServer -from test_etcd import Client, SleepException, etcd_read, etcd_write +from test_etcd import SleepException, etcd_read, etcd_write from test_postgresql import Postgresql, psycopg2_connect from test_zookeeper import MockKazooClient @@ -30,13 +29,11 @@ from test_zookeeper import MockKazooClient class TestPatroni(unittest.TestCase): def setUp(self): - with patch.object(Client, 'machines') as mock_machines: + RestApiServer._BaseServer__is_shut_down = Mock() + RestApiServer._BaseServer__shutdown_request = True + RestApiServer.socket = 0 + with patch.object(etcd.Client, 'machines') as mock_machines: mock_machines.__get__ = Mock(return_value=['http://remotehost:2379']) - self.touched = False - self.init_cancelled = False - RestApiServer._BaseServer__is_shut_down = Mock() - RestApiServer._BaseServer__shutdown_request = True - RestApiServer.socket = 0 with open('postgres0.yml', 'r') as f: config = yaml.load(f) self.p = Patroni(config) @@ -49,8 +46,8 @@ class TestPatroni(unittest.TestCase): self.assertRaises(PatroniException, self.p.get_dcs, '', {}) @patch('time.sleep', Mock(side_effect=SleepException)) - @patch.object(Etcd, 'delete_leader', Mock()) - @patch.object(Client, 'machines') + @patch.object(etcd.Client, 'delete', Mock()) + @patch.object(etcd.Client, 'machines') def test_patroni_main(self, mock_machines): with patch('subprocess.call', Mock(return_value=1)): _main() diff --git a/tests/test_zookeeper.py b/tests/test_zookeeper.py index 5e9ebc82..a784b0eb 100644 --- a/tests/test_zookeeper.py +++ b/tests/test_zookeeper.py @@ -92,7 +92,7 @@ class MockKazooClient(Mock): @patch('requests.get', requests_get) -@patch('patroni.zookeeper.sleep', Mock(side_effect=SleepException())) +@patch('time.sleep', Mock(side_effect=SleepException)) class TestExhibitorEnsembleProvider(unittest.TestCase): def test_init(self):