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

     1  package argocd
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"strings"
     7  	"testing"
     8  
     9  	"github.com/stretchr/testify/assert"
    10  	corev1 "k8s.io/api/core/v1"
    11  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    12  	"k8s.io/apimachinery/pkg/runtime"
    13  	"k8s.io/apimachinery/pkg/types"
    14  	"k8s.io/apimachinery/pkg/util/intstr"
    15  	"k8s.io/client-go/kubernetes/scheme"
    16  	"sigs.k8s.io/controller-runtime/pkg/client"
    17  	"sigs.k8s.io/controller-runtime/pkg/client/fake"
    18  	logf "sigs.k8s.io/controller-runtime/pkg/log"
    19  	"sigs.k8s.io/controller-runtime/pkg/reconcile"
    20  
    21  	"github.com/google/go-cmp/cmp"
    22  	configv1 "github.com/openshift/api/config/v1"
    23  	routev1 "github.com/openshift/api/route/v1"
    24  
    25  	argoproj "github.com/argoproj-labs/argocd-operator/api/v1beta1"
    26  	"github.com/argoproj-labs/argocd-operator/common"
    27  )
    28  
    29  func TestReconcileRouteSetLabels(t *testing.T) {
    30  	routeAPIFound = true
    31  	ctx := context.Background()
    32  	logf.SetLogger(ZapLogger(true))
    33  	argoCD := makeArgoCD(func(a *argoproj.ArgoCD) {
    34  		a.Spec.Server.Route.Enabled = true
    35  		labels := make(map[string]string)
    36  		labels["my-key"] = "my-value"
    37  		a.Spec.Server.Route.Labels = labels
    38  	})
    39  
    40  	resObjs := []client.Object{argoCD}
    41  	subresObjs := []client.Object{argoCD}
    42  	runtimeObjs := []runtime.Object{}
    43  	sch := makeTestReconcilerScheme(argoproj.AddToScheme, configv1.Install, routev1.Install)
    44  	cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs)
    45  	r := makeTestReconciler(cl, sch)
    46  
    47  	assert.NoError(t, createNamespace(r, argoCD.Namespace, ""))
    48  
    49  	req := reconcile.Request{
    50  		NamespacedName: types.NamespacedName{
    51  			Name:      testArgoCDName,
    52  			Namespace: testNamespace,
    53  		},
    54  	}
    55  
    56  	_, err := r.Reconcile(context.TODO(), req)
    57  	assert.NoError(t, err)
    58  
    59  	loaded := &routev1.Route{}
    60  	err = r.Client.Get(ctx, types.NamespacedName{Name: testArgoCDName + "-server", Namespace: testNamespace}, loaded)
    61  	fatalIfError(t, err, "failed to load route %q: %s", testArgoCDName+"-server", err)
    62  
    63  	if diff := cmp.Diff("my-value", loaded.Labels["my-key"]); diff != "" {
    64  		t.Fatalf("failed to reconcile route:\n%s", diff)
    65  	}
    66  
    67  }
    68  func TestReconcileRouteSetsInsecure(t *testing.T) {
    69  	routeAPIFound = true
    70  	ctx := context.Background()
    71  	logf.SetLogger(ZapLogger(true))
    72  	argoCD := makeArgoCD(func(a *argoproj.ArgoCD) {
    73  		a.Spec.Server.Route.Enabled = true
    74  	})
    75  
    76  	resObjs := []client.Object{argoCD}
    77  	subresObjs := []client.Object{argoCD}
    78  	runtimeObjs := []runtime.Object{}
    79  	sch := makeTestReconcilerScheme(argoproj.AddToScheme, configv1.Install, routev1.Install)
    80  	cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs)
    81  	r := makeTestReconciler(cl, sch)
    82  
    83  	assert.NoError(t, createNamespace(r, argoCD.Namespace, ""))
    84  
    85  	req := reconcile.Request{
    86  		NamespacedName: types.NamespacedName{
    87  			Name:      testArgoCDName,
    88  			Namespace: testNamespace,
    89  		},
    90  	}
    91  
    92  	_, err := r.Reconcile(context.TODO(), req)
    93  	assert.NoError(t, err)
    94  
    95  	loaded := &routev1.Route{}
    96  	err = r.Client.Get(ctx, types.NamespacedName{Name: testArgoCDName + "-server", Namespace: testNamespace}, loaded)
    97  	fatalIfError(t, err, "failed to load route %q: %s", testArgoCDName+"-server", err)
    98  
    99  	wantTLSConfig := &routev1.TLSConfig{
   100  		Termination:                   routev1.TLSTerminationPassthrough,
   101  		InsecureEdgeTerminationPolicy: routev1.InsecureEdgeTerminationPolicyRedirect,
   102  	}
   103  	if diff := cmp.Diff(wantTLSConfig, loaded.Spec.TLS); diff != "" {
   104  		t.Fatalf("failed to reconcile route:\n%s", diff)
   105  	}
   106  	wantPort := &routev1.RoutePort{
   107  		TargetPort: intstr.FromString("https"),
   108  	}
   109  	if diff := cmp.Diff(wantPort, loaded.Spec.Port); diff != "" {
   110  		t.Fatalf("failed to reconcile route:\n%s", diff)
   111  	}
   112  
   113  	// second reconciliation after changing the Insecure flag.
   114  	err = r.Client.Get(ctx, req.NamespacedName, argoCD)
   115  	fatalIfError(t, err, "failed to load ArgoCD %q: %s", testArgoCDName+"-server", err)
   116  
   117  	argoCD.Spec.Server.Insecure = true
   118  	err = r.Client.Update(ctx, argoCD)
   119  	fatalIfError(t, err, "failed to update the ArgoCD: %s", err)
   120  
   121  	_, err = r.Reconcile(context.TODO(), req)
   122  	fatalIfError(t, err, "reconcile: (%v): %s", req, err)
   123  
   124  	loaded = &routev1.Route{}
   125  	err = r.Client.Get(ctx, types.NamespacedName{Name: testArgoCDName + "-server", Namespace: testNamespace}, loaded)
   126  	fatalIfError(t, err, "failed to load route %q: %s", testArgoCDName+"-server", err)
   127  
   128  	wantTLSConfig = &routev1.TLSConfig{
   129  		InsecureEdgeTerminationPolicy: routev1.InsecureEdgeTerminationPolicyRedirect,
   130  		Termination:                   routev1.TLSTerminationEdge,
   131  	}
   132  	if diff := cmp.Diff(wantTLSConfig, loaded.Spec.TLS); diff != "" {
   133  		t.Fatalf("failed to reconcile route:\n%s", diff)
   134  	}
   135  	wantPort = &routev1.RoutePort{
   136  		TargetPort: intstr.FromString("http"),
   137  	}
   138  	if diff := cmp.Diff(wantPort, loaded.Spec.Port); diff != "" {
   139  		t.Fatalf("failed to reconcile route:\n%s", diff)
   140  	}
   141  }
   142  
   143  func TestReconcileRouteUnsetsInsecure(t *testing.T) {
   144  	routeAPIFound = true
   145  	ctx := context.Background()
   146  	logf.SetLogger(ZapLogger(true))
   147  	argoCD := makeArgoCD(func(a *argoproj.ArgoCD) {
   148  		a.Spec.Server.Route.Enabled = true
   149  		a.Spec.Server.Insecure = true
   150  	})
   151  
   152  	resObjs := []client.Object{argoCD}
   153  	subresObjs := []client.Object{argoCD}
   154  	runtimeObjs := []runtime.Object{}
   155  	sch := makeTestReconcilerScheme(argoproj.AddToScheme, configv1.Install, routev1.Install)
   156  	cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs)
   157  	r := makeTestReconciler(cl, sch)
   158  
   159  	assert.NoError(t, createNamespace(r, argoCD.Namespace, ""))
   160  
   161  	req := reconcile.Request{
   162  		NamespacedName: types.NamespacedName{
   163  			Name:      testArgoCDName,
   164  			Namespace: testNamespace,
   165  		},
   166  	}
   167  
   168  	_, err := r.Reconcile(context.TODO(), req)
   169  	assert.NoError(t, err)
   170  
   171  	loaded := &routev1.Route{}
   172  	err = r.Client.Get(ctx, types.NamespacedName{Name: testArgoCDName + "-server", Namespace: testNamespace}, loaded)
   173  	fatalIfError(t, err, "failed to load route %q: %s", testArgoCDName+"-server", err)
   174  
   175  	wantTLSConfig := &routev1.TLSConfig{
   176  		InsecureEdgeTerminationPolicy: routev1.InsecureEdgeTerminationPolicyRedirect,
   177  		Termination:                   routev1.TLSTerminationEdge,
   178  	}
   179  	if diff := cmp.Diff(wantTLSConfig, loaded.Spec.TLS); diff != "" {
   180  		t.Fatalf("failed to reconcile route:\n%s", diff)
   181  	}
   182  	wantPort := &routev1.RoutePort{
   183  		TargetPort: intstr.FromString("http"),
   184  	}
   185  	if diff := cmp.Diff(wantPort, loaded.Spec.Port); diff != "" {
   186  		t.Fatalf("failed to reconcile route:\n%s", diff)
   187  	}
   188  
   189  	// second reconciliation after changing the Insecure flag.
   190  	err = r.Client.Get(ctx, req.NamespacedName, argoCD)
   191  	fatalIfError(t, err, "failed to load ArgoCD %q: %s", testArgoCDName+"-server", err)
   192  
   193  	argoCD.Spec.Server.Insecure = false
   194  	err = r.Client.Update(ctx, argoCD)
   195  	fatalIfError(t, err, "failed to update the ArgoCD: %s", err)
   196  
   197  	_, err = r.Reconcile(context.TODO(), req)
   198  	assert.NoError(t, err)
   199  
   200  	loaded = &routev1.Route{}
   201  	err = r.Client.Get(ctx, types.NamespacedName{Name: testArgoCDName + "-server", Namespace: testNamespace}, loaded)
   202  	fatalIfError(t, err, "failed to load route %q: %s", testArgoCDName+"-server", err)
   203  
   204  	wantTLSConfig = &routev1.TLSConfig{
   205  		Termination:                   routev1.TLSTerminationPassthrough,
   206  		InsecureEdgeTerminationPolicy: routev1.InsecureEdgeTerminationPolicyRedirect,
   207  	}
   208  	if diff := cmp.Diff(wantTLSConfig, loaded.Spec.TLS); diff != "" {
   209  		t.Fatalf("failed to reconcile route:\n%s", diff)
   210  	}
   211  	wantPort = &routev1.RoutePort{
   212  		TargetPort: intstr.FromString("https"),
   213  	}
   214  	if diff := cmp.Diff(wantPort, loaded.Spec.Port); diff != "" {
   215  		t.Fatalf("failed to reconcile route:\n%s", diff)
   216  	}
   217  }
   218  
   219  func TestReconcileRouteApplicationSetHost(t *testing.T) {
   220  	routeAPIFound = true
   221  	ctx := context.Background()
   222  	logf.SetLogger(ZapLogger(true))
   223  	argoCD := makeArgoCD(func(a *argoproj.ArgoCD) {
   224  
   225  		a.Spec.ApplicationSet = &argoproj.ArgoCDApplicationSet{
   226  			WebhookServer: argoproj.WebhookServerSpec{
   227  				Host: "webhook-test.org",
   228  				Route: argoproj.ArgoCDRouteSpec{
   229  					Enabled: true,
   230  				},
   231  			},
   232  		}
   233  	})
   234  
   235  	resObjs := []client.Object{argoCD}
   236  	subresObjs := []client.Object{argoCD}
   237  	runtimeObjs := []runtime.Object{}
   238  	sch := makeTestReconcilerScheme(argoproj.AddToScheme, configv1.Install, routev1.Install)
   239  	cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs)
   240  	r := makeTestReconciler(cl, sch)
   241  
   242  	assert.NoError(t, createNamespace(r, argoCD.Namespace, ""))
   243  
   244  	req := reconcile.Request{
   245  		NamespacedName: types.NamespacedName{
   246  			Name:      testArgoCDName,
   247  			Namespace: testNamespace,
   248  		},
   249  	}
   250  
   251  	_, err := r.Reconcile(context.TODO(), req)
   252  	assert.NoError(t, err)
   253  
   254  	loaded := &routev1.Route{}
   255  	err = r.Client.Get(ctx, types.NamespacedName{Name: fmt.Sprintf("%s-%s-%s", testArgoCDName, common.ApplicationSetServiceNameSuffix, "webhook"), Namespace: testNamespace}, loaded)
   256  	fatalIfError(t, err, "failed to load route %q: %s", testArgoCDName+"-server", err)
   257  
   258  	wantTLSConfig := &routev1.TLSConfig{
   259  		InsecureEdgeTerminationPolicy: routev1.InsecureEdgeTerminationPolicyRedirect,
   260  		Termination:                   routev1.TLSTerminationEdge,
   261  	}
   262  	if diff := cmp.Diff(wantTLSConfig, loaded.Spec.TLS); diff != "" {
   263  		t.Fatalf("failed to reconcile route:\n%s", diff)
   264  	}
   265  
   266  	if diff := cmp.Diff(argoCD.Spec.ApplicationSet.WebhookServer.Host, loaded.Spec.Host); diff != "" {
   267  		t.Fatalf("failed to reconcile route:\n%s", diff)
   268  	}
   269  }
   270  
   271  func TestReconcileRouteApplicationSetTlsTermination(t *testing.T) {
   272  	routeAPIFound = true
   273  	ctx := context.Background()
   274  	logf.SetLogger(ZapLogger(true))
   275  	argoCD := makeArgoCD(func(a *argoproj.ArgoCD) {
   276  
   277  		a.Spec.ApplicationSet = &argoproj.ArgoCDApplicationSet{
   278  			WebhookServer: argoproj.WebhookServerSpec{
   279  				Host: "webhook-test.org",
   280  				Route: argoproj.ArgoCDRouteSpec{
   281  					Enabled: true,
   282  					TLS: &routev1.TLSConfig{
   283  						Termination: "passthrough",
   284  					},
   285  				},
   286  			},
   287  		}
   288  	})
   289  
   290  	resObjs := []client.Object{argoCD}
   291  	subresObjs := []client.Object{argoCD}
   292  	runtimeObjs := []runtime.Object{}
   293  	sch := makeTestReconcilerScheme(argoproj.AddToScheme, configv1.Install, routev1.Install)
   294  	cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs)
   295  	r := makeTestReconciler(cl, sch)
   296  
   297  	assert.NoError(t, createNamespace(r, argoCD.Namespace, ""))
   298  
   299  	req := reconcile.Request{
   300  		NamespacedName: types.NamespacedName{
   301  			Name:      testArgoCDName,
   302  			Namespace: testNamespace,
   303  		},
   304  	}
   305  
   306  	_, err := r.Reconcile(context.TODO(), req)
   307  	assert.NoError(t, err)
   308  
   309  	loaded := &routev1.Route{}
   310  	err = r.Client.Get(ctx, types.NamespacedName{Name: fmt.Sprintf("%s-%s-%s", testArgoCDName, common.ApplicationSetServiceNameSuffix, "webhook"), Namespace: testNamespace}, loaded)
   311  	fatalIfError(t, err, "failed to load route %q: %s", testArgoCDName+"-server", err)
   312  
   313  	wantTLSConfig := &routev1.TLSConfig{
   314  		InsecureEdgeTerminationPolicy: routev1.InsecureEdgeTerminationPolicyRedirect,
   315  		Termination:                   routev1.TLSTerminationPassthrough,
   316  	}
   317  	if diff := cmp.Diff(wantTLSConfig, loaded.Spec.TLS); diff != "" {
   318  		t.Fatalf("failed to reconcile route:\n%s", diff)
   319  	}
   320  
   321  	if diff := cmp.Diff(argoCD.Spec.ApplicationSet.WebhookServer.Host, loaded.Spec.Host); diff != "" {
   322  		t.Fatalf("failed to reconcile route:\n%s", diff)
   323  	}
   324  }
   325  
   326  func TestReconcileRouteApplicationSetTls(t *testing.T) {
   327  	routeAPIFound = true
   328  	ctx := context.Background()
   329  	logf.SetLogger(ZapLogger(true))
   330  	wildcardPolicy := routev1.WildcardPolicyType("subdomain")
   331  
   332  	argoCD := makeArgoCD(func(a *argoproj.ArgoCD) {
   333  		a.Spec.ApplicationSet = &argoproj.ArgoCDApplicationSet{
   334  			WebhookServer: argoproj.WebhookServerSpec{
   335  				Route: argoproj.ArgoCDRouteSpec{
   336  					Enabled: true,
   337  					TLS: &routev1.TLSConfig{
   338  						Certificate:                   "test-certificate",
   339  						Key:                           "test-key",
   340  						CACertificate:                 "test-ca-certificate",
   341  						DestinationCACertificate:      "test-destination-ca-certificate",
   342  						InsecureEdgeTerminationPolicy: "Redirect",
   343  					},
   344  					Annotations:    map[string]string{"my-annotation-key": "my-annotation-value"},
   345  					Labels:         map[string]string{"my-label-key": "my-label-value"},
   346  					WildcardPolicy: &wildcardPolicy,
   347  				},
   348  			},
   349  		}
   350  	})
   351  
   352  	resObjs := []client.Object{argoCD}
   353  	subresObjs := []client.Object{argoCD}
   354  	runtimeObjs := []runtime.Object{}
   355  	sch := makeTestReconcilerScheme(argoproj.AddToScheme, configv1.Install, routev1.Install)
   356  	cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs)
   357  	r := makeTestReconciler(cl, sch)
   358  
   359  	assert.NoError(t, createNamespace(r, argoCD.Namespace, ""))
   360  
   361  	req := reconcile.Request{
   362  		NamespacedName: types.NamespacedName{
   363  			Name:      testArgoCDName,
   364  			Namespace: testNamespace,
   365  		},
   366  	}
   367  
   368  	_, err := r.Reconcile(context.TODO(), req)
   369  	assert.NoError(t, err)
   370  
   371  	loaded := &routev1.Route{}
   372  	err = r.Client.Get(ctx, types.NamespacedName{Name: fmt.Sprintf("%s-%s-%s", testArgoCDName, common.ApplicationSetServiceNameSuffix, "webhook"), Namespace: testNamespace}, loaded)
   373  	fatalIfError(t, err, "failed to load route %q: %s", testArgoCDName+"-server", err)
   374  
   375  	wantTLSConfig := &routev1.TLSConfig{
   376  		Termination:                   routev1.TLSTerminationEdge,
   377  		Certificate:                   "test-certificate",
   378  		Key:                           "test-key",
   379  		CACertificate:                 "test-ca-certificate",
   380  		DestinationCACertificate:      "test-destination-ca-certificate",
   381  		InsecureEdgeTerminationPolicy: routev1.InsecureEdgeTerminationPolicyRedirect,
   382  	}
   383  	if diff := cmp.Diff(wantTLSConfig, loaded.Spec.TLS); diff != "" {
   384  		t.Fatalf("failed to reconcile route:\n%s", diff)
   385  	}
   386  
   387  	assert.Empty(t, loaded.Spec.Host)
   388  
   389  	wantPort := &routev1.RoutePort{
   390  		TargetPort: intstr.FromString("webhook"),
   391  	}
   392  	if diff := cmp.Diff(wantPort, loaded.Spec.Port); diff != "" {
   393  		t.Fatalf("failed to reconcile route:\n%s", diff)
   394  	}
   395  
   396  	if diff := cmp.Diff("my-annotation-value", loaded.Annotations["my-annotation-key"]); diff != "" {
   397  		t.Fatalf("failed to reconcile route:\n%s", diff)
   398  	}
   399  
   400  	if diff := cmp.Diff("my-label-value", loaded.Labels["my-label-key"]); diff != "" {
   401  		t.Fatalf("failed to reconcile route:\n%s", diff)
   402  	}
   403  
   404  	if diff := cmp.Diff(wildcardPolicy, loaded.Spec.WildcardPolicy); diff != "" {
   405  		t.Fatalf("failed to reconcile route:\n%s", diff)
   406  	}
   407  }
   408  
   409  func TestReconcileRouteForShorteningHostname(t *testing.T) {
   410  	routeAPIFound = true
   411  	ctx := context.Background()
   412  	logf.SetLogger(ZapLogger(true))
   413  
   414  	tests := []struct {
   415  		testName string
   416  		expected string
   417  		hostname string
   418  	}{
   419  		{
   420  			testName: "longHostname",
   421  			hostname: "myhostnameaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.redhat.com",
   422  			expected: "myhostnameaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.redhat.com",
   423  		},
   424  		{
   425  			testName: "twentySixLetterHostname",
   426  			hostname: "myhostnametwentysixletteraaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.redhat.com",
   427  			expected: "myhostnametwentysixletteraaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.redhat.com",
   428  		},
   429  	}
   430  
   431  	for _, v := range tests {
   432  		t.Run(v.testName, func(t *testing.T) {
   433  
   434  			argoCD := makeArgoCD(func(a *argoproj.ArgoCD) {
   435  				a.Spec.Server.Route.Enabled = true
   436  				a.Spec.ApplicationSet = &argoproj.ArgoCDApplicationSet{
   437  					WebhookServer: argoproj.WebhookServerSpec{
   438  						Route: argoproj.ArgoCDRouteSpec{
   439  							Enabled: true,
   440  						},
   441  						Host: v.hostname,
   442  					},
   443  				}
   444  			})
   445  
   446  			resObjs := []client.Object{argoCD}
   447  			subresObjs := []client.Object{argoCD}
   448  			runtimeObjs := []runtime.Object{}
   449  			sch := makeTestReconcilerScheme(argoproj.AddToScheme, configv1.Install, routev1.Install)
   450  			cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs)
   451  			r := makeTestReconciler(cl, sch)
   452  
   453  			assert.NoError(t, createNamespace(r, argoCD.Namespace, ""))
   454  
   455  			req := reconcile.Request{
   456  				NamespacedName: types.NamespacedName{
   457  					Name:      testArgoCDName,
   458  					Namespace: testNamespace,
   459  				},
   460  			}
   461  
   462  			// Check if it returns nil when hostname is empty
   463  			_, err := r.Reconcile(context.TODO(), req)
   464  			assert.NoError(t, err)
   465  
   466  			// second reconciliation after changing the hostname.
   467  			err = r.Client.Get(ctx, req.NamespacedName, argoCD)
   468  			fatalIfError(t, err, "failed to load ArgoCD %q: %s", testArgoCDName+"-server", err)
   469  
   470  			argoCD.Spec.Server.Host = v.hostname
   471  			err = r.Client.Update(ctx, argoCD)
   472  			fatalIfError(t, err, "failed to update the ArgoCD: %s", err)
   473  
   474  			_, err = r.Reconcile(context.TODO(), req)
   475  			assert.NoError(t, err)
   476  
   477  			loaded := &routev1.Route{}
   478  			err = r.Client.Get(ctx, types.NamespacedName{Name: testArgoCDName + "-server", Namespace: testNamespace}, loaded)
   479  			fatalIfError(t, err, "failed to load route %q: %s", testArgoCDName+"-server", err)
   480  
   481  			if diff := cmp.Diff(v.expected, loaded.Spec.Host); diff != "" {
   482  				t.Fatalf("failed to reconcile route:\n%s", diff)
   483  			}
   484  
   485  			// Check if first label is greater than 20
   486  			labels := strings.Split(loaded.Spec.Host, ".")
   487  			assert.True(t, len(labels[0]) > 20)
   488  
   489  		})
   490  	}
   491  }
   492  
   493  func makeReconciler(t *testing.T, acd *argoproj.ArgoCD, objs ...runtime.Object) *ReconcileArgoCD {
   494  	t.Helper()
   495  	s := scheme.Scheme
   496  	s.AddKnownTypes(argoproj.GroupVersion, acd)
   497  	routev1.Install(s)
   498  	configv1.Install(s)
   499  
   500  	clientObjs := []client.Object{}
   501  	for _, obj := range objs {
   502  		clientObj := obj.(client.Object)
   503  		clientObjs = append(clientObjs, clientObj)
   504  	}
   505  
   506  	cl := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(objs...).WithStatusSubresource(clientObjs...).Build()
   507  
   508  	return &ReconcileArgoCD{
   509  		Client: cl,
   510  		Scheme: s,
   511  	}
   512  }
   513  
   514  func makeArgoCD(opts ...func(*argoproj.ArgoCD)) *argoproj.ArgoCD {
   515  	argoCD := &argoproj.ArgoCD{
   516  		ObjectMeta: metav1.ObjectMeta{
   517  			Name:      testArgoCDName,
   518  			Namespace: testNamespace,
   519  		},
   520  		Spec: argoproj.ArgoCDSpec{},
   521  	}
   522  	for _, o := range opts {
   523  		o(argoCD)
   524  	}
   525  	return argoCD
   526  }
   527  
   528  func fatalIfError(t *testing.T, err error, format string, a ...interface{}) {
   529  	t.Helper()
   530  	if err != nil {
   531  		t.Fatalf(format, a...)
   532  	}
   533  }
   534  
   535  func loadSecret(t *testing.T, c client.Client, name string) *corev1.Secret {
   536  	t.Helper()
   537  	secret := &corev1.Secret{}
   538  	err := c.Get(context.TODO(), types.NamespacedName{Name: name, Namespace: testNamespace}, secret)
   539  	fatalIfError(t, err, "failed to load secret %q", name)
   540  	return secret
   541  }
   542  
   543  func testNamespacedName(name string) types.NamespacedName {
   544  	return types.NamespacedName{
   545  		Name:      name,
   546  		Namespace: testNamespace,
   547  	}
   548  }