@@ -350,10 +350,10 @@ public async Task GrandChildResourceWithConnectionString()
350350
351351 var parentResource = builder . AddResource ( new ParentResourceWithConnectionString ( "parent" ) ) ;
352352 var childResource = builder . AddResource (
353- new ChildResourceWithConnectionString ( "child" , new Dictionary < string , string > { { "Namespace" , "ns" } } , parentResource . Resource )
353+ new ChildResourceWithConnectionString ( "child" , new Dictionary < string , string > { { "Namespace" , "ns" } } , parentResource . Resource )
354354 ) ;
355355 var grandChildResource = builder . AddResource (
356- new ChildResourceWithConnectionString ( "grand-child" , new Dictionary < string , string > { { "Database" , "db" } } , childResource . Resource )
356+ new ChildResourceWithConnectionString ( "grand-child" , new Dictionary < string , string > { { "Database" , "db" } } , childResource . Resource )
357357 ) ;
358358
359359 await using var app = builder . Build ( ) ;
@@ -589,10 +589,10 @@ await events.PublishAsync(new OnResourceChangedContext(
589589
590590 // Parent should have the new state
591591 Assert . Equal ( KnownResourceStates . FailedToStart , parentState ) ;
592-
592+
593593 // Child container (has own lifetime) should NOT receive parent state
594594 Assert . NotEqual ( KnownResourceStates . Running , childContainerState ) ;
595-
595+
596596 // Custom child (does not have own lifetime) SHOULD receive parent state
597597 Assert . Equal ( KnownResourceStates . FailedToStart , customChildState ) ;
598598 }
@@ -635,11 +635,171 @@ await events.PublishAsync(new OnResourceChangedContext(
635635
636636 // Parent should have the new state
637637 Assert . Equal ( KnownResourceStates . FailedToStart , parentState ) ;
638-
638+
639639 // Child project (has own lifetime) should NOT receive parent state
640640 Assert . NotEqual ( KnownResourceStates . Running , childProjectState ) ;
641-
641+
642642 // Custom child (does not have own lifetime) SHOULD receive parent state
643643 Assert . Equal ( KnownResourceStates . FailedToStart , customChildState ) ;
644644 }
645+
646+ [ Fact ]
647+ public async Task WithChildRelationshipUsingResourceBuilderSetsParentPropertyCorrectly ( )
648+ {
649+ var builder = DistributedApplication . CreateBuilder ( ) ;
650+
651+ var parent = builder . AddContainer ( "parent" , "image" ) ;
652+ var child = builder . AddContainer ( "child" , "image" ) ;
653+ var child2 = builder . AddContainer ( "child2" , "image" ) ;
654+
655+ parent . WithChildRelationship ( child )
656+ . WithChildRelationship ( child2 ) ;
657+
658+ using var app = builder . Build ( ) ;
659+ var distributedAppModel = app . Services . GetRequiredService < DistributedApplicationModel > ( ) ;
660+
661+ var events = new DcpExecutorEvents ( ) ;
662+ var resourceNotificationService = ResourceNotificationServiceTestHelpers . Create ( ) ;
663+
664+ var appOrchestrator = CreateOrchestrator ( distributedAppModel , notificationService : resourceNotificationService , dcpEvents : events ) ;
665+ await appOrchestrator . RunApplicationAsync ( ) ;
666+
667+ string ? parentResourceId = null ;
668+ string ? childParentResourceId = null ;
669+ string ? child2ParentResourceId = null ;
670+ var watchResourceTask = Task . Run ( async ( ) =>
671+ {
672+ await foreach ( var item in resourceNotificationService . WatchAsync ( ) )
673+ {
674+ if ( item . Resource == parent . Resource )
675+ {
676+ parentResourceId = item . ResourceId ;
677+ }
678+ else if ( item . Resource == child . Resource )
679+ {
680+ childParentResourceId = item . Snapshot . Properties . SingleOrDefault ( p => p . Name == KnownProperties . Resource . ParentName ) ? . Value ? . ToString ( ) ;
681+ }
682+ else if ( item . Resource == child2 . Resource )
683+ {
684+ child2ParentResourceId = item . Snapshot . Properties . SingleOrDefault ( p => p . Name == KnownProperties . Resource . ParentName ) ? . Value ? . ToString ( ) ;
685+ }
686+
687+ if ( parentResourceId != null && childParentResourceId != null && child2ParentResourceId != null )
688+ {
689+ return ;
690+ }
691+ }
692+ } ) ;
693+
694+ await events . PublishAsync ( new OnResourcesPreparedContext ( CancellationToken . None ) ) ;
695+
696+ await watchResourceTask . DefaultTimeout ( ) ;
697+
698+ Assert . Equal ( parentResourceId , childParentResourceId ) ;
699+ Assert . Equal ( parentResourceId , child2ParentResourceId ) ;
700+ }
701+
702+ [ Fact ]
703+ public async Task WithChildRelationshipUsingResourceSetsParentPropertyCorrectly ( )
704+ {
705+ var builder = DistributedApplication . CreateBuilder ( ) ;
706+
707+ var parent = builder . AddContainer ( "parent" , "image" ) ;
708+ var child = builder . AddContainer ( "child" , "image" ) ;
709+ var child2 = builder . AddContainer ( "child2" , "image" ) ;
710+
711+ parent . WithChildRelationship ( child . Resource )
712+ . WithChildRelationship ( child2 . Resource ) ;
713+
714+ using var app = builder . Build ( ) ;
715+ var distributedAppModel = app . Services . GetRequiredService < DistributedApplicationModel > ( ) ;
716+
717+ var events = new DcpExecutorEvents ( ) ;
718+ var resourceNotificationService = ResourceNotificationServiceTestHelpers . Create ( ) ;
719+
720+ var appOrchestrator = CreateOrchestrator ( distributedAppModel , notificationService : resourceNotificationService , dcpEvents : events ) ;
721+ await appOrchestrator . RunApplicationAsync ( ) ;
722+
723+ string ? parentResourceId = null ;
724+ string ? childParentResourceId = null ;
725+ string ? child2ParentResourceId = null ;
726+ var watchResourceTask = Task . Run ( async ( ) =>
727+ {
728+ await foreach ( var item in resourceNotificationService . WatchAsync ( ) )
729+ {
730+ if ( item . Resource == parent . Resource )
731+ {
732+ parentResourceId = item . ResourceId ;
733+ }
734+ else if ( item . Resource == child . Resource )
735+ {
736+ childParentResourceId = item . Snapshot . Properties . SingleOrDefault ( p => p . Name == KnownProperties . Resource . ParentName ) ? . Value ? . ToString ( ) ;
737+ }
738+ else if ( item . Resource == child2 . Resource )
739+ {
740+ child2ParentResourceId = item . Snapshot . Properties . SingleOrDefault ( p => p . Name == KnownProperties . Resource . ParentName ) ? . Value ? . ToString ( ) ;
741+ }
742+
743+ if ( parentResourceId != null && childParentResourceId != null && child2ParentResourceId != null )
744+ {
745+ return ;
746+ }
747+ }
748+ } ) ;
749+
750+ await events . PublishAsync ( new OnResourcesPreparedContext ( CancellationToken . None ) ) ;
751+
752+ await watchResourceTask . DefaultTimeout ( ) ;
753+
754+ Assert . Equal ( parentResourceId , childParentResourceId ) ;
755+ Assert . Equal ( parentResourceId , child2ParentResourceId ) ;
756+ }
757+
758+ [ Fact ]
759+ public async Task WithChildRelationshipWorksWithProjects ( )
760+ {
761+ var builder = DistributedApplication . CreateBuilder ( ) ;
762+
763+ var parentProject = builder . AddProject < ProjectA > ( "parent-project" ) ;
764+ var childProject = builder . AddProject < ProjectB > ( "child-project" ) ;
765+
766+ parentProject . WithChildRelationship ( childProject ) ;
767+
768+ using var app = builder . Build ( ) ;
769+ var distributedAppModel = app . Services . GetRequiredService < DistributedApplicationModel > ( ) ;
770+
771+ var events = new DcpExecutorEvents ( ) ;
772+ var resourceNotificationService = ResourceNotificationServiceTestHelpers . Create ( ) ;
773+
774+ var appOrchestrator = CreateOrchestrator ( distributedAppModel , notificationService : resourceNotificationService , dcpEvents : events ) ;
775+ await appOrchestrator . RunApplicationAsync ( ) ;
776+
777+ string ? parentProjectResourceId = null ;
778+ string ? childProjectParentResourceId = null ;
779+ var watchResourceTask = Task . Run ( async ( ) =>
780+ {
781+ await foreach ( var item in resourceNotificationService . WatchAsync ( ) )
782+ {
783+ if ( item . Resource == parentProject . Resource )
784+ {
785+ parentProjectResourceId = item . ResourceId ;
786+ }
787+ else if ( item . Resource == childProject . Resource )
788+ {
789+ childProjectParentResourceId = item . Snapshot . Properties . SingleOrDefault ( p => p . Name == KnownProperties . Resource . ParentName ) ? . Value ? . ToString ( ) ;
790+ }
791+
792+ if ( parentProjectResourceId != null && childProjectParentResourceId != null )
793+ {
794+ return ;
795+ }
796+ }
797+ } ) ;
798+
799+ await events . PublishAsync ( new OnResourcesPreparedContext ( CancellationToken . None ) ) ;
800+
801+ await watchResourceTask . DefaultTimeout ( ) ;
802+
803+ Assert . Equal ( parentProjectResourceId , childProjectParentResourceId ) ;
804+ }
645805}
0 commit comments