// Copyright (c) Microsoft. All rights reserved.
using System.Diagnostics;
using System.Reflection;
using Microsoft.DurableTask;
using Microsoft.DurableTask.Client;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.Configuration;
using OpenAI.Chat;
namespace Microsoft.Agents.AI.DurableTask.IntegrationTests;
///
/// Tests for orchestration execution scenarios with Durable Task Agents.
///
[Collection("Sequential")]
[Trait("Category", "Integration")]
public sealed class OrchestrationTests(ITestOutputHelper outputHelper) : IDisposable
{
private static readonly TimeSpan s_defaultTimeout = Debugger.IsAttached
? TimeSpan.FromMinutes(5)
: TimeSpan.FromSeconds(30);
private static readonly IConfiguration s_configuration =
new ConfigurationBuilder()
.AddUserSecrets(Assembly.GetExecutingAssembly())
.AddEnvironmentVariables()
.Build();
private readonly ITestOutputHelper _outputHelper = outputHelper;
private readonly CancellationTokenSource _cts = new(delay: s_defaultTimeout);
private CancellationToken TestTimeoutToken => this._cts.Token;
public void Dispose() => this._cts.Dispose();
[Fact]
public async Task GetAgent_ThrowsWhenAgentNotRegisteredAsync()
{
// Define an orchestration that tries to use an unregistered agent
static async Task TestOrchestrationAsync(TaskOrchestrationContext context)
{
// Get an agent that hasn't been registered
DurableAIAgent agent = context.GetAgent("NonExistentAgent");
// This should throw when RunAsync is called because the agent doesn't exist
await agent.RunAsync("Hello");
return "Should not reach here";
}
// Setup: Create test helper without registering "NonExistentAgent"
using TestHelper testHelper = TestHelper.Start(
this._outputHelper,
configureAgents: agents =>
{
// Register a different agent, but not "NonExistentAgent"
agents.AddAIAgentFactory(
"OtherAgent",
sp => TestHelper.GetAzureOpenAIChatClient(s_configuration).AsAIAgent(
name: "OtherAgent",
instructions: "You are a test agent."));
},
durableTaskRegistry: registry =>
registry.AddOrchestratorFunc(
name: nameof(TestOrchestrationAsync),
orchestrator: TestOrchestrationAsync));
DurableTaskClient client = testHelper.GetClient();
// Act: Start the orchestration
string instanceId = await client.ScheduleNewOrchestrationInstanceAsync(
orchestratorName: nameof(TestOrchestrationAsync),
cancellation: this.TestTimeoutToken);
// Wait for the orchestration to complete and check for failure
OrchestrationMetadata status = await client.WaitForInstanceCompletionAsync(
instanceId,
getInputsAndOutputs: true,
this.TestTimeoutToken);
// Assert: Verify the orchestration failed with the expected exception
Assert.NotNull(status);
Assert.Equal(OrchestrationRuntimeStatus.Failed, status.RuntimeStatus);
Assert.NotNull(status.FailureDetails);
// Verify the exception type is AgentNotRegisteredException
Assert.True(
status.FailureDetails.ErrorType == typeof(AgentNotRegisteredException).FullName,
$"Expected AgentNotRegisteredException but got ErrorType: {status.FailureDetails.ErrorType}, Message: {status.FailureDetails.ErrorMessage}");
// Verify the exception message contains the agent name
Assert.Contains("NonExistentAgent", status.FailureDetails.ErrorMessage, StringComparison.OrdinalIgnoreCase);
}
}