@@ -706,4 +706,169 @@ public async Task PostgresEnvironmentCallbackIsIdempotent()
706706 Assert . Equal ( kvp . Value , config2 [ kvp . Key ] ) ;
707707 } ) ;
708708 }
709+
710+ [ Theory ]
711+ [ InlineData ( "17.6" , 17 ) ]
712+ [ InlineData ( "18.1" , 18 ) ]
713+ [ InlineData ( "18" , 18 ) ]
714+ [ InlineData ( "18-alpine" , 18 ) ]
715+ [ InlineData ( "17.6-bookworm" , 17 ) ]
716+ [ InlineData ( "16.0" , 16 ) ]
717+ [ InlineData ( "9.6" , 9 ) ]
718+ public void TryParsePostgresMajorVersionReturnsTrueForValidTags ( string tag , int expectedMajorVersion )
719+ {
720+ var result = PostgresBuilderExtensions . TryParsePostgresMajorVersion ( tag , out var majorVersion ) ;
721+
722+ Assert . True ( result ) ;
723+ Assert . Equal ( expectedMajorVersion , majorVersion ) ;
724+ }
725+
726+ [ Theory ]
727+ [ InlineData ( "latest" ) ]
728+ [ InlineData ( "alpine" ) ]
729+ [ InlineData ( "" ) ]
730+ [ InlineData ( " " ) ]
731+ [ InlineData ( "abc" ) ]
732+ public void TryParsePostgresMajorVersionReturnsFalseForInvalidTags ( string tag )
733+ {
734+ var result = PostgresBuilderExtensions . TryParsePostgresMajorVersion ( tag , out var majorVersion ) ;
735+
736+ Assert . False ( result ) ;
737+ Assert . Equal ( 0 , majorVersion ) ;
738+ }
739+
740+ [ Theory ]
741+ [ InlineData ( null ) ]
742+ [ InlineData ( true ) ]
743+ [ InlineData ( false ) ]
744+ public void WithDataVolumeUsesLegacyPathForPostgres17 ( bool ? isReadOnly )
745+ {
746+ using var builder = TestDistributedApplicationBuilder . Create ( ) ;
747+ var postgres = builder . AddPostgres ( "myPostgres" ) ;
748+
749+ // Default image is v17.x, so should use legacy path
750+ if ( isReadOnly . HasValue )
751+ {
752+ postgres . WithDataVolume ( isReadOnly : isReadOnly . Value ) ;
753+ }
754+ else
755+ {
756+ postgres . WithDataVolume ( ) ;
757+ }
758+
759+ var volumeAnnotation = postgres . Resource . Annotations . OfType < ContainerMountAnnotation > ( ) . Single ( ) ;
760+
761+ Assert . Equal ( $ "{ builder . GetVolumePrefix ( ) } -myPostgres-data", volumeAnnotation . Source ) ;
762+ Assert . Equal ( "/var/lib/postgresql/data" , volumeAnnotation . Target ) ;
763+ Assert . Equal ( ContainerMountType . Volume , volumeAnnotation . Type ) ;
764+ Assert . Equal ( isReadOnly ?? false , volumeAnnotation . IsReadOnly ) ;
765+ }
766+
767+ [ Theory ]
768+ [ InlineData ( null ) ]
769+ [ InlineData ( true ) ]
770+ [ InlineData ( false ) ]
771+ public void WithDataVolumeUsesNewPathForPostgres18 ( bool ? isReadOnly )
772+ {
773+ using var builder = TestDistributedApplicationBuilder . Create ( ) ;
774+ var postgres = builder . AddPostgres ( "myPostgres" )
775+ . WithImage ( "postgres" , "18.1" ) ;
776+
777+ if ( isReadOnly . HasValue )
778+ {
779+ postgres . WithDataVolume ( isReadOnly : isReadOnly . Value ) ;
780+ }
781+ else
782+ {
783+ postgres . WithDataVolume ( ) ;
784+ }
785+
786+ var volumeAnnotation = postgres . Resource . Annotations . OfType < ContainerMountAnnotation > ( ) . Single ( ) ;
787+
788+ Assert . Equal ( $ "{ builder . GetVolumePrefix ( ) } -myPostgres-data", volumeAnnotation . Source ) ;
789+ Assert . Equal ( "/var/lib/postgresql" , volumeAnnotation . Target ) ;
790+ Assert . Equal ( ContainerMountType . Volume , volumeAnnotation . Type ) ;
791+ Assert . Equal ( isReadOnly ?? false , volumeAnnotation . IsReadOnly ) ;
792+ }
793+
794+ [ Fact ]
795+ public void WithDataVolumeUsesNewPathForPostgres18Alpine ( )
796+ {
797+ using var builder = TestDistributedApplicationBuilder . Create ( ) ;
798+ var postgres = builder . AddPostgres ( "myPostgres" )
799+ . WithImage ( "postgres" , "18-alpine" )
800+ . WithDataVolume ( ) ;
801+
802+ var volumeAnnotation = postgres . Resource . Annotations . OfType < ContainerMountAnnotation > ( ) . Single ( ) ;
803+
804+ Assert . Equal ( "/var/lib/postgresql" , volumeAnnotation . Target ) ;
805+ }
806+
807+ [ Fact ]
808+ public void WithDataVolumeUsesLegacyPathForUnparsableTag ( )
809+ {
810+ using var builder = TestDistributedApplicationBuilder . Create ( ) ;
811+ var postgres = builder . AddPostgres ( "myPostgres" )
812+ . WithImage ( "postgres" , "latest" )
813+ . WithDataVolume ( ) ;
814+
815+ var volumeAnnotation = postgres . Resource . Annotations . OfType < ContainerMountAnnotation > ( ) . Single ( ) ;
816+
817+ // When tag can't be parsed, fall back to legacy path for safety
818+ Assert . Equal ( "/var/lib/postgresql/data" , volumeAnnotation . Target ) ;
819+ }
820+
821+ [ Theory ]
822+ [ InlineData ( null ) ]
823+ [ InlineData ( true ) ]
824+ [ InlineData ( false ) ]
825+ public void WithDataBindMountUsesLegacyPathForPostgres17 ( bool ? isReadOnly )
826+ {
827+ using var builder = TestDistributedApplicationBuilder . Create ( ) ;
828+ var postgres = builder . AddPostgres ( "myPostgres" ) ;
829+
830+ // Default image is v17.x, so should use legacy path
831+ if ( isReadOnly . HasValue )
832+ {
833+ postgres . WithDataBindMount ( "mydata" , isReadOnly : isReadOnly . Value ) ;
834+ }
835+ else
836+ {
837+ postgres . WithDataBindMount ( "mydata" ) ;
838+ }
839+
840+ var volumeAnnotation = postgres . Resource . Annotations . OfType < ContainerMountAnnotation > ( ) . Single ( ) ;
841+
842+ Assert . Equal ( Path . Combine ( builder . AppHostDirectory , "mydata" ) , volumeAnnotation . Source ) ;
843+ Assert . Equal ( "/var/lib/postgresql/data" , volumeAnnotation . Target ) ;
844+ Assert . Equal ( ContainerMountType . BindMount , volumeAnnotation . Type ) ;
845+ Assert . Equal ( isReadOnly ?? false , volumeAnnotation . IsReadOnly ) ;
846+ }
847+
848+ [ Theory ]
849+ [ InlineData ( null ) ]
850+ [ InlineData ( true ) ]
851+ [ InlineData ( false ) ]
852+ public void WithDataBindMountUsesNewPathForPostgres18 ( bool ? isReadOnly )
853+ {
854+ using var builder = TestDistributedApplicationBuilder . Create ( ) ;
855+ var postgres = builder . AddPostgres ( "myPostgres" )
856+ . WithImage ( "postgres" , "18.1" ) ;
857+
858+ if ( isReadOnly . HasValue )
859+ {
860+ postgres . WithDataBindMount ( "mydata" , isReadOnly : isReadOnly . Value ) ;
861+ }
862+ else
863+ {
864+ postgres . WithDataBindMount ( "mydata" ) ;
865+ }
866+
867+ var volumeAnnotation = postgres . Resource . Annotations . OfType < ContainerMountAnnotation > ( ) . Single ( ) ;
868+
869+ Assert . Equal ( Path . Combine ( builder . AppHostDirectory , "mydata" ) , volumeAnnotation . Source ) ;
870+ Assert . Equal ( "/var/lib/postgresql" , volumeAnnotation . Target ) ;
871+ Assert . Equal ( ContainerMountType . BindMount , volumeAnnotation . Type ) ;
872+ Assert . Equal ( isReadOnly ?? false , volumeAnnotation . IsReadOnly ) ;
873+ }
709874}
0 commit comments