mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
613 lines
23 KiB
C#
613 lines
23 KiB
C#
// Copyright (c) Microsoft. All rights reserved.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.Agents.AI.Purview.Models.Common;
|
|
using Microsoft.Extensions.AI;
|
|
using Microsoft.Extensions.Logging.Abstractions;
|
|
using Moq;
|
|
using Moq.Protected;
|
|
|
|
namespace Microsoft.Agents.AI.Purview.UnitTests;
|
|
|
|
/// <summary>
|
|
/// Unit tests for the <see cref="PurviewWrapper"/> class.
|
|
/// </summary>
|
|
public sealed class PurviewWrapperTests : IDisposable
|
|
{
|
|
private readonly Mock<IScopedContentProcessor> _mockProcessor;
|
|
private readonly IBackgroundJobRunner _backgroundJobRunner;
|
|
private readonly PurviewSettings _settings;
|
|
private readonly PurviewWrapper _wrapper;
|
|
|
|
public PurviewWrapperTests()
|
|
{
|
|
this._mockProcessor = new Mock<IScopedContentProcessor>();
|
|
this._settings = new PurviewSettings("TestApp")
|
|
{
|
|
TenantId = "tenant-123",
|
|
PurviewAppLocation = new PurviewAppLocation(PurviewLocationType.Application, "app-123"),
|
|
BlockedPromptMessage = "Prompt blocked by policy",
|
|
BlockedResponseMessage = "Response blocked by policy"
|
|
};
|
|
this._backgroundJobRunner = Mock.Of<IBackgroundJobRunner>();
|
|
this._wrapper = new PurviewWrapper(this._mockProcessor.Object, this._settings, NullLogger.Instance, this._backgroundJobRunner);
|
|
}
|
|
|
|
#region ProcessChatContentAsync Tests
|
|
|
|
[Fact]
|
|
public async Task ProcessChatContentAsync_WithBlockedPrompt_ReturnsBlockedMessageAsync()
|
|
{
|
|
// Arrange
|
|
var messages = new List<ChatMessage>
|
|
{
|
|
new(ChatRole.User, "Sensitive content that should be blocked")
|
|
};
|
|
var mockChatClient = new Mock<IChatClient>();
|
|
|
|
this._mockProcessor.Setup(x => x.ProcessMessagesAsync(
|
|
It.IsAny<IEnumerable<ChatMessage>>(),
|
|
It.IsAny<string>(),
|
|
Activity.UploadText,
|
|
It.IsAny<PurviewSettings>(),
|
|
It.IsAny<string>(),
|
|
It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync((true, "user-123"));
|
|
|
|
// Act
|
|
var result = await this._wrapper.ProcessChatContentAsync(messages, null, mockChatClient.Object, CancellationToken.None);
|
|
|
|
// Assert
|
|
Assert.NotNull(result);
|
|
Assert.Single(result.Messages);
|
|
Assert.Equal(ChatRole.System, result.Messages[0].Role);
|
|
Assert.Equal("Prompt blocked by policy", result.Messages[0].Text);
|
|
mockChatClient.Verify(x => x.GetResponseAsync(
|
|
It.IsAny<IEnumerable<ChatMessage>>(),
|
|
It.IsAny<ChatOptions>(),
|
|
It.IsAny<CancellationToken>()), Times.Never);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ProcessChatContentAsync_WithAllowedPromptAndBlockedResponse_ReturnsBlockedMessageAsync()
|
|
{
|
|
// Arrange
|
|
var messages = new List<ChatMessage>
|
|
{
|
|
new(ChatRole.User, "Test message")
|
|
};
|
|
var mockChatClient = new Mock<IChatClient>();
|
|
var innerResponse = new ChatResponse(new ChatMessage(ChatRole.Assistant, "Sensitive response"));
|
|
|
|
mockChatClient.Setup(x => x.GetResponseAsync(
|
|
It.IsAny<IEnumerable<ChatMessage>>(),
|
|
It.IsAny<ChatOptions>(),
|
|
It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(innerResponse);
|
|
|
|
// Prompt check uses UploadText, response check uses DownloadText
|
|
this._mockProcessor.Setup(x => x.ProcessMessagesAsync(
|
|
It.IsAny<IEnumerable<ChatMessage>>(),
|
|
It.IsAny<string>(),
|
|
Activity.UploadText,
|
|
It.IsAny<PurviewSettings>(),
|
|
It.IsAny<string>(),
|
|
It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync((false, "user-123")); // Prompt allowed
|
|
|
|
this._mockProcessor.Setup(x => x.ProcessMessagesAsync(
|
|
It.IsAny<IEnumerable<ChatMessage>>(),
|
|
It.IsAny<string>(),
|
|
Activity.DownloadText,
|
|
It.IsAny<PurviewSettings>(),
|
|
It.IsAny<string>(),
|
|
It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync((true, "user-123")); // Response blocked
|
|
|
|
// Act
|
|
var result = await this._wrapper.ProcessChatContentAsync(messages, null, mockChatClient.Object, CancellationToken.None);
|
|
|
|
// Assert
|
|
Assert.NotNull(result);
|
|
Assert.Single(result.Messages);
|
|
Assert.Equal(ChatRole.System, result.Messages[0].Role);
|
|
Assert.Equal("Response blocked by policy", result.Messages[0].Text);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ProcessChatContentAsync_WithAllowedPromptAndResponse_ReturnsInnerResponseAsync()
|
|
{
|
|
// Arrange
|
|
var messages = new List<ChatMessage>
|
|
{
|
|
new(ChatRole.User, "Test message")
|
|
};
|
|
var mockChatClient = new Mock<IChatClient>();
|
|
var innerResponse = new ChatResponse(new ChatMessage(ChatRole.Assistant, "Safe response"));
|
|
|
|
mockChatClient.Setup(x => x.GetResponseAsync(
|
|
It.IsAny<IEnumerable<ChatMessage>>(),
|
|
It.IsAny<ChatOptions>(),
|
|
It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(innerResponse);
|
|
|
|
this._mockProcessor.Setup(x => x.ProcessMessagesAsync(
|
|
It.IsAny<IEnumerable<ChatMessage>>(),
|
|
It.IsAny<string>(),
|
|
It.IsAny<Activity>(),
|
|
It.IsAny<PurviewSettings>(),
|
|
It.IsAny<string>(),
|
|
It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync((false, "user-123"));
|
|
|
|
// Act
|
|
var result = await this._wrapper.ProcessChatContentAsync(messages, null, mockChatClient.Object, CancellationToken.None);
|
|
|
|
// Assert
|
|
Assert.Same(innerResponse, result);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ProcessChatContentAsync_WithIgnoreExceptions_ContinuesOnPromptErrorAsync()
|
|
{
|
|
// Arrange
|
|
var settingsWithIgnore = new PurviewSettings("TestApp")
|
|
{
|
|
TenantId = "tenant-123",
|
|
IgnoreExceptions = true,
|
|
PurviewAppLocation = new PurviewAppLocation(PurviewLocationType.Application, "app-123")
|
|
};
|
|
var wrapper = new PurviewWrapper(this._mockProcessor.Object, settingsWithIgnore, NullLogger.Instance, this._backgroundJobRunner);
|
|
|
|
var messages = new List<ChatMessage>
|
|
{
|
|
new(ChatRole.User, "Test message")
|
|
};
|
|
|
|
var expectedResponse = new ChatResponse(new ChatMessage(ChatRole.Assistant, "Response from inner client"));
|
|
var mockChatClient = new Mock<IChatClient>();
|
|
mockChatClient.Setup(x => x.GetResponseAsync(
|
|
It.IsAny<IEnumerable<ChatMessage>>(),
|
|
It.IsAny<ChatOptions>(),
|
|
It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(expectedResponse);
|
|
|
|
this._mockProcessor.SetupSequence(x => x.ProcessMessagesAsync(
|
|
It.IsAny<IEnumerable<ChatMessage>>(),
|
|
It.IsAny<string>(),
|
|
It.IsAny<Activity>(),
|
|
It.IsAny<PurviewSettings>(),
|
|
It.IsAny<string>(),
|
|
It.IsAny<CancellationToken>()))
|
|
.ThrowsAsync(new PurviewRequestException("Prompt processing error")); // Response processing succeeds
|
|
|
|
// Act
|
|
var result = await wrapper.ProcessChatContentAsync(messages, null, mockChatClient.Object, CancellationToken.None);
|
|
|
|
// Assert
|
|
Assert.NotNull(result);
|
|
Assert.Same(expectedResponse, result);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ProcessChatContentAsync_WithoutIgnoreExceptions_ThrowsOnPromptErrorAsync()
|
|
{
|
|
// Arrange
|
|
var messages = new List<ChatMessage>
|
|
{
|
|
new(ChatRole.User, "Test message")
|
|
};
|
|
var mockChatClient = new Mock<IChatClient>();
|
|
|
|
this._mockProcessor.Setup(x => x.ProcessMessagesAsync(
|
|
It.IsAny<IEnumerable<ChatMessage>>(),
|
|
It.IsAny<string>(),
|
|
It.IsAny<Activity>(),
|
|
It.IsAny<PurviewSettings>(),
|
|
It.IsAny<string>(),
|
|
It.IsAny<CancellationToken>()))
|
|
.ThrowsAsync(new PurviewRequestException("Prompt processing error"));
|
|
|
|
// Act & Assert
|
|
await Assert.ThrowsAsync<PurviewRequestException>(() =>
|
|
this._wrapper.ProcessChatContentAsync(messages, null, mockChatClient.Object, CancellationToken.None));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ProcessChatContentAsync_UsesConversationIdFromOptions_Async()
|
|
{
|
|
// Arrange
|
|
var messages = new List<ChatMessage>
|
|
{
|
|
new(ChatRole.User, "Test message")
|
|
};
|
|
var options = new ChatOptions { ConversationId = "conversation-123" };
|
|
var mockChatClient = new Mock<IChatClient>();
|
|
var innerResponse = new ChatResponse(new ChatMessage(ChatRole.Assistant, "Response"));
|
|
|
|
mockChatClient.Setup(x => x.GetResponseAsync(
|
|
It.IsAny<IEnumerable<ChatMessage>>(),
|
|
It.IsAny<ChatOptions>(),
|
|
It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(innerResponse);
|
|
|
|
this._mockProcessor.Setup(x => x.ProcessMessagesAsync(
|
|
It.IsAny<IEnumerable<ChatMessage>>(),
|
|
"conversation-123",
|
|
It.IsAny<Activity>(),
|
|
It.IsAny<PurviewSettings>(),
|
|
It.IsAny<string>(),
|
|
It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync((false, "user-123"));
|
|
|
|
// Act
|
|
await this._wrapper.ProcessChatContentAsync(messages, options, mockChatClient.Object, CancellationToken.None);
|
|
|
|
// Assert - verify prompt uses UploadText and response uses DownloadText
|
|
this._mockProcessor.Verify(x => x.ProcessMessagesAsync(
|
|
It.IsAny<IEnumerable<ChatMessage>>(),
|
|
"conversation-123",
|
|
Activity.UploadText,
|
|
It.IsAny<PurviewSettings>(),
|
|
It.IsAny<string>(),
|
|
It.IsAny<CancellationToken>()), Times.Once);
|
|
this._mockProcessor.Verify(x => x.ProcessMessagesAsync(
|
|
It.IsAny<IEnumerable<ChatMessage>>(),
|
|
"conversation-123",
|
|
Activity.DownloadText,
|
|
It.IsAny<PurviewSettings>(),
|
|
It.IsAny<string>(),
|
|
It.IsAny<CancellationToken>()), Times.Once);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ProcessAgentContentAsync Tests
|
|
|
|
[Fact]
|
|
public async Task ProcessAgentContentAsync_WithBlockedPrompt_ReturnsBlockedMessageAsync()
|
|
{
|
|
// Arrange
|
|
var messages = new List<ChatMessage>
|
|
{
|
|
new(ChatRole.User, "Sensitive content")
|
|
};
|
|
var mockAgent = new Mock<AIAgent>();
|
|
|
|
this._mockProcessor.Setup(x => x.ProcessMessagesAsync(
|
|
It.IsAny<IEnumerable<ChatMessage>>(),
|
|
It.IsAny<string>(),
|
|
Activity.UploadText,
|
|
It.IsAny<PurviewSettings>(),
|
|
It.IsAny<string>(),
|
|
It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync((true, "user-123"));
|
|
|
|
// Act
|
|
var result = await this._wrapper.ProcessAgentContentAsync(messages, null, null, mockAgent.Object, CancellationToken.None);
|
|
|
|
// Assert
|
|
Assert.NotNull(result);
|
|
Assert.Single(result.Messages);
|
|
Assert.Equal(ChatRole.System, result.Messages[0].Role);
|
|
Assert.Equal("Prompt blocked by policy", result.Messages[0].Text);
|
|
|
|
mockAgent.Protected().Verify("RunCoreAsync",
|
|
Times.Never(),
|
|
ItExpr.IsAny<IEnumerable<ChatMessage>>(),
|
|
ItExpr.IsAny<AgentSession>(),
|
|
ItExpr.IsAny<AgentRunOptions>(),
|
|
ItExpr.IsAny<CancellationToken>());
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ProcessAgentContentAsync_WithAllowedPromptAndBlockedResponse_ReturnsBlockedMessageAsync()
|
|
{
|
|
// Arrange
|
|
var messages = new List<ChatMessage>
|
|
{
|
|
new(ChatRole.User, "Test message")
|
|
};
|
|
var mockAgent = new Mock<AIAgent>();
|
|
var innerResponse = new AgentResponse(new ChatMessage(ChatRole.Assistant, "Sensitive response"));
|
|
|
|
mockAgent.Protected()
|
|
.Setup<Task<AgentResponse>>("RunCoreAsync",
|
|
ItExpr.IsAny<IEnumerable<ChatMessage>>(),
|
|
ItExpr.IsAny<AgentSession>(),
|
|
ItExpr.IsAny<AgentRunOptions>(),
|
|
ItExpr.IsAny<CancellationToken>())
|
|
.ReturnsAsync(innerResponse);
|
|
|
|
// Prompt check uses UploadText, response check uses DownloadText
|
|
this._mockProcessor.Setup(x => x.ProcessMessagesAsync(
|
|
It.IsAny<IEnumerable<ChatMessage>>(),
|
|
It.IsAny<string>(),
|
|
Activity.UploadText,
|
|
It.IsAny<PurviewSettings>(),
|
|
It.IsAny<string>(),
|
|
It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync((false, "user-123")); // Prompt allowed
|
|
|
|
this._mockProcessor.Setup(x => x.ProcessMessagesAsync(
|
|
It.IsAny<IEnumerable<ChatMessage>>(),
|
|
It.IsAny<string>(),
|
|
Activity.DownloadText,
|
|
It.IsAny<PurviewSettings>(),
|
|
It.IsAny<string>(),
|
|
It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync((true, "user-123")); // Response blocked
|
|
|
|
// Act
|
|
var result = await this._wrapper.ProcessAgentContentAsync(messages, null, null, mockAgent.Object, CancellationToken.None);
|
|
|
|
// Assert
|
|
Assert.NotNull(result);
|
|
Assert.Single(result.Messages);
|
|
Assert.Equal(ChatRole.System, result.Messages[0].Role);
|
|
Assert.Equal("Response blocked by policy", result.Messages[0].Text);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ProcessAgentContentAsync_WithAllowedPromptAndResponse_ReturnsInnerResponseAsync()
|
|
{
|
|
// Arrange
|
|
var messages = new List<ChatMessage>
|
|
{
|
|
new(ChatRole.User, "Test message")
|
|
};
|
|
var mockAgent = new Mock<AIAgent>();
|
|
var innerResponse = new AgentResponse(new ChatMessage(ChatRole.Assistant, "Safe response"));
|
|
|
|
mockAgent.Protected()
|
|
.Setup<Task<AgentResponse>>("RunCoreAsync",
|
|
ItExpr.IsAny<IEnumerable<ChatMessage>>(),
|
|
ItExpr.IsAny<AgentSession>(),
|
|
ItExpr.IsAny<AgentRunOptions>(),
|
|
ItExpr.IsAny<CancellationToken>())
|
|
.ReturnsAsync(innerResponse);
|
|
|
|
this._mockProcessor.Setup(x => x.ProcessMessagesAsync(
|
|
It.IsAny<IEnumerable<ChatMessage>>(),
|
|
It.IsAny<string>(),
|
|
It.IsAny<Activity>(),
|
|
It.IsAny<PurviewSettings>(),
|
|
It.IsAny<string>(),
|
|
It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync((false, "user-123"));
|
|
|
|
// Act
|
|
var result = await this._wrapper.ProcessAgentContentAsync(messages, null, null, mockAgent.Object, CancellationToken.None);
|
|
|
|
// Assert
|
|
Assert.Same(innerResponse, result);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ProcessAgentContentAsync_WithIgnoreExceptions_ContinuesOnErrorAsync()
|
|
{
|
|
// Arrange
|
|
var settingsWithIgnore = new PurviewSettings("TestApp")
|
|
{
|
|
TenantId = "tenant-123",
|
|
IgnoreExceptions = true,
|
|
PurviewAppLocation = new PurviewAppLocation(PurviewLocationType.Application, "app-123")
|
|
};
|
|
var wrapper = new PurviewWrapper(this._mockProcessor.Object, settingsWithIgnore, NullLogger.Instance, this._backgroundJobRunner);
|
|
|
|
var messages = new List<ChatMessage>
|
|
{
|
|
new(ChatRole.User, "Test message")
|
|
};
|
|
|
|
var expectedResponse = new AgentResponse(new ChatMessage(ChatRole.Assistant, "Response from inner agent"));
|
|
var mockAgent = new Mock<AIAgent>();
|
|
mockAgent.Protected()
|
|
.Setup<Task<AgentResponse>>("RunCoreAsync",
|
|
ItExpr.IsAny<IEnumerable<ChatMessage>>(),
|
|
ItExpr.IsAny<AgentSession>(),
|
|
ItExpr.IsAny<AgentRunOptions>(),
|
|
ItExpr.IsAny<CancellationToken>())
|
|
.ReturnsAsync(expectedResponse);
|
|
|
|
this._mockProcessor.SetupSequence(x => x.ProcessMessagesAsync(
|
|
It.IsAny<IEnumerable<ChatMessage>>(),
|
|
It.IsAny<string>(),
|
|
It.IsAny<Activity>(),
|
|
It.IsAny<PurviewSettings>(),
|
|
It.IsAny<string>(),
|
|
It.IsAny<CancellationToken>()))
|
|
.ThrowsAsync(new PurviewRequestException("Prompt processing error"))
|
|
.ReturnsAsync((false, "user-123")); // Response processing succeeds
|
|
|
|
// Act
|
|
var result = await wrapper.ProcessAgentContentAsync(messages, null, null, mockAgent.Object, CancellationToken.None);
|
|
|
|
// Assert
|
|
Assert.NotNull(result);
|
|
Assert.Same(expectedResponse, result);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ProcessAgentContentAsync_WithoutIgnoreExceptions_ThrowsOnErrorAsync()
|
|
{
|
|
// Arrange
|
|
var messages = new List<ChatMessage>
|
|
{
|
|
new(ChatRole.User, "Test message")
|
|
};
|
|
var mockAgent = new Mock<AIAgent>();
|
|
|
|
this._mockProcessor.Setup(x => x.ProcessMessagesAsync(
|
|
It.IsAny<IEnumerable<ChatMessage>>(),
|
|
It.IsAny<string>(),
|
|
It.IsAny<Activity>(),
|
|
It.IsAny<PurviewSettings>(),
|
|
It.IsAny<string>(),
|
|
It.IsAny<CancellationToken>()))
|
|
.ThrowsAsync(new PurviewRequestException("Processing error"));
|
|
|
|
// Act & Assert
|
|
await Assert.ThrowsAsync<PurviewRequestException>(() =>
|
|
this._wrapper.ProcessAgentContentAsync(messages, null, null, mockAgent.Object, CancellationToken.None));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ProcessAgentContentAsync_ExtractsThreadIdFromMessageAdditionalProperties_Async()
|
|
{
|
|
// Arrange
|
|
var messages = new List<ChatMessage>
|
|
{
|
|
new(ChatRole.User, "Test message")
|
|
{
|
|
AdditionalProperties = new AdditionalPropertiesDictionary
|
|
{
|
|
{ "conversationId", "conversation-from-props" }
|
|
}
|
|
}
|
|
};
|
|
|
|
var expectedResponse = new AgentResponse(new ChatMessage(ChatRole.Assistant, "Response"));
|
|
var mockAgent = new Mock<AIAgent>();
|
|
mockAgent.Protected()
|
|
.Setup<Task<AgentResponse>>("RunCoreAsync",
|
|
ItExpr.IsAny<IEnumerable<ChatMessage>>(),
|
|
ItExpr.IsAny<AgentSession>(),
|
|
ItExpr.IsAny<AgentRunOptions>(),
|
|
ItExpr.IsAny<CancellationToken>())
|
|
.ReturnsAsync(expectedResponse);
|
|
|
|
this._mockProcessor.Setup(x => x.ProcessMessagesAsync(
|
|
It.IsAny<IEnumerable<ChatMessage>>(),
|
|
"conversation-from-props",
|
|
It.IsAny<Activity>(),
|
|
It.IsAny<PurviewSettings>(),
|
|
It.IsAny<string>(),
|
|
It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync((false, "user-123"));
|
|
|
|
// Act
|
|
var result = await this._wrapper.ProcessAgentContentAsync(messages, null, null, mockAgent.Object, CancellationToken.None);
|
|
|
|
// Assert
|
|
Assert.NotNull(result);
|
|
this._mockProcessor.Verify(x => x.ProcessMessagesAsync(
|
|
It.IsAny<IEnumerable<ChatMessage>>(),
|
|
"conversation-from-props",
|
|
Activity.UploadText,
|
|
It.IsAny<PurviewSettings>(),
|
|
It.IsAny<string>(),
|
|
It.IsAny<CancellationToken>()), Times.Once);
|
|
this._mockProcessor.Verify(x => x.ProcessMessagesAsync(
|
|
It.IsAny<IEnumerable<ChatMessage>>(),
|
|
"conversation-from-props",
|
|
Activity.DownloadText,
|
|
It.IsAny<PurviewSettings>(),
|
|
It.IsAny<string>(),
|
|
It.IsAny<CancellationToken>()), Times.Once);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ProcessAgentContentAsync_GeneratesThreadId_WhenNotProvidedAsync()
|
|
{
|
|
// Arrange
|
|
var messages = new List<ChatMessage>
|
|
{
|
|
new(ChatRole.User, "Test message")
|
|
};
|
|
|
|
var expectedResponse = new AgentResponse(new ChatMessage(ChatRole.Assistant, "Response"));
|
|
var mockAgent = new Mock<AIAgent>();
|
|
mockAgent.Protected()
|
|
.Setup<Task<AgentResponse>>("RunCoreAsync",
|
|
ItExpr.IsAny<IEnumerable<ChatMessage>>(),
|
|
ItExpr.IsAny<AgentSession>(),
|
|
ItExpr.IsAny<AgentRunOptions>(),
|
|
ItExpr.IsAny<CancellationToken>())
|
|
.ReturnsAsync(expectedResponse);
|
|
|
|
string? capturedSessionId = null;
|
|
this._mockProcessor.Setup(x => x.ProcessMessagesAsync(
|
|
It.IsAny<IEnumerable<ChatMessage>>(),
|
|
It.IsAny<string>(),
|
|
It.IsAny<Activity>(),
|
|
It.IsAny<PurviewSettings>(),
|
|
It.IsAny<string>(),
|
|
It.IsAny<CancellationToken>()))
|
|
.Callback<IEnumerable<ChatMessage>, string, Activity, PurviewSettings, string, CancellationToken>(
|
|
(_, threadId, _, _, _, _) => capturedSessionId = threadId)
|
|
.ReturnsAsync((false, "user-123"));
|
|
|
|
// Act
|
|
var result = await this._wrapper.ProcessAgentContentAsync(messages, null, null, mockAgent.Object, CancellationToken.None);
|
|
|
|
// Assert
|
|
Assert.NotNull(result);
|
|
Assert.NotNull(capturedSessionId);
|
|
Assert.True(Guid.TryParse(capturedSessionId, out _), "Generated session ID should be a valid GUID");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ProcessAgentContentAsync_PassesResolvedUserId_ToResponseProcessingAsync()
|
|
{
|
|
// Arrange
|
|
var messages = new List<ChatMessage>
|
|
{
|
|
new(ChatRole.User, "Test message")
|
|
};
|
|
var mockAgent = new Mock<AIAgent>();
|
|
var innerResponse = new AgentResponse(new ChatMessage(ChatRole.Assistant, "Response"));
|
|
|
|
mockAgent.Protected()
|
|
.Setup<Task<AgentResponse>>("RunCoreAsync",
|
|
ItExpr.IsAny<IEnumerable<ChatMessage>>(),
|
|
ItExpr.IsAny<AgentSession>(),
|
|
ItExpr.IsAny<AgentRunOptions>(),
|
|
ItExpr.IsAny<CancellationToken>())
|
|
.ReturnsAsync(innerResponse);
|
|
|
|
var callCount = 0;
|
|
string? firstCallUserId = null;
|
|
string? secondCallUserId = null;
|
|
|
|
this._mockProcessor.Setup(x => x.ProcessMessagesAsync(
|
|
It.IsAny<IEnumerable<ChatMessage>>(),
|
|
It.IsAny<string>(),
|
|
It.IsAny<Activity>(),
|
|
It.IsAny<PurviewSettings>(),
|
|
It.IsAny<string>(),
|
|
It.IsAny<CancellationToken>()))
|
|
.Callback<IEnumerable<ChatMessage>, string, Activity, PurviewSettings, string, CancellationToken>(
|
|
(_, _, _, _, userId, _) =>
|
|
{
|
|
if (callCount == 0)
|
|
{
|
|
firstCallUserId = userId;
|
|
}
|
|
else if (callCount == 1)
|
|
{
|
|
secondCallUserId = userId;
|
|
}
|
|
callCount++;
|
|
})
|
|
.ReturnsAsync((false, "resolved-user-456"));
|
|
|
|
// Act
|
|
await this._wrapper.ProcessAgentContentAsync(messages, null, null, mockAgent.Object, CancellationToken.None);
|
|
|
|
// Assert
|
|
Assert.Null(firstCallUserId); // First call (prompt) should have null userId
|
|
Assert.Equal("resolved-user-456", secondCallUserId); // Second call (response) should have resolved userId from first call
|
|
}
|
|
|
|
#endregion
|
|
|
|
public void Dispose()
|
|
{
|
|
this._wrapper.Dispose();
|
|
}
|
|
}
|