diff --git a/redis/multidb/client.py b/redis/multidb/client.py index 1073ea8168..8183d11293 100644 --- a/redis/multidb/client.py +++ b/redis/multidb/client.py @@ -22,10 +22,17 @@ class MultiDBClient(RedisModuleCommands, CoreCommands): """ def __init__(self, config: MultiDbConfig): self._databases = config.databases() - self._health_checks = config.default_health_checks() if config.health_checks is None else config.health_checks + self._health_checks = config.default_health_checks() + + if config.health_checks is not None: + self._health_checks.extend(config.health_checks) + self._health_check_interval = config.health_check_interval - self._failure_detectors = config.default_failure_detectors() \ - if config.failure_detectors is None else config.failure_detectors + self._failure_detectors = config.default_failure_detectors() + + if config.failure_detectors is not None: + self._failure_detectors.extend(config.failure_detectors) + self._failover_strategy = config.default_failover_strategy() \ if config.failover_strategy is None else config.failover_strategy self._failover_strategy.set_databases(self._databases) diff --git a/redis/multidb/config.py b/redis/multidb/config.py index 64ad7c9052..4bacc2c680 100644 --- a/redis/multidb/config.py +++ b/redis/multidb/config.py @@ -51,10 +51,10 @@ class MultiDbConfig: databases_config: A list of database configurations. client_class: The client class used to manage database connections. command_retry: Retry strategy for executing database commands. - failure_detectors: Optional list of failure detectors for monitoring database failures. + failure_detectors: Optional list of additional failure detectors for monitoring database failures. failure_threshold: Threshold for determining database failure. failures_interval: Time interval for tracking database failures. - health_checks: Optional list of health checks performed on databases. + health_checks: Optional list of additional health checks performed on databases. health_check_interval: Time interval for executing health checks. health_check_retries: Number of retry attempts for performing health checks. health_check_backoff: Backoff strategy for health check retries. diff --git a/tests/test_multidb/conftest.py b/tests/test_multidb/conftest.py index ad2057a118..f85e0a6fd7 100644 --- a/tests/test_multidb/conftest.py +++ b/tests/test_multidb/conftest.py @@ -94,7 +94,6 @@ def mock_multi_db_config( config = MultiDbConfig( databases_config=[Mock(spec=DatabaseConfig)], failure_detectors=[mock_fd], - health_checks=[mock_hc], health_check_interval=hc_interval, failover_strategy=mock_fs, auto_fallback_interval=auto_fallback_interval, diff --git a/tests/test_multidb/test_client.py b/tests/test_multidb/test_client.py index cf3877957f..c14f605c2a 100644 --- a/tests/test_multidb/test_client.py +++ b/tests/test_multidb/test_client.py @@ -32,26 +32,20 @@ class TestMultiDbClient: indirect=True, ) def test_execute_command_against_correct_db_on_successful_initialization( - self, mock_multi_db_config, mock_db, mock_db1, mock_db2 + self, mock_multi_db_config, mock_db, mock_db1, mock_db2, mock_hc ): databases = create_weighted_list(mock_db, mock_db1, mock_db2) - with patch.object( - mock_multi_db_config, - 'databases', - return_value=databases - ): + with patch.object(mock_multi_db_config,'databases',return_value=databases), \ + patch.object(mock_multi_db_config,'default_health_checks', return_value=[mock_hc]): mock_db1.client.execute_command.return_value = 'OK1' - for hc in mock_multi_db_config.health_checks: - hc.check_health.return_value = True + mock_hc.check_health.return_value = True client = MultiDBClient(mock_multi_db_config) assert mock_multi_db_config.failover_strategy.set_databases.call_count == 1 assert client.set('key', 'value') == 'OK1' - - for hc in mock_multi_db_config.health_checks: - assert hc.check_health.call_count == 3 + assert mock_hc.check_health.call_count == 3 assert mock_db.circuit.state == CBState.CLOSED assert mock_db1.circuit.state == CBState.CLOSED @@ -70,26 +64,20 @@ def test_execute_command_against_correct_db_on_successful_initialization( indirect=True, ) def test_execute_command_against_correct_db_and_closed_circuit( - self, mock_multi_db_config, mock_db, mock_db1, mock_db2 + self, mock_multi_db_config, mock_db, mock_db1, mock_db2, mock_hc ): databases = create_weighted_list(mock_db, mock_db1, mock_db2) - with patch.object( - mock_multi_db_config, - 'databases', - return_value=databases - ): + with patch.object(mock_multi_db_config,'databases',return_value=databases), \ + patch.object(mock_multi_db_config,'default_health_checks', return_value=[mock_hc]): mock_db1.client.execute_command.return_value = 'OK1' - for hc in mock_multi_db_config.health_checks: - hc.check_health.side_effect = [False, True, True] + mock_hc.check_health.side_effect = [False, True, True] client = MultiDBClient(mock_multi_db_config) assert mock_multi_db_config.failover_strategy.set_databases.call_count == 1 assert client.set('key', 'value') == 'OK1' - - for hc in mock_multi_db_config.health_checks: - assert hc.check_health.call_count == 3 + assert mock_hc.check_health.call_count == 3 assert mock_db.circuit.state == CBState.CLOSED assert mock_db1.circuit.state == CBState.CLOSED @@ -124,20 +112,14 @@ def test_execute_command_against_correct_db_on_background_health_check_determine databases = create_weighted_list(mock_db, mock_db1, mock_db2) - with patch.object( - mock_multi_db_config, - 'databases', - return_value=databases - ): + with patch.object(mock_multi_db_config,'databases',return_value=databases), \ + patch.object(mock_multi_db_config,'default_health_checks', return_value=[EchoHealthCheck( + retry=Retry(retries=DEFAULT_HEALTH_CHECK_RETRIES, backoff=DEFAULT_HEALTH_CHECK_BACKOFF) + )]): mock_db.client.execute_command.side_effect = ['healthcheck', 'healthcheck', 'healthcheck', 'OK', 'error'] mock_db1.client.execute_command.side_effect = ['healthcheck', 'OK1', 'error', 'error', 'healthcheck', 'OK1'] mock_db2.client.execute_command.side_effect = ['healthcheck', 'healthcheck', 'OK2', 'error', 'error'] mock_multi_db_config.health_check_interval = 0.1 - mock_multi_db_config.health_checks = [ - EchoHealthCheck( - retry=Retry(retries=DEFAULT_HEALTH_CHECK_RETRIES, backoff=DEFAULT_HEALTH_CHECK_BACKOFF) - ) - ] mock_multi_db_config.failover_strategy = WeightBasedFailoverStrategy( retry=Retry(retries=DEFAULT_FAILOVER_RETRIES, backoff=DEFAULT_FAILOVER_BACKOFF) ) @@ -168,21 +150,15 @@ def test_execute_command_auto_fallback_to_highest_weight_db( ): databases = create_weighted_list(mock_db, mock_db1, mock_db2) - with patch.object( - mock_multi_db_config, - 'databases', - return_value=databases - ): + with patch.object(mock_multi_db_config,'databases',return_value=databases), \ + patch.object(mock_multi_db_config,'default_health_checks', return_value=[EchoHealthCheck( + retry=Retry(retries=DEFAULT_HEALTH_CHECK_RETRIES, backoff=DEFAULT_HEALTH_CHECK_BACKOFF) + )]): mock_db.client.execute_command.side_effect = ['healthcheck', 'healthcheck', 'healthcheck', 'healthcheck', 'healthcheck'] mock_db1.client.execute_command.side_effect = ['healthcheck', 'OK1', 'error', 'healthcheck', 'healthcheck', 'OK1'] mock_db2.client.execute_command.side_effect = ['healthcheck', 'healthcheck', 'OK2', 'healthcheck', 'healthcheck', 'healthcheck'] mock_multi_db_config.health_check_interval = 0.1 mock_multi_db_config.auto_fallback_interval = 0.2 - mock_multi_db_config.health_checks = [ - EchoHealthCheck( - retry=Retry(retries=DEFAULT_HEALTH_CHECK_RETRIES, backoff=DEFAULT_HEALTH_CHECK_BACKOFF) - ) - ] mock_multi_db_config.failover_strategy = WeightBasedFailoverStrategy( retry=Retry(retries=DEFAULT_FAILOVER_RETRIES, backoff=DEFAULT_FAILOVER_BACKOFF) ) @@ -223,17 +199,13 @@ def test_execute_command_auto_fallback_to_highest_weight_db( indirect=True, ) def test_execute_command_throws_exception_on_failed_initialization( - self, mock_multi_db_config, mock_db, mock_db1, mock_db2 + self, mock_multi_db_config, mock_db, mock_db1, mock_db2, mock_hc ): databases = create_weighted_list(mock_db, mock_db1, mock_db2) - with patch.object( - mock_multi_db_config, - 'databases', - return_value=databases - ): - for hc in mock_multi_db_config.health_checks: - hc.check_health.return_value = False + with patch.object(mock_multi_db_config,'databases',return_value=databases), \ + patch.object(mock_multi_db_config,'default_health_checks', return_value=[mock_hc]): + mock_hc.check_health.return_value = False client = MultiDBClient(mock_multi_db_config) assert mock_multi_db_config.failover_strategy.set_databases.call_count == 1 @@ -241,8 +213,7 @@ def test_execute_command_throws_exception_on_failed_initialization( with pytest.raises(NoValidDatabaseException, match='Initial connection failed - no active database found'): client.set('key', 'value') - for hc in mock_multi_db_config.health_checks: - assert hc.check_health.call_count == 3 + assert mock_hc.check_health.call_count == 3 assert mock_db.state == DBState.DISCONNECTED assert mock_db1.state == DBState.DISCONNECTED @@ -261,26 +232,20 @@ def test_execute_command_throws_exception_on_failed_initialization( indirect=True, ) def test_add_database_throws_exception_on_same_database( - self, mock_multi_db_config, mock_db, mock_db1, mock_db2 + self, mock_multi_db_config, mock_db, mock_db1, mock_db2, mock_hc ): databases = create_weighted_list(mock_db, mock_db1, mock_db2) - with patch.object( - mock_multi_db_config, - 'databases', - return_value=databases - ): - for hc in mock_multi_db_config.health_checks: - hc.check_health.return_value = False + with patch.object(mock_multi_db_config,'databases',return_value=databases), \ + patch.object(mock_multi_db_config,'default_health_checks', return_value=[mock_hc]): + mock_hc.check_health.return_value = False client = MultiDBClient(mock_multi_db_config) assert mock_multi_db_config.failover_strategy.set_databases.call_count == 1 with pytest.raises(ValueError, match='Given database already exists'): client.add_database(mock_db) - - for hc in mock_multi_db_config.health_checks: - assert hc.check_health.call_count == 3 + assert mock_hc.check_health.call_count == 3 @pytest.mark.parametrize( 'mock_multi_db_config,mock_db, mock_db1, mock_db2', @@ -295,36 +260,28 @@ def test_add_database_throws_exception_on_same_database( indirect=True, ) def test_add_database_makes_new_database_active( - self, mock_multi_db_config, mock_db, mock_db1, mock_db2 + self, mock_multi_db_config, mock_db, mock_db1, mock_db2, mock_hc ): databases = create_weighted_list(mock_db, mock_db2) - with patch.object( - mock_multi_db_config, - 'databases', - return_value=databases - ): + with patch.object(mock_multi_db_config,'databases',return_value=databases), \ + patch.object(mock_multi_db_config,'default_health_checks', return_value=[mock_hc]): mock_db1.client.execute_command.return_value = 'OK1' mock_db2.client.execute_command.return_value = 'OK2' - for hc in mock_multi_db_config.health_checks: - hc.check_health.return_value = True + mock_hc.check_health.return_value = True client = MultiDBClient(mock_multi_db_config) assert mock_multi_db_config.failover_strategy.set_databases.call_count == 1 assert client.set('key', 'value') == 'OK2' - - for hc in mock_multi_db_config.health_checks: - assert hc.check_health.call_count == 2 + assert mock_hc.check_health.call_count == 2 assert mock_db.state == DBState.PASSIVE assert mock_db2.state == DBState.ACTIVE client.add_database(mock_db1) - - for hc in mock_multi_db_config.health_checks: - assert hc.check_health.call_count == 3 + assert mock_hc.check_health.call_count == 3 assert client.set('key', 'value') == 'OK1' @@ -345,28 +302,22 @@ def test_add_database_makes_new_database_active( indirect=True, ) def test_remove_highest_weighted_database( - self, mock_multi_db_config, mock_db, mock_db1, mock_db2 + self, mock_multi_db_config, mock_db, mock_db1, mock_db2, mock_hc ): databases = create_weighted_list(mock_db, mock_db1, mock_db2) - with patch.object( - mock_multi_db_config, - 'databases', - return_value=databases - ): + with patch.object(mock_multi_db_config,'databases',return_value=databases), \ + patch.object(mock_multi_db_config,'default_health_checks', return_value=[mock_hc]): mock_db1.client.execute_command.return_value = 'OK1' mock_db2.client.execute_command.return_value = 'OK2' - for hc in mock_multi_db_config.health_checks: - hc.check_health.return_value = True + mock_hc.check_health.return_value = True client = MultiDBClient(mock_multi_db_config) assert mock_multi_db_config.failover_strategy.set_databases.call_count == 1 assert client.set('key', 'value') == 'OK1' - - for hc in mock_multi_db_config.health_checks: - assert hc.check_health.call_count == 3 + assert mock_hc.check_health.call_count == 3 assert mock_db.state == DBState.PASSIVE assert mock_db1.state == DBState.ACTIVE @@ -392,28 +343,22 @@ def test_remove_highest_weighted_database( indirect=True, ) def test_update_database_weight_to_be_highest( - self, mock_multi_db_config, mock_db, mock_db1, mock_db2 + self, mock_multi_db_config, mock_db, mock_db1, mock_db2, mock_hc ): databases = create_weighted_list(mock_db, mock_db1, mock_db2) - with patch.object( - mock_multi_db_config, - 'databases', - return_value=databases - ): + with patch.object(mock_multi_db_config,'databases',return_value=databases), \ + patch.object(mock_multi_db_config,'default_health_checks', return_value=[mock_hc]): mock_db1.client.execute_command.return_value = 'OK1' mock_db2.client.execute_command.return_value = 'OK2' - for hc in mock_multi_db_config.health_checks: - hc.check_health.return_value = True + mock_hc.check_health.return_value = True client = MultiDBClient(mock_multi_db_config) assert mock_multi_db_config.failover_strategy.set_databases.call_count == 1 assert client.set('key', 'value') == 'OK1' - - for hc in mock_multi_db_config.health_checks: - assert hc.check_health.call_count == 3 + assert mock_hc.check_health.call_count == 3 assert mock_db.state == DBState.PASSIVE assert mock_db1.state == DBState.ACTIVE @@ -441,15 +386,12 @@ def test_update_database_weight_to_be_highest( indirect=True, ) def test_add_new_failure_detector( - self, mock_multi_db_config, mock_db, mock_db1, mock_db2 + self, mock_multi_db_config, mock_db, mock_db1, mock_db2, mock_hc ): databases = create_weighted_list(mock_db, mock_db1, mock_db2) - with patch.object( - mock_multi_db_config, - 'databases', - return_value=databases - ): + with patch.object(mock_multi_db_config,'databases',return_value=databases), \ + patch.object(mock_multi_db_config,'default_health_checks', return_value=[mock_hc]): mock_db1.client.execute_command.return_value = 'OK1' mock_multi_db_config.event_dispatcher = EventDispatcher() mock_fd = mock_multi_db_config.failure_detectors[0] @@ -460,15 +402,12 @@ def test_add_new_failure_detector( exception=Exception(), ) - for hc in mock_multi_db_config.health_checks: - hc.check_health.return_value = True + mock_hc.check_health.return_value = True client = MultiDBClient(mock_multi_db_config) assert mock_multi_db_config.failover_strategy.set_databases.call_count == 1 assert client.set('key', 'value') == 'OK1' - - for hc in mock_multi_db_config.health_checks: - assert hc.check_health.call_count == 3 + assert mock_hc.check_health.call_count == 3 # Simulate failing command events that lead to a failure detection for i in range(5): @@ -499,26 +438,20 @@ def test_add_new_failure_detector( indirect=True, ) def test_add_new_health_check( - self, mock_multi_db_config, mock_db, mock_db1, mock_db2 + self, mock_multi_db_config, mock_db, mock_db1, mock_db2, mock_hc ): databases = create_weighted_list(mock_db, mock_db1, mock_db2) - with patch.object( - mock_multi_db_config, - 'databases', - return_value=databases - ): + with patch.object(mock_multi_db_config,'databases',return_value=databases), \ + patch.object(mock_multi_db_config,'default_health_checks', return_value=[mock_hc]): mock_db1.client.execute_command.return_value = 'OK1' - for hc in mock_multi_db_config.health_checks: - hc.check_health.return_value = True + mock_hc.check_health.return_value = True client = MultiDBClient(mock_multi_db_config) assert mock_multi_db_config.failover_strategy.set_databases.call_count == 1 assert client.set('key', 'value') == 'OK1' - - for hc in mock_multi_db_config.health_checks: - assert hc.check_health.call_count == 3 + assert mock_hc.check_health.call_count == 3 another_hc = Mock(spec=HealthCheck) another_hc.check_health.return_value = True @@ -526,6 +459,7 @@ def test_add_new_health_check( client.add_health_check(another_hc) client._check_db_health(mock_db1) + assert mock_hc.check_health.call_count == 4 assert another_hc.check_health.call_count == 1 @pytest.mark.parametrize( @@ -541,27 +475,21 @@ def test_add_new_health_check( indirect=True, ) def test_set_active_database( - self, mock_multi_db_config, mock_db, mock_db1, mock_db2 + self, mock_multi_db_config, mock_db, mock_db1, mock_db2, mock_hc ): databases = create_weighted_list(mock_db, mock_db1, mock_db2) - with patch.object( - mock_multi_db_config, - 'databases', - return_value=databases - ): + with patch.object(mock_multi_db_config,'databases',return_value=databases), \ + patch.object(mock_multi_db_config,'default_health_checks', return_value=[mock_hc]): mock_db1.client.execute_command.return_value = 'OK1' mock_db.client.execute_command.return_value = 'OK' - for hc in mock_multi_db_config.health_checks: - hc.check_health.return_value = True + mock_hc.check_health.return_value = True client = MultiDBClient(mock_multi_db_config) assert mock_multi_db_config.failover_strategy.set_databases.call_count == 1 assert client.set('key', 'value') == 'OK1' - - for hc in mock_multi_db_config.health_checks: - assert hc.check_health.call_count == 3 + assert mock_hc.check_health.call_count == 3 assert mock_db.state == DBState.PASSIVE assert mock_db1.state == DBState.ACTIVE @@ -577,8 +505,7 @@ def test_set_active_database( with pytest.raises(ValueError, match='Given database is not a member of database list'): client.set_active_database(Mock(spec=AbstractDatabase)) - for hc in mock_multi_db_config.health_checks: - hc.check_health.return_value = False + mock_hc.check_health.return_value = False with pytest.raises(NoValidDatabaseException, match='Cannot set active database, database is unhealthy'): client.set_active_database(mock_db1) \ No newline at end of file diff --git a/tests/test_multidb/test_pipeline.py b/tests/test_multidb/test_pipeline.py index 9caad235df..f0d2a0dbe3 100644 --- a/tests/test_multidb/test_pipeline.py +++ b/tests/test_multidb/test_pipeline.py @@ -36,21 +36,17 @@ class TestPipeline: indirect=True, ) def test_executes_pipeline_against_correct_db( - self, mock_multi_db_config, mock_db, mock_db1, mock_db2 + self, mock_multi_db_config, mock_db, mock_db1, mock_db2, mock_hc ): databases = create_weighted_list(mock_db, mock_db1, mock_db2) - with patch.object( - mock_multi_db_config, - 'databases', - return_value=databases - ): + with patch.object(mock_multi_db_config,'databases',return_value=databases), \ + patch.object(mock_multi_db_config,'default_health_checks', return_value=[mock_hc]): pipe = mock_pipe() pipe.execute.return_value = ['OK1', 'value1'] mock_db1.client.pipeline.return_value = pipe - for hc in mock_multi_db_config.health_checks: - hc.check_health.return_value = True + mock_hc.check_health.return_value = True client = MultiDBClient(mock_multi_db_config) assert mock_multi_db_config.failover_strategy.set_databases.call_count == 1 @@ -60,9 +56,7 @@ def test_executes_pipeline_against_correct_db( pipe.get('key1') assert pipe.execute() == ['OK1', 'value1'] - - for hc in mock_multi_db_config.health_checks: - assert hc.check_health.call_count == 3 + assert mock_hc.check_health.call_count == 3 @pytest.mark.parametrize( 'mock_multi_db_config,mock_db, mock_db1, mock_db2', @@ -77,21 +71,17 @@ def test_executes_pipeline_against_correct_db( indirect=True, ) def test_execute_pipeline_against_correct_db_and_closed_circuit( - self, mock_multi_db_config, mock_db, mock_db1, mock_db2 + self, mock_multi_db_config, mock_db, mock_db1, mock_db2, mock_hc ): databases = create_weighted_list(mock_db, mock_db1, mock_db2) - with patch.object( - mock_multi_db_config, - 'databases', - return_value=databases - ): + with patch.object(mock_multi_db_config,'databases',return_value=databases), \ + patch.object(mock_multi_db_config,'default_health_checks', return_value=[mock_hc]): pipe = mock_pipe() pipe.execute.return_value = ['OK1', 'value1'] mock_db1.client.pipeline.return_value = pipe - for hc in mock_multi_db_config.health_checks: - hc.check_health.side_effect = [False, True, True] + mock_hc.check_health.side_effect = [False, True, True] client = MultiDBClient(mock_multi_db_config) assert mock_multi_db_config.failover_strategy.set_databases.call_count == 1 @@ -101,9 +91,7 @@ def test_execute_pipeline_against_correct_db_and_closed_circuit( pipe.get('key1') assert pipe.execute() == ['OK1', 'value1'] - - for hc in mock_multi_db_config.health_checks: - assert hc.check_health.call_count == 3 + assert mock_hc.check_health.call_count == 3 assert mock_db.circuit.state == CBState.CLOSED assert mock_db1.circuit.state == CBState.CLOSED @@ -122,7 +110,7 @@ def test_execute_pipeline_against_correct_db_and_closed_circuit( indirect=True, ) def test_execute_pipeline_against_correct_db_on_background_health_check_determine_active_db_unhealthy( - self, mock_multi_db_config, mock_db, mock_db1, mock_db2 + self, mock_multi_db_config, mock_db, mock_db1, mock_db2, mock_hc ): cb = PBCircuitBreakerAdapter(pybreaker.CircuitBreaker(reset_timeout=5)) cb.database = mock_db @@ -138,11 +126,10 @@ def test_execute_pipeline_against_correct_db_on_background_health_check_determin databases = create_weighted_list(mock_db, mock_db1, mock_db2) - with patch.object( - mock_multi_db_config, - 'databases', - return_value=databases - ): + with patch.object(mock_multi_db_config,'databases',return_value=databases), \ + patch.object(mock_multi_db_config,'default_health_checks', return_value=[EchoHealthCheck( + retry=Retry(retries=DEFAULT_HEALTH_CHECK_RETRIES, backoff=DEFAULT_HEALTH_CHECK_BACKOFF) + )]): mock_db.client.execute_command.side_effect = ['healthcheck', 'healthcheck', 'healthcheck', 'error'] mock_db1.client.execute_command.side_effect = ['healthcheck', 'error', 'error', 'healthcheck'] mock_db2.client.execute_command.side_effect = ['healthcheck', 'healthcheck', 'error', 'error'] @@ -160,11 +147,6 @@ def test_execute_pipeline_against_correct_db_on_background_health_check_determin mock_db2.client.pipeline.return_value = pipe2 mock_multi_db_config.health_check_interval = 0.1 - mock_multi_db_config.health_checks = [ - EchoHealthCheck( - retry=Retry(retries=DEFAULT_HEALTH_CHECK_RETRIES, backoff=DEFAULT_HEALTH_CHECK_BACKOFF) - ) - ] mock_multi_db_config.failover_strategy = WeightBasedFailoverStrategy( retry=Retry(retries=DEFAULT_FAILOVER_RETRIES, backoff=DEFAULT_FAILOVER_BACKOFF) ) @@ -216,19 +198,15 @@ class TestTransaction: indirect=True, ) def test_executes_transaction_against_correct_db( - self, mock_multi_db_config, mock_db, mock_db1, mock_db2 + self, mock_multi_db_config, mock_db, mock_db1, mock_db2, mock_hc ): databases = create_weighted_list(mock_db, mock_db1, mock_db2) - with patch.object( - mock_multi_db_config, - 'databases', - return_value=databases - ): + with patch.object(mock_multi_db_config,'databases',return_value=databases), \ + patch.object(mock_multi_db_config,'default_health_checks', return_value=[mock_hc]): mock_db1.client.transaction.return_value = ['OK1', 'value1'] - for hc in mock_multi_db_config.health_checks: - hc.check_health.return_value = True + mock_hc.check_health.return_value = True client = MultiDBClient(mock_multi_db_config) assert mock_multi_db_config.failover_strategy.set_databases.call_count == 1 @@ -238,9 +216,7 @@ def callback(pipe: Pipeline): pipe.get('key1') assert client.transaction(callback) == ['OK1', 'value1'] - - for hc in mock_multi_db_config.health_checks: - assert hc.check_health.call_count == 3 + assert mock_hc.check_health.call_count == 3 @pytest.mark.parametrize( 'mock_multi_db_config,mock_db, mock_db1, mock_db2', @@ -255,19 +231,15 @@ def callback(pipe: Pipeline): indirect=True, ) def test_execute_transaction_against_correct_db_and_closed_circuit( - self, mock_multi_db_config, mock_db, mock_db1, mock_db2 + self, mock_multi_db_config, mock_db, mock_db1, mock_db2, mock_hc ): databases = create_weighted_list(mock_db, mock_db1, mock_db2) - with patch.object( - mock_multi_db_config, - 'databases', - return_value=databases - ): + with patch.object(mock_multi_db_config,'databases',return_value=databases), \ + patch.object(mock_multi_db_config,'default_health_checks', return_value=[mock_hc]): mock_db1.client.transaction.return_value = ['OK1', 'value1'] - for hc in mock_multi_db_config.health_checks: - hc.check_health.side_effect = [False, True, True] + mock_hc.check_health.side_effect = [False, True, True] client = MultiDBClient(mock_multi_db_config) assert mock_multi_db_config.failover_strategy.set_databases.call_count == 1 @@ -277,9 +249,7 @@ def callback(pipe: Pipeline): pipe.get('key1') assert client.transaction(callback) == ['OK1', 'value1'] - - for hc in mock_multi_db_config.health_checks: - assert hc.check_health.call_count == 3 + assert mock_hc.check_health.call_count == 3 assert mock_db.circuit.state == CBState.CLOSED assert mock_db1.circuit.state == CBState.CLOSED @@ -314,11 +284,10 @@ def test_execute_transaction_against_correct_db_on_background_health_check_deter databases = create_weighted_list(mock_db, mock_db1, mock_db2) - with patch.object( - mock_multi_db_config, - 'databases', - return_value=databases - ): + with patch.object(mock_multi_db_config,'databases',return_value=databases), \ + patch.object(mock_multi_db_config,'default_health_checks', return_value=[EchoHealthCheck( + retry=Retry(retries=DEFAULT_HEALTH_CHECK_RETRIES, backoff=DEFAULT_HEALTH_CHECK_BACKOFF) + )]): mock_db.client.execute_command.side_effect = ['healthcheck', 'healthcheck', 'healthcheck', 'error'] mock_db1.client.execute_command.side_effect = ['healthcheck', 'error', 'error', 'healthcheck'] mock_db2.client.execute_command.side_effect = ['healthcheck', 'healthcheck', 'error', 'error'] @@ -328,11 +297,6 @@ def test_execute_transaction_against_correct_db_on_background_health_check_deter mock_db2.client.transaction.return_value = ['OK2', 'value'] mock_multi_db_config.health_check_interval = 0.1 - mock_multi_db_config.health_checks = [ - EchoHealthCheck( - retry=Retry(retries=DEFAULT_HEALTH_CHECK_RETRIES, backoff=DEFAULT_HEALTH_CHECK_BACKOFF) - ) - ] mock_multi_db_config.failover_strategy = WeightBasedFailoverStrategy( retry=Retry(retries=DEFAULT_FAILOVER_RETRIES, backoff=DEFAULT_FAILOVER_BACKOFF) ) diff --git a/tests/test_scenario/conftest.py b/tests/test_scenario/conftest.py index 486dc948f1..b347fe50ba 100644 --- a/tests/test_scenario/conftest.py +++ b/tests/test_scenario/conftest.py @@ -51,7 +51,6 @@ def r_multi_db(request) -> tuple[MultiDBClient, CheckActiveDatabaseChangedListen # Retry configuration different for health checks as initial health check require more time in case # if infrastructure wasn't restored from the previous test. - health_checks = [EchoHealthCheck(Retry(ExponentialBackoff(cap=5, base=0.5), retries=3))] health_check_interval = request.param.get('health_check_interval', DEFAULT_HEALTH_CHECK_INTERVAL) event_dispatcher = EventDispatcher() listener = CheckActiveDatabaseChangedListener() @@ -84,10 +83,11 @@ def r_multi_db(request) -> tuple[MultiDBClient, CheckActiveDatabaseChangedListen config = MultiDbConfig( databases_config=db_configs, - health_checks=health_checks, command_retry=command_retry, failure_threshold=failure_threshold, health_check_interval=health_check_interval, + health_check_backoff=ExponentialBackoff(cap=0.5, base=0.05), + health_check_retries=3, event_dispatcher=event_dispatcher, )