| File: Publishing\RadiusServiceDiscoveryTests.cs | Web Access |
| Project: src\tests\Aspire.Hosting.Radius.Tests\Aspire.Hosting.Radius.Tests.csproj (Aspire.Hosting.Radius.Tests) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. #pragma warning disable ASPIREPROJECTS001 // ProjectLaunchDefaultsAnnotation is experimental. using Aspire.Hosting.ApplicationModel; using Aspire.Hosting.Radius.Publishing; using System.Net.Sockets; namespace Aspire.Hosting.Radius.Tests.Publishing; public class RadiusServiceDiscoveryTests { [Fact] public void GetServiceName_DoublesResourceName() { var resource = new ContainerResource("apiservice"); Assert.Equal("apiservice-apiservice", RadiusServiceDiscovery.GetServiceName(resource)); } [Fact] public void ResolveServicePort_PrefersTargetPort() { var resource = new ContainerResource("api"); resource.Annotations.Add(new EndpointAnnotation(ProtocolType.Tcp, uriScheme: "http", name: "http", port: 5000, targetPort: 8080)); Assert.Equal(8080, RadiusServiceDiscovery.ResolveServicePort(resource, "http")); } [Fact] public void ResolveServicePort_ContainerUsesHostPortAsContainerPort() { // A container with only a host port listens on that port (ResolveEndpoints treats it as the // implicit container port). var resource = new ContainerResource("api"); resource.Annotations.Add(new EndpointAnnotation(ProtocolType.Tcp, uriScheme: "http", name: "http", port: 5000)); Assert.Equal(5000, RadiusServiceDiscovery.ResolveServicePort(resource, "http")); } [Fact] public void ResolveServicePort_DefaultsProjectDefaultHttpToStandardContainerPort() { // A project's default HTTP endpoint has no resolved port at publish time (the deployment // tool would assign one); it must still get a container port so the recipe creates a Service. var resource = new ProjectResource("webapp"); resource.Annotations.Add(new EndpointAnnotation(ProtocolType.Tcp, uriScheme: "http", name: "http")); Assert.Equal(RadiusServiceDiscovery.DefaultProjectContainerPort, RadiusServiceDiscovery.ResolveServicePort(resource, "http")); } [Fact] public void ResolveServicePort_DefaultsExplicitPortlessHttpsToContainerPort() { // An explicit portless HTTPS endpoint (not the synthetic default) must still get a container // port so the recipe creates a Service — matching the Kubernetes publisher's 8080 default. var resource = new ProjectResource("webapp"); resource.Annotations.Add(new EndpointAnnotation(ProtocolType.Tcp, uriScheme: "https", name: "https")); Assert.Equal(RadiusServiceDiscovery.DefaultProjectContainerPort, RadiusServiceDiscovery.ResolveServicePort(resource, "https")); } [Fact] public void ResolveServicePort_SkipsSyntheticDefaultHttpsEndpoint() { // The synthetic default HTTPS endpoint is skipped: containers don't terminate TLS in-cluster // and the framework reuses the HTTP port for it, so no separate Service is created. var resource = new ProjectResource("webapp"); var https = new EndpointAnnotation(ProtocolType.Tcp, uriScheme: "https", name: "https"); resource.Annotations.Add(https); resource.Annotations.Add(new ProjectLaunchDefaultsAnnotation { DefaultHttpsEndpoint = https }); Assert.Null(RadiusServiceDiscovery.ResolveServicePort(resource, "https")); } [Fact] public void ResolveServicePort_AllocatesDistinctPortsForMultiplePortlessEndpoints() { // Multiple portless endpoints must not collapse onto the same Service port; ResolveEndpoints // allocates a distinct port for each so the recipe emits a valid multi-port Service. var resource = new ContainerResource("api"); resource.Annotations.Add(new EndpointAnnotation(ProtocolType.Tcp, uriScheme: "tcp", name: "one")); resource.Annotations.Add(new EndpointAnnotation(ProtocolType.Tcp, uriScheme: "tcp", name: "two")); var first = RadiusServiceDiscovery.ResolveServicePort(resource, "one"); var second = RadiusServiceDiscovery.ResolveServicePort(resource, "two"); Assert.NotNull(first); Assert.NotNull(second); Assert.NotEqual(first, second); } }