mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
b03a4fb95e
* Initial plan * Infrastructure setup * Plan for minimal client * Plan update * Basic agentic chat * cleanup * Cleanups * More cleanups * Cleanups * More cleanups * Test plan * Sample * Fix streaming and error handling * Fix notifications * Cleanups * cleanup sample * Additional tests * Additional tests * Run dotnet format * Remove unnecessary files * Mark packages as non packable * Fix build * Address feedback * Fix build * Fix remaining warnings * Feedback * Feedback and cleanup * Cleanup * Cleanups * Cleanups * Cleanups * Retrieve existing messages from the store to send them along the way and update the sample client * Run dotnet format * Add ADR for AG-UI * Switch to use the SG and use a convention for run ids * Cleanup MapAGUI API * Fix formatting * Fix solution * Fix solution
153 lines
5.6 KiB
C#
153 lines
5.6 KiB
C#
// Copyright (c) Microsoft. All rights reserved.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.Shared;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.Extensions.Logging;
|
|
using Microsoft.Extensions.Logging.Abstractions;
|
|
|
|
namespace Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.UnitTests;
|
|
|
|
/// <summary>
|
|
/// Unit tests for the <see cref="AGUIServerSentEventsResult"/> class.
|
|
/// </summary>
|
|
public sealed class AGUIServerSentEventsResultTests
|
|
{
|
|
[Fact]
|
|
public async Task ExecuteAsync_SetsCorrectResponseHeaders_ContentTypeAndCacheControlAsync()
|
|
{
|
|
// Arrange
|
|
List<BaseEvent> events = [];
|
|
ILogger<AGUIServerSentEventsResult> logger = NullLogger<AGUIServerSentEventsResult>.Instance;
|
|
AGUIServerSentEventsResult result = new(events.ToAsyncEnumerableAsync(), logger);
|
|
DefaultHttpContext httpContext = new();
|
|
httpContext.Response.Body = new MemoryStream();
|
|
|
|
// Act
|
|
await result.ExecuteAsync(httpContext);
|
|
|
|
// Assert
|
|
Assert.Equal("text/event-stream", httpContext.Response.ContentType);
|
|
Assert.Equal("no-cache,no-store", httpContext.Response.Headers.CacheControl.ToString());
|
|
Assert.Equal("no-cache", httpContext.Response.Headers.Pragma.ToString());
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ExecuteAsync_SerializesEventsInSSEFormat_WithDataPrefixAndNewlinesAsync()
|
|
{
|
|
// Arrange
|
|
List<BaseEvent> events =
|
|
[
|
|
new RunStartedEvent { ThreadId = "thread1", RunId = "run1" },
|
|
new RunFinishedEvent { ThreadId = "thread1", RunId = "run1" }
|
|
];
|
|
ILogger<AGUIServerSentEventsResult> logger = NullLogger<AGUIServerSentEventsResult>.Instance;
|
|
AGUIServerSentEventsResult result = new(events.ToAsyncEnumerableAsync(), logger);
|
|
DefaultHttpContext httpContext = new();
|
|
MemoryStream responseStream = new();
|
|
httpContext.Response.Body = responseStream;
|
|
|
|
// Act
|
|
await result.ExecuteAsync(httpContext);
|
|
|
|
// Assert
|
|
string responseContent = Encoding.UTF8.GetString(responseStream.ToArray());
|
|
Assert.Contains("data: ", responseContent);
|
|
Assert.Contains("\n\n", responseContent);
|
|
string[] eventStrings = responseContent.Split("\n\n", StringSplitOptions.RemoveEmptyEntries);
|
|
Assert.Equal(2, eventStrings.Length);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ExecuteAsync_FlushesResponse_AfterEachEventAsync()
|
|
{
|
|
// Arrange
|
|
List<BaseEvent> events =
|
|
[
|
|
new RunStartedEvent { ThreadId = "thread1", RunId = "run1" },
|
|
new TextMessageContentEvent { MessageId = "msg1", Delta = "Hello" },
|
|
new RunFinishedEvent { ThreadId = "thread1", RunId = "run1" }
|
|
];
|
|
ILogger<AGUIServerSentEventsResult> logger = NullLogger<AGUIServerSentEventsResult>.Instance;
|
|
AGUIServerSentEventsResult result = new(events.ToAsyncEnumerableAsync(), logger);
|
|
DefaultHttpContext httpContext = new();
|
|
MemoryStream responseStream = new();
|
|
httpContext.Response.Body = responseStream;
|
|
|
|
// Act
|
|
await result.ExecuteAsync(httpContext);
|
|
|
|
// Assert
|
|
string responseContent = Encoding.UTF8.GetString(responseStream.ToArray());
|
|
string[] eventStrings = responseContent.Split("\n\n", StringSplitOptions.RemoveEmptyEntries);
|
|
Assert.Equal(3, eventStrings.Length);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ExecuteAsync_WithEmptyEventStream_CompletesSuccessfullyAsync()
|
|
{
|
|
// Arrange
|
|
List<BaseEvent> events = [];
|
|
ILogger<AGUIServerSentEventsResult> logger = NullLogger<AGUIServerSentEventsResult>.Instance;
|
|
AGUIServerSentEventsResult result = new(events.ToAsyncEnumerableAsync(), logger);
|
|
DefaultHttpContext httpContext = new();
|
|
httpContext.Response.Body = new MemoryStream();
|
|
|
|
// Act
|
|
await result.ExecuteAsync(httpContext);
|
|
|
|
// Assert
|
|
Assert.Equal(StatusCodes.Status200OK, result.StatusCode);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ExecuteAsync_RespectsCancellationToken_WhenCancelledAsync()
|
|
{
|
|
// Arrange
|
|
using CancellationTokenSource cts = new();
|
|
List<BaseEvent> events =
|
|
[
|
|
new RunStartedEvent { ThreadId = "thread1", RunId = "run1" },
|
|
new TextMessageContentEvent { MessageId = "msg1", Delta = "Hello" }
|
|
];
|
|
|
|
async IAsyncEnumerable<BaseEvent> GetEventsWithCancellationAsync()
|
|
{
|
|
foreach (BaseEvent evt in events)
|
|
{
|
|
yield return evt;
|
|
await Task.Delay(10);
|
|
}
|
|
}
|
|
|
|
ILogger<AGUIServerSentEventsResult> logger = NullLogger<AGUIServerSentEventsResult>.Instance;
|
|
AGUIServerSentEventsResult result = new(GetEventsWithCancellationAsync(), logger);
|
|
DefaultHttpContext httpContext = new();
|
|
httpContext.Response.Body = new MemoryStream();
|
|
httpContext.RequestAborted = cts.Token;
|
|
|
|
// Act
|
|
cts.Cancel();
|
|
|
|
// Assert
|
|
await Assert.ThrowsAnyAsync<OperationCanceledException>(() => result.ExecuteAsync(httpContext));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ExecuteAsync_WithNullHttpContext_ThrowsArgumentNullExceptionAsync()
|
|
{
|
|
// Arrange
|
|
List<BaseEvent> events = [];
|
|
ILogger<AGUIServerSentEventsResult> logger = NullLogger<AGUIServerSentEventsResult>.Instance;
|
|
AGUIServerSentEventsResult result = new(events.ToAsyncEnumerableAsync(), logger);
|
|
|
|
// Act & Assert
|
|
await Assert.ThrowsAsync<ArgumentNullException>(() => result.ExecuteAsync(null!));
|
|
}
|
|
}
|