diff --git a/src/CommunityToolkit.Aspire.Hosting.Dapr/DaprDistributedApplicationLifecycleHook.cs b/src/CommunityToolkit.Aspire.Hosting.Dapr/DaprDistributedApplicationLifecycleHook.cs index 09df82683..4b3649423 100644 --- a/src/CommunityToolkit.Aspire.Hosting.Dapr/DaprDistributedApplicationLifecycleHook.cs +++ b/src/CommunityToolkit.Aspire.Hosting.Dapr/DaprDistributedApplicationLifecycleHook.cs @@ -61,7 +61,15 @@ private async Task OnBeforeStartAsync(BeforeStartEvent @event, CancellationToken var daprSidecar = daprAnnotation.Sidecar; - + // Propagate WaitAnnotations from the original resource to the Dapr sidecar + if (resource.TryGetAnnotationsOfType(out var waitAnnotations)) + { + foreach (var waitAnnotation in waitAnnotations) + { + daprSidecar.Annotations.Add(waitAnnotation); + } + } + var sidecarOptionsAnnotation = daprSidecar.Annotations.OfType().LastOrDefault(); var sidecarOptions = sidecarOptionsAnnotation?.Options; @@ -205,6 +213,15 @@ private async Task OnBeforeStartAsync(BeforeStartEvent @event, CancellationToken var daprCliResourceName = $"{daprSidecar.Name}-cli"; var daprCli = new ExecutableResource(daprCliResourceName, fileName, appHostDirectory); + // Propagate WaitAnnotations from the original resource to the Dapr CLI executable + if (resource.TryGetAnnotationsOfType(out var resourceWaitAnnotations)) + { + foreach (var waitAnnotation in resourceWaitAnnotations) + { + daprCli.Annotations.Add(waitAnnotation); + } + } + // Make the Dapr CLI wait for the component resources it references foreach (var componentRef in componentReferenceAnnotations) { diff --git a/tests/CommunityToolkit.Aspire.Hosting.Dapr.Tests/WithDaprSidecarTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Dapr.Tests/WithDaprSidecarTests.cs index e7129ba01..5d3b39a59 100644 --- a/tests/CommunityToolkit.Aspire.Hosting.Dapr.Tests/WithDaprSidecarTests.cs +++ b/tests/CommunityToolkit.Aspire.Hosting.Dapr.Tests/WithDaprSidecarTests.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using Aspire.Hosting; -using Aspire.Hosting.ApplicationModel; namespace CommunityToolkit.Aspire.Hosting.Dapr.Tests; @@ -111,4 +110,72 @@ public void DaprSidecarCanReferenceComponents() Assert.Contains(referenceAnnotations, a => a.Component.Name == "statestore"); Assert.Contains(referenceAnnotations, a => a.Component.Name == "pubsub"); } + + [Fact] + public void ResourceWithDaprSidecarAndNoWaitAnnotations_CreatesBasicSidecar() + { + var builder = DistributedApplication.CreateBuilder(); + + var app = builder.AddProject("test") + .WithDaprSidecar(); + + // Verify no wait annotations on the main resource + Assert.Empty(app.Resource.Annotations.OfType()); + + // Verify the sidecar resource exists + var sidecarResource = Assert.Single(builder.Resources.OfType()); + + // Verify the sidecar is properly linked + var sidecarAnnotation = Assert.Single(app.Resource.Annotations.OfType()); + Assert.Equal(sidecarResource, sidecarAnnotation.Sidecar); + } + + [Fact] + public void ResourceWithWaitAnnotationAndDaprSidecar_SetsUpCorrectDependencies() + { + var builder = DistributedApplication.CreateBuilder(); + + var database = builder.AddContainer("db", "postgres"); + + var app = builder.AddProject("test") + .WaitFor(database) + .WithDaprSidecar(); + + // Verify the main resource has the wait annotation + var waitAnnotation = Assert.Single(app.Resource.Annotations.OfType()); + Assert.Equal("db", waitAnnotation.Resource.Name); + + // Verify the sidecar resource exists + var sidecarResource = Assert.Single(builder.Resources.OfType()); + Assert.NotNull(sidecarResource); + + // The actual propagation happens in the lifecycle hook, but we can verify the setup is correct + var sidecarAnnotation = Assert.Single(app.Resource.Annotations.OfType()); + Assert.Equal(sidecarResource, sidecarAnnotation.Sidecar); + } + + [Fact] + public void ResourceWithMultipleWaitAnnotationsAndDaprSidecar_HasAllWaitDependencies() + { + var builder = DistributedApplication.CreateBuilder(); + + var database = builder.AddContainer("db", "postgres"); + var redis = builder.AddContainer("cache", "redis"); + + var app = builder.AddProject("test") + .WaitFor(database) + .WaitFor(redis) + .WithDaprSidecar(); + + // Verify the main resource has both wait annotations + var waitAnnotations = app.Resource.Annotations.OfType().ToList(); + Assert.Equal(2, waitAnnotations.Count); + Assert.Contains(waitAnnotations, w => w.Resource.Name == "db"); + Assert.Contains(waitAnnotations, w => w.Resource.Name == "cache"); + + // Verify the sidecar resource exists and is properly linked + var sidecarResource = Assert.Single(builder.Resources.OfType()); + var sidecarAnnotation = Assert.Single(app.Resource.Annotations.OfType()); + Assert.Equal(sidecarResource, sidecarAnnotation.Sidecar); + } }