Skip to content

Commit ff7f863

Browse files
authored
Improve e2e integration tests and isolate tests from other things; includes patch to Serializer (#5497)
* integration tests used to use the samples - now they are separate * patch dictionary problem in serializer * add Message Registry with dead letter queue that gets checked on new subs.
1 parent 3abc022 commit ff7f863

File tree

40 files changed

+1420
-131
lines changed

40 files changed

+1420
-131
lines changed

dotnet/AutoGen.sln

+23-2
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,13 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AutoGen.AgentChat
140140
EndProject
141141
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AutoGen.AgentChat.Tests", "test\Microsoft.AutoGen.AgentChat.Tests\Microsoft.AutoGen.AgentChat.Tests.csproj", "{217A4F86-8ADD-4998-90BA-880092A019F5}"
142142
EndProject
143-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HelloAgent.AppHost", "test\Microsoft.AutoGen.Integration.Tests.AppHosts\HelloAgent.AppHost\HelloAgent.AppHost.csproj", "{0C371D65-7EF9-44EA-8128-A105DA82A80E}"
143+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Microsoft.AutoGen.Integration.Tests.AppHosts", "Microsoft.AutoGen.Integration.Tests.AppHosts", "{D1C2B0BB-1276-4146-A699-D1983AE8ED04}"
144+
EndProject
145+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HelloAgentTests", "test\Microsoft.AutoGen.Integration.Tests.AppHosts\HelloAgentTests\HelloAgentTests.csproj", "{CD10E29A-725E-4BEF-9CFF-6C0E0A652926}"
146+
EndProject
147+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InMemoryTests.AppHost", "test\Microsoft.AutoGen.Integration.Tests.AppHosts\InMemoryTests.AppHost\InMemoryTests.AppHost.csproj", "{1E4E1ED4-7701-4A05-A861-64461C3B1EE3}"
148+
EndProject
149+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XlangTests.AppHost", "test\Microsoft.AutoGen.Integration.Tests.AppHosts\XLangTests.AppHost\XlangTests.AppHost.csproj", "{62CDFB27-3B02-4D4B-B789-8AAD5E20688A}"
144150
EndProject
145151
Global
146152
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -372,6 +378,18 @@ Global
372378
{0C371D65-7EF9-44EA-8128-A105DA82A80E}.Debug|Any CPU.Build.0 = Debug|Any CPU
373379
{0C371D65-7EF9-44EA-8128-A105DA82A80E}.Release|Any CPU.ActiveCfg = Release|Any CPU
374380
{0C371D65-7EF9-44EA-8128-A105DA82A80E}.Release|Any CPU.Build.0 = Release|Any CPU
381+
{CD10E29A-725E-4BEF-9CFF-6C0E0A652926}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
382+
{CD10E29A-725E-4BEF-9CFF-6C0E0A652926}.Debug|Any CPU.Build.0 = Debug|Any CPU
383+
{CD10E29A-725E-4BEF-9CFF-6C0E0A652926}.Release|Any CPU.ActiveCfg = Release|Any CPU
384+
{CD10E29A-725E-4BEF-9CFF-6C0E0A652926}.Release|Any CPU.Build.0 = Release|Any CPU
385+
{1E4E1ED4-7701-4A05-A861-64461C3B1EE3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
386+
{1E4E1ED4-7701-4A05-A861-64461C3B1EE3}.Debug|Any CPU.Build.0 = Debug|Any CPU
387+
{1E4E1ED4-7701-4A05-A861-64461C3B1EE3}.Release|Any CPU.ActiveCfg = Release|Any CPU
388+
{1E4E1ED4-7701-4A05-A861-64461C3B1EE3}.Release|Any CPU.Build.0 = Release|Any CPU
389+
{62CDFB27-3B02-4D4B-B789-8AAD5E20688A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
390+
{62CDFB27-3B02-4D4B-B789-8AAD5E20688A}.Debug|Any CPU.Build.0 = Debug|Any CPU
391+
{62CDFB27-3B02-4D4B-B789-8AAD5E20688A}.Release|Any CPU.ActiveCfg = Release|Any CPU
392+
{62CDFB27-3B02-4D4B-B789-8AAD5E20688A}.Release|Any CPU.Build.0 = Release|Any CPU
375393
EndGlobalSection
376394
GlobalSection(SolutionProperties) = preSolution
377395
HideSolutionNode = FALSE
@@ -436,7 +454,10 @@ Global
436454
{EF954ED3-87D5-40F1-8557-E7179F43EA0E} = {18BF8DD7-0585-48BF-8F97-AD333080CE06}
437455
{7F828599-56E8-4597-8F68-EE26FD631417} = {18BF8DD7-0585-48BF-8F97-AD333080CE06}
438456
{217A4F86-8ADD-4998-90BA-880092A019F5} = {F823671B-3ECA-4AE6-86DA-25E920D3FE64}
439-
{0C371D65-7EF9-44EA-8128-A105DA82A80E} = {F42F9C8E-7BD9-4687-9B63-AFFA461AF5C1}
457+
{D1C2B0BB-1276-4146-A699-D1983AE8ED04} = {F823671B-3ECA-4AE6-86DA-25E920D3FE64}
458+
{CD10E29A-725E-4BEF-9CFF-6C0E0A652926} = {D1C2B0BB-1276-4146-A699-D1983AE8ED04}
459+
{1E4E1ED4-7701-4A05-A861-64461C3B1EE3} = {D1C2B0BB-1276-4146-A699-D1983AE8ED04}
460+
{62CDFB27-3B02-4D4B-B789-8AAD5E20688A} = {D1C2B0BB-1276-4146-A699-D1983AE8ED04}
440461
EndGlobalSection
441462
GlobalSection(ExtensibilityGlobals) = postSolution
442463
SolutionGuid = {93384647-528D-46C8-922C-8DB36A382F0B}

dotnet/samples/Hello/HelloAgent/HelloAgent.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
<ProjectReference Include="..\..\..\src\Microsoft.AutoGen\Contracts\Microsoft.AutoGen.Contracts.csproj" />
2424
<ProjectReference Include="..\..\..\src\Microsoft.AutoGen\Core.Grpc\Microsoft.AutoGen.Core.Grpc.csproj" />
2525
<ProjectReference Include="..\..\..\src\Microsoft.AutoGen\Core\Microsoft.AutoGen.Core.csproj" />
26+
<ProjectReference Include="..\..\..\src\Microsoft.AutoGen\Core.Grpc\Microsoft.AutoGen.Core.Grpc.csproj" />
2627
</ItemGroup>
2728

2829
<ItemGroup>

dotnet/samples/Hello/HelloAgent/Program.cs

+16-8
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,22 @@
44
using Microsoft.AutoGen.Agents;
55
using Microsoft.AutoGen.Contracts;
66
using Microsoft.AutoGen.Core;
7+
using Microsoft.AutoGen.Core.Grpc;
78
using Samples;
8-
9-
// Set up app builder for in-process runtime, allow message delivery to self, and add the Hello agent
10-
AgentsAppBuilder appBuilder = new AgentsAppBuilder()
11-
.UseInProcessRuntime(deliverToSelf: true)
12-
.AddAgent<HelloAgent>("HelloAgent");
9+
var appBuilder = new AgentsAppBuilder(); // Create app builder
10+
// if we are using distributed, we need the AGENT_HOST var defined and then we will use the grpc runtime
11+
if (Environment.GetEnvironmentVariable("AGENT_HOST") is string agentHost)
12+
{
13+
appBuilder.AddGrpcAgentWorker(agentHost)
14+
.AddAgent<HelloAgent>("HelloAgent");
15+
}
16+
else
17+
{
18+
// Set up app builder for in-process runtime, allow message delivery to self, and add the Hello agent
19+
appBuilder.UseInProcessRuntime(deliverToSelf: true).AddAgent<HelloAgent>("HelloAgent");
20+
}
1321
var app = await appBuilder.BuildAsync(); // Build the app
1422
// Create a custom message type from proto and define message
15-
NewMessageReceived message = new NewMessageReceived { Message = "Hello World!" };
16-
await app.PublishMessageAsync(message, new TopicId("HelloTopic")); // Publish custom message (handler has been set in HelloAgent)
17-
await app.WaitForShutdownAsync(); // Wait for shutdown from agent
23+
var message = new NewMessageReceived { Message = "Hello World!" };
24+
await app.PublishMessageAsync(message, new TopicId("HelloTopic")).ConfigureAwait(false); // Publish custom message (handler has been set in HelloAgent)
25+
await app.WaitForShutdownAsync().ConfigureAwait(false); // Wait for shutdown from agent

dotnet/src/Microsoft.AutoGen/Agents/IOAgent/ConsoleAgent/IHandleConsole.cs

+4-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// IHandleConsole.cs
3-
using Google.Protobuf;
43
using Microsoft.AutoGen.Contracts;
54

65
namespace Microsoft.AutoGen.Agents;
@@ -14,13 +13,12 @@ public interface IHandleConsole : IHandle<Output>, IHandle<Input>, IProcessIO
1413
/// <summary>
1514
/// Prototype for Publish Message Async method
1615
/// </summary>
17-
/// <typeparam name="T"></typeparam>
1816
/// <param name="message"></param>
1917
/// <param name="topic"></param>
2018
/// <param name="messageId"></param>
21-
/// <param name="token"></param>
19+
/// <param name="cancellationToken"></param>
2220
/// <returns>ValueTask</returns>
23-
ValueTask PublishMessageAsync<T>(T message, TopicId topic, string? messageId, CancellationToken token = default) where T : IMessage;
21+
ValueTask PublishMessageAsync(object message, TopicId topic, string? messageId = null, CancellationToken cancellationToken = default);
2422

2523
/// <summary>
2624
/// Receives events of type Output and writes them to the console
@@ -39,7 +37,7 @@ async ValueTask IHandle<Output>.HandleAsync(Output item, MessageContext messageC
3937
{
4038
Route = "console"
4139
};
42-
await PublishMessageAsync(evt, new TopicId("OutputWritten"), null, token: CancellationToken.None).ConfigureAwait(false);
40+
await PublishMessageAsync(evt, new TopicId("OutputWritten"), null, cancellationToken: CancellationToken.None).ConfigureAwait(false);
4341
}
4442

4543
/// <summary>
@@ -60,6 +58,6 @@ async ValueTask IHandle<Input>.HandleAsync(Input item, MessageContext messageCon
6058
{
6159
Route = "console"
6260
};
63-
await PublishMessageAsync(evt, new TopicId("InputProcessed"), null, token: CancellationToken.None).ConfigureAwait(false);
61+
await PublishMessageAsync(evt, new TopicId("InputProcessed"), null, cancellationToken: CancellationToken.None).ConfigureAwait(false);
6462
}
6563
}

dotnet/src/Microsoft.AutoGen/Agents/IOAgent/FileAgent/IHandleFileIO.cs

+5-8
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// IHandleFileIO.cs
3-
4-
using Google.Protobuf;
53
using Microsoft.AutoGen.Contracts;
64
using Microsoft.Extensions.Logging;
75

@@ -25,13 +23,12 @@ public interface IHandleFileIO : IHandle<Input>, IHandle<Output>, IProcessIO
2523
/// <summary>
2624
/// Prototype for Publish Message Async method
2725
/// </summary>
28-
/// <typeparam name="T"></typeparam>
2926
/// <param name="message"></param>
3027
/// <param name="topic"></param>
3128
/// <param name="messageId"></param>
32-
/// <param name="token"></param>
29+
/// <param name="cancellationToken"></param>
3330
/// <returns>ValueTask</returns>
34-
ValueTask PublishMessageAsync<T>(T message, TopicId topic, string? messageId, CancellationToken token = default) where T : IMessage;
31+
ValueTask PublishMessageAsync(object message, TopicId topic, string? messageId = null, CancellationToken cancellationToken = default);
3532
async ValueTask IHandle<Input>.HandleAsync(Input item, MessageContext messageContext)
3633
{
3734

@@ -45,7 +42,7 @@ async ValueTask IHandle<Input>.HandleAsync(Input item, MessageContext messageCon
4542
{
4643
Message = errorMessage
4744
};
48-
await PublishMessageAsync(err, new TopicId("IOError"), null, token: CancellationToken.None).ConfigureAwait(false);
45+
await PublishMessageAsync(err, new TopicId("IOError"), null, cancellationToken: CancellationToken.None).ConfigureAwait(false);
4946
return;
5047
}
5148
string content;
@@ -58,7 +55,7 @@ async ValueTask IHandle<Input>.HandleAsync(Input item, MessageContext messageCon
5855
{
5956
Route = Route
6057
};
61-
await PublishMessageAsync(evt, new TopicId("InputProcessed"), null, token: CancellationToken.None).ConfigureAwait(false);
58+
await PublishMessageAsync(evt, new TopicId("InputProcessed"), null, cancellationToken: CancellationToken.None).ConfigureAwait(false);
6259
}
6360
async ValueTask IHandle<Output>.HandleAsync(Output item, MessageContext messageContext)
6461
{
@@ -70,6 +67,6 @@ async ValueTask IHandle<Output>.HandleAsync(Output item, MessageContext messageC
7067
{
7168
Route = Route
7269
};
73-
await PublishMessageAsync(evt, new TopicId("OutputWritten"), null, token: CancellationToken.None).ConfigureAwait(false);
70+
await PublishMessageAsync(evt, new TopicId("OutputWritten"), null, cancellationToken: CancellationToken.None).ConfigureAwait(false);
7471
}
7572
}

dotnet/src/Microsoft.AutoGen/Core.Grpc/ProtobufSerializationRegistry.cs

+1-4
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,7 @@ public bool Exists(Type type)
2828

2929
public void RegisterSerializer(Type type, IProtobufMessageSerializer serializer)
3030
{
31-
if (_serializers.ContainsKey(TypeNameResolver.ResolveTypeName(type)))
32-
{
33-
throw new InvalidOperationException($"Serializer already registered for {type.FullName}");
34-
}
31+
_serializers.TryAdd(TypeNameResolver.ResolveTypeName(type), serializer);
3532
_serializers[TypeNameResolver.ResolveTypeName(type)] = serializer;
3633
}
3734
}

dotnet/src/Microsoft.AutoGen/RuntimeGateway.Grpc/Abstractions/AgentsRegistryState.cs

+28
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,40 @@
44
using Microsoft.AutoGen.Protobuf;
55

66
namespace Microsoft.AutoGen.RuntimeGateway.Grpc.Abstractions;
7+
8+
/// <summary>
9+
/// Stores agent subscription information such as topic and prefix mappings,
10+
/// and maintains an ETag for concurrency checks.
11+
/// </summary>
712
public class AgentsRegistryState
813
{
14+
/// <summary>
15+
/// Maps each agent ID to the set of topics they subscribe to.
16+
/// </summary>
917
public ConcurrentDictionary<string, HashSet<string>> AgentsToTopicsMap { get; set; } = [];
18+
19+
/// <summary>
20+
/// Maps each agent ID to the set of topic prefixes they subscribe to.
21+
/// </summary>
1022
public ConcurrentDictionary<string, HashSet<string>> AgentsToTopicsPrefixMap { get; set; } = [];
23+
24+
/// <summary>
25+
/// Maps each topic name to the set of agent types subscribed to it.
26+
/// </summary>
1127
public ConcurrentDictionary<string, HashSet<string>> TopicToAgentTypesMap { get; set; } = [];
28+
29+
/// <summary>
30+
/// Maps each topic prefix to the set of agent types subscribed to it.
31+
/// </summary>
1232
public ConcurrentDictionary<string, HashSet<string>> TopicPrefixToAgentTypesMap { get; set; } = [];
33+
34+
/// <summary>
35+
/// Stores subscriptions by GUID
36+
/// </summary>
1337
public ConcurrentDictionary<string, HashSet<Subscription>> GuidSubscriptionsMap { get; set; } = [];
38+
39+
/// <summary>
40+
/// The concurrency ETag for identifying the registry's version or state.
41+
/// </summary>
1442
public string Etag { get; set; } = Guid.NewGuid().ToString();
1543
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// IMessageRegistryGrain.cs
3+
4+
using Microsoft.AutoGen.Contracts;
5+
6+
namespace Microsoft.AutoGen.RuntimeGateway.Grpc.Abstractions;
7+
8+
public interface IMessageRegistryGrain : IGrainWithIntegerKey
9+
{
10+
/// <summary>
11+
/// Writes a message to the dead-letter queue for the given topic.
12+
/// </summary>
13+
Task WriteMessageAsync(string topic, CloudEvent message);
14+
15+
/// <summary>
16+
/// Removes all messages for the given topic from the dead-letter queue.
17+
/// </summary>
18+
/// <param name="topic">The topic to remove messages for.</param>
19+
/// <returns>A task representing the asynchronous operation, with the list of removed messages as the result.</returns>
20+
Task<List<CloudEvent>> RemoveMessagesAsync(string topic);
21+
}
22+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// MessageRegistryState.cs
3+
4+
using System.Collections.Concurrent;
5+
using Microsoft.AutoGen.Contracts;
6+
7+
namespace Microsoft.AutoGen.RuntimeGateway.Grpc.Abstractions;
8+
9+
/// <summary>
10+
/// Holds a dead-letter queue by topic type.
11+
/// </summary>
12+
public class MessageRegistryState
13+
{
14+
/// <summary>
15+
/// Dictionary mapping topic types to a list of CloudEvents that failed delivery.
16+
/// </summary>
17+
public ConcurrentDictionary<string, List<CloudEvent>> DeadLetterQueue { get; set; } = new();
18+
}

0 commit comments

Comments
 (0)