| File: ResourceWorkloadTests.cs | Web Access |
| Project: src\tests\Aspire.Hosting.Native.Core.Tests\Aspire.Hosting.Native.Core.Tests.csproj (Aspire.Hosting.Native.Core.Tests) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Text.Json.Nodes; using Aspire.Hosting.Native.Core.Tests.TestServices; using Aspire.Hosting.Native.Model; using Aspire.Hosting.Native.Runtime; using static Aspire.Hosting.Native.Core.Tests.TestServices.RpcTestClient; namespace Aspire.Hosting.Native.Core.Tests; public class ResourceWorkloadTests { [Fact] public async Task StartupFailureDoesNotFenceRetirementWhenNoCleanupRemains() { using var model = new ApplicationModel(); var resource = model.AddResource("cache", "example/Redis"); using var runtime = new RuntimeGeneration(model.Seal(), UnavailableWorkloadExecutor.Instance); using var owner = runtime.ClaimResource(resource); await Assert.ThrowsAsync<NotSupportedException>(() => owner.StartWorkload(new ContainerWorkload("example:1", 6379, [], []))); await Assert.ThrowsAsync<NotSupportedException>(() => runtime.Completion); runtime.Dispose(); await runtime.Completion.WaitAsync(TimeSpan.FromSeconds(10)); } [Fact] public async Task ContainersCanRunWithoutExposingAnEndpoint() { var executor = new WorkloadTestExecutor(); executor.ReleaseCleanup(); using var context = new RuntimeRpcTestContext(executor); var endpoint = Result(await context.Integration.InvokeAsync("startContainer", Arguments( ("context", context.Writer), ("container", new JsonObject { ["image"] = "example/background-worker:1", ["targetPort"] = 0, ["environment"] = new JsonArray(), ["arguments"] = new JsonArray() })))); Assert.Equal(0, endpoint["port"]!.GetValue<int>()); Assert.Empty(context.Read()["resources"]![0]!["urls"]!.AsArray()); await context.Author.InvokeAsync("retireGeneration", Arguments( ("context", context.Session), ("composition", context.Composition))); Assert.Single(executor.Removed); } [Fact] public async Task RetirementRevokesAuthorityBeforeWaitingForCleanupAndBlocksReplacement() { var executor = new WorkloadTestExecutor(); using var context = new RuntimeRpcTestContext(executor); try { var endpoint = Result(await context.Integration.InvokeAsync("startContainer", Arguments( ("context", context.Writer), ("container", new JsonObject { ["image"] = "example:1", ["targetPort"] = 6379, ["environment"] = new JsonArray(), ["arguments"] = new JsonArray() })))); Assert.Equal(5050, endpoint["port"]!.GetValue<int>()); var retiring = context.Author.InvokeAsync("retireGeneration", Arguments( ("context", context.Session), ("composition", context.Composition))); await executor.CleanupStarted.Task.WaitAsync(TimeSpan.FromSeconds(10)); Assert.False(retiring.IsCompleted); Assert.Equal("HANDLE_NOT_FOUND", context.Publish("Running", true)["result"]!["$error"]!["code"]!.GetValue<string>()); Assert.Equal("OPERATION_REJECTED", context.Author.Invoke("startGeneration", Arguments( ("context", context.Session)))["result"]!["$error"]!["code"]!.GetValue<string>()); executor.ReleaseCleanup(); Assert.Null((await retiring.WaitAsync(TimeSpan.FromSeconds(10)))["result"]); Assert.Single(executor.Removed); Assert.NotNull(context.Author.StartGeneration(context.Session)); } finally { executor.ReleaseCleanup(); } } [Fact] public async Task DependenciesWaitForIntegrationHealthBeforeStartingTheDependentWorkload() { using var model = new ApplicationModel(); var cache = model.AddResource("cache", "example/Redis"); var web = model.AddResource("web", "example/Web"); model.AddDependency(web, cache); var executor = new WorkloadTestExecutor(); using var runtime = new RuntimeGeneration(model.Seal(), executor); using var cacheOwner = runtime.ClaimResource(cache); using var webOwner = runtime.ClaimResource(web); try { var webStart = webOwner.StartWorkload(new ContainerWorkload("example:1", 80, [], [])); Assert.Empty(executor.Started); await cacheOwner.StartWorkload(new ContainerWorkload("example:1", 6379, [], [])); Assert.False(webStart.IsCompleted); cacheOwner.Publish(ResourceState.Running, healthy: true, []); await webStart.WaitAsync(TimeSpan.FromSeconds(10)); Assert.Equal([cache.ResourceId, web.ResourceId], executor.Started.Select(start => start.ResourceId)); } finally { executor.ReleaseCleanup(); runtime.Dispose(); await runtime.Completion.WaitAsync(TimeSpan.FromSeconds(10)); } Assert.Equal(2, executor.Removed.Count); } }