Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add EventStore Hosting and Client integrations #277

Merged
merged 30 commits into from
Nov 29, 2024
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
f543c2b
Add EventStore Hosting and Client integrations
fredimachado Nov 21, 2024
5da0502
Update CODEOWNERS
fredimachado Nov 21, 2024
259b29b
Address PR feedback
fredimachado Nov 22, 2024
bb12675
Add client integration tests
fredimachado Nov 22, 2024
6843bd9
Update AddEventStoreTests.cs
fredimachado Nov 23, 2024
a8b8066
Add HealthCheckTimeout setting
fredimachado Nov 25, 2024
ebd5908
Remove HealthCheckTimeout from Conformance tests
fredimachado Nov 25, 2024
8998861
Remove Atom Pub over HTTP as support is deprecated
fredimachado Nov 25, 2024
2daf3c8
Add Functional tests
fredimachado Nov 25, 2024
1d93d6c
Log volume and mount can be added manually
fredimachado Nov 25, 2024
65a034b
Merge branch 'main' into eventstore-integration
aaronpowell Nov 26, 2024
a3c762f
Merge branch 'main' into eventstore-integration
aaronpowell Nov 26, 2024
bae8ad2
Merge branch 'main' into eventstore-integration
aaronpowell Nov 27, 2024
7cad08f
Merge branch 'main' into eventstore-integration
aaronpowell Nov 27, 2024
d0c35a0
Remove unused const
fredimachado Nov 27, 2024
8553d6f
Update EventStoreFunctionalTests.cs
fredimachado Nov 28, 2024
6a1b859
Update EventStoreFunctionalTests.cs
fredimachado Nov 28, 2024
9fc57ec
Update EventStoreFunctionalTests.cs
fredimachado Nov 28, 2024
90fceff
Wait for resource to be healthy
fredimachado Nov 28, 2024
58f537c
Update EventStoreFunctionalTests.cs
fredimachado Nov 28, 2024
61d2676
Update EventStoreFunctionalTests.cs
fredimachado Nov 28, 2024
396fe02
Fix typo
fredimachado Nov 28, 2024
20e91bf
Use Cts
fredimachado Nov 28, 2024
cdae698
Update EventStoreFunctionalTests.cs
fredimachado Nov 28, 2024
282d122
Check last test
fredimachado Nov 28, 2024
8011a92
Update EventStoreFunctionalTests.cs
fredimachado Nov 28, 2024
30f10e9
Trying all tests
fredimachado Nov 28, 2024
0ff0242
Update EventStoreFunctionalTests.cs
fredimachado Nov 28, 2024
d9c770b
Update EventStoreFunctionalTests.cs
fredimachado Nov 28, 2024
f0d33f8
Update EventStoreFunctionalTests.cs
fredimachado Nov 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions CommunityToolkit.Aspire.sln
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,18 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommunityToolkit.Aspire.Hos
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommunityToolkit.Aspire.EventStore.Tests", "tests\CommunityToolkit.Aspire.EventStore.Tests\CommunityToolkit.Aspire.EventStore.Tests.csproj", "{C696480B-C2E0-4ACA-BD5E-A62BF8558024}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommunityToolkit.Aspire.Hosting.ActiveMQ", "src\CommunityToolkit.Aspire.Hosting.ActiveMQ\CommunityToolkit.Aspire.Hosting.ActiveMQ.csproj", "{56C3C409-10FF-4CA5-99AD-0D35C5418B2A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "activemq", "activemq", "{BF4C4E57-DAAF-4EE5-B330-1923106BAE69}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost", "examples\activemq\CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost\CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.csproj", "{CF6CF1C3-EBE1-41CE-9B34-0C2F931AEA12}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommunityToolkit.Aspire.Hosting.ActiveMQ.ServiceDefaults", "examples\activemq\CommunityToolkit.Aspire.Hosting.ActiveMQ.ServiceDefaults\CommunityToolkit.Aspire.Hosting.ActiveMQ.ServiceDefaults.csproj", "{978EED2A-43BB-4DE6-8563-3A9972869661}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommunityToolkit.Aspire.Hosting.ActiveMQ.MassTransit", "examples\activemq\CommunityToolkit.Aspire.Hosting.ActiveMQ.MassTransit\CommunityToolkit.Aspire.Hosting.ActiveMQ.MassTransit.csproj", "{A87F7800-BD24-4577-8F15-50D33C8DACF1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommunityToolkit.Aspire.Hosting.ActiveMQ.Tests", "tests\CommunityToolkit.Aspire.Hosting.ActiveMQ.Tests\CommunityToolkit.Aspire.Hosting.ActiveMQ.Tests.csproj", "{1200FB2E-F476-4151-BDFD-1DAEE3E99FF5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -415,6 +427,26 @@ Global
{C696480B-C2E0-4ACA-BD5E-A62BF8558024}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C696480B-C2E0-4ACA-BD5E-A62BF8558024}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C696480B-C2E0-4ACA-BD5E-A62BF8558024}.Release|Any CPU.Build.0 = Release|Any CPU
{56C3C409-10FF-4CA5-99AD-0D35C5418B2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{56C3C409-10FF-4CA5-99AD-0D35C5418B2A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{56C3C409-10FF-4CA5-99AD-0D35C5418B2A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{56C3C409-10FF-4CA5-99AD-0D35C5418B2A}.Release|Any CPU.Build.0 = Release|Any CPU
{CF6CF1C3-EBE1-41CE-9B34-0C2F931AEA12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CF6CF1C3-EBE1-41CE-9B34-0C2F931AEA12}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CF6CF1C3-EBE1-41CE-9B34-0C2F931AEA12}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CF6CF1C3-EBE1-41CE-9B34-0C2F931AEA12}.Release|Any CPU.Build.0 = Release|Any CPU
{978EED2A-43BB-4DE6-8563-3A9972869661}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{978EED2A-43BB-4DE6-8563-3A9972869661}.Debug|Any CPU.Build.0 = Debug|Any CPU
{978EED2A-43BB-4DE6-8563-3A9972869661}.Release|Any CPU.ActiveCfg = Release|Any CPU
{978EED2A-43BB-4DE6-8563-3A9972869661}.Release|Any CPU.Build.0 = Release|Any CPU
{A87F7800-BD24-4577-8F15-50D33C8DACF1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A87F7800-BD24-4577-8F15-50D33C8DACF1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A87F7800-BD24-4577-8F15-50D33C8DACF1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A87F7800-BD24-4577-8F15-50D33C8DACF1}.Release|Any CPU.Build.0 = Release|Any CPU
{1200FB2E-F476-4151-BDFD-1DAEE3E99FF5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1200FB2E-F476-4151-BDFD-1DAEE3E99FF5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1200FB2E-F476-4151-BDFD-1DAEE3E99FF5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1200FB2E-F476-4151-BDFD-1DAEE3E99FF5}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -496,6 +528,12 @@ Global
{0A4E5B43-155A-4FDA-A50F-0B86CF1705E7} = {114DDF07-489A-419B-BE76-E5A289F12791}
{019D6506-9D68-41AD-A7A1-A27B2FFE1253} = {114DDF07-489A-419B-BE76-E5A289F12791}
{C696480B-C2E0-4ACA-BD5E-A62BF8558024} = {899F0713-7FC6-4750-BAFC-AC650B35B453}
{56C3C409-10FF-4CA5-99AD-0D35C5418B2A} = {414151D4-7009-4E78-A5C6-D99EBD1E67D1}
{BF4C4E57-DAAF-4EE5-B330-1923106BAE69} = {8519CC01-1370-47C8-AD94-B0F326B1563F}
{CF6CF1C3-EBE1-41CE-9B34-0C2F931AEA12} = {BF4C4E57-DAAF-4EE5-B330-1923106BAE69}
{978EED2A-43BB-4DE6-8563-3A9972869661} = {BF4C4E57-DAAF-4EE5-B330-1923106BAE69}
{A87F7800-BD24-4577-8F15-50D33C8DACF1} = {BF4C4E57-DAAF-4EE5-B330-1923106BAE69}
{1200FB2E-F476-4151-BDFD-1DAEE3E99FF5} = {899F0713-7FC6-4750-BAFC-AC650B35B453}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {08B1D4B8-D2C5-4A64-BB8B-E1A2B29525F0}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ namespace Aspire.Hosting;
public static class EventStoreBuilderExtensions
{
private const string DataTargetFolder = "/var/lib/eventstore";
private const string LogTargetFolder = "/var/log/eventstore";

/// <summary>
/// Adds an EventStore resource to the application model. A container is used for local development.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using Aspire.Components.Common.Tests;
using Aspire.Hosting;
using Aspire.Hosting.Utils;
using CommunityToolkit.Aspire.Testing;
using EventStore.Client;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Hosting;
Expand All @@ -20,17 +19,17 @@ public class EventStoreFunctionalTests(ITestOutputHelper testOutputHelper)
[Fact]
public async Task VerifyEventStoreResource()
{
using var builder = TestDistributedApplicationBuilder.Create(testOutputHelper);
using var builder = TestDistributedApplicationBuilder.Create().WithTestAndResourceLogging(testOutputHelper);

var eventstore = builder.AddEventStore("eventstore");

using var app = builder.Build();

await app.StartAsync();

#pragma warning disable CTASPIRE001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
await app.WaitForTextAsync("Processor ConnectorsStreamSupervisor Running", "eventstore");
#pragma warning restore CTASPIRE001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
var rns = app.Services.GetRequiredService<ResourceNotificationService>();

await rns.WaitForResourceHealthyAsync(eventstore.Resource.Name, default);

var hostBuilder = Host.CreateApplicationBuilder();

Expand All @@ -44,7 +43,8 @@ public async Task VerifyEventStoreResource()

var eventStoreClient = host.Services.GetRequiredService<EventStoreClient>();

await CreateTestData(eventStoreClient);
var id = await CreateTestDataAsync(eventStoreClient);
await VerifyTestDataAsync(eventStoreClient, id);
}

[Theory]
Expand All @@ -58,8 +58,7 @@ public async Task WithDataShouldPersistStateBetweenUsages(bool useVolume)

try
{
using var builder1 = TestDistributedApplicationBuilder.Create(testOutputHelper);

using var builder1 = TestDistributedApplicationBuilder.Create().WithTestAndResourceLogging(testOutputHelper);
var eventstore1 = builder1.AddEventStore("eventstore");

if (useVolume)
Expand All @@ -76,16 +75,28 @@ public async Task WithDataShouldPersistStateBetweenUsages(bool useVolume)
else
{
bindMountPath = Directory.CreateTempSubdirectory().FullName;

if (!OperatingSystem.IsWindows())
{
// Change permissions for non-root accounts (container user account)
const UnixFileMode OwnershipPermissions =
UnixFileMode.UserRead | UnixFileMode.UserWrite | UnixFileMode.UserExecute |
UnixFileMode.GroupRead | UnixFileMode.GroupWrite | UnixFileMode.GroupExecute |
UnixFileMode.OtherRead | UnixFileMode.OtherWrite | UnixFileMode.OtherExecute;

File.SetUnixFileMode(bindMountPath, OwnershipPermissions);
}

eventstore1.WithDataBindMount(bindMountPath);
}

using (var app = builder1.Build())
{
await app.StartAsync();

#pragma warning disable CTASPIRE001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
await app.WaitForTextAsync("Processor ConnectorsStreamSupervisor Running", eventstore1.Resource.Name);
#pragma warning restore CTASPIRE001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
var rns = app.Services.GetRequiredService<ResourceNotificationService>();

await rns.WaitForResourceHealthyAsync(eventstore1.Resource.Name, default);

try
{
Expand All @@ -100,7 +111,8 @@ public async Task WithDataShouldPersistStateBetweenUsages(bool useVolume)
await host.StartAsync();

var eventStoreClient = host.Services.GetRequiredService<EventStoreClient>();
id = await CreateTestData(eventStoreClient);
id = await CreateTestDataAsync(eventStoreClient);
await VerifyTestDataAsync(eventStoreClient, id.Value);
}
}
finally
Expand All @@ -110,8 +122,7 @@ public async Task WithDataShouldPersistStateBetweenUsages(bool useVolume)
}
}

using var builder2 = TestDistributedApplicationBuilder.Create(testOutputHelper);

using var builder2 = TestDistributedApplicationBuilder.Create().WithTestAndResourceLogging(testOutputHelper);
var eventstore2 = builder2.AddEventStore("eventstore");

if (useVolume)
Expand All @@ -120,16 +131,18 @@ public async Task WithDataShouldPersistStateBetweenUsages(bool useVolume)
}
else
{
//EventStore shutdown can be slightly delayed, so second instance might fail to start when using the same bind mount before shutdown.
await Task.Delay(TimeSpan.FromSeconds(5));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could incur flakiness.

Related dotnet/aspire#4878

eventstore2.WithDataBindMount(bindMountPath!);
}

using (var app = builder2.Build())
{
await app.StartAsync();

#pragma warning disable CTASPIRE001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
await app.WaitForTextAsync("Processor ConnectorsStreamSupervisor Running", eventstore2.Resource.Name);
#pragma warning restore CTASPIRE001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
var rns = app.Services.GetRequiredService<ResourceNotificationService>();

await rns.WaitForResourceHealthyAsync(eventstore1.Resource.Name, default);

try
{
Expand All @@ -144,7 +157,7 @@ public async Task WithDataShouldPersistStateBetweenUsages(bool useVolume)
await host.StartAsync();
var eventStoreClient = host.Services.GetRequiredService<EventStoreClient>();

await VerifyTestData(eventStoreClient, id.Value);
await VerifyTestDataAsync(eventStoreClient, id.Value);
}
}
finally
Expand Down Expand Up @@ -179,8 +192,8 @@ public async Task WithDataShouldPersistStateBetweenUsages(bool useVolume)
[Fact]
public async Task VerifyWaitForEventStoreBlocksDependentResources()
{
var cts = new CancellationTokenSource(TimeSpan.FromMinutes(10));
using var builder = TestDistributedApplicationBuilder.Create(testOutputHelper);
var cts = new CancellationTokenSource(TimeSpan.FromMinutes(5));
using var builder = TestDistributedApplicationBuilder.Create().WithTestAndResourceLogging(testOutputHelper);

var healthCheckTcs = new TaskCompletionSource<HealthCheckResult>();
builder.Services.AddHealthChecks().AddAsyncCheck("blocking_check", () =>
Expand All @@ -191,7 +204,7 @@ public async Task VerifyWaitForEventStoreBlocksDependentResources()
var resource = builder.AddEventStore("resource")
.WithHealthCheck("blocking_check");

var dependentResource = builder.AddEventStore("dependentresource")
var dependentResource = builder.AddContainer("nginx", "mcr.microsoft.com/cbl-mariner/base/nginx", "1.22")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a light (meaning small image size and fast startup) container image?
If it is we could use this image for dependent resources in health check tests like this test to speed up our tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly, I used this specifically because it's lightweight and fast to start.
I've seen usages of this image for the same purpose in the main Aspire repo.

.WaitFor(resource);

using var app = builder.Build();
Expand All @@ -206,7 +219,7 @@ public async Task VerifyWaitForEventStoreBlocksDependentResources()

healthCheckTcs.SetResult(HealthCheckResult.Healthy());

await rns.WaitForResourceAsync(resource.Resource.Name, re => re.Snapshot.HealthStatus == HealthStatus.Healthy, cts.Token);
await rns.WaitForResourceHealthyAsync(resource.Resource.Name, cts.Token);

await rns.WaitForResourceAsync(dependentResource.Resource.Name, KnownResourceStates.Running, cts.Token);

Expand All @@ -215,7 +228,7 @@ public async Task VerifyWaitForEventStoreBlocksDependentResources()
await app.StopAsync();
}

private static async Task<Guid> CreateTestData(EventStoreClient eventStoreClient)
private static async Task<Guid> CreateTestDataAsync(EventStoreClient eventStoreClient)
{
var id = Guid.NewGuid();
var accountCreated = new AccountCreated(id, TestAccountName);
Expand All @@ -226,12 +239,10 @@ private static async Task<Guid> CreateTestData(EventStoreClient eventStoreClient
var writeResult = await eventStoreClient.AppendToStreamAsync(streamName, StreamRevision.None, [eventData]);
Assert.NotNull(writeResult);

await VerifyTestData(eventStoreClient, id);

return id;
}

private static async Task VerifyTestData(EventStoreClient eventStoreClient, Guid id)
private static async Task VerifyTestDataAsync(EventStoreClient eventStoreClient, Guid id)
{
var streamName = $"{TestStreamNamePrefix}{id}";

Expand Down
Loading