Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Optional Streaming Timeout Tests Design

## Scope

Make the five timeout and keep-alive tests added for PR #950 opt-in so they do not run
automatically with the normal `StreamingResponseTests` suite.

## Design

Add a test-local `OptionalStreamingTimeoutFactAttribute` derived from xUnit's
`FactAttribute`. The attribute will set `Skip` unless the environment variable
`XUNITSTREAMINGTIMEOUTTESTENABLED` is exactly `1`.

Apply the attribute to:

- `SendStreamTimedOutNotification_DisablesStreaming_AndFinalResponseIsStillSent`
- `ChannelStreamingTimeout_UpdatesCheckpointAndFinalMessage`
- `M365Copilot_IdleStream_SendsConfiguredWorkingNotice`
- `M365Copilot_TimeoutWithoutText_SendsFinalTimeoutMessage`
- `M365Copilot_TimeoutWithBufferedText_SendsTerminatingActivitiesAndFinalResponse`

No production code, project configuration, or CI configuration will change.

## Execution

Normal test runs discover the five tests as skipped. Developers can run them explicitly
from PowerShell with:

```powershell
$env:XUNITSTREAMINGTIMEOUTTESTENABLED = '1'
dotnet test src\tests\Microsoft.Agents.Builder.Tests\Microsoft.Agents.Builder.Tests.csproj `
--filter "FullyQualifiedName~StreamingResponseTests"
```

Removing the environment variable restores the default skipped behavior.

## Validation

Run the filtered test class without the environment variable and verify five skipped tests.
Then run it with the environment variable set and verify all tests pass on both target
frameworks.
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Streaming Response Timeout Tests Design

## Scope

Add focused unit coverage to `StreamingResponseTests.cs` for the behaviors identified in
PR #950's review comment. Production code remains unchanged.

## Test Strategy

The tests will use the existing `TurnContext.StreamingResponse` public surface and mocked
`IChannelAdapter` operations for observable assertions. Small test-only reflection helpers
will set private timeout state or duration fields where waiting for the real 35-second or
105-second thresholds would make the tests slow and unreliable.

Reflection will be limited to named fields on the concrete internal `StreamingResponse`
instance. Helpers will fail immediately if a field is renamed or cannot be found.

## Coverage

1. Verify `SendStreamTimedOutNotification` sends the supplied stop notification, disables
streaming for the turn, and allows subsequently buffered content to be delivered when
`EndStreamAsync` completes.
2. Simulate a channel streaming-timeout response and verify timeout checkpoints and the
eventual final message use activity updates rather than creating additional sends.
3. Force the M365 Copilot working-notice threshold and verify the configured
`StreamingTakingTooLongMessage` is emitted as an informative streaming activity.
4. Force the M365 Copilot overall timeout with no buffered text and verify the timeout
message is sent and streaming is disabled.
5. Force the M365 Copilot overall timeout with buffered text and verify the terminating
timeout activities are sent and the buffered final response remains deliverable through
the non-streaming path.

## Synchronization and Assertions

Tests will use adapter callbacks and the existing condition-based wait helpers rather than
fixed sleeps. Assertions will distinguish `SendActivitiesAsync` from `UpdateActivityAsync`,
inspect activity type and `StreamInfo`, and confirm `IsStreamingChannel` transitions.

## Validation

Run the targeted `Microsoft.Agents.Builder.Tests` project filtered to
`StreamingResponseTests`. If the target frameworks require separate execution, run the
supported .NET target that exercises the modified test file.
4 changes: 2 additions & 2 deletions src/Build.Shared.props
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DefineConstants>TRACE</DefineConstants>
<DebugType>pdbonly</DebugType>
<DebugType>portable</DebugType>
<Optimize>true</Optimize>
</PropertyGroup>

Expand All @@ -73,7 +73,7 @@

<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<DefineConstants>TRACE</DefineConstants>
<DebugType>pdbonly</DebugType>
<DebugType>portable</DebugType>
<Optimize>true</Optimize>
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ public interface IStreamingResponse
/// </summary>
List<ClientCitation>? Citations { get; }

/// <summary>
/// This is the displayed message that is sent to the user when a stream trips one of the timeouts for the channel.
/// </summary>
string StreamingTakingTooLongMessage { get; set; }

/// <summary>
/// Adds an attachment to the collection of attachments for the final message.
/// </summary>
Expand Down Expand Up @@ -152,7 +157,6 @@ public interface IStreamingResponse
/// Queues a chunk of partial message text to be sent to the client.
/// </summary>
/// <param name="text">Partial text of the message to send.</param>
/// <param name="citations">Citations to include in the message.</param>
/// <exception cref="System.InvalidOperationException">Throws if the stream has already ended.</exception>
void QueueTextChunk(string text);

Expand All @@ -168,5 +172,13 @@ public interface IStreamingResponse
/// </summary>
/// <returns>Number of updates sent so far.</returns>
int UpdatesSent();

/// <summary>
/// Cancels the stream and sends a final message to the client indicating that the stream was cancelled, but does not stop the underlying operation. This is useful for long-running operations that may be cancelled by the user or timeout, but should continue to run in the background.
/// </summary>
/// <param name="Message">Message that will be sent to the client indicating the stream was cancelled.</param>
/// <param name="cancellationToken"></param>
/// <returns>True if the stream was successfully cancelled, false otherwise.</returns>
Task<bool> SendStreamTimedOutNotification(string Message, CancellationToken cancellationToken = default);
}
}
Loading
Loading