@@ -771,10 +771,12 @@ func TestNotifications_removeUnmanagedNotificationsSourceNamespaceResources(t *t
771771 subresObjs := []client.Object {a }
772772 runtimeObjs := []runtime.Object {}
773773 sch := makeTestReconcilerScheme (argoproj .AddToScheme )
774+ err := v1alpha1 .AddToScheme (sch )
775+ assert .NoError (t , err )
774776 cl := makeTestReconcilerClient (sch , resObjs , subresObjs , runtimeObjs )
775777 r := makeTestReconciler (cl , sch , testclient .NewSimpleClientset ())
776778
777- err : = createNamespace (r , ns1 , "" )
779+ err = createNamespace (r , ns1 , "" )
778780 assert .NoError (t , err )
779781 err = createNamespace (r , ns2 , "" )
780782 assert .NoError (t , err )
@@ -809,6 +811,12 @@ func TestNotifications_removeUnmanagedNotificationsSourceNamespaceResources(t *t
809811 assert .Error (t , err )
810812 assert .True (t , errors .IsNotFound (err ))
811813
814+ // NotificationsConfiguration CR should be deleted from ns1
815+ notifCfg := & v1alpha1.NotificationsConfiguration {}
816+ err = r .Get (context .TODO (), client.ObjectKey {Name : DefaultNotificationsConfigurationInstanceName , Namespace : ns1 }, notifCfg )
817+ assert .Error (t , err )
818+ assert .True (t , errors .IsNotFound (err ))
819+
812820 // notifications tracking label should be removed
813821 namespace := & v1.Namespace {}
814822 err = r .Get (context .TODO (), client.ObjectKey {Name : ns1 }, namespace )
@@ -826,10 +834,225 @@ func TestNotifications_removeUnmanagedNotificationsSourceNamespaceResources(t *t
826834 err = r .Get (context .TODO (), client.ObjectKey {Name : resName , Namespace : ns2 }, roleBinding )
827835 assert .NoError (t , err )
828836
837+ // NotificationsConfiguration CR should still exist in ns2
838+ notifCfg = & v1alpha1.NotificationsConfiguration {}
839+ err = r .Get (context .TODO (), client.ObjectKey {Name : DefaultNotificationsConfigurationInstanceName , Namespace : ns2 }, notifCfg )
840+ assert .NoError (t , err )
841+
829842 namespace = & v1.Namespace {}
830843 err = r .Get (context .TODO (), client.ObjectKey {Name : ns2 }, namespace )
831844 assert .NoError (t , err )
832845 val , found := namespace .Labels [common .ArgoCDNotificationsManagedByClusterArgoCDLabel ]
833846 assert .True (t , found )
834847 assert .Equal (t , a .Namespace , val )
835848}
849+
850+ func TestReconcileNotifications_CreateNotificationsConfigurationInSourceNamespace_WithDefaults (t * testing.T ) {
851+ logf .SetLogger (ZapLogger (true ))
852+ sourceNamespace := "ns1"
853+ a := makeTestArgoCD (func (a * argoproj.ArgoCD ) {
854+ a .Spec .Notifications .Enabled = true
855+ a .Spec .Notifications .SourceNamespaces = []string {sourceNamespace }
856+ a .Spec .SourceNamespaces = []string {sourceNamespace }
857+ })
858+
859+ resObjs := []client.Object {a }
860+ subresObjs := []client.Object {a }
861+ runtimeObjs := []runtime.Object {}
862+ sch := makeTestReconcilerScheme (argoproj .AddToScheme )
863+ err := v1alpha1 .AddToScheme (sch )
864+ assert .NoError (t , err )
865+ cl := makeTestReconcilerClient (sch , resObjs , subresObjs , runtimeObjs )
866+ r := makeTestReconciler (cl , sch , testclient .NewSimpleClientset ())
867+
868+ // Create the source namespace
869+ err = createNamespace (r , sourceNamespace , "" )
870+ assert .NoError (t , err )
871+
872+ // Reconcile should create NotificationsConfiguration CR in source namespace with defaults
873+ // (since no NotificationsConfiguration exists in instance namespace)
874+ err = r .reconcileSourceNamespaceNotificationsConfigurationCR (a , sourceNamespace )
875+ assert .NoError (t , err )
876+
877+ // Verify NotificationsConfiguration CR exists in source namespace
878+ notifCfg := & v1alpha1.NotificationsConfiguration {}
879+ err = r .Get (context .TODO (), types.NamespacedName {
880+ Name : DefaultNotificationsConfigurationInstanceName ,
881+ Namespace : sourceNamespace ,
882+ }, notifCfg )
883+ assert .NoError (t , err )
884+
885+ // Verify it has the expected defaults
886+ expectedContext := getDefaultNotificationsContext ()
887+ expectedTriggers := getDefaultNotificationsTriggers ()
888+ expectedTemplates := getDefaultNotificationsTemplates ()
889+
890+ // Normalize nil to empty map for comparison (Kubernetes may serialize empty maps as nil)
891+ actualContext := notifCfg .Spec .Context
892+ if actualContext == nil {
893+ actualContext = map [string ]string {}
894+ }
895+
896+ assert .Equal (t , expectedContext , actualContext )
897+ assert .Equal (t , expectedTriggers , notifCfg .Spec .Triggers )
898+ assert .Equal (t , expectedTemplates , notifCfg .Spec .Templates )
899+ }
900+
901+ func TestReconcileNotifications_PropagateNotificationsConfigurationFromInstanceNamespace (t * testing.T ) {
902+ logf .SetLogger (ZapLogger (true ))
903+ sourceNamespace := "ns1"
904+ a := makeTestArgoCD (func (a * argoproj.ArgoCD ) {
905+ a .Spec .Notifications .Enabled = true
906+ a .Spec .Notifications .SourceNamespaces = []string {sourceNamespace }
907+ a .Spec .SourceNamespaces = []string {sourceNamespace }
908+ })
909+
910+ // Create a custom NotificationsConfiguration in the instance namespace
911+ customInstanceCfg := & v1alpha1.NotificationsConfiguration {
912+ ObjectMeta : metav1.ObjectMeta {
913+ Name : DefaultNotificationsConfigurationInstanceName ,
914+ Namespace : a .Namespace ,
915+ },
916+ Spec : v1alpha1.NotificationsConfigurationSpec {
917+ Context : map [string ]string {
918+ "customKey" : "customValue" ,
919+ "argocdUrl" : "https://custom-argocd.example.com" ,
920+ },
921+ Triggers : map [string ]string {
922+ "trigger.custom" : "custom trigger definition" ,
923+ },
924+ Templates : map [string ]string {
925+ "template.custom" : "custom template definition" ,
926+ },
927+ Services : map [string ]string {
928+ "service.custom" : "custom service definition" ,
929+ },
930+ Subscriptions : map [string ]string {
931+ "subscription.custom" : "custom subscription definition" ,
932+ },
933+ },
934+ }
935+
936+ resObjs := []client.Object {a , customInstanceCfg }
937+ subresObjs := []client.Object {a , customInstanceCfg }
938+ runtimeObjs := []runtime.Object {}
939+ sch := makeTestReconcilerScheme (argoproj .AddToScheme )
940+ err := v1alpha1 .AddToScheme (sch )
941+ assert .NoError (t , err )
942+ cl := makeTestReconcilerClient (sch , resObjs , subresObjs , runtimeObjs )
943+ r := makeTestReconciler (cl , sch , testclient .NewSimpleClientset ())
944+
945+ // Create the source namespace
946+ err = createNamespace (r , sourceNamespace , "" )
947+ assert .NoError (t , err )
948+
949+ // Reconcile should propagate the NotificationsConfiguration from instance namespace
950+ err = r .reconcileSourceNamespaceNotificationsConfigurationCR (a , sourceNamespace )
951+ assert .NoError (t , err )
952+
953+ // Verify NotificationsConfiguration CR exists in source namespace
954+ sourceNotifCfg := & v1alpha1.NotificationsConfiguration {}
955+ err = r .Get (context .TODO (), types.NamespacedName {
956+ Name : DefaultNotificationsConfigurationInstanceName ,
957+ Namespace : sourceNamespace ,
958+ }, sourceNotifCfg )
959+ assert .NoError (t , err )
960+
961+ // Verify it matches the instance namespace configuration (propagated)
962+ assert .Equal (t , customInstanceCfg .Spec .Context , sourceNotifCfg .Spec .Context )
963+ assert .Equal (t , customInstanceCfg .Spec .Triggers , sourceNotifCfg .Spec .Triggers )
964+ assert .Equal (t , customInstanceCfg .Spec .Templates , sourceNotifCfg .Spec .Templates )
965+ assert .Equal (t , customInstanceCfg .Spec .Services , sourceNotifCfg .Spec .Services )
966+ assert .Equal (t , customInstanceCfg .Spec .Subscriptions , sourceNotifCfg .Spec .Subscriptions )
967+
968+ // Now update the instance namespace configuration and verify it gets propagated
969+ customInstanceCfg .Spec .Context ["newKey" ] = "newValue"
970+ err = r .Update (context .TODO (), customInstanceCfg )
971+ assert .NoError (t , err )
972+
973+ // Reconcile again
974+ err = r .reconcileSourceNamespaceNotificationsConfigurationCR (a , sourceNamespace )
975+ assert .NoError (t , err )
976+
977+ // Verify the source namespace configuration was updated
978+ err = r .Get (context .TODO (), types.NamespacedName {
979+ Name : DefaultNotificationsConfigurationInstanceName ,
980+ Namespace : sourceNamespace ,
981+ }, sourceNotifCfg )
982+ assert .NoError (t , err )
983+ // The source namespace config should reflect the updated instance config different from sourceNotifCfg
984+ assert .NotEqual (t , customInstanceCfg .Spec .Context , sourceNotifCfg .Spec .Context )
985+ }
986+
987+ func TestReconcileNotifications_NotificationsConfigurationInSourceNamespaceWhenDisabled (t * testing.T ) {
988+ logf .SetLogger (ZapLogger (true ))
989+ sourceNamespace := "ns1"
990+ a := makeTestArgoCD (func (a * argoproj.ArgoCD ) {
991+ a .Spec .Notifications .Enabled = false
992+ a .Spec .Notifications .SourceNamespaces = []string {sourceNamespace }
993+ a .Spec .SourceNamespaces = []string {sourceNamespace }
994+ })
995+
996+ resObjs := []client.Object {a }
997+ subresObjs := []client.Object {a }
998+ runtimeObjs := []runtime.Object {}
999+ sch := makeTestReconcilerScheme (argoproj .AddToScheme )
1000+ err := v1alpha1 .AddToScheme (sch )
1001+ assert .NoError (t , err )
1002+ cl := makeTestReconcilerClient (sch , resObjs , subresObjs , runtimeObjs )
1003+ r := makeTestReconciler (cl , sch , testclient .NewSimpleClientset ())
1004+
1005+ // Create the source namespace
1006+ err = createNamespace (r , sourceNamespace , "" )
1007+ assert .NoError (t , err )
1008+
1009+ // Reconcile should not create NotificationsConfiguration CR when notifications are disabled
1010+ err = r .reconcileSourceNamespaceNotificationsConfigurationCR (a , sourceNamespace )
1011+ assert .NoError (t , err )
1012+
1013+ // Verify NotificationsConfiguration CR does not exist
1014+ notifCfg := & v1alpha1.NotificationsConfiguration {}
1015+ err = r .Get (context .TODO (), types.NamespacedName {
1016+ Name : DefaultNotificationsConfigurationInstanceName ,
1017+ Namespace : sourceNamespace ,
1018+ }, notifCfg )
1019+ assert .Error (t , err )
1020+ assert .True (t , errors .IsNotFound (err ))
1021+ }
1022+
1023+ func TestReconcileNotifications_SourceNamespaceResourcesIncludeNotificationsConfiguration (t * testing.T ) {
1024+ logf .SetLogger (ZapLogger (true ))
1025+ sourceNamespace := "ns1"
1026+ a := makeTestArgoCD (func (a * argoproj.ArgoCD ) {
1027+ a .Spec .Notifications .Enabled = true
1028+ a .Spec .Notifications .SourceNamespaces = []string {sourceNamespace }
1029+ a .Spec .SourceNamespaces = []string {sourceNamespace }
1030+ })
1031+
1032+ resObjs := []client.Object {a }
1033+ subresObjs := []client.Object {a }
1034+ runtimeObjs := []runtime.Object {}
1035+ sch := makeTestReconcilerScheme (argoproj .AddToScheme )
1036+ err := v1alpha1 .AddToScheme (sch )
1037+ assert .NoError (t , err )
1038+ cl := makeTestReconcilerClient (sch , resObjs , subresObjs , runtimeObjs )
1039+ r := makeTestReconciler (cl , sch , testclient .NewSimpleClientset ())
1040+
1041+ // Create the source namespace
1042+ err = createNamespace (r , sourceNamespace , "" )
1043+ assert .NoError (t , err )
1044+
1045+ // Reconcile source namespace resources (this should create NotificationsConfiguration CR)
1046+ err = r .reconcileNotificationsSourceNamespacesResources (a )
1047+ assert .NoError (t , err )
1048+
1049+ // Verify NotificationsConfiguration CR was created in source namespace
1050+ notifCfg := & v1alpha1.NotificationsConfiguration {}
1051+ err = r .Get (context .TODO (), types.NamespacedName {
1052+ Name : DefaultNotificationsConfigurationInstanceName ,
1053+ Namespace : sourceNamespace ,
1054+ }, notifCfg )
1055+ assert .NoError (t , err )
1056+ assert .Equal (t , DefaultNotificationsConfigurationInstanceName , notifCfg .Name )
1057+ assert .Equal (t , sourceNamespace , notifCfg .Namespace )
1058+ }
0 commit comments