@@ -798,6 +798,197 @@ func TestMultiDriverAddTemplate(t *testing.T) {
798798 })
799799}
800800
801+ func Test_AddConstraint_SemanticEqualWithLabelsAndAnnotations (t * testing.T ) {
802+ templateA := cts .New (cts .OptTargets (
803+ cts .TargetCustomEngines (
804+ "h1" ,
805+ cts .Code ("driverA" , (& schema.Source {RejectWith : "REJECTING" }).ToUnstructured ()),
806+ ),
807+ ))
808+
809+ driverA := fake .New ("driverA" )
810+ client , err := NewClient (
811+ Targets (& handlertest.Handler {Name : ptr.To [string ]("h1" )}),
812+ Driver (driverA ),
813+ EnforcementPoints ("test" ),
814+ )
815+ if err != nil {
816+ t .Fatal (err )
817+ }
818+
819+ ctx , cancel := context .WithCancel (context .Background ())
820+ defer cancel ()
821+
822+ // Add template
823+ if _ , err := client .AddTemplate (ctx , templateA .DeepCopy ()); err != nil {
824+ t .Fatal (err )
825+ }
826+
827+ t .Run ("Add constraint with metadata" , func (t * testing.T ) {
828+ // Create constraint with specific labels and annotations
829+ constraint := cts .MakeConstraint (t , "Fakes" , "test-constraint" )
830+ constraint .SetLabels (map [string ]string {"env" : "prod" , "team" : "security" })
831+ constraint .SetAnnotations (map [string ]string {"audit" : "enabled" , "export" : "true" })
832+
833+ resp , err := client .AddConstraint (ctx , constraint .DeepCopy ())
834+ if err != nil {
835+ t .Fatal (err )
836+ }
837+
838+ if ! resp .Handled ["h1" ] {
839+ t .Errorf ("Expected constraint to be handled by 'h1' handler, got: %v" , resp .Handled )
840+ }
841+
842+ // Verify constraint was added to driver
843+ storedConstraints := driverA .GetConstraintsForTemplate (templateA )
844+ if len (storedConstraints ) != 1 {
845+ t .Errorf ("Expected 1 constraint, got %d" , len (storedConstraints ))
846+ }
847+ if _ , exists := storedConstraints ["test-constraint" ]; ! exists {
848+ t .Errorf ("Expected constraint 'test-constraint' to be stored" )
849+ }
850+ })
851+
852+ t .Run ("Add identical constraint - should be no-op" , func (t * testing.T ) {
853+ // Create identical constraint
854+ identicalConstraint := cts .MakeConstraint (t , "Fakes" , "test-constraint" )
855+ identicalConstraint .SetLabels (map [string ]string {"env" : "prod" , "team" : "security" })
856+ identicalConstraint .SetAnnotations (map [string ]string {"audit" : "enabled" , "export" : "true" })
857+
858+ // Track initial state
859+ initialConstraints := driverA .GetConstraintsForTemplate (templateA )
860+ initialCount := len (initialConstraints )
861+
862+ resp , err := client .AddConstraint (ctx , identicalConstraint .DeepCopy ())
863+ if err != nil {
864+ t .Fatal (err )
865+ }
866+
867+ if ! resp .Handled ["h1" ] {
868+ t .Errorf ("Expected constraint to be handled by 'h1' handler, got: %v" , resp .Handled )
869+ }
870+
871+ // Verify no duplicate was created
872+ finalConstraints := driverA .GetConstraintsForTemplate (templateA )
873+ if len (finalConstraints ) != initialCount {
874+ t .Errorf ("Expected constraint count to remain %d, got %d" , initialCount , len (finalConstraints ))
875+ }
876+ })
877+
878+ t .Run ("Add constraint with different labels - should update" , func (t * testing.T ) {
879+ // Create constraint with different labels
880+ updatedConstraint := cts .MakeConstraint (t , "Fakes" , "test-constraint" )
881+ updatedConstraint .SetLabels (map [string ]string {"env" : "staging" , "team" : "security" }) // Changed env
882+ updatedConstraint .SetAnnotations (map [string ]string {"audit" : "enabled" , "export" : "true" })
883+
884+ resp , err := client .AddConstraint (ctx , updatedConstraint .DeepCopy ())
885+ if err != nil {
886+ t .Fatal (err )
887+ }
888+
889+ if ! resp .Handled ["h1" ] {
890+ t .Errorf ("Expected constraint to be handled by 'h1' handler, got: %v" , resp .Handled )
891+ }
892+
893+ // Verify constraint was updated in driver
894+ storedConstraints := driverA .GetConstraintsForTemplate (templateA )
895+ if len (storedConstraints ) != 1 {
896+ t .Errorf ("Expected 1 constraint, got %d" , len (storedConstraints ))
897+ }
898+
899+ stored := storedConstraints ["test-constraint" ]
900+ if stored == nil {
901+ t .Fatal ("Expected constraint 'test-constraint' to be stored" )
902+ }
903+
904+ // Compare labels and annotations using DeepEqual
905+ if ! reflect .DeepEqual (stored .GetLabels (), updatedConstraint .GetLabels ()) {
906+ t .Errorf ("Labels mismatch: got %v, want %v" , stored .GetLabels (), updatedConstraint .GetLabels ())
907+ }
908+
909+ if ! reflect .DeepEqual (stored .GetAnnotations (), updatedConstraint .GetAnnotations ()) {
910+ t .Errorf ("Annotations mismatch: got %v, want %v" , stored .GetAnnotations (), updatedConstraint .GetAnnotations ())
911+ }
912+ })
913+
914+ t .Run ("Add constraint with different annotations - should update" , func (t * testing.T ) {
915+ // Create constraint with different annotations
916+ updatedConstraint := cts .MakeConstraint (t , "Fakes" , "test-constraint" )
917+ updatedConstraint .SetLabels (map [string ]string {"env" : "staging" , "team" : "security" })
918+ updatedConstraint .SetAnnotations (map [string ]string {"audit" : "disabled" , "export" : "false" }) // Changed annotations
919+
920+ resp , err := client .AddConstraint (ctx , updatedConstraint .DeepCopy ())
921+ if err != nil {
922+ t .Fatal (err )
923+ }
924+
925+ if ! resp .Handled ["h1" ] {
926+ t .Errorf ("Expected constraint to be handled by 'h1' handler, got: %v" , resp .Handled )
927+ }
928+
929+ // Verify constraint was updated in driver
930+ storedConstraints := driverA .GetConstraintsForTemplate (templateA )
931+ stored := storedConstraints ["test-constraint" ]
932+ if stored == nil {
933+ t .Fatal ("Expected constraint 'test-constraint' to be stored" )
934+ }
935+ // Compare labels and annotations using DeepEqual
936+ if ! reflect .DeepEqual (stored .GetLabels (), updatedConstraint .GetLabels ()) {
937+ t .Errorf ("Labels mismatch: got %v, want %v" , stored .GetLabels (), updatedConstraint .GetLabels ())
938+ }
939+
940+ if ! reflect .DeepEqual (stored .GetAnnotations (), updatedConstraint .GetAnnotations ()) {
941+ t .Errorf ("Annotations mismatch: got %v, want %v" , stored .GetAnnotations (), updatedConstraint .GetAnnotations ())
942+ }
943+ })
944+
945+ t .Run ("Add constraint with different spec - should update" , func (t * testing.T ) {
946+ // Create constraint with different spec but same metadata
947+ updatedConstraint := cts .MakeConstraint (t , "Fakes" , "test-constraint" )
948+ updatedConstraint .SetLabels (map [string ]string {"env" : "staging" , "team" : "security" })
949+ updatedConstraint .SetAnnotations (map [string ]string {"audit" : "disabled" , "export" : "false" })
950+ err := unstructured .SetNestedField (updatedConstraint .Object , "warn" , "spec" , "enforcementAction" )
951+ if err != nil {
952+ t .Fatal (err )
953+ }
954+
955+ resp , err := client .AddConstraint (ctx , updatedConstraint .DeepCopy ())
956+ if err != nil {
957+ t .Fatal (err )
958+ }
959+
960+ if ! resp .Handled ["h1" ] {
961+ t .Errorf ("Expected constraint to be handled by 'h1' handler, got: %v" , resp .Handled )
962+ }
963+
964+ // Verify constraint was updated
965+ storedConstraints := driverA .GetConstraintsForTemplate (templateA )
966+ if len (storedConstraints ) != 1 {
967+ t .Errorf ("Expected 1 constraint, got %d" , len (storedConstraints ))
968+ }
969+
970+ stored := storedConstraints ["test-constraint" ]
971+ if stored == nil {
972+ t .Fatal ("Expected constraint 'test-constraint' to be stored" )
973+ }
974+
975+ // Compare the stored constraint directly with the updated constraint using DeepEqual
976+ if ! reflect .DeepEqual (stored .GetLabels (), updatedConstraint .GetLabels ()) {
977+ t .Errorf ("Labels mismatch: got %v, want %v" , stored .GetLabels (), updatedConstraint .GetLabels ())
978+ }
979+
980+ if ! reflect .DeepEqual (stored .GetAnnotations (), updatedConstraint .GetAnnotations ()) {
981+ t .Errorf ("Annotations mismatch: got %v, want %v" , stored .GetAnnotations (), updatedConstraint .GetAnnotations ())
982+ }
983+
984+ storedSpec , _ , _ := unstructured .NestedMap (stored .Object , "spec" )
985+ updatedSpec , _ , _ := unstructured .NestedMap (updatedConstraint .Object , "spec" )
986+ if ! reflect .DeepEqual (storedSpec , updatedSpec ) {
987+ t .Errorf ("Spec mismatch: got %v, want %v" , storedSpec , updatedSpec )
988+ }
989+ })
990+ }
991+
801992func TestMultiDriverRemoveTemplate (t * testing.T ) {
802993 templateA := cts .New (cts .OptTargets (
803994 cts .TargetCustomEngines (
0 commit comments