diff --git a/features/patroni_api.feature b/features/patroni_api.feature index 05eedaf0..107a7199 100644 --- a/features/patroni_api.feature +++ b/features/patroni_api.feature @@ -71,6 +71,14 @@ Scenario: check the switchover via the API in the pause mode And postgres1 role is the primary after 10 seconds And postgres0 role is the secondary after 10 seconds And replication works from postgres1 to postgres0 after 20 seconds + When I issue a GET request to http://127.0.0.1:8008/master + Then I receive a response code 503 + When I issue a GET request to http://127.0.0.1:8008/replica + Then I receive a response code 200 + When I issue a GET request to http://127.0.0.1:8009/master + Then I receive a response code 200 + When I issue a GET request to http://127.0.0.1:8009/replica + Then I receive a response code 503 Scenario: check the scheduled switchover Given I issue a scheduled switchover from postgres1 to postgres0 in 3 seconds @@ -84,6 +92,14 @@ Scenario: check the scheduled switchover And postgres0 role is the primary after 10 seconds And postgres1 role is the secondary after 10 seconds And replication works from postgres0 to postgres1 after 25 seconds + When I issue a GET request to http://127.0.0.1:8008/master + Then I receive a response code 200 + When I issue a GET request to http://127.0.0.1:8008/replica + Then I receive a response code 503 + When I issue a GET request to http://127.0.0.1:8009/master + Then I receive a response code 503 + When I issue a GET request to http://127.0.0.1:8009/replica + Then I receive a response code 200 Scenario: check the scheduled restart Given I issue a PATCH request to http://127.0.0.1:8008/config with {"postgresql": {"parameters": {"superuser_reserved_connections": "6"}}} diff --git a/setup.py b/setup.py index 74322f8e..d81011ef 100644 --- a/setup.py +++ b/setup.py @@ -32,9 +32,10 @@ VERSION = read_version(MAIN_PACKAGE) DESCRIPTION = 'PostgreSQL High-Available orchestrator and CLI' LICENSE = 'The MIT License' URL = 'https://github.com/zalando/patroni' -AUTHOR = 'Alexander Kukushkin, Oleksii Kliukin, Feike Steenbergen' -AUTHOR_EMAIL = 'alexander.kukushkin@zalando.de, oleksii.kliukin@zalando.de, feike.steenbergen@zalando.de' -KEYWORDS = 'etcd governor patroni postgresql postgres ha haproxy confd zookeeper exhibitor consul streaming replication' +AUTHOR = 'Alexander Kukushkin, Dmitrii Dolgov, Oleksii Kliukin' +AUTHOR_EMAIL = 'alexander.kukushkin@zalando.de, dmitrii.dolgov@zalando.de, alexk@hintbits.com' +KEYWORDS = 'etcd governor patroni postgresql postgres ha haproxy confd' +\ + ' zookeeper exhibitor consul streaming replication kubernetes k8s' COVERAGE_XML = True COVERAGE_HTML = False @@ -43,14 +44,17 @@ JUNIT_XML = True # Add here all kinds of additional classifiers as defined under # https://pypi.python.org/pypi?%3Aaction=list_classifiers CLASSIFIERS = [ - 'Development Status :: 4 - Beta', + 'Development Status :: 5 - Production/Stable', 'Environment :: Console', 'Intended Audience :: Developers', 'Intended Audience :: System Administrators', 'License :: OSI Approved :: MIT License', + 'Operating System :: MacOS', 'Operating System :: POSIX :: Linux', + 'Operating System :: POSIX :: BSD :: FreeBSD', 'Programming Language :: Python', 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', diff --git a/tests/test_config.py b/tests/test_config.py index 26d64395..3d899e38 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -70,6 +70,7 @@ class TestConfig(unittest.TestCase): self.assertRaises(Exception, config.reload_local_configuration, True) self.assertTrue(config.reload_local_configuration(True)) self.assertTrue(config.reload_local_configuration()) + self.assertIsNone(config.reload_local_configuration()) @patch('tempfile.mkstemp', Mock(return_value=[3000, 'blabla'])) @patch('os.path.exists', Mock(return_value=True)) diff --git a/tests/test_consul.py b/tests/test_consul.py index fad173d2..496caaa2 100644 --- a/tests/test_consul.py +++ b/tests/test_consul.py @@ -62,7 +62,7 @@ class TestHTTPClient(unittest.TestCase): def test_put(self): self.client.put(Mock(), '/v1/session/create') - self.client.put(Mock(), '/v1/session/create', data='{"foo": "bar"}') + self.client.put(Mock(), '/v1/session/create', params=[], data='{"foo": "bar"}') @patch.object(consul.Consul.KV, 'get', kv_get) diff --git a/tests/test_ctl.py b/tests/test_ctl.py index 46987769..12b22770 100644 --- a/tests/test_ctl.py +++ b/tests/test_ctl.py @@ -225,6 +225,22 @@ class TestCtl(unittest.TestCase): result = self.runner.invoke(ctl, ['dsn', 'alpha', '--member', 'dummy']) assert result.exit_code == 1 + @patch('requests.post') + @patch('patroni.ctl.get_dcs') + def test_reload(self, mock_get_dcs, mock_post): + mock_get_dcs.return_value.get_cluster = get_cluster_initialized_with_leader + + result = self.runner.invoke(ctl, ['reload', 'alpha'], input='y') + assert 'Failed: reload for member' in result.output + + mock_post.return_value.status_code = 200 + result = self.runner.invoke(ctl, ['reload', 'alpha'], input='y') + assert 'No changes to apply on member' in result.output + + mock_post.return_value.status_code = 202 + result = self.runner.invoke(ctl, ['reload', 'alpha'], input='y') + assert 'Reload request received for member' in result.output + @patch('requests.post', requests_get) @patch('patroni.ctl.get_dcs') def test_restart_reinit(self, mock_get_dcs): diff --git a/tests/test_ha.py b/tests/test_ha.py index 7bc170da..b5364669 100644 --- a/tests/test_ha.py +++ b/tests/test_ha.py @@ -175,6 +175,9 @@ class TestHa(unittest.TestCase): self.p.replica_cached_timeline = Mock(side_effect=Exception) self.ha.touch_member() + def test_is_leader(self): + self.assertFalse(self.ha.is_leader()) + def test_start_as_replica(self): self.p.is_healthy = false self.assertEquals(self.ha.run_cycle(), 'starting as a secondary')