Replace flaky Task.Delay with TaskCompletionSource for deterministic test synchronization

- Added TaskCompletionSource fields to Spy class for each notification type
- Test handlers now signal completion through TaskCompletionSource
- Tests await TaskCompletionSource instead of arbitrary delays
- Eliminates timing-dependent flakiness in CI systems

Co-authored-by: KnibbsyMan <23156317+KnibbsyMan@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2025-12-24 23:47:55 +00:00
parent f834b040f9
commit 2ff1693cd5
3 changed files with 25 additions and 4 deletions

View file

@ -5,6 +5,11 @@ namespace Elsa.Workflows.IntegrationTests.Scenarios.WorkflowDispatchNotification
public class Spy
{
private readonly TaskCompletionSource<bool> _workflowDefinitionDispatchingTcs = new();
private readonly TaskCompletionSource<bool> _workflowDefinitionDispatchedTcs = new();
private readonly TaskCompletionSource<bool> _workflowInstanceDispatchingTcs = new();
private readonly TaskCompletionSource<bool> _workflowInstanceDispatchedTcs = new();
public bool WorkflowDefinitionDispatchingWasCalled { get; set; }
public bool WorkflowDefinitionDispatchedWasCalled { get; set; }
public bool WorkflowInstanceDispatchingWasCalled { get; set; }
@ -13,4 +18,14 @@ public class Spy
public DispatchWorkflowDefinitionRequest? CapturedDefinitionRequest { get; set; }
public DispatchWorkflowInstanceRequest? CapturedInstanceRequest { get; set; }
public DispatchWorkflowResponse? CapturedResponse { get; set; }
public Task WaitForWorkflowDefinitionDispatchingAsync() => _workflowDefinitionDispatchingTcs.Task;
public Task WaitForWorkflowDefinitionDispatchedAsync() => _workflowDefinitionDispatchedTcs.Task;
public Task WaitForWorkflowInstanceDispatchingAsync() => _workflowInstanceDispatchingTcs.Task;
public Task WaitForWorkflowInstanceDispatchedAsync() => _workflowInstanceDispatchedTcs.Task;
public void SignalWorkflowDefinitionDispatching() => _workflowDefinitionDispatchingTcs.TrySetResult(true);
public void SignalWorkflowDefinitionDispatched() => _workflowDefinitionDispatchedTcs.TrySetResult(true);
public void SignalWorkflowInstanceDispatching() => _workflowInstanceDispatchingTcs.TrySetResult(true);
public void SignalWorkflowInstanceDispatched() => _workflowInstanceDispatchedTcs.TrySetResult(true);
}

View file

@ -20,6 +20,7 @@ public class TestHandler :
{
_spy.WorkflowDefinitionDispatchingWasCalled = true;
_spy.CapturedDefinitionRequest = notification.Request;
_spy.SignalWorkflowDefinitionDispatching();
return Task.CompletedTask;
}
@ -27,6 +28,7 @@ public class TestHandler :
{
_spy.WorkflowDefinitionDispatchedWasCalled = true;
_spy.CapturedResponse = notification.Response;
_spy.SignalWorkflowDefinitionDispatched();
return Task.CompletedTask;
}
@ -34,6 +36,7 @@ public class TestHandler :
{
_spy.WorkflowInstanceDispatchingWasCalled = true;
_spy.CapturedInstanceRequest = notification.Request;
_spy.SignalWorkflowInstanceDispatching();
return Task.CompletedTask;
}
@ -41,6 +44,7 @@ public class TestHandler :
{
_spy.WorkflowInstanceDispatchedWasCalled = true;
_spy.CapturedResponse = notification.Response;
_spy.SignalWorkflowInstanceDispatched();
return Task.CompletedTask;
}
}

View file

@ -43,8 +43,9 @@ public class Tests
// Act
await _workflowDispatcher.DispatchAsync(request, null);
// Allow async notification handlers to complete
await Task.Delay(100);
// Wait for notification handlers to complete
await _spy.WaitForWorkflowDefinitionDispatchingAsync();
await _spy.WaitForWorkflowDefinitionDispatchedAsync();
// Assert
Assert.True(_spy.WorkflowDefinitionDispatchingWasCalled, "WorkflowDefinitionDispatching notification should be called");
@ -70,8 +71,9 @@ public class Tests
// Act
await _workflowDispatcher.DispatchAsync(request, null);
// Allow async notification handlers to complete
await Task.Delay(100);
// Wait for notification handlers to complete
await _spy.WaitForWorkflowInstanceDispatchingAsync();
await _spy.WaitForWorkflowInstanceDispatchedAsync();
// Assert
Assert.True(_spy.WorkflowInstanceDispatchingWasCalled, "WorkflowInstanceDispatching notification should be called");