// Copyright (c) Microsoft. All rights reserved. using System; using System.ClientModel; using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.Extensions.AI; using OpenAI.Responses; namespace Microsoft.Agents.AI.OpenAI.UnitTests.ChatClient; /// /// Unit tests for the class. /// public sealed class AsyncStreamingResponseUpdateCollectionResultTests { /// /// Verify that GetContinuationToken returns null. /// [Fact] public void GetContinuationToken_ReturnsNull() { // Arrange IAsyncEnumerable updates = CreateTestUpdatesAsync(); AsyncCollectionResult collectionResult = new AsyncStreamingResponseUpdateCollectionResult(updates); // Act ContinuationToken? token = collectionResult.GetContinuationToken(null!); // Assert Assert.Null(token); } /// /// Verify that GetRawPagesAsync returns a single page. /// [Fact] public async Task GetRawPagesAsync_ReturnsSinglePageAsync() { // Arrange IAsyncEnumerable updates = CreateTestUpdatesAsync(); AsyncCollectionResult collectionResult = new AsyncStreamingResponseUpdateCollectionResult(updates); // Act List pages = []; await foreach (ClientResult page in collectionResult.GetRawPagesAsync()) { pages.Add(page); } // Assert Assert.Single(pages); } /// /// Verify that iterating through the collection yields streaming updates when RawRepresentation is a StreamingResponseUpdate. /// [Fact] public async Task IterateCollection_WithStreamingResponseUpdateRawRepresentation_YieldsUpdatesAsync() { // Arrange StreamingResponseUpdate rawUpdate = CreateStreamingResponseUpdate(); IAsyncEnumerable updates = CreateTestUpdatesWithRawRepresentationAsync(rawUpdate); AsyncCollectionResult collectionResult = new AsyncStreamingResponseUpdateCollectionResult(updates); // Act List results = []; await foreach (StreamingResponseUpdate update in collectionResult) { results.Add(update); } // Assert Assert.Single(results); Assert.Same(rawUpdate, results[0]); } /// /// Verify that iterating through the collection yields updates when RawRepresentation is a ChatResponseUpdate containing a StreamingResponseUpdate. /// [Fact] public async Task IterateCollection_WithChatResponseUpdateContainingStreamingResponseUpdate_YieldsUpdatesAsync() { // Arrange StreamingResponseUpdate rawUpdate = CreateStreamingResponseUpdate(); ChatResponseUpdate chatResponseUpdate = new() { RawRepresentation = rawUpdate }; IAsyncEnumerable updates = CreateTestUpdatesWithChatResponseUpdateAsync(chatResponseUpdate); AsyncCollectionResult collectionResult = new AsyncStreamingResponseUpdateCollectionResult(updates); // Act List results = []; await foreach (StreamingResponseUpdate update in collectionResult) { results.Add(update); } // Assert Assert.Single(results); Assert.Same(rawUpdate, results[0]); } /// /// Verify that iterating through the collection skips updates when RawRepresentation is not a StreamingResponseUpdate. /// [Fact] public async Task IterateCollection_WithNonStreamingResponseUpdateRawRepresentation_SkipsUpdateAsync() { // Arrange IAsyncEnumerable updates = CreateTestUpdatesAsync(); AsyncCollectionResult collectionResult = new AsyncStreamingResponseUpdateCollectionResult(updates); // Act List results = []; await foreach (StreamingResponseUpdate update in collectionResult) { results.Add(update); } // Assert Assert.Empty(results); } /// /// Verify that iterating through the collection skips updates when RawRepresentation is a ChatResponseUpdate without StreamingResponseUpdate. /// [Fact] public async Task IterateCollection_WithChatResponseUpdateWithoutStreamingResponseUpdate_SkipsUpdateAsync() { // Arrange ChatResponseUpdate chatResponseUpdate = new() { RawRepresentation = "not a streaming update" }; IAsyncEnumerable updates = CreateTestUpdatesWithChatResponseUpdateAsync(chatResponseUpdate); AsyncCollectionResult collectionResult = new AsyncStreamingResponseUpdateCollectionResult(updates); // Act List results = []; await foreach (StreamingResponseUpdate update in collectionResult) { results.Add(update); } // Assert Assert.Empty(results); } private static async IAsyncEnumerable CreateTestUpdatesAsync() { yield return new AgentResponseUpdate(ChatRole.Assistant, "test"); await Task.CompletedTask; } private static async IAsyncEnumerable CreateTestUpdatesWithRawRepresentationAsync(object rawRepresentation) { AgentResponseUpdate update = new(ChatRole.Assistant, "test") { RawRepresentation = rawRepresentation }; yield return update; await Task.CompletedTask; } private static async IAsyncEnumerable CreateTestUpdatesWithChatResponseUpdateAsync(ChatResponseUpdate chatResponseUpdate) { AgentResponseUpdate update = new(ChatRole.Assistant, "test") { RawRepresentation = chatResponseUpdate }; yield return update; await Task.CompletedTask; } private static StreamingResponseUpdate CreateStreamingResponseUpdate() { const string Json = """ { "type": "response.output_item.added", "sequence_number": 1, "output_index": 0, "item": { "id": "item_abc123", "type": "message", "status": "in_progress", "role": "assistant", "content": [] } } """; return System.ClientModel.Primitives.ModelReaderWriter.Read(BinaryData.FromString(Json))!; } }