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

     1  // Copyright 2020 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  	"sort"
    20  	"testing"
    21  
    22  	"github.com/go-logr/logr"
    23  
    24  	"github.com/argoproj-labs/argocd-operator/common"
    25  
    26  	"github.com/stretchr/testify/assert"
    27  	appsv1 "k8s.io/api/apps/v1"
    28  	corev1 "k8s.io/api/core/v1"
    29  	v1 "k8s.io/api/rbac/v1"
    30  	resourcev1 "k8s.io/apimachinery/pkg/api/resource"
    31  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    32  	"k8s.io/apimachinery/pkg/runtime"
    33  	"k8s.io/client-go/kubernetes/scheme"
    34  	"sigs.k8s.io/controller-runtime/pkg/client"
    35  	"sigs.k8s.io/controller-runtime/pkg/client/fake"
    36  	"sigs.k8s.io/controller-runtime/pkg/log/zap"
    37  
    38  	"github.com/argoproj-labs/argocd-operator/controllers/argoutil"
    39  
    40  	argoproj "github.com/argoproj-labs/argocd-operator/api/v1beta1"
    41  )
    42  
    43  const (
    44  	testNamespace             = "argocd"
    45  	testArgoCDName            = "argocd"
    46  	testApplicationController = "argocd-application-controller"
    47  )
    48  
    49  func ZapLogger(development bool) logr.Logger {
    50  	return zap.New(zap.UseDevMode(development))
    51  }
    52  
    53  type SchemeOpt func(*runtime.Scheme) error
    54  
    55  func makeTestReconciler(client client.Client, sch *runtime.Scheme) *ReconcileArgoCD {
    56  	return &ReconcileArgoCD{
    57  		Client: client,
    58  		Scheme: sch,
    59  	}
    60  }
    61  
    62  func makeTestReconcilerClient(sch *runtime.Scheme, resObjs, subresObjs []client.Object, runtimeObj []runtime.Object) client.Client {
    63  	client := fake.NewClientBuilder().WithScheme(sch)
    64  	if len(resObjs) > 0 {
    65  		client = client.WithObjects(resObjs...)
    66  	}
    67  	if len(subresObjs) > 0 {
    68  		client = client.WithStatusSubresource(subresObjs...)
    69  	}
    70  	if len(runtimeObj) > 0 {
    71  		client = client.WithRuntimeObjects(runtimeObj...)
    72  	}
    73  	return client.Build()
    74  }
    75  
    76  func makeTestReconcilerScheme(sOpts ...SchemeOpt) *runtime.Scheme {
    77  	s := scheme.Scheme
    78  	for _, opt := range sOpts {
    79  		_ = opt(s)
    80  	}
    81  
    82  	return s
    83  }
    84  
    85  type argoCDOpt func(*argoproj.ArgoCD)
    86  
    87  func makeTestArgoCD(opts ...argoCDOpt) *argoproj.ArgoCD {
    88  	a := &argoproj.ArgoCD{
    89  		ObjectMeta: metav1.ObjectMeta{
    90  			Name:      testArgoCDName,
    91  			Namespace: testNamespace,
    92  		},
    93  	}
    94  	for _, o := range opts {
    95  		o(a)
    96  	}
    97  	return a
    98  }
    99  
   100  func makeTestArgoCDForKeycloak() *argoproj.ArgoCD {
   101  	a := &argoproj.ArgoCD{
   102  		ObjectMeta: metav1.ObjectMeta{
   103  			Name:      testArgoCDName,
   104  			Namespace: testNamespace,
   105  		},
   106  		Spec: argoproj.ArgoCDSpec{
   107  			SSO: &argoproj.ArgoCDSSOSpec{
   108  				Provider: "keycloak",
   109  			},
   110  			Server: argoproj.ArgoCDServerSpec{
   111  				Route: argoproj.ArgoCDRouteSpec{
   112  					Enabled: true,
   113  				},
   114  			},
   115  		},
   116  	}
   117  	return a
   118  }
   119  
   120  func makeTestArgoCDWithResources(opts ...argoCDOpt) *argoproj.ArgoCD {
   121  	a := &argoproj.ArgoCD{
   122  		ObjectMeta: metav1.ObjectMeta{
   123  			Name:      testArgoCDName,
   124  			Namespace: testNamespace,
   125  		},
   126  		Spec: argoproj.ArgoCDSpec{
   127  			ApplicationSet: &argoproj.ArgoCDApplicationSet{
   128  				Resources: makeTestApplicationSetResources(),
   129  			},
   130  			HA: argoproj.ArgoCDHASpec{
   131  				Resources: makeTestHAResources(),
   132  			},
   133  			SSO: &argoproj.ArgoCDSSOSpec{
   134  				Provider: "dex",
   135  				Dex: &argoproj.ArgoCDDexSpec{
   136  					Resources: makeTestDexResources(),
   137  				},
   138  			},
   139  			Controller: argoproj.ArgoCDApplicationControllerSpec{
   140  				Resources: makeTestControllerResources(),
   141  			},
   142  		},
   143  	}
   144  	for _, o := range opts {
   145  		o(a)
   146  	}
   147  	return a
   148  }
   149  
   150  func makeTestClusterRole() *v1.ClusterRole {
   151  	return &v1.ClusterRole{
   152  		ObjectMeta: metav1.ObjectMeta{
   153  			Name:      testApplicationController,
   154  			Namespace: testNamespace,
   155  		},
   156  		Rules: makeTestPolicyRules(),
   157  	}
   158  }
   159  
   160  func makeTestDeployment() *appsv1.Deployment {
   161  	var replicas int32 = 1
   162  	return &appsv1.Deployment{
   163  		ObjectMeta: metav1.ObjectMeta{
   164  			Name:      testApplicationController,
   165  			Namespace: testNamespace,
   166  		},
   167  		Spec: appsv1.DeploymentSpec{
   168  			Replicas: &replicas,
   169  			Selector: &metav1.LabelSelector{
   170  				MatchLabels: map[string]string{
   171  					"app": "name",
   172  				},
   173  			},
   174  			Template: corev1.PodTemplateSpec{
   175  				Spec: corev1.PodSpec{
   176  					Containers: []corev1.Container{
   177  						{
   178  							Command: []string{"testing"},
   179  							Image:   "test-image",
   180  						},
   181  					},
   182  				},
   183  			},
   184  		},
   185  	}
   186  }
   187  
   188  func makeTestPolicyRules() []v1.PolicyRule {
   189  	return []v1.PolicyRule{
   190  		{
   191  			APIGroups: []string{
   192  				"foo.example.com",
   193  			},
   194  			Resources: []string{
   195  				"*",
   196  			},
   197  			Verbs: []string{
   198  				"*",
   199  			},
   200  		},
   201  	}
   202  }
   203  
   204  func initialCerts(t *testing.T, host string) argoCDOpt {
   205  	t.Helper()
   206  	return func(a *argoproj.ArgoCD) {
   207  		key, err := argoutil.NewPrivateKey()
   208  		assert.NoError(t, err)
   209  		cert, err := argoutil.NewSelfSignedCACertificate(a.Name, key)
   210  		assert.NoError(t, err)
   211  		encoded := argoutil.EncodeCertificatePEM(cert)
   212  
   213  		a.Spec.TLS.InitialCerts = map[string]string{
   214  			host: string(encoded),
   215  		}
   216  	}
   217  }
   218  
   219  func stringMapKeys(m map[string]string) []string {
   220  	r := []string{}
   221  	for k := range m {
   222  		r = append(r, k)
   223  	}
   224  	sort.Strings(r)
   225  	return r
   226  }
   227  
   228  func makeTestControllerResources() *corev1.ResourceRequirements {
   229  	return &corev1.ResourceRequirements{
   230  		Requests: corev1.ResourceList{
   231  			corev1.ResourceMemory: resourcev1.MustParse("1024Mi"),
   232  			corev1.ResourceCPU:    resourcev1.MustParse("1000m"),
   233  		},
   234  		Limits: corev1.ResourceList{
   235  			corev1.ResourceMemory: resourcev1.MustParse("2048Mi"),
   236  			corev1.ResourceCPU:    resourcev1.MustParse("2000m"),
   237  		},
   238  	}
   239  }
   240  
   241  func makeTestApplicationSetResources() *corev1.ResourceRequirements {
   242  	return &corev1.ResourceRequirements{
   243  		Requests: corev1.ResourceList{
   244  			corev1.ResourceMemory: resourcev1.MustParse("1024Mi"),
   245  			corev1.ResourceCPU:    resourcev1.MustParse("1"),
   246  		},
   247  		Limits: corev1.ResourceList{
   248  			corev1.ResourceMemory: resourcev1.MustParse("2048Mi"),
   249  			corev1.ResourceCPU:    resourcev1.MustParse("2"),
   250  		},
   251  	}
   252  }
   253  
   254  func makeTestHAResources() *corev1.ResourceRequirements {
   255  	return &corev1.ResourceRequirements{
   256  		Requests: corev1.ResourceList{
   257  			corev1.ResourceMemory: resourcev1.MustParse("128Mi"),
   258  			corev1.ResourceCPU:    resourcev1.MustParse("250m"),
   259  		},
   260  		Limits: corev1.ResourceList{
   261  			corev1.ResourceMemory: resourcev1.MustParse("256Mi"),
   262  			corev1.ResourceCPU:    resourcev1.MustParse("500m"),
   263  		},
   264  	}
   265  }
   266  
   267  func makeTestDexResources() *corev1.ResourceRequirements {
   268  	return &corev1.ResourceRequirements{
   269  		Requests: corev1.ResourceList{
   270  			corev1.ResourceMemory: resourcev1.MustParse("128Mi"),
   271  			corev1.ResourceCPU:    resourcev1.MustParse("250m"),
   272  		},
   273  		Limits: corev1.ResourceList{
   274  			corev1.ResourceMemory: resourcev1.MustParse("256Mi"),
   275  			corev1.ResourceCPU:    resourcev1.MustParse("500m"),
   276  		},
   277  	}
   278  }
   279  
   280  func createNamespace(r *ReconcileArgoCD, n string, managedBy string) error {
   281  	ns := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: n}}
   282  	if managedBy != "" {
   283  		ns.Labels = map[string]string{common.ArgoCDManagedByLabel: managedBy}
   284  	}
   285  
   286  	if r.ManagedNamespaces == nil {
   287  		r.ManagedNamespaces = &corev1.NamespaceList{}
   288  	}
   289  	r.ManagedNamespaces.Items = append(r.ManagedNamespaces.Items, *ns)
   290  
   291  	return r.Client.Create(context.TODO(), ns)
   292  }
   293  
   294  func createNamespaceManagedByClusterArgoCDLabel(r *ReconcileArgoCD, n string, managedBy string) error {
   295  	ns := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: n}}
   296  	if managedBy != "" {
   297  		ns.Labels = map[string]string{common.ArgoCDManagedByClusterArgoCDLabel: managedBy}
   298  	}
   299  
   300  	if r.ManagedSourceNamespaces == nil {
   301  		r.ManagedSourceNamespaces = make(map[string]string)
   302  	}
   303  	r.ManagedSourceNamespaces[ns.Name] = ""
   304  
   305  	return r.Client.Create(context.TODO(), ns)
   306  }
   307  
   308  func merge(base map[string]string, diff map[string]string) map[string]string {
   309  	result := make(map[string]string)
   310  
   311  	for k, v := range base {
   312  		result[k] = v
   313  	}
   314  	for k, v := range diff {
   315  		result[k] = v
   316  	}
   317  
   318  	return result
   319  }