@@ -349,7 +349,7 @@ public async Task UnsupportedEndpointPortsExecutableNotReplicatedProxyless()
349349
350350 [ Theory ]
351351 [ InlineData ( 1 , "ServiceA" ) ]
352- [ InlineData ( 2 , "ServiceA-suffix " ) ]
352+ [ InlineData ( 2 , "ServiceA" ) ]
353353 public async Task EndpointOtelServiceName ( int replicaCount , string expectedName )
354354 {
355355 var builder = DistributedApplication . CreateBuilder ( new DistributedApplicationOptions
@@ -367,8 +367,13 @@ public async Task EndpointOtelServiceName(int replicaCount, string expectedName)
367367 var appExecutor = CreateAppExecutor ( distributedAppModel , app . Services , kubernetesService : kubernetesService , dcpOptions : dcpOptions ) ;
368368 await appExecutor . RunApplicationAsync ( ) ;
369369
370- var ers = Assert . Single ( kubernetesService . CreatedResources . OfType < ExecutableReplicaSet > ( ) ) ;
371- Assert . Equal ( expectedName , ers . Spec ? . Template . Annotations ? [ CustomResource . OtelServiceNameAnnotation ] ) ;
370+ var executables = kubernetesService . CreatedResources . OfType < Executable > ( ) . ToList ( ) ;
371+ Assert . Equal ( replicaCount , executables . Count ) ;
372+
373+ foreach ( var exe in executables )
374+ {
375+ Assert . Equal ( expectedName , exe . Metadata . Annotations [ CustomResource . OtelServiceNameAnnotation ] ) ;
376+ }
372377 }
373378
374379 [ Fact ]
@@ -602,25 +607,30 @@ public async Task EndpointPortsProjectNoPortNoTargetPort()
602607 var appExecutor = CreateAppExecutor ( distributedAppModel , app . Services , kubernetesService : kubernetesService ) ;
603608 await appExecutor . RunApplicationAsync ( ) ;
604609
605- var ers = Assert . Single ( kubernetesService . CreatedResources . OfType < ExecutableReplicaSet > ( ) ) ;
606- Assert . True ( ers . Spec . Template . TryGetAnnotationAsObjectList < ServiceProducerAnnotation > ( CustomResource . ServiceProducerAnnotation , out var spAnnList ) ) ;
610+ var exes = kubernetesService . CreatedResources . OfType < Executable > ( ) . ToList ( ) ;
611+ Assert . Equal ( 3 , exes . Count ) ;
607612
608- // Neither Port, nor TargetPort are set
609- // Clients use proxy, MAY have the proxy port injected.
610- // Proxy gets autogenerated port.
611- // Each replica gets a different autogenerated port that MUST be injected via env var/startup param.
612- var svc = kubernetesService . CreatedResources . OfType < Service > ( ) . Single ( s => s . Name ( ) == "ServiceA-NoPortNoTargetPort" ) ;
613- Assert . Equal ( AddressAllocationModes . Localhost , svc . Spec . AddressAllocationMode ) ;
614- Assert . True ( svc . Status ? . EffectivePort >= TestKubernetesService . StartOfAutoPortRange ) ;
615- Assert . True ( spAnnList . Single ( ann => ann . ServiceName == "ServiceA-NoPortNoTargetPort" ) . Port is null ,
616- "Expected service producer (target) port to not be set (leave allocation to DCP)" ) ;
617- var envVarVal = ers . Spec . Template . Spec . Env ? . Single ( v => v . Name == "NO_PORT_NO_TARGET_PORT" ) . Value ;
618- Assert . False ( string . IsNullOrWhiteSpace ( envVarVal ) ) ;
619- Assert . Contains ( """portForServing "ServiceA-NoPortNoTargetPort" """ , envVarVal ) ;
620-
621- // ASPNETCORE_URLS should not include dontinjectme, as it was excluded using WithEndpointsInEnvironment
622- var aspnetCoreUrls = ers . Spec . Template . Spec . Env ? . Single ( v => v . Name == "ASPNETCORE_URLS" ) . Value ;
623- Assert . Equal ( "http://localhost:{{- portForServing \" ServiceA-http\" -}};http://localhost:{{- portForServing \" ServiceA-hp1\" -}}" , aspnetCoreUrls ) ;
613+ foreach ( var dcpExe in exes )
614+ {
615+ Assert . True ( dcpExe . TryGetAnnotationAsObjectList < ServiceProducerAnnotation > ( CustomResource . ServiceProducerAnnotation , out var spAnnList ) ) ;
616+
617+ // Neither Port, nor TargetPort are set
618+ // Clients use proxy, MAY have the proxy port injected.
619+ // Proxy gets autogenerated port.
620+ // Each replica gets a different autogenerated port that MUST be injected via env var/startup param.
621+ var svc = kubernetesService . CreatedResources . OfType < Service > ( ) . Single ( s => s . Name ( ) == "ServiceA-NoPortNoTargetPort" ) ;
622+ Assert . Equal ( AddressAllocationModes . Localhost , svc . Spec . AddressAllocationMode ) ;
623+ Assert . True ( svc . Status ? . EffectivePort >= TestKubernetesService . StartOfAutoPortRange ) ;
624+ Assert . True ( spAnnList . Single ( ann => ann . ServiceName == "ServiceA-NoPortNoTargetPort" ) . Port is null ,
625+ "Expected service producer (target) port to not be set (leave allocation to DCP)" ) ;
626+ var envVarVal = dcpExe . Spec . Env ? . Single ( v => v . Name == "NO_PORT_NO_TARGET_PORT" ) . Value ;
627+ Assert . False ( string . IsNullOrWhiteSpace ( envVarVal ) ) ;
628+ Assert . Contains ( """portForServing "ServiceA-NoPortNoTargetPort" """ , envVarVal ) ;
629+
630+ // ASPNETCORE_URLS should not include dontinjectme, as it was excluded using WithEndpointsInEnvironment
631+ var aspnetCoreUrls = dcpExe . Spec . Env ? . Single ( v => v . Name == "ASPNETCORE_URLS" ) . Value ;
632+ Assert . Equal ( "http://localhost:{{- portForServing \" ServiceA-http\" -}};http://localhost:{{- portForServing \" ServiceA-hp1\" -}}" , aspnetCoreUrls ) ;
633+ }
624634 }
625635
626636 [ Fact ]
@@ -642,77 +652,25 @@ public async Task EndpointPortsProjectPortSetNoTargetPort()
642652 var appExecutor = CreateAppExecutor ( distributedAppModel , app . Services , kubernetesService : kubernetesService ) ;
643653 await appExecutor . RunApplicationAsync ( ) ;
644654
645- var ers = Assert . Single ( kubernetesService . CreatedResources . OfType < ExecutableReplicaSet > ( ) ) ;
646- Assert . True ( ers . Spec . Template . TryGetAnnotationAsObjectList < ServiceProducerAnnotation > ( CustomResource . ServiceProducerAnnotation , out var spAnnList ) ) ;
655+ var exes = kubernetesService . CreatedResources . OfType < Executable > ( ) . ToList ( ) ;
656+ Assert . Equal ( 3 , exes . Count ) ;
647657
648- // Port is set, but TargetPort is empty.
649- // Clients use proxy, MAY have the proxy port injected.
650- // Proxy uses Port.
651- // Each replica gets a different autogenerated port that MUST be injected via env var/startup param.
652- var svc = kubernetesService . CreatedResources . OfType < Service > ( ) . Single ( s => s . Name ( ) == "ServiceA-PortSetNoTargetPort" ) ;
653- Assert . Equal ( AddressAllocationModes . Localhost , svc . Spec . AddressAllocationMode ) ;
654- Assert . Equal ( desiredPortOne , svc . Status ? . EffectivePort ) ;
655- Assert . True ( spAnnList . Single ( ann => ann . ServiceName == "ServiceA-PortSetNoTargetPort" ) . Port is null ,
656- "Expected service producer (target) port to not be set (leave allocation to DCP)" ) ;
657- var envVarVal = ers . Spec . Template . Spec . Env ? . Single ( v => v . Name == "PORT_SET_NO_TARGET_PORT" ) . Value ;
658- Assert . False ( string . IsNullOrWhiteSpace ( envVarVal ) ) ;
659- Assert . Contains ( """portForServing "ServiceA-PortSetNoTargetPort" """ , envVarVal ) ;
660- }
661-
662- /// <summary>
663- /// Verifies that applying unsupported endpoint port configuration to a Project resource results in an error.
664- /// </summary>
665- /// <remarks>
666- /// Projects are run by DCP via ExecutableReplicaSet and must use a proxy to enable dynamic scaling.
667- /// Any Endpoint configuration that does not enable proxying should result in an error.
668- /// Similarly, specifying a TargetPort is not supported because each replica must get a distinct port.
669- /// </remarks>
670- [ Fact ]
671- public async Task UnsupportedEndpointPortsProject ( )
672- {
673- const int desiredPortOne = TestKubernetesService . StartOfAutoPortRange - 1000 ;
674- const int desiredPortTwo = TestKubernetesService . StartOfAutoPortRange - 999 ;
675- const int desiredPortThree = TestKubernetesService . StartOfAutoPortRange - 998 ;
676-
677- ( Action < IResourceBuilder < ProjectResource > > AddEndpoint , string ErrorMessageFragment ) [ ] testcases = [
678- // Invalid configuration: TargetPort is set (Port left empty).
679- (
680- pr => pr . WithEndpoint ( name : "NoPortTargetPortSet" , targetPort : desiredPortOne , env : "NO_PORT_TARGET_PORT_SET" , isProxied : true ) ,
681- "setting TargetPort is not allowed"
682- ) ,
683-
684- // Invalid configuration: both TargetPort and Port are set.
685- (
686- pr => pr . WithEndpoint ( name : "PortAndTargetPortSet" , port : desiredPortTwo , targetPort : desiredPortThree , env : "PORT_AND_TARGET_PORT_SET" , isProxied : true ) ,
687- "setting TargetPort is not allowed"
688- ) ,
689-
690- // Invalid configuration: proxy-less endpoints and (replicated) projects do not work together
691- (
692- pr => pr . WithEndpoint ( name : "NoPortNoTargetPort" , env : "NO_PORT_NO_TARGET_PORT" , isProxied : false ) ,
693- "features do not work together"
694- )
695- ] ;
696-
697- foreach ( var tc in testcases )
658+ foreach ( var dcpExe in exes )
698659 {
699- var builder = DistributedApplication . CreateBuilder ( new DistributedApplicationOptions
700- {
701- AssemblyName = typeof ( DistributedApplicationTests ) . Assembly . FullName
702- } ) ;
703-
704- // Invalid configuration: TargetPort is set (Port left empty).
705-
706- var pr = builder . AddProject < Projects . ServiceA > ( "ServiceA" ) ;
707- tc . AddEndpoint ( pr ) ;
708- pr . WithReplicas ( 3 ) ;
709-
710- var kubernetesService = new TestKubernetesService ( ) ;
711- using var app = builder . Build ( ) ;
712- var distributedAppModel = app . Services . GetRequiredService < DistributedApplicationModel > ( ) ;
713- var appExecutor = CreateAppExecutor ( distributedAppModel , app . Services , kubernetesService : kubernetesService ) ;
714- var exception = await Assert . ThrowsAsync < InvalidOperationException > ( ( ) => appExecutor . RunApplicationAsync ( ) ) ;
715- Assert . Contains ( tc . ErrorMessageFragment , exception . Message ) ;
660+ Assert . True ( dcpExe . TryGetAnnotationAsObjectList < ServiceProducerAnnotation > ( CustomResource . ServiceProducerAnnotation , out var spAnnList ) ) ;
661+
662+ // Port is set, but TargetPort is empty.
663+ // Clients use proxy, MAY have the proxy port injected.
664+ // Proxy uses Port.
665+ // Each replica gets a different autogenerated port that MUST be injected via env var/startup param.
666+ var svc = kubernetesService . CreatedResources . OfType < Service > ( ) . Single ( s => s . Name ( ) == "ServiceA-PortSetNoTargetPort" ) ;
667+ Assert . Equal ( AddressAllocationModes . Localhost , svc . Spec . AddressAllocationMode ) ;
668+ Assert . Equal ( desiredPortOne , svc . Status ? . EffectivePort ) ;
669+ Assert . True ( spAnnList . Single ( ann => ann . ServiceName == "ServiceA-PortSetNoTargetPort" ) . Port is null ,
670+ "Expected service producer (target) port to not be set (leave allocation to DCP)" ) ;
671+ var envVarVal = dcpExe . Spec . Env ? . Single ( v => v . Name == "PORT_SET_NO_TARGET_PORT" ) . Value ;
672+ Assert . False ( string . IsNullOrWhiteSpace ( envVarVal ) ) ;
673+ Assert . Contains ( """portForServing "ServiceA-PortSetNoTargetPort" """ , envVarVal ) ;
716674 }
717675 }
718676
0 commit comments