From c902190e670208efcd47eb309f77e380ceb1cfa6 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 12 Dec 2022 21:44:55 -0800 Subject: [PATCH] cmd/k8s-operator: factor out some of the larger expected test outputs. For other test cases, the operator is going to produce similar generated objects in several codepaths, and those objects are large. Move them out to helpers so that the main test code stays a bit more intelligible. The top-level Service that we start and end with remains in the main test body, because its shape at the start and end is one of the main things that varies a lot between test cases. Updates #502. Signed-off-by: David Anderson --- cmd/k8s-operator/operator_test.go | 113 +++++++++++++++++------------- 1 file changed, 63 insertions(+), 50 deletions(-) diff --git a/cmd/k8s-operator/operator_test.go b/cmd/k8s-operator/operator_test.go index 7c9126e50..a87286f08 100644 --- a/cmd/k8s-operator/operator_test.go +++ b/cmd/k8s-operator/operator_test.go @@ -57,13 +57,59 @@ func TestController(t *testing.T) { fullName, shortName := findGenName(t, fc, "default", "test") - expectEqual(t, fc, &corev1.Secret{ + expectEqual(t, fc, expectedSecret(fullName)) + expectEqual(t, fc, expectedHeadlessService(shortName)) + expectEqual(t, fc, expectedSTS(shortName, fullName)) + + // Normally the Tailscale proxy pod would come up here and write its info + // into the secret. Simulate that, then verify reconcile again and verify + // that we get to the end. + mustUpdate(t, fc, "operator-ns", fullName, func(s *corev1.Secret) { + if s.Data == nil { + s.Data = map[string][]byte{} + } + s.Data["device_id"] = []byte("ts-id-1234") + s.Data["device_fqdn"] = []byte("tailscale.device.name.") + }) + expectReconciled(t, sr, "default", "test") + want := &corev1.Service{ + TypeMeta: metav1.TypeMeta{ + Kind: "Service", + APIVersion: "v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "default", + ResourceVersion: "4", + Finalizers: []string{"tailscale.com/finalizer"}, + UID: types.UID("1234-UID"), + }, + Spec: corev1.ServiceSpec{ + ClusterIP: "10.20.30.40", + Type: corev1.ServiceTypeLoadBalancer, + LoadBalancerClass: ptr.To("tailscale"), + }, + Status: corev1.ServiceStatus{ + LoadBalancer: corev1.LoadBalancerStatus{ + Ingress: []corev1.LoadBalancerIngress{ + { + Hostname: "tailscale.device.name", + }, + }, + }, + }, + } + expectEqual(t, fc, want) +} + +func expectedSecret(name string) *corev1.Secret { + return &corev1.Secret{ TypeMeta: metav1.TypeMeta{ Kind: "Secret", APIVersion: "v1", }, ObjectMeta: metav1.ObjectMeta{ - Name: fullName, + Name: name, Namespace: "operator-ns", ResourceVersion: "1", Labels: map[string]string{ @@ -76,14 +122,17 @@ func TestController(t *testing.T) { StringData: map[string]string{ "authkey": "secret-authkey", }, - }) - expectEqual(t, fc, &corev1.Service{ + } +} + +func expectedHeadlessService(name string) *corev1.Service { + return &corev1.Service{ TypeMeta: metav1.TypeMeta{ Kind: "Service", APIVersion: "v1", }, ObjectMeta: metav1.ObjectMeta{ - Name: shortName, + Name: name, GenerateName: "ts-test-", Namespace: "operator-ns", ResourceVersion: "1", @@ -100,14 +149,17 @@ func TestController(t *testing.T) { }, ClusterIP: "None", }, - }) - expectEqual(t, fc, &appsv1.StatefulSet{ + } +} + +func expectedSTS(stsName, secretName string) *appsv1.StatefulSet { + return &appsv1.StatefulSet{ TypeMeta: metav1.TypeMeta{ Kind: "StatefulSet", APIVersion: "apps/v1", }, ObjectMeta: metav1.ObjectMeta{ - Name: shortName, + Name: stsName, Namespace: "operator-ns", ResourceVersion: "1", Labels: map[string]string{ @@ -122,7 +174,7 @@ func TestController(t *testing.T) { Selector: &metav1.LabelSelector{ MatchLabels: map[string]string{"app": "1234-UID"}, }, - ServiceName: shortName, + ServiceName: stsName, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ DeletionGracePeriodSeconds: ptr.To[int64](10), @@ -149,7 +201,7 @@ func TestController(t *testing.T) { {Name: "TS_USERSPACE", Value: "false"}, {Name: "TS_AUTH_ONCE", Value: "true"}, {Name: "TS_DEST_IP", Value: "10.20.30.40"}, - {Name: "TS_KUBE_SECRET", Value: fullName}, + {Name: "TS_KUBE_SECRET", Value: secretName}, }, SecurityContext: &corev1.SecurityContext{ Capabilities: &corev1.Capabilities{ @@ -162,46 +214,7 @@ func TestController(t *testing.T) { }, }, }, - }) - - // Normally the Tailscale proxy pod would come up here and write its info - // into the secret. Simulate that, then verify reconcile again and verify - // that we get to the end. - mustUpdate(t, fc, "operator-ns", fullName, func(s *corev1.Secret) { - if s.Data == nil { - s.Data = map[string][]byte{} - } - s.Data["device_id"] = []byte("ts-id-1234") - s.Data["device_fqdn"] = []byte("tailscale.device.name.") - }) - expectReconciled(t, sr, "default", "test") - expectEqual(t, fc, &corev1.Service{ - TypeMeta: metav1.TypeMeta{ - Kind: "Service", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "test", - Namespace: "default", - ResourceVersion: "4", - Finalizers: []string{"tailscale.com/finalizer"}, - UID: types.UID("1234-UID"), - }, - Spec: corev1.ServiceSpec{ - ClusterIP: "10.20.30.40", - Type: corev1.ServiceTypeLoadBalancer, - LoadBalancerClass: ptr.To("tailscale"), - }, - Status: corev1.ServiceStatus{ - LoadBalancer: corev1.LoadBalancerStatus{ - Ingress: []corev1.LoadBalancerIngress{ - { - Hostname: "tailscale.device.name", - }, - }, - }, - }, - }) + } } func findGenName(t *testing.T, client client.Client, ns, name string) (full, noSuffix string) {