From 69858b5a16ed0e1b639f621ff09dbf430a9c1460 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 14 May 2026 03:50:26 +0000 Subject: [PATCH 1/2] test: remove finite timeout in BlocksUntilSignaledAsync to fix race Agent-Logs-Url: https://github.com/microsoft/agent-framework/sessions/962b7404-4266-4a16-906c-ba3e607c2764 Co-authored-by: lokitoth <6936551+lokitoth@users.noreply.github.com> --- .../InputWaiterAndOutputFilterTests.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/InputWaiterAndOutputFilterTests.cs b/dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/InputWaiterAndOutputFilterTests.cs index dead5454b4d..ab83b340f93 100644 --- a/dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/InputWaiterAndOutputFilterTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/InputWaiterAndOutputFilterTests.cs @@ -34,7 +34,12 @@ public async Task InputWaiter_WaitForInputAsync_CompletesAfterSignalAsync() [Fact] public async Task InputWaiter_WaitForInputAsync_BlocksUntilSignaledAsync() { - Task waitTask = this._waiter.WaitForInputAsync(TimeSpan.FromSeconds(5)); + // Use the no-timeout overload: the wait must only be released by SignalInput. + // Passing a finite timeout here is racy on slow hosts: if the test thread is + // paused longer than the timeout (e.g., heavy CI load or GC) before the + // assertion runs, SemaphoreSlim's internal timer fires and waitTask completes + // on its own, causing the "should not complete before signaled" check to flake. + Task waitTask = this._waiter.WaitForInputAsync(CancellationToken.None); Task completedBeforeSignal = await Task.WhenAny(waitTask, Task.Delay(100)); completedBeforeSignal.Should().NotBeSameAs( From 139ea7226d1ac1df347511cf8e437d1916a95445 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 14 May 2026 12:47:29 +0000 Subject: [PATCH 2/2] address review: clarify comment, add timeout test, cross-reference test names Agent-Logs-Url: https://github.com/microsoft/agent-framework/sessions/e406a5f2-ad31-4d37-b090-69e10713f885 Co-authored-by: lokitoth <6936551+lokitoth@users.noreply.github.com> --- .../InputWaiterAndOutputFilterTests.cs | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/InputWaiterAndOutputFilterTests.cs b/dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/InputWaiterAndOutputFilterTests.cs index ab83b340f93..c7c231c63e8 100644 --- a/dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/InputWaiterAndOutputFilterTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/InputWaiterAndOutputFilterTests.cs @@ -34,11 +34,12 @@ public async Task InputWaiter_WaitForInputAsync_CompletesAfterSignalAsync() [Fact] public async Task InputWaiter_WaitForInputAsync_BlocksUntilSignaledAsync() { - // Use the no-timeout overload: the wait must only be released by SignalInput. - // Passing a finite timeout here is racy on slow hosts: if the test thread is - // paused longer than the timeout (e.g., heavy CI load or GC) before the - // assertion runs, SemaphoreSlim's internal timer fires and waitTask completes - // on its own, causing the "should not complete before signaled" check to flake. + // Use the no-timeout overload so that the wait can only be released by SignalInput. + // A finite timeout would make this test's logic racy: the component correctly + // honors the timeout, but if the test thread is starved of CPU time (CI load, + // GC pause) long enough for the timeout to fire, waitTask completes before + // SignalInput is called and the "should not complete before signaled" assertion + // flakes. Timeout behavior is covered separately below. Task waitTask = this._waiter.WaitForInputAsync(CancellationToken.None); Task completedBeforeSignal = await Task.WhenAny(waitTask, Task.Delay(100)); @@ -105,6 +106,21 @@ public async Task InputWaiter_WaitForInputAsync_CanBeSignaledMultipleTimesSequen this._waiter.SignalInput(); await this._waiter.WaitForInputAsync(TimeSpan.FromSeconds(1)); } + + [Fact] + public async Task InputWaiter_WaitForInputAsync_CompletesWhenTimeoutExpiresAsync() + { + // Verify that a finite timeout releases the block even without a signal. + // We only assert that it *does* complete (within a generous outer bound); + // we intentionally do not assert that it stays blocked until the timeout, + // because that would re-introduce the same wall-clock flakiness + // described in BlocksUntilSignaledAsync (see comment on that test). + Task waitTask = this._waiter.WaitForInputAsync(TimeSpan.FromMilliseconds(300)); + + Task completed = await Task.WhenAny(waitTask, Task.Delay(TimeSpan.FromSeconds(5))); + completed.Should().BeSameAs(waitTask, "the wait task should complete once the timeout expires"); + await waitTask; + } } public class OutputFilterTests