mirror of
https://github.com/outbackdingo/patroni.git
synced 2026-08-25 14:53:37 +00:00
Make GlobalConfig really global (#2935)
1. extract `GlobalConfig` class to its own module 2. make the module instantiate the `GlobalConfig` object on load and replace sys.modules with the this instance 3. don't pass `GlobalConfig` object around, but use `patroni.global_config` module everywhere. 4. move `ignore_slots_matchers`, `max_timelines_history`, and `permanent_slots` from `ClusterConfig` to `GlobalConfig`. 5. add `use_slots` property to global_config and remove duplicated code from `Cluster` and `Postgresql.ConfigHandler`. Besides that improve readability of couple of checks in ha.py and formatting of `/config` key when saved from patronictl.
This commit is contained in:
+12
-17
@@ -8,8 +8,8 @@ from io import BytesIO as IO
|
||||
from mock import Mock, PropertyMock, patch
|
||||
from socketserver import ThreadingMixIn
|
||||
|
||||
from patroni import global_config
|
||||
from patroni.api import RestApiHandler, RestApiServer
|
||||
from patroni.config import GlobalConfig
|
||||
from patroni.dcs import ClusterConfig, Member
|
||||
from patroni.exceptions import PostgresConnectionException
|
||||
from patroni.ha import _MemberStatus
|
||||
@@ -148,16 +148,9 @@ class MockLogger(object):
|
||||
records_lost = 1
|
||||
|
||||
|
||||
class MockConfig(object):
|
||||
|
||||
def get_global_config(self, _):
|
||||
return GlobalConfig({})
|
||||
|
||||
|
||||
class MockPatroni(object):
|
||||
|
||||
ha = MockHa()
|
||||
config = MockConfig()
|
||||
postgresql = ha.state_handler
|
||||
dcs = Mock()
|
||||
logger = MockLogger()
|
||||
@@ -211,7 +204,7 @@ class TestRestApiHandler(unittest.TestCase):
|
||||
def test_do_GET(self):
|
||||
MockPatroni.dcs.cluster.last_lsn = 20
|
||||
MockPatroni.dcs.cluster.sync.members = [MockPostgresql.name]
|
||||
with patch.object(GlobalConfig, 'is_synchronous_mode', PropertyMock(return_value=True)):
|
||||
with patch.object(global_config.__class__, 'is_synchronous_mode', PropertyMock(return_value=True)):
|
||||
MockRestApiServer(RestApiHandler, 'GET /replica')
|
||||
MockRestApiServer(RestApiHandler, 'GET /replica?lag=1M')
|
||||
MockRestApiServer(RestApiHandler, 'GET /replica?lag=10MB')
|
||||
@@ -234,7 +227,7 @@ class TestRestApiHandler(unittest.TestCase):
|
||||
with patch.object(MockHa, 'is_leader', Mock(return_value=True)):
|
||||
MockRestApiServer(RestApiHandler, 'GET /replica')
|
||||
MockRestApiServer(RestApiHandler, 'GET /read-only-sync')
|
||||
with patch.object(GlobalConfig, 'is_standby_cluster', Mock(return_value=True)):
|
||||
with patch.object(global_config.__class__, 'is_standby_cluster', Mock(return_value=True)):
|
||||
MockRestApiServer(RestApiHandler, 'GET /standby_leader')
|
||||
MockPatroni.dcs.cluster = None
|
||||
with patch.object(RestApiHandler, 'get_postgresql_status', Mock(return_value={'role': 'primary'})):
|
||||
@@ -244,8 +237,8 @@ class TestRestApiHandler(unittest.TestCase):
|
||||
self.assertIsNotNone(MockRestApiServer(RestApiHandler, 'GET /primary'))
|
||||
with patch.object(RestApiServer, 'query', Mock(return_value=[('', 1, '', '', '', '', False, None, None, '')])):
|
||||
self.assertIsNotNone(MockRestApiServer(RestApiHandler, 'GET /patroni'))
|
||||
with patch.object(GlobalConfig, 'is_standby_cluster', Mock(return_value=True)), \
|
||||
patch.object(GlobalConfig, 'is_paused', Mock(return_value=True)):
|
||||
with patch.object(global_config.__class__, 'is_standby_cluster', Mock(return_value=True)), \
|
||||
patch.object(global_config.__class__, 'is_paused', Mock(return_value=True)):
|
||||
MockRestApiServer(RestApiHandler, 'GET /standby_leader')
|
||||
|
||||
# test tags
|
||||
@@ -475,7 +468,7 @@ class TestRestApiHandler(unittest.TestCase):
|
||||
request = make_request(role='primary', postgres_version='9.5.2')
|
||||
MockRestApiServer(RestApiHandler, request)
|
||||
|
||||
with patch.object(GlobalConfig, 'is_paused', PropertyMock(return_value=True)):
|
||||
with patch.object(global_config.__class__, 'is_paused', PropertyMock(return_value=True)):
|
||||
MockRestApiServer(RestApiHandler, make_request(schedule='2016-08-42 12:45TZ+1', role='primary'))
|
||||
# Valid timeout
|
||||
MockRestApiServer(RestApiHandler, make_request(timeout='60s'))
|
||||
@@ -537,7 +530,7 @@ class TestRestApiHandler(unittest.TestCase):
|
||||
|
||||
# Switchover in pause mode
|
||||
with patch.object(RestApiHandler, 'write_response') as response_mock, \
|
||||
patch.object(GlobalConfig, 'is_paused', PropertyMock(return_value=True)):
|
||||
patch.object(global_config.__class__, 'is_paused', PropertyMock(return_value=True)):
|
||||
MockRestApiServer(RestApiHandler, request)
|
||||
response_mock.assert_called_with(
|
||||
400, 'Switchover is possible only to a specific candidate in a paused state')
|
||||
@@ -546,7 +539,8 @@ class TestRestApiHandler(unittest.TestCase):
|
||||
for is_synchronous_mode, response in (
|
||||
(True, 'switchover is not possible: can not find sync_standby'),
|
||||
(False, 'switchover is not possible: cluster does not have members except leader')):
|
||||
with patch.object(GlobalConfig, 'is_synchronous_mode', PropertyMock(return_value=is_synchronous_mode)), \
|
||||
with patch.object(global_config.__class__, 'is_synchronous_mode',
|
||||
PropertyMock(return_value=is_synchronous_mode)), \
|
||||
patch.object(RestApiHandler, 'write_response') as response_mock:
|
||||
MockRestApiServer(RestApiHandler, request)
|
||||
response_mock.assert_called_with(412, response)
|
||||
@@ -571,7 +565,8 @@ class TestRestApiHandler(unittest.TestCase):
|
||||
cluster.sync.matches.return_value = False
|
||||
for is_synchronous_mode, response in (
|
||||
(True, 'candidate name does not match with sync_standby'), (False, 'candidate does not exists')):
|
||||
with patch.object(GlobalConfig, 'is_synchronous_mode', PropertyMock(return_value=is_synchronous_mode)), \
|
||||
with patch.object(global_config.__class__, 'is_synchronous_mode',
|
||||
PropertyMock(return_value=is_synchronous_mode)), \
|
||||
patch.object(RestApiHandler, 'write_response') as response_mock:
|
||||
MockRestApiServer(RestApiHandler, request)
|
||||
response_mock.assert_called_with(412, response)
|
||||
@@ -632,7 +627,7 @@ class TestRestApiHandler(unittest.TestCase):
|
||||
|
||||
# Schedule in paused mode
|
||||
with patch.object(RestApiHandler, 'write_response') as response_mock, \
|
||||
patch.object(GlobalConfig, 'is_paused', PropertyMock(return_value=True)):
|
||||
patch.object(global_config.__class__, 'is_paused', PropertyMock(return_value=True)):
|
||||
dcs.manual_failover.return_value = False
|
||||
MockRestApiServer(RestApiHandler, request)
|
||||
response_mock.assert_called_with(400, "Can't schedule switchover in the paused state")
|
||||
|
||||
@@ -5,7 +5,11 @@ import io
|
||||
|
||||
from copy import deepcopy
|
||||
from mock import MagicMock, Mock, patch
|
||||
from patroni.config import Config, ConfigParseError, GlobalConfig
|
||||
|
||||
from patroni import global_config
|
||||
from patroni.config import ClusterConfig, Config, ConfigParseError
|
||||
|
||||
from .test_ha import get_cluster_initialized_with_only_leader
|
||||
|
||||
|
||||
class TestConfig(unittest.TestCase):
|
||||
@@ -248,4 +252,6 @@ class TestConfig(unittest.TestCase):
|
||||
def test_global_config_is_synchronous_mode(self):
|
||||
# we should ignore synchronous_mode setting in a standby cluster
|
||||
config = {'standby_cluster': {'host': 'some_host'}, 'synchronous_mode': True}
|
||||
self.assertFalse(GlobalConfig(config).is_synchronous_mode)
|
||||
cluster = get_cluster_initialized_with_only_leader(cluster_config=ClusterConfig(1, config, 1))
|
||||
test_config = global_config.from_cluster(cluster)
|
||||
self.assertFalse(test_config.is_synchronous_mode)
|
||||
|
||||
+6
-5
@@ -7,6 +7,7 @@ import unittest
|
||||
from click.testing import CliRunner
|
||||
from datetime import datetime, timedelta
|
||||
from mock import patch, Mock, PropertyMock
|
||||
from patroni import global_config
|
||||
from patroni.ctl import ctl, load_config, output_members, get_dcs, parse_dcs, \
|
||||
get_all_members, get_any_member, get_cursor, query_member, PatroniCtlException, apply_config_changes, \
|
||||
format_config_for_editing, show_diff, invoke_editor, format_pg_version, CONFIG_FILE_PATH, PatronictlPrettyTable
|
||||
@@ -147,7 +148,7 @@ class TestCtl(unittest.TestCase):
|
||||
self.assertEqual(result.exit_code, 0)
|
||||
|
||||
# Scheduled in pause mode
|
||||
with patch('patroni.config.GlobalConfig.is_paused', PropertyMock(return_value=True)):
|
||||
with patch.object(global_config.__class__, 'is_paused', PropertyMock(return_value=True)):
|
||||
result = self.runner.invoke(ctl, ['switchover', 'dummy', '--group', '0',
|
||||
'--force', '--scheduled', '2015-01-01T12:00:00'])
|
||||
self.assertEqual(result.exit_code, 1)
|
||||
@@ -369,7 +370,7 @@ class TestCtl(unittest.TestCase):
|
||||
result = self.runner.invoke(ctl, ['restart', 'alpha', 'other', '--force', '--scheduled', '2300-10-01T14:30'])
|
||||
assert 'Failed: flush scheduled restart' in result.output
|
||||
|
||||
with patch('patroni.config.GlobalConfig.is_paused', PropertyMock(return_value=True)):
|
||||
with patch.object(global_config.__class__, 'is_paused', PropertyMock(return_value=True)):
|
||||
result = self.runner.invoke(ctl,
|
||||
['restart', 'alpha', 'other', '--force', '--scheduled', '2300-10-01T14:30'])
|
||||
assert result.exit_code == 1
|
||||
@@ -533,7 +534,7 @@ class TestCtl(unittest.TestCase):
|
||||
result = self.runner.invoke(ctl, ['pause', 'dummy'])
|
||||
assert 'Failed' in result.output
|
||||
|
||||
with patch('patroni.config.GlobalConfig.is_paused', PropertyMock(return_value=True)):
|
||||
with patch.object(global_config.__class__, 'is_paused', PropertyMock(return_value=True)):
|
||||
result = self.runner.invoke(ctl, ['pause', 'dummy'])
|
||||
assert 'Cluster is already paused' in result.output
|
||||
|
||||
@@ -552,11 +553,11 @@ class TestCtl(unittest.TestCase):
|
||||
@patch('patroni.dcs.AbstractDCS.get_cluster', Mock(return_value=get_cluster_initialized_with_leader()))
|
||||
def test_resume_cluster(self, mock_post):
|
||||
mock_post.return_value.status = 200
|
||||
with patch('patroni.config.GlobalConfig.is_paused', PropertyMock(return_value=False)):
|
||||
with patch.object(global_config.__class__, 'is_paused', PropertyMock(return_value=False)):
|
||||
result = self.runner.invoke(ctl, ['resume', 'dummy'])
|
||||
assert 'Cluster is not paused' in result.output
|
||||
|
||||
with patch('patroni.config.GlobalConfig.is_paused', PropertyMock(return_value=True)):
|
||||
with patch.object(global_config.__class__, 'is_paused', PropertyMock(return_value=True)):
|
||||
result = self.runner.invoke(ctl, ['resume', 'dummy'])
|
||||
assert 'Success' in result.output
|
||||
|
||||
|
||||
+18
-14
@@ -4,6 +4,7 @@ import os
|
||||
import sys
|
||||
|
||||
from mock import Mock, MagicMock, PropertyMock, patch, mock_open
|
||||
from patroni import global_config
|
||||
from patroni.collections import CaseInsensitiveSet
|
||||
from patroni.config import Config
|
||||
from patroni.dcs import Cluster, ClusterConfig, Failover, Leader, Member, get_dcs, Status, SyncState, TimelineHistory
|
||||
@@ -217,6 +218,7 @@ class TestHa(PostgresInit):
|
||||
self.ha = Ha(MockPatroni(self.p, self.e))
|
||||
self.ha.old_cluster = self.e.get_cluster()
|
||||
self.ha.cluster = get_cluster_initialized_without_leader()
|
||||
global_config.update(self.ha.cluster)
|
||||
self.ha.load_cluster_from_dcs = Mock()
|
||||
|
||||
def test_update_lock(self):
|
||||
@@ -251,8 +253,10 @@ class TestHa(PostgresInit):
|
||||
@patch('patroni.dcs.etcd.Etcd.initialize', return_value=True)
|
||||
def test_bootstrap_as_standby_leader(self, initialize):
|
||||
self.p.data_directory_empty = true
|
||||
self.ha.cluster = get_cluster_not_initialized_without_leader(
|
||||
cluster_config=ClusterConfig(1, {"standby_cluster": {"port": 5432}}, 1))
|
||||
global_config.update(self.ha.cluster)
|
||||
self.ha.cluster = get_cluster_not_initialized_without_leader(cluster_config=ClusterConfig(0, {}, 0))
|
||||
self.ha.patroni.config._dynamic_configuration = {"standby_cluster": {"port": 5432}}
|
||||
self.assertEqual(self.ha.run_cycle(), 'trying to bootstrap a new standby leader')
|
||||
|
||||
def test_bootstrap_waiting_for_standby_leader(self):
|
||||
@@ -318,7 +322,7 @@ class TestHa(PostgresInit):
|
||||
self.ha.state_handler.cancellable._process = Mock()
|
||||
self.ha._crash_recovery_started -= 600
|
||||
self.ha.cluster.config.data.update({'maximum_lag_on_failover': 10})
|
||||
self.ha.global_config = self.ha.patroni.config.get_global_config(self.ha.cluster)
|
||||
global_config.update(self.ha.cluster)
|
||||
self.assertEqual(self.ha.run_cycle(), 'terminated crash recovery because of startup timeout')
|
||||
|
||||
@patch.object(Rewind, 'ensure_clean_shutdown', Mock())
|
||||
@@ -509,7 +513,7 @@ class TestHa(PostgresInit):
|
||||
def test_check_failsafe_topology(self):
|
||||
self.ha.load_cluster_from_dcs = Mock(side_effect=DCSError('Etcd is not responding properly'))
|
||||
self.ha.cluster = get_cluster_initialized_with_leader_and_failsafe()
|
||||
self.ha.global_config = self.ha.patroni.config.get_global_config(self.ha.cluster)
|
||||
global_config.update(self.ha.cluster)
|
||||
self.ha.dcs._last_failsafe = self.ha.cluster.failsafe
|
||||
self.assertEqual(self.ha.run_cycle(), 'demoting self because DCS is not accessible and I was a leader')
|
||||
self.ha.state_handler.name = self.ha.cluster.leader.name
|
||||
@@ -529,7 +533,7 @@ class TestHa(PostgresInit):
|
||||
def test_no_dcs_connection_primary_failsafe(self):
|
||||
self.ha.load_cluster_from_dcs = Mock(side_effect=DCSError('Etcd is not responding properly'))
|
||||
self.ha.cluster = get_cluster_initialized_with_leader_and_failsafe()
|
||||
self.ha.global_config = self.ha.patroni.config.get_global_config(self.ha.cluster)
|
||||
global_config.update(self.ha.cluster)
|
||||
self.ha.dcs._last_failsafe = self.ha.cluster.failsafe
|
||||
self.ha.state_handler.name = self.ha.cluster.leader.name
|
||||
self.assertEqual(self.ha.run_cycle(),
|
||||
@@ -546,7 +550,7 @@ class TestHa(PostgresInit):
|
||||
def test_no_dcs_connection_replica_failsafe(self):
|
||||
self.ha.load_cluster_from_dcs = Mock(side_effect=DCSError('Etcd is not responding properly'))
|
||||
self.ha.cluster = get_cluster_initialized_with_leader_and_failsafe()
|
||||
self.ha.global_config = self.ha.patroni.config.get_global_config(self.ha.cluster)
|
||||
global_config.update(self.ha.cluster)
|
||||
self.ha.update_failsafe({'name': 'leader', 'api_url': 'http://127.0.0.1:8008/patroni',
|
||||
'conn_url': 'postgres://127.0.0.1:5432/postgres', 'slots': {'foo': 1000}})
|
||||
self.p.is_primary = false
|
||||
@@ -766,7 +770,7 @@ class TestHa(PostgresInit):
|
||||
with patch('patroni.ha.logger.info') as mock_info:
|
||||
self.ha.fetch_node_status = get_node_status(wal_position=1)
|
||||
self.ha.cluster.config.data.update({'maximum_lag_on_failover': 5})
|
||||
self.ha.global_config = self.ha.patroni.config.get_global_config(self.ha.cluster)
|
||||
global_config.update(self.ha.cluster)
|
||||
self.assertEqual(self.ha.run_cycle(), 'no action. I am (postgresql0), the leader with the lock')
|
||||
self.assertEqual(mock_info.call_args_list[0][0], ('Member %s exceeds maximum replication lag', 'leader'))
|
||||
|
||||
@@ -1032,7 +1036,7 @@ class TestHa(PostgresInit):
|
||||
def test__is_healthiest_node(self):
|
||||
self.p.is_primary = false
|
||||
self.ha.cluster = get_cluster_initialized_without_leader(sync=('postgresql1', self.p.name))
|
||||
self.ha.global_config = self.ha.patroni.config.get_global_config(self.ha.cluster)
|
||||
global_config.update(self.ha.cluster)
|
||||
self.assertTrue(self.ha._is_healthiest_node(self.ha.old_cluster.members))
|
||||
self.ha.fetch_node_status = get_node_status() # accessible, in_recovery
|
||||
self.assertTrue(self.ha._is_healthiest_node(self.ha.old_cluster.members))
|
||||
@@ -1049,7 +1053,7 @@ class TestHa(PostgresInit):
|
||||
with patch.object(Ha, 'is_synchronous_mode', Mock(return_value=True)):
|
||||
self.assertTrue(self.ha._is_healthiest_node(self.ha.old_cluster.members))
|
||||
self.ha.cluster.config.data.update({'maximum_lag_on_failover': 5})
|
||||
self.ha.global_config = self.ha.patroni.config.get_global_config(self.ha.cluster)
|
||||
global_config.update(self.ha.cluster)
|
||||
with patch('patroni.postgresql.Postgresql.last_operation', return_value=1):
|
||||
self.assertFalse(self.ha._is_healthiest_node(self.ha.old_cluster.members))
|
||||
with patch('patroni.postgresql.Postgresql.replica_cached_timeline', return_value=None):
|
||||
@@ -1272,7 +1276,7 @@ class TestHa(PostgresInit):
|
||||
self.p.is_running = false
|
||||
self.ha.cluster = get_cluster_initialized_with_leader(sync=(self.p.name, 'other'))
|
||||
self.ha.cluster.config.data.update({'synchronous_mode': True, 'primary_start_timeout': 0})
|
||||
self.ha.global_config = self.ha.patroni.config.get_global_config(self.ha.cluster)
|
||||
global_config.update(self.ha.cluster)
|
||||
self.ha.has_lock = true
|
||||
self.ha.update_lock = true
|
||||
self.ha.fetch_node_status = get_node_status() # accessible, in_recovery
|
||||
@@ -1282,13 +1286,13 @@ class TestHa(PostgresInit):
|
||||
def test_primary_stop_timeout(self):
|
||||
self.assertEqual(self.ha.primary_stop_timeout(), None)
|
||||
self.ha.cluster.config.data.update({'primary_stop_timeout': 30})
|
||||
self.ha.global_config = self.ha.patroni.config.get_global_config(self.ha.cluster)
|
||||
global_config.update(self.ha.cluster)
|
||||
with patch.object(Ha, 'is_synchronous_mode', Mock(return_value=True)):
|
||||
self.assertEqual(self.ha.primary_stop_timeout(), 30)
|
||||
with patch.object(Ha, 'is_synchronous_mode', Mock(return_value=False)):
|
||||
self.assertEqual(self.ha.primary_stop_timeout(), None)
|
||||
self.ha.cluster.config.data['primary_stop_timeout'] = None
|
||||
self.ha.global_config = self.ha.patroni.config.get_global_config(self.ha.cluster)
|
||||
global_config.update(self.ha.cluster)
|
||||
self.assertEqual(self.ha.primary_stop_timeout(), None)
|
||||
|
||||
@patch('patroni.postgresql.Postgresql.follow')
|
||||
@@ -1380,8 +1384,9 @@ class TestHa(PostgresInit):
|
||||
# Test sync set to '*' when synchronous_mode_strict is enabled
|
||||
mock_set_sync.reset_mock()
|
||||
self.p.sync_handler.current_state = Mock(return_value=(CaseInsensitiveSet(), CaseInsensitiveSet()))
|
||||
with patch('patroni.config.GlobalConfig.is_synchronous_mode_strict', PropertyMock(return_value=True)):
|
||||
self.ha.run_cycle()
|
||||
self.ha.cluster.config.data['synchronous_mode_strict'] = True
|
||||
global_config.update(self.ha.cluster)
|
||||
self.ha.run_cycle()
|
||||
mock_set_sync.assert_called_once_with(CaseInsensitiveSet('*'))
|
||||
|
||||
def test_sync_replication_become_primary(self):
|
||||
@@ -1514,7 +1519,6 @@ class TestHa(PostgresInit):
|
||||
|
||||
@patch('patroni.postgresql.mtime', Mock(return_value=1588316884))
|
||||
@patch('builtins.open', Mock(side_effect=Exception))
|
||||
@patch.object(Cluster, 'is_unlocked', Mock(return_value=False))
|
||||
def test_restore_cluster_config(self):
|
||||
self.ha.cluster.config.data.clear()
|
||||
self.ha.has_lock = true
|
||||
|
||||
@@ -154,6 +154,7 @@ class TestPatroni(unittest.TestCase):
|
||||
self.p.api.start = Mock()
|
||||
self.p.logger.start = Mock()
|
||||
self.p.config._dynamic_configuration = {}
|
||||
self.assertRaises(SleepException, self.p.run)
|
||||
with patch('patroni.dcs.Cluster.is_unlocked', Mock(return_value=True)):
|
||||
self.assertRaises(SleepException, self.p.run)
|
||||
with patch('patroni.config.Config.reload_local_configuration', Mock(return_value=False)):
|
||||
|
||||
@@ -9,9 +9,9 @@ from mock import Mock, MagicMock, PropertyMock, patch, mock_open
|
||||
|
||||
import patroni.psycopg as psycopg
|
||||
|
||||
from patroni import global_config
|
||||
from patroni.async_executor import CriticalTask
|
||||
from patroni.collections import CaseInsensitiveSet
|
||||
from patroni.config import GlobalConfig
|
||||
from patroni.dcs import RemoteMember
|
||||
from patroni.exceptions import PostgresConnectionException, PatroniException
|
||||
from patroni.postgresql import Postgresql, STATE_REJECT, STATE_NO_RESPONSE
|
||||
@@ -692,12 +692,12 @@ class TestPostgresql(BaseTestPostgresql):
|
||||
|
||||
def test_get_server_parameters(self):
|
||||
config = {'parameters': {'wal_level': 'hot_standby', 'max_prepared_transactions': 100}, 'listen': '0'}
|
||||
self.p._global_config = GlobalConfig({'synchronous_mode': True})
|
||||
self.p.config.get_server_parameters(config)
|
||||
self.p._global_config = GlobalConfig({'synchronous_mode': True, 'synchronous_mode_strict': True})
|
||||
self.p.config.get_server_parameters(config)
|
||||
self.p.config.set_synchronous_standby_names('foo')
|
||||
self.assertTrue(str(self.p.config.get_server_parameters(config)).startswith('<CaseInsensitiveDict'))
|
||||
with patch.object(global_config.__class__, 'is_synchronous_mode', PropertyMock(return_value=True)):
|
||||
self.p.config.get_server_parameters(config)
|
||||
with patch.object(global_config.__class__, 'is_synchronous_mode_strict', PropertyMock(return_value=True)):
|
||||
self.p.config.get_server_parameters(config)
|
||||
self.p.config.set_synchronous_standby_names('foo')
|
||||
self.assertTrue(str(self.p.config.get_server_parameters(config)).startswith('<CaseInsensitiveDict'))
|
||||
|
||||
@patch('time.sleep', Mock())
|
||||
def test__wait_for_connection_close(self):
|
||||
|
||||
+6
-4
@@ -6,8 +6,7 @@ import unittest
|
||||
from mock import Mock, PropertyMock, patch
|
||||
from threading import Thread
|
||||
|
||||
from patroni import psycopg
|
||||
from patroni.config import GlobalConfig
|
||||
from patroni import global_config, psycopg
|
||||
from patroni.dcs import Cluster, ClusterConfig, Member, Status, SyncState
|
||||
from patroni.postgresql import Postgresql
|
||||
from patroni.postgresql.misc import fsync_dir
|
||||
@@ -29,12 +28,12 @@ class TestSlotsHandler(BaseTestPostgresql):
|
||||
@patch.object(Postgresql, 'is_running', Mock(return_value=True))
|
||||
def setUp(self):
|
||||
super(TestSlotsHandler, self).setUp()
|
||||
self.p._global_config = GlobalConfig({})
|
||||
self.s = self.p.slots_handler
|
||||
self.p.start()
|
||||
config = ClusterConfig(1, {'slots': {'ls': {'database': 'a', 'plugin': 'b'}, 'ls2': None}}, 1)
|
||||
self.cluster = Cluster(True, config, self.leader, Status(0, {'ls': 12345, 'ls2': 12345}),
|
||||
[self.me, self.other, self.leadermem], None, SyncState.empty(), None, None)
|
||||
global_config.update(self.cluster)
|
||||
|
||||
def test_sync_replication_slots(self):
|
||||
config = ClusterConfig(1, {'slots': {'test_3': {'database': 'a', 'plugin': 'b'},
|
||||
@@ -42,11 +41,12 @@ class TestSlotsHandler(BaseTestPostgresql):
|
||||
'ignore_slots': [{'name': 'blabla'}]}, 1)
|
||||
cluster = Cluster(True, config, self.leader, Status(0, {'test_3': 10}),
|
||||
[self.me, self.other, self.leadermem], None, SyncState.empty(), None, None)
|
||||
global_config.update(cluster)
|
||||
with mock.patch('patroni.postgresql.Postgresql._query', Mock(side_effect=psycopg.OperationalError)):
|
||||
self.s.sync_replication_slots(cluster, False)
|
||||
self.p.set_role('standby_leader')
|
||||
with patch.object(SlotsHandler, 'drop_replication_slot', Mock(return_value=(True, False))), \
|
||||
patch.object(GlobalConfig, 'is_standby_cluster', PropertyMock(return_value=True)), \
|
||||
patch.object(global_config.__class__, 'is_standby_cluster', PropertyMock(return_value=True)), \
|
||||
patch('patroni.postgresql.slots.logger.debug') as mock_debug:
|
||||
self.s.sync_replication_slots(cluster, False)
|
||||
mock_debug.assert_called_once()
|
||||
@@ -94,6 +94,7 @@ class TestSlotsHandler(BaseTestPostgresql):
|
||||
'ignore_slots': [{'name': 'blabla'}]}, 1)
|
||||
cluster = Cluster(True, config, self.leader, Status.empty(), [self.me, self.other, self.leadermem],
|
||||
None, SyncState.empty(), None, None)
|
||||
global_config.update(cluster)
|
||||
|
||||
self.s.sync_replication_slots(cluster, False)
|
||||
with patch.object(Postgresql, '_query') as mock_query:
|
||||
@@ -189,6 +190,7 @@ class TestSlotsHandler(BaseTestPostgresql):
|
||||
config = ClusterConfig(1, {'slots': {'blabla': {'type': 'physical'}, 'leader': None}}, 1)
|
||||
cluster = Cluster(True, config, self.leader, Status(0, {'blabla': 12346}),
|
||||
[self.me, self.other, self.leadermem], None, SyncState.empty(), None, None)
|
||||
global_config.update(cluster)
|
||||
self.s.sync_replication_slots(cluster, False)
|
||||
with patch.object(SlotsHandler, '_query', Mock(side_effect=[[('blabla', 'physical', 12345, None, None, None,
|
||||
None, None)], Exception])) as mock_query, \
|
||||
|
||||
+3
-4
@@ -1,9 +1,9 @@
|
||||
import os
|
||||
|
||||
from mock import Mock, patch
|
||||
from mock import Mock, patch, PropertyMock
|
||||
|
||||
from patroni import global_config
|
||||
from patroni.collections import CaseInsensitiveSet
|
||||
from patroni.config import GlobalConfig
|
||||
from patroni.dcs import Cluster, SyncState
|
||||
from patroni.postgresql import Postgresql
|
||||
|
||||
@@ -13,6 +13,7 @@ from . import BaseTestPostgresql, psycopg_connect, mock_available_gucs
|
||||
@patch('subprocess.call', Mock(return_value=0))
|
||||
@patch('patroni.psycopg.connect', psycopg_connect)
|
||||
@patch.object(Postgresql, 'available_gucs', mock_available_gucs)
|
||||
@patch.object(global_config.__class__, 'is_synchronous_mode', PropertyMock(return_value=True))
|
||||
class TestSync(BaseTestPostgresql):
|
||||
|
||||
@patch('subprocess.call', Mock(return_value=0))
|
||||
@@ -24,7 +25,6 @@ class TestSync(BaseTestPostgresql):
|
||||
def setUp(self):
|
||||
super(TestSync, self).setUp()
|
||||
self.p.config.write_postgresql_conf()
|
||||
self.p._global_config = GlobalConfig({'synchronous_mode': True})
|
||||
self.s = self.p.sync_handler
|
||||
|
||||
@patch.object(Postgresql, 'last_operation', Mock(return_value=1))
|
||||
@@ -96,7 +96,6 @@ class TestSync(BaseTestPostgresql):
|
||||
self.assertEqual(value_in_conf(), None)
|
||||
|
||||
mock_reload.reset_mock()
|
||||
self.p._global_config = GlobalConfig({'synchronous_mode': True})
|
||||
self.s.set_synchronous_standby_names(CaseInsensitiveSet('*'))
|
||||
mock_reload.assert_called()
|
||||
self.assertEqual(value_in_conf(), "synchronous_standby_names = '*'")
|
||||
|
||||
Reference in New Issue
Block a user