github.com/argoproj-labs/argocd-operator@v0.10.0/controllers/argocd/applicationset_test.go (about)

     1  // Copyright 2021 ArgoCD Operator Developers
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  // 	http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package argocd
    16  
    17  import (
    18  	"context"
    19  	"os"
    20  	"sort"
    21  	"testing"
    22  
    23  	"github.com/google/go-cmp/cmp"
    24  	"github.com/stretchr/testify/assert"
    25  	appsv1 "k8s.io/api/apps/v1"
    26  	corev1 "k8s.io/api/core/v1"
    27  	v1 "k8s.io/api/core/v1"
    28  	rbacv1 "k8s.io/api/rbac/v1"
    29  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    30  	"k8s.io/apimachinery/pkg/runtime"
    31  	"k8s.io/apimachinery/pkg/types"
    32  	"sigs.k8s.io/controller-runtime/pkg/client"
    33  	logf "sigs.k8s.io/controller-runtime/pkg/log"
    34  
    35  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    36  	cntrlClient "sigs.k8s.io/controller-runtime/pkg/client"
    37  
    38  	argoproj "github.com/argoproj-labs/argocd-operator/api/v1beta1"
    39  	"github.com/argoproj-labs/argocd-operator/common"
    40  	"github.com/argoproj-labs/argocd-operator/controllers/argoutil"
    41  )
    42  
    43  func applicationSetDefaultVolumeMounts() []corev1.VolumeMount {
    44  	repoMounts := repoServerDefaultVolumeMounts()
    45  	ignoredMounts := map[string]bool{
    46  		"plugins":                             true,
    47  		"argocd-repo-server-tls":              true,
    48  		common.ArgoCDRedisServerTLSSecretName: true,
    49  	}
    50  	mounts := make([]corev1.VolumeMount, len(repoMounts)-len(ignoredMounts), len(repoMounts)-len(ignoredMounts))
    51  	j := 0
    52  	for _, mount := range repoMounts {
    53  		if !ignoredMounts[mount.Name] {
    54  			mounts[j] = mount
    55  			j += 1
    56  		}
    57  	}
    58  	return mounts
    59  }
    60  
    61  func applicationSetDefaultVolumes() []corev1.Volume {
    62  	repoVolumes := repoServerDefaultVolumes()
    63  	ignoredVolumes := map[string]bool{
    64  		"var-files":                           true,
    65  		"plugins":                             true,
    66  		"argocd-repo-server-tls":              true,
    67  		common.ArgoCDRedisServerTLSSecretName: true,
    68  	}
    69  	volumes := make([]corev1.Volume, len(repoVolumes)-len(ignoredVolumes), len(repoVolumes)-len(ignoredVolumes))
    70  	j := 0
    71  	for _, volume := range repoVolumes {
    72  		if !ignoredVolumes[volume.Name] {
    73  			volumes[j] = volume
    74  			j += 1
    75  		}
    76  	}
    77  	return volumes
    78  }
    79  
    80  func TestReconcileApplicationSet_CreateDeployments(t *testing.T) {
    81  	logf.SetLogger(ZapLogger(true))
    82  	a := makeTestArgoCD()
    83  	a.Spec.ApplicationSet = &argoproj.ArgoCDApplicationSet{}
    84  
    85  	resObjs := []client.Object{a}
    86  	subresObjs := []client.Object{a}
    87  	runtimeObjs := []runtime.Object{}
    88  	sch := makeTestReconcilerScheme(argoproj.AddToScheme)
    89  	cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs)
    90  	r := makeTestReconciler(cl, sch)
    91  
    92  	sa := corev1.ServiceAccount{}
    93  
    94  	assert.NoError(t, r.reconcileApplicationSetDeployment(a, &sa))
    95  
    96  	deployment := &appsv1.Deployment{}
    97  	assert.NoError(t, r.Client.Get(
    98  		context.TODO(),
    99  		types.NamespacedName{
   100  			Name:      "argocd-applicationset-controller",
   101  			Namespace: a.Namespace,
   102  		},
   103  		deployment))
   104  
   105  	// Ensure the created Deployment has the expected properties
   106  	checkExpectedDeploymentValues(t, r, deployment, &sa, a)
   107  }
   108  
   109  func checkExpectedDeploymentValues(t *testing.T, r *ReconcileArgoCD, deployment *appsv1.Deployment, sa *corev1.ServiceAccount, a *argoproj.ArgoCD) {
   110  	assert.Equal(t, deployment.Spec.Template.Spec.ServiceAccountName, sa.ObjectMeta.Name)
   111  	appsetAssertExpectedLabels(t, &deployment.ObjectMeta)
   112  
   113  	want := []corev1.Container{r.applicationSetContainer(a, false)}
   114  
   115  	if diff := cmp.Diff(want, deployment.Spec.Template.Spec.Containers); diff != "" {
   116  		t.Fatalf("failed to reconcile applicationset-controller deployment containers:\n%s", diff)
   117  	}
   118  
   119  	volumes := []corev1.Volume{
   120  		{
   121  			Name: "ssh-known-hosts",
   122  			VolumeSource: corev1.VolumeSource{
   123  				ConfigMap: &corev1.ConfigMapVolumeSource{
   124  					LocalObjectReference: corev1.LocalObjectReference{
   125  						Name: common.ArgoCDKnownHostsConfigMapName,
   126  					},
   127  				},
   128  			},
   129  		},
   130  		{
   131  			Name: "tls-certs",
   132  			VolumeSource: corev1.VolumeSource{
   133  				ConfigMap: &corev1.ConfigMapVolumeSource{
   134  					LocalObjectReference: corev1.LocalObjectReference{
   135  						Name: common.ArgoCDTLSCertsConfigMapName,
   136  					},
   137  				},
   138  			},
   139  		},
   140  		{
   141  			Name: "gpg-keys",
   142  			VolumeSource: corev1.VolumeSource{
   143  				ConfigMap: &corev1.ConfigMapVolumeSource{
   144  					LocalObjectReference: corev1.LocalObjectReference{
   145  						Name: common.ArgoCDGPGKeysConfigMapName,
   146  					},
   147  				},
   148  			},
   149  		},
   150  		{
   151  			Name: "gpg-keyring",
   152  			VolumeSource: corev1.VolumeSource{
   153  				EmptyDir: &corev1.EmptyDirVolumeSource{},
   154  			},
   155  		},
   156  		{
   157  			Name: "tmp",
   158  			VolumeSource: corev1.VolumeSource{
   159  				EmptyDir: &corev1.EmptyDirVolumeSource{},
   160  			},
   161  		},
   162  	}
   163  
   164  	if a.Spec.ApplicationSet.SCMRootCAConfigMap != "" && argoutil.IsObjectFound(r.Client, a.Namespace, common.ArgoCDAppSetGitlabSCMTLSCertsConfigMapName, a) {
   165  		volumes = append(volumes, corev1.Volume{
   166  			Name: "appset-gitlab-scm-tls-cert",
   167  			VolumeSource: corev1.VolumeSource{
   168  				ConfigMap: &corev1.ConfigMapVolumeSource{
   169  					LocalObjectReference: corev1.LocalObjectReference{
   170  						Name: common.ArgoCDAppSetGitlabSCMTLSCertsConfigMapName,
   171  					},
   172  				},
   173  			},
   174  		})
   175  	}
   176  
   177  	if diff := cmp.Diff(volumes, deployment.Spec.Template.Spec.Volumes); diff != "" {
   178  		t.Fatalf("failed to reconcile applicationset-controller deployment volumes:\n%s", diff)
   179  	}
   180  
   181  	expectedSelector := &metav1.LabelSelector{
   182  		MatchLabels: map[string]string{
   183  			common.ArgoCDKeyName: deployment.Name,
   184  		},
   185  	}
   186  
   187  	if diff := cmp.Diff(expectedSelector, deployment.Spec.Selector); diff != "" {
   188  		t.Fatalf("failed to reconcile applicationset-controller label selector:\n%s", diff)
   189  	}
   190  }
   191  
   192  func TestReconcileApplicationSetProxyConfiguration(t *testing.T) {
   193  	logf.SetLogger(ZapLogger(true))
   194  
   195  	// Proxy Env vars
   196  	setProxyEnvVars(t)
   197  
   198  	a := makeTestArgoCD()
   199  	a.Spec.ApplicationSet = &argoproj.ArgoCDApplicationSet{}
   200  
   201  	resObjs := []client.Object{a}
   202  	subresObjs := []client.Object{a}
   203  	runtimeObjs := []runtime.Object{}
   204  	sch := makeTestReconcilerScheme(argoproj.AddToScheme)
   205  	cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs)
   206  	r := makeTestReconciler(cl, sch)
   207  
   208  	sa := corev1.ServiceAccount{}
   209  
   210  	r.reconcileApplicationSetDeployment(a, &sa)
   211  
   212  	want := []corev1.EnvVar{
   213  		{
   214  			Name:  "HTTPS_PROXY",
   215  			Value: "https://example.com",
   216  		},
   217  		{
   218  			Name:  "HTTP_PROXY",
   219  			Value: "http://example.com",
   220  		},
   221  		{
   222  			Name: "NAMESPACE",
   223  			ValueFrom: &corev1.EnvVarSource{
   224  				FieldRef: &corev1.ObjectFieldSelector{
   225  					FieldPath: "metadata.namespace",
   226  				},
   227  			},
   228  		},
   229  		{
   230  			Name:  "NO_PROXY",
   231  			Value: ".cluster.local",
   232  		},
   233  	}
   234  
   235  	deployment := &appsv1.Deployment{}
   236  
   237  	// reconcile ApplicationSets
   238  	r.Client.Get(
   239  		context.TODO(),
   240  		types.NamespacedName{
   241  			Name:      "argocd-applicationset-controller",
   242  			Namespace: a.Namespace,
   243  		},
   244  		deployment)
   245  
   246  	if diff := cmp.Diff(want, deployment.Spec.Template.Spec.Containers[0].Env); diff != "" {
   247  		t.Fatalf("failed to reconcile applicationset-controller deployment containers:\n%s", diff)
   248  	}
   249  
   250  }
   251  
   252  func TestReconcileApplicationSet_UpdateExistingDeployments(t *testing.T) {
   253  	logf.SetLogger(ZapLogger(true))
   254  	a := makeTestArgoCD()
   255  
   256  	a.Spec.ApplicationSet = &argoproj.ArgoCDApplicationSet{}
   257  
   258  	existingDeployment := &appsv1.Deployment{
   259  		ObjectMeta: metav1.ObjectMeta{
   260  			Name:      a.Name + "-applicationset-controller",
   261  			Namespace: a.Namespace,
   262  		},
   263  		Spec: appsv1.DeploymentSpec{
   264  			Template: corev1.PodTemplateSpec{
   265  				Spec: corev1.PodSpec{
   266  					Containers: []corev1.Container{
   267  						{
   268  							Name: "fake-container",
   269  						},
   270  					},
   271  				},
   272  			},
   273  		},
   274  	}
   275  
   276  	resObjs := []client.Object{a, existingDeployment}
   277  	subresObjs := []client.Object{a, existingDeployment}
   278  	runtimeObjs := []runtime.Object{}
   279  	sch := makeTestReconcilerScheme(argoproj.AddToScheme)
   280  	cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs)
   281  	r := makeTestReconciler(cl, sch)
   282  
   283  	sa := corev1.ServiceAccount{}
   284  
   285  	assert.NoError(t, r.reconcileApplicationSetDeployment(a, &sa))
   286  
   287  	deployment := &appsv1.Deployment{}
   288  	assert.NoError(t, r.Client.Get(
   289  		context.TODO(),
   290  		types.NamespacedName{
   291  			Name:      "argocd-applicationset-controller",
   292  			Namespace: a.Namespace,
   293  		},
   294  		deployment))
   295  
   296  	// Ensure the updated Deployment has the expected properties
   297  	checkExpectedDeploymentValues(t, r, deployment, &sa, a)
   298  
   299  }
   300  
   301  func TestReconcileApplicationSet_Deployments_resourceRequirements(t *testing.T) {
   302  	logf.SetLogger(ZapLogger(true))
   303  	a := makeTestArgoCDWithResources()
   304  
   305  	resObjs := []client.Object{a}
   306  	subresObjs := []client.Object{a}
   307  	runtimeObjs := []runtime.Object{}
   308  	sch := makeTestReconcilerScheme(argoproj.AddToScheme)
   309  	cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs)
   310  	r := makeTestReconciler(cl, sch)
   311  
   312  	sa := corev1.ServiceAccount{}
   313  
   314  	assert.NoError(t, r.reconcileApplicationSetDeployment(a, &sa))
   315  
   316  	deployment := &appsv1.Deployment{}
   317  	assert.NoError(t, r.Client.Get(
   318  		context.TODO(),
   319  		types.NamespacedName{
   320  			Name:      "argocd-applicationset-controller",
   321  			Namespace: a.Namespace,
   322  		},
   323  		deployment))
   324  
   325  	assert.Equal(t, deployment.Spec.Template.Spec.ServiceAccountName, sa.ObjectMeta.Name)
   326  	appsetAssertExpectedLabels(t, &deployment.ObjectMeta)
   327  
   328  	containerWant := []corev1.Container{r.applicationSetContainer(a, false)}
   329  
   330  	if diff := cmp.Diff(containerWant, deployment.Spec.Template.Spec.Containers); diff != "" {
   331  		t.Fatalf("failed to reconcile argocd-server deployment:\n%s", diff)
   332  	}
   333  
   334  	volumesWant := applicationSetDefaultVolumes()
   335  
   336  	if diff := cmp.Diff(volumesWant, deployment.Spec.Template.Spec.Volumes); diff != "" {
   337  		t.Fatalf("failed to reconcile argocd-server deployment:\n%s", diff)
   338  	}
   339  }
   340  
   341  func TestReconcileApplicationSet_Deployments_SpecOverride(t *testing.T) {
   342  	logf.SetLogger(ZapLogger(true))
   343  
   344  	tests := []struct {
   345  		name                   string
   346  		appSetField            *argoproj.ArgoCDApplicationSet
   347  		envVars                map[string]string
   348  		expectedContainerImage string
   349  	}{
   350  		{
   351  			name:                   "unspecified fields should use default",
   352  			appSetField:            &argoproj.ArgoCDApplicationSet{},
   353  			expectedContainerImage: argoutil.CombineImageTag(common.ArgoCDDefaultArgoImage, common.ArgoCDDefaultArgoVersion),
   354  		},
   355  		{
   356  			name: "ensure that sha hashes are formatted correctly",
   357  			appSetField: &argoproj.ArgoCDApplicationSet{
   358  				Image:   "custom-image",
   359  				Version: "sha256:b835999eb5cf75d01a2678cd971095926d9c2566c9ffe746d04b83a6a0a2849f",
   360  			},
   361  			expectedContainerImage: "custom-image@sha256:b835999eb5cf75d01a2678cd971095926d9c2566c9ffe746d04b83a6a0a2849f",
   362  		},
   363  		{
   364  			name: "custom image should properly substitute",
   365  			appSetField: &argoproj.ArgoCDApplicationSet{
   366  				Image:   "custom-image",
   367  				Version: "custom-version",
   368  			},
   369  			expectedContainerImage: "custom-image:custom-version",
   370  		},
   371  		{
   372  			name:                   "verify env var substitution overrides default",
   373  			appSetField:            &argoproj.ArgoCDApplicationSet{},
   374  			envVars:                map[string]string{common.ArgoCDImageEnvName: "custom-env-image"},
   375  			expectedContainerImage: "custom-env-image",
   376  		},
   377  
   378  		{
   379  			name: "env var should not override spec fields",
   380  			appSetField: &argoproj.ArgoCDApplicationSet{
   381  				Image:   "custom-image",
   382  				Version: "custom-version",
   383  			},
   384  			envVars:                map[string]string{common.ArgoCDImageEnvName: "custom-env-image"},
   385  			expectedContainerImage: "custom-image:custom-version",
   386  		},
   387  		{
   388  			name: "ensure scm tls cert mount is present",
   389  			appSetField: &argoproj.ArgoCDApplicationSet{
   390  				SCMRootCAConfigMap: "test-scm-tls-mount",
   391  			},
   392  			envVars:                map[string]string{common.ArgoCDImageEnvName: "custom-env-image"},
   393  			expectedContainerImage: "custom-env-image",
   394  		},
   395  	}
   396  
   397  	for _, test := range tests {
   398  		t.Run(test.name, func(t *testing.T) {
   399  
   400  			for testEnvName, testEnvValue := range test.envVars {
   401  				t.Setenv(testEnvName, testEnvValue)
   402  			}
   403  
   404  			a := makeTestArgoCD()
   405  			resObjs := []client.Object{a}
   406  			subresObjs := []client.Object{a}
   407  			runtimeObjs := []runtime.Object{}
   408  			sch := makeTestReconcilerScheme(argoproj.AddToScheme)
   409  			cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs)
   410  			r := makeTestReconciler(cl, sch)
   411  			cm := newConfigMapWithName(getCAConfigMapName(a), a)
   412  			r.Client.Create(context.Background(), cm, &client.CreateOptions{})
   413  
   414  			a.Spec.ApplicationSet = test.appSetField
   415  
   416  			sa := corev1.ServiceAccount{}
   417  			assert.NoError(t, r.reconcileApplicationSetDeployment(a, &sa))
   418  
   419  			deployment := &appsv1.Deployment{}
   420  			assert.NoError(t, r.Client.Get(
   421  				context.TODO(),
   422  				types.NamespacedName{
   423  					Name:      "argocd-applicationset-controller",
   424  					Namespace: a.Namespace,
   425  				},
   426  				deployment))
   427  
   428  			specImage := deployment.Spec.Template.Spec.Containers[0].Image
   429  			assert.Equal(t, test.expectedContainerImage, specImage)
   430  			checkExpectedDeploymentValues(t, r, deployment, &sa, a)
   431  		})
   432  	}
   433  
   434  }
   435  
   436  func TestReconcileApplicationSet_Deployments_Command(t *testing.T) {
   437  	logf.SetLogger(ZapLogger(true))
   438  
   439  	tests := []struct {
   440  		name           string
   441  		argocdSpec     argoproj.ArgoCDSpec
   442  		expectedCmd    []string
   443  		notExpectedCmd []string
   444  	}{
   445  		{
   446  			name: "Appset in any namespaces without scm provider list",
   447  			argocdSpec: argoproj.ArgoCDSpec{
   448  				ApplicationSet: &argoproj.ArgoCDApplicationSet{
   449  					SourceNamespaces: []string{"foo", "bar"},
   450  				},
   451  				SourceNamespaces: []string{"foo", "bar"},
   452  			},
   453  			expectedCmd: []string{"--applicationset-namespaces", "foo,bar", "--enable-scm-providers=false"},
   454  		},
   455  		{
   456  			name: "with SCM provider list",
   457  			argocdSpec: argoproj.ArgoCDSpec{
   458  				ApplicationSet: &argoproj.ArgoCDApplicationSet{
   459  					SourceNamespaces: []string{"foo"},
   460  					SCMProviders:     []string{"github.com"},
   461  				},
   462  				SourceNamespaces: []string{"foo", "bar"},
   463  			},
   464  			expectedCmd: []string{"--applicationset-namespaces", "foo", "--allowed-scm-providers", "github.com"},
   465  		},
   466  		{
   467  			name: "Appsets namespaces without Apps namespaces",
   468  			argocdSpec: argoproj.ArgoCDSpec{
   469  				ApplicationSet: &argoproj.ArgoCDApplicationSet{
   470  					SourceNamespaces: []string{"foo"},
   471  					SCMProviders:     []string{"github.com"},
   472  				},
   473  				SourceNamespaces: []string{},
   474  			},
   475  			expectedCmd:    []string{"--allowed-scm-providers", "github.com"},
   476  			notExpectedCmd: []string{"--applicationset-namespaces", "foo"},
   477  		},
   478  	}
   479  
   480  	for _, test := range tests {
   481  		t.Run(test.name, func(t *testing.T) {
   482  
   483  			a := makeTestArgoCD()
   484  			ns1 := v1.Namespace{
   485  				ObjectMeta: metav1.ObjectMeta{
   486  					Name: "foo",
   487  				},
   488  			}
   489  			ns2 := v1.Namespace{
   490  				ObjectMeta: metav1.ObjectMeta{
   491  					Name: "bar",
   492  				},
   493  			}
   494  			resObjs := []client.Object{a, &ns1, &ns2}
   495  			subresObjs := []client.Object{a}
   496  			runtimeObjs := []runtime.Object{}
   497  			sch := makeTestReconcilerScheme(argoproj.AddToScheme)
   498  			cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs)
   499  			r := makeTestReconciler(cl, sch)
   500  			cm := newConfigMapWithName(getCAConfigMapName(a), a)
   501  			r.Client.Create(context.Background(), cm, &client.CreateOptions{})
   502  
   503  			a.Spec = test.argocdSpec
   504  
   505  			sa := corev1.ServiceAccount{}
   506  			assert.NoError(t, r.reconcileApplicationSetDeployment(a, &sa))
   507  
   508  			deployment := &appsv1.Deployment{}
   509  			assert.NoError(t, r.Client.Get(
   510  				context.TODO(),
   511  				types.NamespacedName{
   512  					Name:      "argocd-applicationset-controller",
   513  					Namespace: a.Namespace,
   514  				},
   515  				deployment))
   516  
   517  			cmds := deployment.Spec.Template.Spec.Containers[0].Command
   518  			for _, c := range test.expectedCmd {
   519  				assert.True(t, contains(cmds, c))
   520  			}
   521  			for _, c := range test.notExpectedCmd {
   522  				assert.False(t, contains(cmds, c))
   523  			}
   524  		})
   525  	}
   526  }
   527  
   528  func TestReconcileApplicationSet_ServiceAccount(t *testing.T) {
   529  	logf.SetLogger(ZapLogger(true))
   530  	a := makeTestArgoCD()
   531  	resObjs := []client.Object{a}
   532  	subresObjs := []client.Object{a}
   533  	runtimeObjs := []runtime.Object{}
   534  	sch := makeTestReconcilerScheme(argoproj.AddToScheme)
   535  	cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs)
   536  	r := makeTestReconciler(cl, sch)
   537  
   538  	a.Spec.ApplicationSet = &argoproj.ArgoCDApplicationSet{
   539  		Enabled: boolPtr(true),
   540  	}
   541  
   542  	retSa, err := r.reconcileApplicationSetServiceAccount(a)
   543  	assert.NoError(t, err)
   544  
   545  	sa := &corev1.ServiceAccount{}
   546  	assert.NoError(t, r.Client.Get(
   547  		context.TODO(),
   548  		types.NamespacedName{
   549  			Name:      "argocd-applicationset-controller",
   550  			Namespace: a.Namespace,
   551  		},
   552  		sa))
   553  
   554  	assert.Equal(t, sa.Name, retSa.Name)
   555  
   556  	appsetAssertExpectedLabels(t, &sa.ObjectMeta)
   557  }
   558  
   559  // Test creation/cleanup of applicationset-controller clusterrole & clusterrolebinding
   560  func TestReconcileApplicationSet_ClusterRBACCreationAndCleanup(t *testing.T) {
   561  	logf.SetLogger(ZapLogger(true))
   562  	a := makeTestArgoCD()
   563  
   564  	resName := "argocd-argocd-argocd-applicationset-controller"
   565  
   566  	resObjs := []client.Object{a}
   567  	subresObjs := []client.Object{a}
   568  	runtimeObjs := []runtime.Object{}
   569  	sch := makeTestReconcilerScheme(argoproj.AddToScheme)
   570  	cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs)
   571  	r := makeTestReconciler(cl, sch)
   572  
   573  	a.Spec.ApplicationSet = &argoproj.ArgoCDApplicationSet{
   574  		Enabled: boolPtr(true),
   575  	}
   576  
   577  	sa := &corev1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Name: "sa-name"}}
   578  
   579  	// test: ArgoCD is not cluster-scoped, resources shouldn't be created
   580  	role, err := r.reconcileApplicationSetClusterRole(a)
   581  	assert.NoError(t, err)
   582  	err = r.reconcileApplicationSetClusterRoleBinding(a, role, sa)
   583  	assert.NoError(t, err)
   584  
   585  	// clusterrole should not be created
   586  	cr := &rbacv1.ClusterRole{}
   587  	err = r.Client.Get(context.TODO(), cntrlClient.ObjectKey{Name: resName}, cr)
   588  	assert.Error(t, err)
   589  	assert.True(t, apierrors.IsNotFound(err))
   590  
   591  	// clusterrolebinding should not be created
   592  	crb := &rbacv1.ClusterRoleBinding{}
   593  	err = r.Client.Get(context.TODO(), cntrlClient.ObjectKey{Name: resName}, crb)
   594  	assert.Error(t, err)
   595  	assert.True(t, apierrors.IsNotFound(err))
   596  
   597  	// test: make ArgoCD cluster-scoped, resources should be created
   598  	os.Setenv("ARGOCD_CLUSTER_CONFIG_NAMESPACES", a.Namespace)
   599  
   600  	role, err = r.reconcileApplicationSetClusterRole(a)
   601  	assert.NoError(t, err)
   602  	err = r.reconcileApplicationSetClusterRoleBinding(a, role, sa)
   603  	assert.NoError(t, err)
   604  
   605  	// clusterrole should be created
   606  	cr = &rbacv1.ClusterRole{}
   607  	err = r.Client.Get(context.TODO(), cntrlClient.ObjectKey{Name: resName}, cr)
   608  	assert.NoError(t, err)
   609  
   610  	// clusterrolebinding should be created
   611  	crb = &rbacv1.ClusterRoleBinding{}
   612  	err = r.Client.Get(context.TODO(), cntrlClient.ObjectKey{Name: resName}, crb)
   613  	assert.NoError(t, err)
   614  	assert.Equal(t, crb.RoleRef.Name, cr.Name)
   615  	assert.Equal(t, crb.Subjects[0].Name, sa.Name)
   616  
   617  	// test: make ArgoCD namespaced-scope, existing resources should be deleted
   618  	os.Setenv("ARGOCD_CLUSTER_CONFIG_NAMESPACES", "")
   619  	role, err = r.reconcileApplicationSetClusterRole(a)
   620  	assert.NoError(t, err)
   621  	err = r.reconcileApplicationSetClusterRoleBinding(a, role, sa)
   622  	assert.NoError(t, err)
   623  
   624  	// clusterrole should not exists
   625  	cr = &rbacv1.ClusterRole{}
   626  	err = r.Client.Get(context.TODO(), cntrlClient.ObjectKey{Name: resName}, cr)
   627  	assert.Error(t, err)
   628  	assert.True(t, apierrors.IsNotFound(err))
   629  
   630  	// clusterrolebinding should not exists
   631  	crb = &rbacv1.ClusterRoleBinding{}
   632  	err = r.Client.Get(context.TODO(), cntrlClient.ObjectKey{Name: resName}, crb)
   633  	assert.Error(t, err)
   634  	assert.True(t, apierrors.IsNotFound(err))
   635  }
   636  
   637  // Test creation/cleanup of applicationset-controller role & rolebinding in source namespaces
   638  // Appset resources are only created if target source ns is subset of apps source namespaces
   639  func TestReconcileApplicationSet_SourceNamespacesRBACCreation(t *testing.T) {
   640  	logf.SetLogger(ZapLogger(true))
   641  
   642  	tests := []struct {
   643  		name         string
   644  		argoCDSpec   argoproj.ArgoCDSpec
   645  		expectErr    bool
   646  		existInNs    []string
   647  		notExistInNs []string
   648  	}{
   649  		{
   650  			name: "No appset & app source namespaces", // no resources should be created
   651  			argoCDSpec: argoproj.ArgoCDSpec{
   652  				ApplicationSet:   nil,
   653  				SourceNamespaces: []string(nil),
   654  			},
   655  			expectErr: false,
   656  		},
   657  		{
   658  			name: "appset source ns not subset of app source ns", // resources shouldn't be created in allowed namespaces
   659  			argoCDSpec: argoproj.ArgoCDSpec{
   660  				ApplicationSet: &argoproj.ArgoCDApplicationSet{
   661  					SourceNamespaces: []string{"foo", "bar"},
   662  				},
   663  				SourceNamespaces: []string(nil),
   664  			},
   665  			expectErr:    false,
   666  			existInNs:    []string{},
   667  			notExistInNs: []string{"foo", "bar"},
   668  		},
   669  		{
   670  			name: "appset source ns subset of app source ns ", // resources should be created is all appset ns
   671  			argoCDSpec: argoproj.ArgoCDSpec{
   672  				ApplicationSet: &argoproj.ArgoCDApplicationSet{
   673  					SourceNamespaces: []string{"foo", "bar"},
   674  				},
   675  				SourceNamespaces: []string{"foo", "bar"},
   676  			},
   677  			expectErr:    false,
   678  			existInNs:    []string{"foo", "bar"},
   679  			notExistInNs: []string{},
   680  		},
   681  		{
   682  			name: "appset source ns partial subset of app source ns ", // resources should be created only in ns part of app source ns
   683  			argoCDSpec: argoproj.ArgoCDSpec{
   684  				ApplicationSet: &argoproj.ArgoCDApplicationSet{
   685  					SourceNamespaces: []string{"foo", "bar"},
   686  				},
   687  				SourceNamespaces: []string{"foo"},
   688  			},
   689  			expectErr:    false,
   690  			existInNs:    []string{"foo"},
   691  			notExistInNs: []string{"bar"},
   692  		},
   693  	}
   694  
   695  	for _, test := range tests {
   696  		t.Run(test.name, func(t *testing.T) {
   697  
   698  			a := makeTestArgoCD()
   699  			resObjs := []client.Object{a}
   700  			subresObjs := []client.Object{a}
   701  			runtimeObjs := []runtime.Object{}
   702  			sch := makeTestReconcilerScheme(argoproj.AddToScheme)
   703  			cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs)
   704  			r := makeTestReconciler(cl, sch)
   705  			a.Spec = test.argoCDSpec
   706  
   707  			for _, ns := range append(test.existInNs, test.notExistInNs...) {
   708  				createNamespace(r, ns, "")
   709  			}
   710  
   711  			err := r.reconcileApplicationSetSourceNamespacesResources(a)
   712  			if test.expectErr {
   713  				assert.Error(t, err)
   714  			}
   715  
   716  			// resources for applicationset-controller should be created in target ns
   717  			for _, ns := range test.existInNs {
   718  				resName := getResourceNameForApplicationSetSourceNamespaces(a)
   719  
   720  				role := &rbacv1.Role{}
   721  				err = r.Client.Get(context.TODO(), cntrlClient.ObjectKey{Name: resName, Namespace: ns}, role)
   722  				assert.NoError(t, err)
   723  
   724  				roleBinding := &rbacv1.RoleBinding{}
   725  				err = r.Client.Get(context.TODO(), cntrlClient.ObjectKey{Name: resName, Namespace: ns}, roleBinding)
   726  				assert.NoError(t, err)
   727  			}
   728  
   729  			// appset tracker label should be added on the target namespace
   730  			for _, ns := range test.existInNs {
   731  				namespace := &v1.Namespace{}
   732  				err = r.Client.Get(context.TODO(), cntrlClient.ObjectKey{Name: ns}, namespace)
   733  				assert.NoError(t, err)
   734  				val, found := namespace.Labels[common.ArgoCDApplicationSetManagedByClusterArgoCDLabel]
   735  				assert.True(t, found)
   736  				assert.Equal(t, a.Namespace, val)
   737  			}
   738  
   739  			// resources for applicationset-controller shouldn't be created in target ns
   740  			for _, ns := range test.notExistInNs {
   741  				resName := getResourceNameForApplicationSetSourceNamespaces(a)
   742  
   743  				role := &rbacv1.Role{}
   744  				err = r.Client.Get(context.TODO(), cntrlClient.ObjectKey{Name: resName, Namespace: ns}, role)
   745  				assert.Error(t, err)
   746  				assert.True(t, apierrors.IsNotFound(err))
   747  
   748  				roleBinding := &rbacv1.RoleBinding{}
   749  				err = r.Client.Get(context.TODO(), cntrlClient.ObjectKey{Name: resName, Namespace: ns}, roleBinding)
   750  				assert.Error(t, err)
   751  				assert.True(t, apierrors.IsNotFound(err))
   752  			}
   753  
   754  			// appset tracker label shouldn't be added on the target namespace
   755  			for _, ns := range test.notExistInNs {
   756  				namespace := &v1.Namespace{}
   757  				err = r.Client.Get(context.TODO(), cntrlClient.ObjectKey{Name: ns}, namespace)
   758  				assert.NoError(t, err)
   759  				_, found := namespace.Labels[common.ArgoCDApplicationSetManagedByClusterArgoCDLabel]
   760  				assert.False(t, found)
   761  			}
   762  
   763  		})
   764  	}
   765  }
   766  
   767  func TestReconcileApplicationSet_Role(t *testing.T) {
   768  	logf.SetLogger(ZapLogger(true))
   769  	a := makeTestArgoCD()
   770  
   771  	resObjs := []client.Object{a}
   772  	subresObjs := []client.Object{a}
   773  	runtimeObjs := []runtime.Object{}
   774  	sch := makeTestReconcilerScheme(argoproj.AddToScheme)
   775  	cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs)
   776  	r := makeTestReconciler(cl, sch)
   777  
   778  	a.Spec.ApplicationSet = &argoproj.ArgoCDApplicationSet{
   779  		Enabled: boolPtr(true),
   780  	}
   781  
   782  	roleRet, err := r.reconcileApplicationSetRole(a)
   783  	assert.NoError(t, err)
   784  
   785  	role := &rbacv1.Role{}
   786  	assert.NoError(t, r.Client.Get(
   787  		context.TODO(),
   788  		types.NamespacedName{
   789  			Name:      "argocd-applicationset-controller",
   790  			Namespace: a.Namespace,
   791  		},
   792  		role))
   793  
   794  	assert.Equal(t, roleRet.Name, role.Name)
   795  	appsetAssertExpectedLabels(t, &role.ObjectMeta)
   796  
   797  	expectedResources := []string{
   798  		"deployments",
   799  		"secrets",
   800  		"configmaps",
   801  		"events",
   802  		"applicationsets/status",
   803  		"applications",
   804  		"applicationsets",
   805  		"appprojects",
   806  		"applicationsets/finalizers",
   807  		"leases",
   808  	}
   809  
   810  	foundResources := []string{}
   811  
   812  	for _, rule := range role.Rules {
   813  		for _, resource := range rule.Resources {
   814  			foundResources = append(foundResources, resource)
   815  		}
   816  	}
   817  
   818  	sort.Strings(expectedResources)
   819  	sort.Strings(foundResources)
   820  
   821  	assert.Equal(t, expectedResources, foundResources)
   822  }
   823  
   824  func TestReconcileApplicationSet_RoleBinding(t *testing.T) {
   825  	logf.SetLogger(ZapLogger(true))
   826  	a := makeTestArgoCD()
   827  
   828  	resObjs := []client.Object{a}
   829  	subresObjs := []client.Object{a}
   830  	runtimeObjs := []runtime.Object{}
   831  	sch := makeTestReconcilerScheme(argoproj.AddToScheme)
   832  	cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs)
   833  	r := makeTestReconciler(cl, sch)
   834  
   835  	a.Spec.ApplicationSet = &argoproj.ArgoCDApplicationSet{
   836  		Enabled: boolPtr(true),
   837  	}
   838  
   839  	role := &rbacv1.Role{ObjectMeta: metav1.ObjectMeta{Name: "role-name"}}
   840  	sa := &corev1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Name: "sa-name"}}
   841  
   842  	err := r.reconcileApplicationSetRoleBinding(a, role, sa)
   843  	assert.NoError(t, err)
   844  
   845  	roleBinding := &rbacv1.RoleBinding{}
   846  	assert.NoError(t, r.Client.Get(
   847  		context.TODO(),
   848  		types.NamespacedName{
   849  			Name:      "argocd-applicationset-controller",
   850  			Namespace: a.Namespace,
   851  		},
   852  		roleBinding))
   853  
   854  	appsetAssertExpectedLabels(t, &roleBinding.ObjectMeta)
   855  
   856  	assert.Equal(t, roleBinding.RoleRef.Name, role.Name)
   857  	assert.Equal(t, roleBinding.Subjects[0].Name, sa.Name)
   858  
   859  }
   860  
   861  func appsetAssertExpectedLabels(t *testing.T, meta *metav1.ObjectMeta) {
   862  	assert.Equal(t, meta.Labels["app.kubernetes.io/name"], "argocd-applicationset-controller")
   863  	assert.Equal(t, meta.Labels["app.kubernetes.io/part-of"], "argocd-applicationset")
   864  	assert.Equal(t, meta.Labels["app.kubernetes.io/component"], "controller")
   865  }
   866  
   867  func setProxyEnvVars(t *testing.T) {
   868  	t.Setenv("HTTPS_PROXY", "https://example.com")
   869  	t.Setenv("HTTP_PROXY", "http://example.com")
   870  	t.Setenv("NO_PROXY", ".cluster.local")
   871  }
   872  
   873  func TestReconcileApplicationSet_Service(t *testing.T) {
   874  	logf.SetLogger(ZapLogger(true))
   875  	a := makeTestArgoCD()
   876  	a.Spec.ApplicationSet = &argoproj.ArgoCDApplicationSet{}
   877  
   878  	resObjs := []client.Object{a}
   879  	subresObjs := []client.Object{a}
   880  	runtimeObjs := []runtime.Object{}
   881  	sch := makeTestReconcilerScheme(argoproj.AddToScheme)
   882  	cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs)
   883  	r := makeTestReconciler(cl, sch)
   884  
   885  	s := newServiceWithSuffix(common.ApplicationSetServiceNameSuffix, common.ApplicationSetServiceNameSuffix, a)
   886  
   887  	assert.NoError(t, r.reconcileApplicationSetService(a))
   888  	assert.NoError(t, r.Client.Get(context.TODO(), types.NamespacedName{Namespace: s.Namespace, Name: s.Name}, s))
   889  }
   890  
   891  func TestArgoCDApplicationSetCommand(t *testing.T) {
   892  	a := makeTestArgoCD()
   893  	a.Spec.ApplicationSet = &argoproj.ArgoCDApplicationSet{}
   894  
   895  	resObjs := []client.Object{a}
   896  	subresObjs := []client.Object{a}
   897  	runtimeObjs := []runtime.Object{}
   898  	sch := makeTestReconcilerScheme(argoproj.AddToScheme)
   899  	cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs)
   900  	r := makeTestReconciler(cl, sch)
   901  
   902  	baseCommand := []string{
   903  		"entrypoint.sh",
   904  		"argocd-applicationset-controller",
   905  		"--argocd-repo-server",
   906  		"argocd-repo-server.argocd.svc.cluster.local:8081",
   907  		"--loglevel",
   908  		"info",
   909  	}
   910  
   911  	// When a single command argument is passed
   912  	a.Spec.ApplicationSet.ExtraCommandArgs = []string{
   913  		"--foo",
   914  		"bar",
   915  	}
   916  
   917  	deployment := &appsv1.Deployment{}
   918  	assert.NoError(t, r.reconcileApplicationSetController(a))
   919  
   920  	assert.NoError(t, r.Client.Get(
   921  		context.TODO(),
   922  		types.NamespacedName{
   923  			Name:      "argocd-applicationset-controller",
   924  			Namespace: a.Namespace,
   925  		},
   926  		deployment))
   927  
   928  	cmd := append(baseCommand, "--foo", "bar")
   929  	assert.Equal(t, cmd, deployment.Spec.Template.Spec.Containers[0].Command)
   930  
   931  	// When multiple command arguments are passed
   932  	a.Spec.ApplicationSet.ExtraCommandArgs = []string{
   933  		"--foo",
   934  		"bar",
   935  		"--ping",
   936  		"pong",
   937  		"test",
   938  	}
   939  
   940  	assert.NoError(t, r.reconcileApplicationSetController(a))
   941  	assert.NoError(t, r.Client.Get(
   942  		context.TODO(),
   943  		types.NamespacedName{
   944  			Name:      "argocd-applicationset-controller",
   945  			Namespace: a.Namespace,
   946  		},
   947  		deployment))
   948  
   949  	cmd = append(cmd, "--ping", "pong", "test")
   950  	assert.Equal(t, cmd, deployment.Spec.Template.Spec.Containers[0].Command)
   951  
   952  	// When one of the ExtraCommandArgs already exists in cmd with same or different value
   953  	a.Spec.ApplicationSet.ExtraCommandArgs = []string{
   954  		"--argocd-repo-server",
   955  		"foo.scv.cluster.local:6379",
   956  	}
   957  
   958  	assert.NoError(t, r.reconcileApplicationSetController(a))
   959  	assert.NoError(t, r.Client.Get(
   960  		context.TODO(),
   961  		types.NamespacedName{
   962  			Name:      "argocd-applicationset-controller",
   963  			Namespace: a.Namespace,
   964  		},
   965  		deployment))
   966  
   967  	assert.Equal(t, baseCommand, deployment.Spec.Template.Spec.Containers[0].Command)
   968  
   969  	// Remove all the command arguments that were added.
   970  	a.Spec.ApplicationSet.ExtraCommandArgs = []string{}
   971  
   972  	assert.NoError(t, r.reconcileApplicationSetController(a))
   973  	assert.NoError(t, r.Client.Get(
   974  		context.TODO(),
   975  		types.NamespacedName{
   976  			Name:      "argocd-applicationset-controller",
   977  			Namespace: a.Namespace,
   978  		},
   979  		deployment))
   980  
   981  	assert.Equal(t, baseCommand, deployment.Spec.Template.Spec.Containers[0].Command)
   982  }
   983  
   984  func TestArgoCDApplicationSetEnv(t *testing.T) {
   985  	a := makeTestArgoCD()
   986  	a.Spec.ApplicationSet = &argoproj.ArgoCDApplicationSet{}
   987  
   988  	resObjs := []client.Object{a}
   989  	subresObjs := []client.Object{a}
   990  	runtimeObjs := []runtime.Object{}
   991  	sch := makeTestReconcilerScheme(argoproj.AddToScheme)
   992  	cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs)
   993  	r := makeTestReconciler(cl, sch)
   994  
   995  	defaultEnv := []corev1.EnvVar{
   996  		{
   997  			Name: "NAMESPACE",
   998  			ValueFrom: &corev1.EnvVarSource{
   999  				FieldRef: &corev1.ObjectFieldSelector{
  1000  					APIVersion: "",
  1001  					FieldPath:  "metadata.namespace",
  1002  				},
  1003  			},
  1004  		},
  1005  	}
  1006  
  1007  	// Pass an environment variable using Argo CD CR.
  1008  	customEnv := []corev1.EnvVar{
  1009  		{
  1010  			Name:  "foo",
  1011  			Value: "bar",
  1012  		},
  1013  	}
  1014  	a.Spec.ApplicationSet.Env = customEnv
  1015  
  1016  	deployment := &appsv1.Deployment{}
  1017  	assert.NoError(t, r.reconcileApplicationSetController(a))
  1018  
  1019  	assert.NoError(t, r.Client.Get(
  1020  		context.TODO(),
  1021  		types.NamespacedName{
  1022  			Name:      "argocd-applicationset-controller",
  1023  			Namespace: a.Namespace,
  1024  		},
  1025  		deployment))
  1026  
  1027  	expectedEnv := append(defaultEnv, customEnv...)
  1028  	assert.Equal(t, expectedEnv, deployment.Spec.Template.Spec.Containers[0].Env)
  1029  
  1030  	// Remove all the env vars that were added.
  1031  	a.Spec.ApplicationSet.Env = []corev1.EnvVar{}
  1032  
  1033  	assert.NoError(t, r.reconcileApplicationSetController(a))
  1034  	assert.NoError(t, r.Client.Get(
  1035  		context.TODO(),
  1036  		types.NamespacedName{
  1037  			Name:      "argocd-applicationset-controller",
  1038  			Namespace: a.Namespace,
  1039  		},
  1040  		deployment))
  1041  
  1042  	assert.Equal(t, defaultEnv, deployment.Spec.Template.Spec.Containers[0].Env)
  1043  }
  1044  
  1045  func TestArgoCDApplicationSet_getApplicationSetSourceNamespaces(t *testing.T) {
  1046  	logf.SetLogger(ZapLogger(true))
  1047  
  1048  	tests := []struct {
  1049  		name        string
  1050  		appSetField *argoproj.ArgoCDApplicationSet
  1051  		expected    []string
  1052  	}{
  1053  		{
  1054  			name:        "Appsets not enabled",
  1055  			appSetField: nil,
  1056  			expected:    []string(nil),
  1057  		},
  1058  		{
  1059  			name: "No appset source namespaces",
  1060  			appSetField: &argoproj.ArgoCDApplicationSet{
  1061  				Enabled: boolPtr(true),
  1062  			},
  1063  			expected: []string(nil),
  1064  		},
  1065  		{
  1066  			name: "Appset source namespaces",
  1067  			appSetField: &argoproj.ArgoCDApplicationSet{
  1068  				SourceNamespaces: []string{"foo", "bar"},
  1069  			},
  1070  			expected: []string{"foo", "bar"},
  1071  		},
  1072  	}
  1073  
  1074  	for _, test := range tests {
  1075  		t.Run(test.name, func(t *testing.T) {
  1076  
  1077  			a := makeTestArgoCD()
  1078  			resObjs := []client.Object{a}
  1079  			subresObjs := []client.Object{a}
  1080  			runtimeObjs := []runtime.Object{}
  1081  			sch := makeTestReconcilerScheme(argoproj.AddToScheme)
  1082  			cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs)
  1083  			r := makeTestReconciler(cl, sch)
  1084  			cm := newConfigMapWithName(getCAConfigMapName(a), a)
  1085  			r.Client.Create(context.Background(), cm, &client.CreateOptions{})
  1086  
  1087  			a.Spec.ApplicationSet = test.appSetField
  1088  
  1089  			actual := r.getApplicationSetSourceNamespaces(a)
  1090  			assert.Equal(t, test.expected, actual)
  1091  		})
  1092  	}
  1093  }
  1094  
  1095  func TestArgoCDApplicationSet_setManagedApplicationSetSourceNamespaces(t *testing.T) {
  1096  	a := makeTestArgoCD()
  1097  	ns1 := v1.Namespace{
  1098  		ObjectMeta: metav1.ObjectMeta{
  1099  			Name: "test-namespace-1",
  1100  			Labels: map[string]string{
  1101  				common.ArgoCDApplicationSetManagedByClusterArgoCDLabel: testNamespace,
  1102  			},
  1103  		},
  1104  	}
  1105  	ns2 := v1.Namespace{
  1106  		ObjectMeta: metav1.ObjectMeta{
  1107  			Name: "test-namespace-2",
  1108  		},
  1109  	}
  1110  
  1111  	resObjs := []client.Object{a, &ns1, &ns2}
  1112  	subresObjs := []client.Object{a}
  1113  	runtimeObjs := []runtime.Object{}
  1114  	sch := makeTestReconcilerScheme(argoproj.AddToScheme)
  1115  	cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs)
  1116  	r := makeTestReconciler(cl, sch)
  1117  
  1118  	err := r.setManagedApplicationSetSourceNamespaces(a)
  1119  	assert.NoError(t, err)
  1120  
  1121  	assert.Equal(t, 1, len(r.ManagedApplicationSetSourceNamespaces))
  1122  	assert.Contains(t, r.ManagedApplicationSetSourceNamespaces, "test-namespace-1")
  1123  }
  1124  
  1125  func TestArgoCDApplicationSet_removeUnmanagedApplicationSetSourceNamespaceResources(t *testing.T) {
  1126  	ns1 := "foo"
  1127  	ns2 := "bar"
  1128  	a := makeTestArgoCD()
  1129  	a.Spec = argoproj.ArgoCDSpec{
  1130  		SourceNamespaces: []string{ns1, ns2},
  1131  		ApplicationSet: &argoproj.ArgoCDApplicationSet{
  1132  			SourceNamespaces: []string{ns1, ns2},
  1133  		},
  1134  	}
  1135  
  1136  	resObjs := []client.Object{a}
  1137  	subresObjs := []client.Object{a}
  1138  	runtimeObjs := []runtime.Object{}
  1139  	sch := makeTestReconcilerScheme(argoproj.AddToScheme)
  1140  	cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs)
  1141  	r := makeTestReconciler(cl, sch)
  1142  
  1143  	createNamespace(r, ns1, "")
  1144  	createNamespace(r, ns2, "")
  1145  
  1146  	// create resources
  1147  	err := r.reconcileApplicationSetSourceNamespacesResources(a)
  1148  	assert.NoError(t, err)
  1149  
  1150  	// remove appset ns
  1151  	a.Spec = argoproj.ArgoCDSpec{
  1152  		SourceNamespaces: []string{ns2},
  1153  		ApplicationSet: &argoproj.ArgoCDApplicationSet{
  1154  			SourceNamespaces: []string{ns1, ns2},
  1155  		},
  1156  	}
  1157  
  1158  	// clean up unmanaged namespaces resources
  1159  	err = r.removeUnmanagedApplicationSetSourceNamespaceResources(a)
  1160  	assert.NoError(t, err)
  1161  
  1162  	// resources shouldn't exist in ns1
  1163  	resName := getResourceNameForApplicationSetSourceNamespaces(a)
  1164  
  1165  	role := &rbacv1.Role{}
  1166  	err = r.Client.Get(context.TODO(), cntrlClient.ObjectKey{Name: resName, Namespace: ns1}, role)
  1167  	assert.Error(t, err)
  1168  	assert.True(t, apierrors.IsNotFound(err))
  1169  
  1170  	roleBinding := &rbacv1.RoleBinding{}
  1171  	err = r.Client.Get(context.TODO(), cntrlClient.ObjectKey{Name: resName, Namespace: ns1}, roleBinding)
  1172  	assert.Error(t, err)
  1173  	assert.True(t, apierrors.IsNotFound(err))
  1174  
  1175  	// appset tracking label should be removed
  1176  	namespace := &v1.Namespace{}
  1177  	err = r.Client.Get(context.TODO(), cntrlClient.ObjectKey{Name: ns1}, namespace)
  1178  	assert.NoError(t, err)
  1179  	_, found := namespace.Labels[common.ArgoCDApplicationSetManagedByClusterArgoCDLabel]
  1180  	assert.False(t, found)
  1181  
  1182  	// resources in ns2 shouldn't be touched
  1183  
  1184  	role = &rbacv1.Role{}
  1185  	err = r.Client.Get(context.TODO(), cntrlClient.ObjectKey{Name: resName, Namespace: ns2}, role)
  1186  	assert.NoError(t, err)
  1187  
  1188  	roleBinding = &rbacv1.RoleBinding{}
  1189  	err = r.Client.Get(context.TODO(), cntrlClient.ObjectKey{Name: resName, Namespace: ns2}, roleBinding)
  1190  	assert.NoError(t, err)
  1191  
  1192  	namespace = &v1.Namespace{}
  1193  	err = r.Client.Get(context.TODO(), cntrlClient.ObjectKey{Name: ns2}, namespace)
  1194  	assert.NoError(t, err)
  1195  	val, found := namespace.Labels[common.ArgoCDApplicationSetManagedByClusterArgoCDLabel]
  1196  	assert.True(t, found)
  1197  	assert.Equal(t, a.Namespace, val)
  1198  }