Skip to content

Commit 2834177

Browse files
Bernd VerstCopilot
andcommitted
Add sync client recreation test coverage
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 937231d commit 2834177

1 file changed

Lines changed: 69 additions & 1 deletion

File tree

tests/durabletask/test_client.py

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ def test_sync_client_does_not_recreate_caller_owned_channel():
413413

414414
with patch("durabletask.client.shared.get_grpc_channel") as mock_get_channel, patch(
415415
"durabletask.client.stubs.TaskHubSidecarServiceStub", return_value=stub
416-
) as mock_stub:
416+
) as mock_stub, patch("threading.Timer") as mock_timer:
417417
client = TaskHubGrpcClient(
418418
channel=provided_channel,
419419
resiliency_options=GrpcClientResiliencyOptions(channel_recreate_failure_threshold=1),
@@ -426,6 +426,74 @@ def test_sync_client_does_not_recreate_caller_owned_channel():
426426
assert client._channel is provided_channel
427427
mock_get_channel.assert_not_called()
428428
mock_stub.assert_called_once_with(provided_channel)
429+
mock_timer.assert_not_called()
430+
431+
432+
def test_sync_client_recreate_cooldown_prevents_immediate_repeated_recreation():
433+
first_channel = MagicMock(name="first-channel")
434+
second_channel = MagicMock(name="second-channel")
435+
third_channel = MagicMock(name="third-channel")
436+
first_stub = MagicMock()
437+
second_stub = MagicMock()
438+
third_stub = MagicMock()
439+
first_stub.GetInstance.side_effect = FakeRpcError(grpc.StatusCode.UNAVAILABLE)
440+
second_stub.GetInstance.side_effect = [
441+
FakeRpcError(grpc.StatusCode.UNAVAILABLE),
442+
FakeRpcError(grpc.StatusCode.UNAVAILABLE),
443+
]
444+
timer1 = MagicMock(name="close-timer-1")
445+
timer2 = MagicMock(name="close-timer-2")
446+
447+
with patch(
448+
"durabletask.client.shared.get_grpc_channel",
449+
side_effect=[first_channel, second_channel, third_channel],
450+
) as mock_get_channel, patch(
451+
"durabletask.client.stubs.TaskHubSidecarServiceStub",
452+
side_effect=[first_stub, second_stub, third_stub],
453+
), patch(
454+
"durabletask.client.time.monotonic", side_effect=[100.0, 101.0, 131.0]
455+
), patch("threading.Timer", side_effect=[timer1, timer2]) as mock_timer:
456+
client = TaskHubGrpcClient(
457+
host_address=HOST_ADDRESS,
458+
resiliency_options=GrpcClientResiliencyOptions(
459+
channel_recreate_failure_threshold=1,
460+
min_recreate_interval_seconds=30.0,
461+
),
462+
)
463+
with pytest.raises(FakeRpcError):
464+
client.get_orchestration_state("abc")
465+
assert client._channel is second_channel
466+
assert mock_get_channel.call_count == 2
467+
468+
with pytest.raises(FakeRpcError):
469+
client.get_orchestration_state("abc")
470+
assert client._channel is second_channel
471+
assert mock_get_channel.call_count == 2
472+
mock_timer.assert_called_once_with(30.0, first_channel.close)
473+
474+
with pytest.raises(FakeRpcError):
475+
client.get_orchestration_state("abc")
476+
assert client._channel is third_channel
477+
478+
expected_channel_call = call(
479+
host_address=HOST_ADDRESS,
480+
secure_channel=False,
481+
interceptors=None,
482+
channel_options=None,
483+
)
484+
assert mock_get_channel.call_args_list == [
485+
expected_channel_call,
486+
expected_channel_call,
487+
expected_channel_call,
488+
]
489+
assert mock_timer.call_args_list == [
490+
call(30.0, first_channel.close),
491+
call(30.0, second_channel.close),
492+
]
493+
assert timer1.daemon is True
494+
assert timer2.daemon is True
495+
timer1.start.assert_called_once_with()
496+
timer2.start.assert_called_once_with()
429497

430498

431499
def test_sync_client_resets_failure_tracking_after_success():

0 commit comments

Comments
 (0)