aspire icon indicating copy to clipboard operation
aspire copied to clipboard

Error when trying to use DistributedApplicationTestingBuilder with resource with unproxied ports

Open DamianEdwards opened this issue 1 year ago • 7 comments

Trying to use DistributedApplicationTestingBuilder in Aspire.Hosting.Testing with a resource that uses unproxied ports results in an exception:

System.InvalidOperationException : Service 'webfrontend_https_66317ca1' needs to specify a port for endpoint 'https' since it isn't using a proxy.
ApplicationExecutor.AddAllocatedEndpointInfo(IEnumerable`1 resources) line 867
ApplicationExecutor.CreateContainersAndExecutablesAsync(CancellationToken cancellationToken) line 836
ApplicationExecutor.RunApplicationAsync(CancellationToken cancellationToken) line 121
DcpHostService.StartAsync(CancellationToken cancellationToken) line 70
Host.<StartAsync>b__15_1(IHostedService service, CancellationToken token)
Host.ForeachService[T](IEnumerable`1 services, CancellationToken token, Boolean concurrent, Boolean abortOnFirstException, List`1 exceptions, Func`3 operation)
Host.StartAsync(CancellationToken cancellationToken)
ObservedHost.StartAsync(CancellationToken cancellationToken) line 369
DistributedApplicationFactory.StartAsync(CancellationToken cancellationToken) line 52
DelegatedHost.StartAsync(CancellationToken cancellationToken) line 158
DelegatedDistributedApplication.StartAsync(CancellationToken cancellationToken) line 133
WebTests.GetWebResourceRootReturnsOkStatusCode() line 13
WebTests.GetWebResourceRootReturnsOkStatusCode() line 20

To reproduce, create a new Aspire Starter App with a tests project and disable the endpoint proxies for the webfrontend resource:

var builder = DistributedApplication.CreateBuilder(args);

var apiService = builder.AddProject<Projects.AspireApp7_ApiService>("apiservice");

builder.AddProject<Projects.AspireApp7_Web>("webfrontend")
    .WithEndpoint("http", ea => ea.IsProxied = false)
    .WithEndpoint("https", ea => ea.IsProxied = false)
    .WithExternalHttpEndpoints()
    .WithReference(apiService);

builder.Build().Run();

Run the application and note that it works just fine.

Run the test it will fail with the exception above.

DamianEdwards avatar May 24 '24 16:05 DamianEdwards

@ReubenBond perhaps something to do with the port randomization routine?

DamianEdwards avatar May 24 '24 16:05 DamianEdwards

Your hypothesis sounds right. Taking a look

ReubenBond avatar May 24 '24 17:05 ReubenBond

The relevant line is here, but it already looks correct to me: we are accounting for non-proxied ports by no-op'ing. I wonder what's going wrong in this case. My guess is that we aren't loading the launch settings, so it has no default port.

ReubenBond avatar May 24 '24 17:05 ReubenBond

Hmm if we aren't loading launch settings how does it get endpoints at all? Or do you mean we simply ignore the ports specified in the launch settings when running under the test host?

DamianEdwards avatar May 24 '24 17:05 DamianEdwards

Yep, that's it. If I specify a launch profile in the sample, it works:

var builder = DistributedApplication.CreateBuilder(args);
builder.AddRedis("redis1");
builder.AddProject<Projects.TestingAppHost1_MyWebApp>("mywebapp1", "https") // Specify "https" to make it work
    .WithEndpoint("http", ea => ea.IsProxied = false)
    .WithEndpoint("https", ea => ea.IsProxied = false)
    .WithExternalHttpEndpoints();
builder.AddProject<Projects.TestingAppHost1_MyWorker>("myworker1")
    .WithEndpoint(name: "myendpoint1");
builder.AddPostgres("postgres1");
builder.Build().Run();

ReubenBond avatar May 24 '24 17:05 ReubenBond

Hmm if we aren't loading launch settings how does it get endpoints at all? Or do you mean we simply ignore the ports specified in the launch settings when running under the test host?

By default, for proxied ports, DCP picks ports for the app and tells the app what to bind to. When running under the test host, we aren't getting a launch profile specified, so non-proxied ports have no default values specified.

ReubenBond avatar May 24 '24 17:05 ReubenBond

Note I found this after having issues using CreateHttpClient with a custom resource that has an unproxied endpoint named "http" with a specified port. In that case, it fails with:

System.ArgumentException : Endpoint '' for resource 'ingress' not found. (Parameter 'endpointName')

DistributedApplicationHostingTestingExtensions.GetEndpointUriStringCore(DistributedApplication app, String resourceName, String endpointName) line 99
DistributedApplicationHostingTestingExtensions.CreateHttpClient(DistributedApplication app, String resourceName, String endpointName) line 25
YarpResourceSample.GetAppsThroughYarpIngressResourceReturnsOkStatusCode() line 21
YarpResourceSample.GetAppsThroughYarpIngressResourceReturnsOkStatusCode() line 27

DamianEdwards avatar May 24 '24 17:05 DamianEdwards