From a5b500b870c3c67152877fd5b18d10e73be4b8af Mon Sep 17 00:00:00 2001 From: Carl Montanari Date: Mon, 16 Oct 2023 18:11:29 -0700 Subject: [PATCH 1/6] tests: re-org some test things, ultra dumb helm test suite --- Makefile | 2 + charts/clabernetes/.helmignore | 3 + .../tests/clicker/clicker_enabled_test.go | 25 +++ .../test-fixtures/clicker-enabled-values.yaml | 3 + .../golden/_subchart-clicker-clusterrole.yaml | 30 ++++ .../_subchart-clicker-clusterrolebinding.yaml | 42 +++++ .../golden/_subchart-clicker-job.yaml | 64 ++++++++ .../_subchart-clicker-serviceaccount.yaml | 14 ++ .../golden/certificate-secret.yaml | 15 ++ .../test-fixtures/golden/clusterrole.yaml | 65 ++++++++ .../golden/clusterrolebinding.yaml | 21 +++ .../test-fixtures/golden/configmap.yaml | 24 +++ .../test-fixtures/golden/deployment.yaml | 110 +++++++++++++ .../test-fixtures/golden/serviceaccount.yaml | 14 ++ .../default_vaules/default_values_test.go | 90 ++++++++++ .../golden/certificate-secret.yaml | 15 ++ .../test-fixtures/golden/clusterrole.yaml | 65 ++++++++ .../golden/clusterrolebinding.yaml | 21 +++ .../test-fixtures/golden/configmap.yaml | 24 +++ .../test-fixtures/golden/deployment.yaml | 110 +++++++++++++ .../test-fixtures/golden/serviceaccount.yaml | 14 ++ charts/clicker/.helmignore | 3 + .../default_vaules/default_values_test.go | 90 ++++++++++ .../test-fixtures/golden/clusterrole.yaml | 30 ++++ .../golden/clusterrolebinding.yaml | 42 +++++ .../test-fixtures/golden/job.yaml | 64 ++++++++ .../test-fixtures/golden/serviceaccount.yaml | 14 ++ .../basic/containerlab_basic_test.go | 20 +-- testhelper/command.go | 21 +++ testhelper/helm.go | 155 ++++++++++++++++++ e2e/suite/command.go => testhelper/kubectl.go | 47 ++---- {e2e/suite => testhelper}/kubernetes.go | 2 +- {e2e => testhelper}/suite/eventually.go | 0 {e2e => testhelper}/suite/files.go | 0 {e2e => testhelper}/suite/logging.go | 6 - {e2e => testhelper}/suite/run.go | 12 +- {e2e => testhelper}/suite/steps.go | 23 +-- testhelper/yq.go | 23 +++ 38 files changed, 1252 insertions(+), 71 deletions(-) create mode 100644 charts/clabernetes/tests/clicker/clicker_enabled_test.go create mode 100644 charts/clabernetes/tests/clicker/test-fixtures/clicker-enabled-values.yaml create mode 100755 charts/clabernetes/tests/clicker/test-fixtures/golden/_subchart-clicker-clusterrole.yaml create mode 100755 charts/clabernetes/tests/clicker/test-fixtures/golden/_subchart-clicker-clusterrolebinding.yaml create mode 100755 charts/clabernetes/tests/clicker/test-fixtures/golden/_subchart-clicker-job.yaml create mode 100755 charts/clabernetes/tests/clicker/test-fixtures/golden/_subchart-clicker-serviceaccount.yaml create mode 100755 charts/clabernetes/tests/clicker/test-fixtures/golden/certificate-secret.yaml create mode 100755 charts/clabernetes/tests/clicker/test-fixtures/golden/clusterrole.yaml create mode 100755 charts/clabernetes/tests/clicker/test-fixtures/golden/clusterrolebinding.yaml create mode 100755 charts/clabernetes/tests/clicker/test-fixtures/golden/configmap.yaml create mode 100755 charts/clabernetes/tests/clicker/test-fixtures/golden/deployment.yaml create mode 100755 charts/clabernetes/tests/clicker/test-fixtures/golden/serviceaccount.yaml create mode 100644 charts/clabernetes/tests/default_vaules/default_values_test.go create mode 100755 charts/clabernetes/tests/default_vaules/test-fixtures/golden/certificate-secret.yaml create mode 100755 charts/clabernetes/tests/default_vaules/test-fixtures/golden/clusterrole.yaml create mode 100755 charts/clabernetes/tests/default_vaules/test-fixtures/golden/clusterrolebinding.yaml create mode 100755 charts/clabernetes/tests/default_vaules/test-fixtures/golden/configmap.yaml create mode 100755 charts/clabernetes/tests/default_vaules/test-fixtures/golden/deployment.yaml create mode 100755 charts/clabernetes/tests/default_vaules/test-fixtures/golden/serviceaccount.yaml create mode 100644 charts/clicker/tests/default_vaules/default_values_test.go create mode 100755 charts/clicker/tests/default_vaules/test-fixtures/golden/clusterrole.yaml create mode 100755 charts/clicker/tests/default_vaules/test-fixtures/golden/clusterrolebinding.yaml create mode 100755 charts/clicker/tests/default_vaules/test-fixtures/golden/job.yaml create mode 100755 charts/clicker/tests/default_vaules/test-fixtures/golden/serviceaccount.yaml create mode 100644 testhelper/command.go create mode 100644 testhelper/helm.go rename e2e/suite/command.go => testhelper/kubectl.go (63%) rename {e2e/suite => testhelper}/kubernetes.go (99%) rename {e2e => testhelper}/suite/eventually.go (100%) rename {e2e => testhelper}/suite/files.go (100%) rename {e2e => testhelper}/suite/logging.go (68%) rename {e2e => testhelper}/suite/run.go (81%) rename {e2e => testhelper}/suite/steps.go (74%) create mode 100644 testhelper/yq.go diff --git a/Makefile b/Makefile index d6e67ec1..793c8307 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,8 @@ fmt: ## Run formatters lint: fmt ## Run linters; runs with GOOS env var for linting on darwin golangci-lint run + helm lint --quiet charts/clabernetes + helm lint --quiet charts/clicker test: ## Run unit tests gotestsum --format testname --hide-summary=skipped -- -coverprofile=cover.out `go list ./... | grep -v e2e` diff --git a/charts/clabernetes/.helmignore b/charts/clabernetes/.helmignore index f0c13194..0c975daa 100644 --- a/charts/clabernetes/.helmignore +++ b/charts/clabernetes/.helmignore @@ -19,3 +19,6 @@ .project .idea/ *.tmproj + +# ignore +tests \ No newline at end of file diff --git a/charts/clabernetes/tests/clicker/clicker_enabled_test.go b/charts/clabernetes/tests/clicker/clicker_enabled_test.go new file mode 100644 index 00000000..b6e40fa7 --- /dev/null +++ b/charts/clabernetes/tests/clicker/clicker_enabled_test.go @@ -0,0 +1,25 @@ +package default_vaules_test + +import ( + "os" + "testing" + + clabernetestesthelper "github.com/srl-labs/clabernetes/testhelper" +) + +func TestMain(m *testing.M) { + clabernetestesthelper.Flags() + + os.Exit(m.Run()) +} + +// TestDefaultValues -- really just here to ensure that we dont accidentally break our charts; this +// will probably be *highly* irritating in times of lots of chart updates, but, once we know the +// template are in a good place we can always just re-generate the "golden" outputs. +func TestClickerEnabled(t *testing.T) { + t.Parallel() + + testName := "clicker-enabled" + + clabernetestesthelper.HelmTest(t, testName) +} diff --git a/charts/clabernetes/tests/clicker/test-fixtures/clicker-enabled-values.yaml b/charts/clabernetes/tests/clicker/test-fixtures/clicker-enabled-values.yaml new file mode 100644 index 00000000..c80f8c3a --- /dev/null +++ b/charts/clabernetes/tests/clicker/test-fixtures/clicker-enabled-values.yaml @@ -0,0 +1,3 @@ +--- +clicker: + enabled: true diff --git a/charts/clabernetes/tests/clicker/test-fixtures/golden/_subchart-clicker-clusterrole.yaml b/charts/clabernetes/tests/clicker/test-fixtures/golden/_subchart-clicker-clusterrole.yaml new file mode 100755 index 00000000..3f03c8d2 --- /dev/null +++ b/charts/clabernetes/tests/clicker/test-fixtures/golden/_subchart-clicker-clusterrole.yaml @@ -0,0 +1,30 @@ +--- +# Source: clabernetes/charts/clicker/templates/clusterrole.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + chart: "clicker-0.0.16" + release: release-name + heritage: Helm + clabernetes/app: clabernetes + clabernetes/name: "clabernetes-clicker-cluster-role" + clabernetes/component: cluster-role + name: "clabernetes-clicker-cluster-role" +rules: + - apiGroups: + - "" + resources: + - nodes + verbs: + - "*" + - apiGroups: + - "" + resources: + - pods + verbs: + - get + - list + - create + - watch + - delete diff --git a/charts/clabernetes/tests/clicker/test-fixtures/golden/_subchart-clicker-clusterrolebinding.yaml b/charts/clabernetes/tests/clicker/test-fixtures/golden/_subchart-clicker-clusterrolebinding.yaml new file mode 100755 index 00000000..7de39437 --- /dev/null +++ b/charts/clabernetes/tests/clicker/test-fixtures/golden/_subchart-clicker-clusterrolebinding.yaml @@ -0,0 +1,42 @@ +--- +# Source: clabernetes/charts/clicker/templates/clusterrolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: clabernetes-clicker + labels: + chart: "clicker-0.0.16" + release: release-name + heritage: Helm + clabernetes/app: clabernetes + clabernetes/name: "clabernetes-clicker-cluster-role-binding" + clabernetes/component: cluster-role-binding +subjects: + - kind: ServiceAccount + name: "clabernetes-clicker-service-account" + namespace: clabernetes +roleRef: + kind: ClusterRole + name: "clabernetes-cluster-role" + apiGroup: rbac.authorization.k8s.io +--- +# Source: clabernetes/charts/clicker/templates/clusterrolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: clabernetes-clicker-nodes + labels: + chart: "clicker-0.0.16" + release: release-name + heritage: Helm + clabernetes/app: clabernetes + clabernetes/name: "clabernetes-clicker-cluster-role-binding" + clabernetes/component: cluster-role-binding +subjects: + - kind: ServiceAccount + name: "clabernetes-clicker-service-account" + namespace: clabernetes +roleRef: + kind: ClusterRole + name: "clabernetes-clicker-cluster-role" + apiGroup: rbac.authorization.k8s.io diff --git a/charts/clabernetes/tests/clicker/test-fixtures/golden/_subchart-clicker-job.yaml b/charts/clabernetes/tests/clicker/test-fixtures/golden/_subchart-clicker-job.yaml new file mode 100755 index 00000000..37f8e037 --- /dev/null +++ b/charts/clabernetes/tests/clicker/test-fixtures/golden/_subchart-clicker-job.yaml @@ -0,0 +1,64 @@ +--- +# Source: clabernetes/charts/clicker/templates/job.yaml +apiVersion: batch/v1 +kind: Job +metadata: + name: clabernetes-clicker + namespace: clabernetes + labels: + chart: "clicker-0.0.16" + release: release-name + heritage: Helm + clabernetes/app: clabernetes + clabernetes/name: "clabernetes-clicker" + clabernetes/component: clicker +spec: + template: + metadata: + labels: + chart: "clicker-0.0.16" + release: release-name + heritage: Helm + clabernetes/app: clabernetes + clabernetes/name: "clabernetes-clicker" + clabernetes/component: clicker + spec: + containers: + - name: clicker + image: "ghcr.io/srl-labs/clabernetes/clabernetes-manager:0.0.16" + imagePullPolicy: IfNotPresent + command: [ + "/clabernetes/manager", + "clicker", + ] + env: + - name: APP_NAME + value: clabernetes + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: CLICKER_LOGGER_LEVEL + value: info + - name: CLICKER_WORKER_COMMAND + value: /bin/sh + - name: CLICKER_WORKER_SCRIPT + value: echo "hello, there" + - name: CLICKER_WORKER_RESOURCES + value: "requests:\n cpu: 50m\n memory: 128Mi" + - name: CLICKER_GLOBAL_ANNOTATIONS + value: "{}" + - name: CLICKER_GLOBAL_LABELS + value: "{}" + resources: + requests: + memory: 128Mi + cpu: 50m + restartPolicy: Never + serviceAccountName: "clabernetes-clicker-service-account" + backoffLimit: 4 + ttlSecondsAfterFinished: 300 diff --git a/charts/clabernetes/tests/clicker/test-fixtures/golden/_subchart-clicker-serviceaccount.yaml b/charts/clabernetes/tests/clicker/test-fixtures/golden/_subchart-clicker-serviceaccount.yaml new file mode 100755 index 00000000..a77e0f57 --- /dev/null +++ b/charts/clabernetes/tests/clicker/test-fixtures/golden/_subchart-clicker-serviceaccount.yaml @@ -0,0 +1,14 @@ +--- +# Source: clabernetes/charts/clicker/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: "clabernetes-clicker-service-account" + namespace: clabernetes + labels: + chart: "clicker-0.0.16" + release: release-name + heritage: Helm + clabernetes/app: clabernetes + clabernetes/name: "clabernetes-clicker-service-account" + clabernetes/component: service-account diff --git a/charts/clabernetes/tests/clicker/test-fixtures/golden/certificate-secret.yaml b/charts/clabernetes/tests/clicker/test-fixtures/golden/certificate-secret.yaml new file mode 100755 index 00000000..32bdf5cf --- /dev/null +++ b/charts/clabernetes/tests/clicker/test-fixtures/golden/certificate-secret.yaml @@ -0,0 +1,15 @@ +--- +# Source: clabernetes/templates/certificate-secret.yaml +apiVersion: v1 +kind: Secret +metadata: + labels: + chart: "clabernetes-0.0.16" + release: release-name + heritage: Helm + clabernetes/app: clabernetes + clabernetes/name: "clabernetes-certificate" + clabernetes/component: certificate + clabernetes/part-of: manager + name: "clabernetes-certificate" +data: {} diff --git a/charts/clabernetes/tests/clicker/test-fixtures/golden/clusterrole.yaml b/charts/clabernetes/tests/clicker/test-fixtures/golden/clusterrole.yaml new file mode 100755 index 00000000..c19aff5a --- /dev/null +++ b/charts/clabernetes/tests/clicker/test-fixtures/golden/clusterrole.yaml @@ -0,0 +1,65 @@ +--- +# Source: clabernetes/templates/clusterrole.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + chart: "clabernetes-0.0.16" + release: release-name + heritage: Helm + clabernetes/app: clabernetes + clabernetes/name: "clabernetes-cluster-role" + clabernetes/component: cluster-role + name: "clabernetes-cluster-role" +rules: + - apiGroups: + - topology.clabernetes + resources: + - "*" + verbs: + - "*" + - apiGroups: + - apiextensions.k8s.io + resources: + - "*" + verbs: + - "*" + - apiGroups: + - "" + resources: + - namespaces + - secrets + - configmaps + - services + verbs: + - get + - list + - create + - update + - delete + - patch + - watch + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - create + - update + - delete + - patch + - watch + - apiGroups: + - apps + resources: + - deployments + verbs: + - get + - list + - create + - update + - delete + - patch + - watch diff --git a/charts/clabernetes/tests/clicker/test-fixtures/golden/clusterrolebinding.yaml b/charts/clabernetes/tests/clicker/test-fixtures/golden/clusterrolebinding.yaml new file mode 100755 index 00000000..97fe8a81 --- /dev/null +++ b/charts/clabernetes/tests/clicker/test-fixtures/golden/clusterrolebinding.yaml @@ -0,0 +1,21 @@ +--- +# Source: clabernetes/templates/clusterrolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: clabernetes-manager + labels: + chart: "clabernetes-0.0.16" + release: release-name + heritage: Helm + clabernetes/app: clabernetes + clabernetes/name: "clabernetes-cluster-role-binding" + clabernetes/component: cluster-role-binding +subjects: + - kind: ServiceAccount + name: "clabernetes-service-account" + namespace: clabernetes +roleRef: + kind: ClusterRole + name: "clabernetes-cluster-role" + apiGroup: rbac.authorization.k8s.io diff --git a/charts/clabernetes/tests/clicker/test-fixtures/golden/configmap.yaml b/charts/clabernetes/tests/clicker/test-fixtures/golden/configmap.yaml new file mode 100755 index 00000000..a7d240f9 --- /dev/null +++ b/charts/clabernetes/tests/clicker/test-fixtures/golden/configmap.yaml @@ -0,0 +1,24 @@ +--- +# Source: clabernetes/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: clabernetes-config + namespace: clabernetes + labels: + chart: "clabernetes-0.0.16" + release: release-name + heritage: Helm + clabernetes/app: clabernetes + clabernetes/name: "clabernetes-config" + clabernetes/component: config +data: + globalAnnotations: |- + --- + {} + globalLabels: |- + --- + {} + defaultResources: |- + --- + {} diff --git a/charts/clabernetes/tests/clicker/test-fixtures/golden/deployment.yaml b/charts/clabernetes/tests/clicker/test-fixtures/golden/deployment.yaml new file mode 100755 index 00000000..89ff66b6 --- /dev/null +++ b/charts/clabernetes/tests/clicker/test-fixtures/golden/deployment.yaml @@ -0,0 +1,110 @@ +--- +# Source: clabernetes/templates/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: clabernetes-manager + namespace: clabernetes + labels: + chart: "clabernetes-0.0.16" + release: release-name + heritage: Helm + clabernetes/app: clabernetes + clabernetes/name: "clabernetes-manager" + clabernetes/component: manager +spec: + selector: + matchLabels: + clabernetes/app: clabernetes + release: release-name + replicas: + strategy: + rollingUpdate: + maxSurge: 1 + maxUnavailable: 1 + type: RollingUpdate + template: + metadata: + labels: + chart: "clabernetes-0.0.16" + release: release-name + heritage: Helm + clabernetes/app: clabernetes + clabernetes/name: "clabernetes-manager" + clabernetes/component: manager + spec: + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + labelSelector: + matchLabels: + clabernetes/app: clabernetes + clabernetes/name: "clabernetes-manager" + clabernetes/component: manager + topologyKey: kubernetes.io/hostname + - weight: 50 + podAffinityTerm: + labelSelector: + matchLabels: + clabernetes/app: clabernetes + clabernetes/name: "clabernetes-manager" + clabernetes/component: manager + topologyKey: topology.kubernetes.io/zone + terminationGracePeriodSeconds: 10 + serviceAccountName: "clabernetes-service-account" + initContainers: + - name: init + image: "ghcr.io/srl-labs/clabernetes/clabernetes-manager:0.0.16" + imagePullPolicy: IfNotPresent + command: ["/clabernetes/manager", "run", "--initializer"] + env: + - name: APP_NAME + value: clabernetes + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: MANAGER_LOGGER_LEVEL + value: info + resources: + requests: + memory: 128Mi + cpu: 50m + containers: + - name: manager + image: "ghcr.io/srl-labs/clabernetes/clabernetes-manager:0.0.16" + imagePullPolicy: IfNotPresent + command: ["/clabernetes/manager", "run"] + env: + - name: APP_NAME + value: clabernetes + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: CLIENT_OPERATION_TIMEOUT_MULTIPLIER + value: "1" + - name: MANAGER_LOGGER_LEVEL + value: info + - name: CONTROLLER_LOGGER_LEVEL + value: info + - name: LAUNCHER_LOGGER_LEVEL + value: info + - name: LAUNCHER_PULL_POLICY + value: "IfNotPresent" + - name: LAUNCHER_IMAGE + value: "ghcr.io/srl-labs/clabernetes/clabernetes-launcher:0.0.16" + resources: + requests: + memory: 128Mi + cpu: 50m diff --git a/charts/clabernetes/tests/clicker/test-fixtures/golden/serviceaccount.yaml b/charts/clabernetes/tests/clicker/test-fixtures/golden/serviceaccount.yaml new file mode 100755 index 00000000..81dd4361 --- /dev/null +++ b/charts/clabernetes/tests/clicker/test-fixtures/golden/serviceaccount.yaml @@ -0,0 +1,14 @@ +--- +# Source: clabernetes/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: "clabernetes-service-account" + namespace: clabernetes + labels: + chart: "clabernetes-0.0.16" + release: release-name + heritage: Helm + clabernetes/app: clabernetes + clabernetes/name: "clabernetes-service-account" + clabernetes/component: service-account diff --git a/charts/clabernetes/tests/default_vaules/default_values_test.go b/charts/clabernetes/tests/default_vaules/default_values_test.go new file mode 100644 index 00000000..2a312722 --- /dev/null +++ b/charts/clabernetes/tests/default_vaules/default_values_test.go @@ -0,0 +1,90 @@ +package default_vaules_test + +import ( + "fmt" + "os" + "path/filepath" + "testing" + + clabernetesconstants "github.com/srl-labs/clabernetes/constants" + + clabernetestesthelper "github.com/srl-labs/clabernetes/testhelper" +) + +func TestMain(m *testing.M) { + clabernetestesthelper.Flags() + + os.Exit(m.Run()) +} + +// TestDefaultValues -- really just here to ensure that we dont accidentally break our charts; this +// will probably be *highly* irritating in times of lots of chart updates, but, once we know the +// template are in a good place we can always just re-generate the "golden" outputs. +func TestDefaultValues(t *testing.T) { + t.Parallel() + + testName := "default-values" + + // we have to make the chartname/templates dir too since thats where helm wants to write things + actualRootDir := fmt.Sprintf("test-fixtures/%s-actual", testName) + actualDir := fmt.Sprintf("%s/clabernetes/templates", actualRootDir) + + err := os.MkdirAll(actualDir, clabernetesconstants.PermissionsEveryoneRead) + if err != nil { + t.Fatalf( + "failed creating actual output directory %q, error: %s", actualDir, err, + ) + } + + defer func() { + if !*clabernetestesthelper.SkipCleanup { + err = os.RemoveAll(actualRootDir) + if err != nil { + t.Logf("failed cleaning up actual output directory %q, error: %s", actualDir, err) + } + } + }() + + clabernetestesthelper.HelmCommand( + t, + "template", + "../../.", + "--output-dir", + actualRootDir, + ) + + var actualFileNames []string + + actualFileNames, err = filepath.Glob(fmt.Sprintf("%s/*.yaml", actualDir)) + if err != nil { + t.Fatalf("failed globbing actual files, error: '%s'", err) + } + + actualFileContents := map[string][]byte{} + + for _, actualFileName := range actualFileNames { + var actualFileContent []byte + + actualFileContent, err = os.ReadFile(actualFileName) //nolint:gosec + if err != nil { + t.Fatalf( + "failed reading contents of actual output file %q, error: %s", actualFileName, err, + ) + } + + actualFileContents[actualFileName] = actualFileContent + } + + if *clabernetestesthelper.Update { + for actualFileName, actualFileContent := range actualFileContents { + clabernetestesthelper.WriteTestFixtureFile( + t, + fmt.Sprintf("golden/%s", filepath.Base(actualFileName)), + actualFileContent, + ) + } + + // we just wrote the golden file of course it will match, no need to check + return + } +} diff --git a/charts/clabernetes/tests/default_vaules/test-fixtures/golden/certificate-secret.yaml b/charts/clabernetes/tests/default_vaules/test-fixtures/golden/certificate-secret.yaml new file mode 100755 index 00000000..32bdf5cf --- /dev/null +++ b/charts/clabernetes/tests/default_vaules/test-fixtures/golden/certificate-secret.yaml @@ -0,0 +1,15 @@ +--- +# Source: clabernetes/templates/certificate-secret.yaml +apiVersion: v1 +kind: Secret +metadata: + labels: + chart: "clabernetes-0.0.16" + release: release-name + heritage: Helm + clabernetes/app: clabernetes + clabernetes/name: "clabernetes-certificate" + clabernetes/component: certificate + clabernetes/part-of: manager + name: "clabernetes-certificate" +data: {} diff --git a/charts/clabernetes/tests/default_vaules/test-fixtures/golden/clusterrole.yaml b/charts/clabernetes/tests/default_vaules/test-fixtures/golden/clusterrole.yaml new file mode 100755 index 00000000..c19aff5a --- /dev/null +++ b/charts/clabernetes/tests/default_vaules/test-fixtures/golden/clusterrole.yaml @@ -0,0 +1,65 @@ +--- +# Source: clabernetes/templates/clusterrole.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + chart: "clabernetes-0.0.16" + release: release-name + heritage: Helm + clabernetes/app: clabernetes + clabernetes/name: "clabernetes-cluster-role" + clabernetes/component: cluster-role + name: "clabernetes-cluster-role" +rules: + - apiGroups: + - topology.clabernetes + resources: + - "*" + verbs: + - "*" + - apiGroups: + - apiextensions.k8s.io + resources: + - "*" + verbs: + - "*" + - apiGroups: + - "" + resources: + - namespaces + - secrets + - configmaps + - services + verbs: + - get + - list + - create + - update + - delete + - patch + - watch + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - create + - update + - delete + - patch + - watch + - apiGroups: + - apps + resources: + - deployments + verbs: + - get + - list + - create + - update + - delete + - patch + - watch diff --git a/charts/clabernetes/tests/default_vaules/test-fixtures/golden/clusterrolebinding.yaml b/charts/clabernetes/tests/default_vaules/test-fixtures/golden/clusterrolebinding.yaml new file mode 100755 index 00000000..97fe8a81 --- /dev/null +++ b/charts/clabernetes/tests/default_vaules/test-fixtures/golden/clusterrolebinding.yaml @@ -0,0 +1,21 @@ +--- +# Source: clabernetes/templates/clusterrolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: clabernetes-manager + labels: + chart: "clabernetes-0.0.16" + release: release-name + heritage: Helm + clabernetes/app: clabernetes + clabernetes/name: "clabernetes-cluster-role-binding" + clabernetes/component: cluster-role-binding +subjects: + - kind: ServiceAccount + name: "clabernetes-service-account" + namespace: clabernetes +roleRef: + kind: ClusterRole + name: "clabernetes-cluster-role" + apiGroup: rbac.authorization.k8s.io diff --git a/charts/clabernetes/tests/default_vaules/test-fixtures/golden/configmap.yaml b/charts/clabernetes/tests/default_vaules/test-fixtures/golden/configmap.yaml new file mode 100755 index 00000000..a7d240f9 --- /dev/null +++ b/charts/clabernetes/tests/default_vaules/test-fixtures/golden/configmap.yaml @@ -0,0 +1,24 @@ +--- +# Source: clabernetes/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: clabernetes-config + namespace: clabernetes + labels: + chart: "clabernetes-0.0.16" + release: release-name + heritage: Helm + clabernetes/app: clabernetes + clabernetes/name: "clabernetes-config" + clabernetes/component: config +data: + globalAnnotations: |- + --- + {} + globalLabels: |- + --- + {} + defaultResources: |- + --- + {} diff --git a/charts/clabernetes/tests/default_vaules/test-fixtures/golden/deployment.yaml b/charts/clabernetes/tests/default_vaules/test-fixtures/golden/deployment.yaml new file mode 100755 index 00000000..89ff66b6 --- /dev/null +++ b/charts/clabernetes/tests/default_vaules/test-fixtures/golden/deployment.yaml @@ -0,0 +1,110 @@ +--- +# Source: clabernetes/templates/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: clabernetes-manager + namespace: clabernetes + labels: + chart: "clabernetes-0.0.16" + release: release-name + heritage: Helm + clabernetes/app: clabernetes + clabernetes/name: "clabernetes-manager" + clabernetes/component: manager +spec: + selector: + matchLabels: + clabernetes/app: clabernetes + release: release-name + replicas: + strategy: + rollingUpdate: + maxSurge: 1 + maxUnavailable: 1 + type: RollingUpdate + template: + metadata: + labels: + chart: "clabernetes-0.0.16" + release: release-name + heritage: Helm + clabernetes/app: clabernetes + clabernetes/name: "clabernetes-manager" + clabernetes/component: manager + spec: + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + labelSelector: + matchLabels: + clabernetes/app: clabernetes + clabernetes/name: "clabernetes-manager" + clabernetes/component: manager + topologyKey: kubernetes.io/hostname + - weight: 50 + podAffinityTerm: + labelSelector: + matchLabels: + clabernetes/app: clabernetes + clabernetes/name: "clabernetes-manager" + clabernetes/component: manager + topologyKey: topology.kubernetes.io/zone + terminationGracePeriodSeconds: 10 + serviceAccountName: "clabernetes-service-account" + initContainers: + - name: init + image: "ghcr.io/srl-labs/clabernetes/clabernetes-manager:0.0.16" + imagePullPolicy: IfNotPresent + command: ["/clabernetes/manager", "run", "--initializer"] + env: + - name: APP_NAME + value: clabernetes + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: MANAGER_LOGGER_LEVEL + value: info + resources: + requests: + memory: 128Mi + cpu: 50m + containers: + - name: manager + image: "ghcr.io/srl-labs/clabernetes/clabernetes-manager:0.0.16" + imagePullPolicy: IfNotPresent + command: ["/clabernetes/manager", "run"] + env: + - name: APP_NAME + value: clabernetes + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: CLIENT_OPERATION_TIMEOUT_MULTIPLIER + value: "1" + - name: MANAGER_LOGGER_LEVEL + value: info + - name: CONTROLLER_LOGGER_LEVEL + value: info + - name: LAUNCHER_LOGGER_LEVEL + value: info + - name: LAUNCHER_PULL_POLICY + value: "IfNotPresent" + - name: LAUNCHER_IMAGE + value: "ghcr.io/srl-labs/clabernetes/clabernetes-launcher:0.0.16" + resources: + requests: + memory: 128Mi + cpu: 50m diff --git a/charts/clabernetes/tests/default_vaules/test-fixtures/golden/serviceaccount.yaml b/charts/clabernetes/tests/default_vaules/test-fixtures/golden/serviceaccount.yaml new file mode 100755 index 00000000..81dd4361 --- /dev/null +++ b/charts/clabernetes/tests/default_vaules/test-fixtures/golden/serviceaccount.yaml @@ -0,0 +1,14 @@ +--- +# Source: clabernetes/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: "clabernetes-service-account" + namespace: clabernetes + labels: + chart: "clabernetes-0.0.16" + release: release-name + heritage: Helm + clabernetes/app: clabernetes + clabernetes/name: "clabernetes-service-account" + clabernetes/component: service-account diff --git a/charts/clicker/.helmignore b/charts/clicker/.helmignore index f0c13194..0c975daa 100644 --- a/charts/clicker/.helmignore +++ b/charts/clicker/.helmignore @@ -19,3 +19,6 @@ .project .idea/ *.tmproj + +# ignore +tests \ No newline at end of file diff --git a/charts/clicker/tests/default_vaules/default_values_test.go b/charts/clicker/tests/default_vaules/default_values_test.go new file mode 100644 index 00000000..7d45a65c --- /dev/null +++ b/charts/clicker/tests/default_vaules/default_values_test.go @@ -0,0 +1,90 @@ +package default_vaules_test + +import ( + "fmt" + "os" + "path/filepath" + "testing" + + clabernetesconstants "github.com/srl-labs/clabernetes/constants" + + clabernetestesthelper "github.com/srl-labs/clabernetes/testhelper" +) + +func TestMain(m *testing.M) { + clabernetestesthelper.Flags() + + os.Exit(m.Run()) +} + +// TestDefaultValues -- really just here to ensure that we dont accidentally break our charts; this +// will probably be *highly* irritating in times of lots of chart updates, but, once we know the +// template are in a good place we can always just re-generate the "golden" outputs. +func TestDefaultValues(t *testing.T) { + t.Parallel() + + testName := "default-values" + + // we have to make the chartname/templates dir too since thats where helm wants to write things + actualRootDir := fmt.Sprintf("test-fixtures/%s-actual", testName) + actualDir := fmt.Sprintf("%s/clicker/templates", actualRootDir) + + err := os.MkdirAll(actualDir, clabernetesconstants.PermissionsEveryoneRead) + if err != nil { + t.Fatalf( + "failed creating actual output directory %q, error: %s", actualDir, err, + ) + } + + defer func() { + if !*clabernetestesthelper.SkipCleanup { + err = os.RemoveAll(actualRootDir) + if err != nil { + t.Logf("failed cleaning up actual output directory %q, error: %s", actualDir, err) + } + } + }() + + clabernetestesthelper.HelmCommand( + t, + "template", + "../../.", + "--output-dir", + actualRootDir, + ) + + var actualFileNames []string + + actualFileNames, err = filepath.Glob(fmt.Sprintf("%s/*.yaml", actualDir)) + if err != nil { + t.Fatalf("failed globbing actual files, error: '%s'", err) + } + + actualFileContents := map[string][]byte{} + + for _, actualFileName := range actualFileNames { + var actualFileContent []byte + + actualFileContent, err = os.ReadFile(actualFileName) //nolint:gosec + if err != nil { + t.Fatalf( + "failed reading contents of actual output file %q, error: %s", actualFileName, err, + ) + } + + actualFileContents[actualFileName] = actualFileContent + } + + if *clabernetestesthelper.Update { + for actualFileName, actualFileContent := range actualFileContents { + clabernetestesthelper.WriteTestFixtureFile( + t, + fmt.Sprintf("golden/%s", filepath.Base(actualFileName)), + actualFileContent, + ) + } + + // we just wrote the golden file of course it will match, no need to check + return + } +} diff --git a/charts/clicker/tests/default_vaules/test-fixtures/golden/clusterrole.yaml b/charts/clicker/tests/default_vaules/test-fixtures/golden/clusterrole.yaml new file mode 100755 index 00000000..6dfa747a --- /dev/null +++ b/charts/clicker/tests/default_vaules/test-fixtures/golden/clusterrole.yaml @@ -0,0 +1,30 @@ +--- +# Source: clicker/templates/clusterrole.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + chart: "clicker-0.0.16" + release: release-name + heritage: Helm + clabernetes/app: clabernetes + clabernetes/name: "clabernetes-clicker-cluster-role" + clabernetes/component: cluster-role + name: "clabernetes-clicker-cluster-role" +rules: + - apiGroups: + - "" + resources: + - nodes + verbs: + - "*" + - apiGroups: + - "" + resources: + - pods + verbs: + - get + - list + - create + - watch + - delete diff --git a/charts/clicker/tests/default_vaules/test-fixtures/golden/clusterrolebinding.yaml b/charts/clicker/tests/default_vaules/test-fixtures/golden/clusterrolebinding.yaml new file mode 100755 index 00000000..dc319bf8 --- /dev/null +++ b/charts/clicker/tests/default_vaules/test-fixtures/golden/clusterrolebinding.yaml @@ -0,0 +1,42 @@ +--- +# Source: clicker/templates/clusterrolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: clabernetes-clicker + labels: + chart: "clicker-0.0.16" + release: release-name + heritage: Helm + clabernetes/app: clabernetes + clabernetes/name: "clabernetes-clicker-cluster-role-binding" + clabernetes/component: cluster-role-binding +subjects: + - kind: ServiceAccount + name: "clabernetes-clicker-service-account" + namespace: clabernetes +roleRef: + kind: ClusterRole + name: "clabernetes-cluster-role" + apiGroup: rbac.authorization.k8s.io +--- +# Source: clicker/templates/clusterrolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: clabernetes-clicker-nodes + labels: + chart: "clicker-0.0.16" + release: release-name + heritage: Helm + clabernetes/app: clabernetes + clabernetes/name: "clabernetes-clicker-cluster-role-binding" + clabernetes/component: cluster-role-binding +subjects: + - kind: ServiceAccount + name: "clabernetes-clicker-service-account" + namespace: clabernetes +roleRef: + kind: ClusterRole + name: "clabernetes-clicker-cluster-role" + apiGroup: rbac.authorization.k8s.io diff --git a/charts/clicker/tests/default_vaules/test-fixtures/golden/job.yaml b/charts/clicker/tests/default_vaules/test-fixtures/golden/job.yaml new file mode 100755 index 00000000..55c47fea --- /dev/null +++ b/charts/clicker/tests/default_vaules/test-fixtures/golden/job.yaml @@ -0,0 +1,64 @@ +--- +# Source: clicker/templates/job.yaml +apiVersion: batch/v1 +kind: Job +metadata: + name: clabernetes-clicker + namespace: clabernetes + labels: + chart: "clicker-0.0.16" + release: release-name + heritage: Helm + clabernetes/app: clabernetes + clabernetes/name: "clabernetes-clicker" + clabernetes/component: clicker +spec: + template: + metadata: + labels: + chart: "clicker-0.0.16" + release: release-name + heritage: Helm + clabernetes/app: clabernetes + clabernetes/name: "clabernetes-clicker" + clabernetes/component: clicker + spec: + containers: + - name: clicker + image: "ghcr.io/srl-labs/clabernetes/clabernetes-manager:0.0.16" + imagePullPolicy: IfNotPresent + command: [ + "/clabernetes/manager", + "clicker", + ] + env: + - name: APP_NAME + value: clabernetes + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: CLICKER_LOGGER_LEVEL + value: info + - name: CLICKER_WORKER_COMMAND + value: /bin/sh + - name: CLICKER_WORKER_SCRIPT + value: echo "hello, there" + - name: CLICKER_WORKER_RESOURCES + value: "requests:\n cpu: 50m\n memory: 128Mi" + - name: CLICKER_GLOBAL_ANNOTATIONS + value: "{}" + - name: CLICKER_GLOBAL_LABELS + value: "{}" + resources: + requests: + memory: 128Mi + cpu: 50m + restartPolicy: Never + serviceAccountName: "clabernetes-clicker-service-account" + backoffLimit: 4 + ttlSecondsAfterFinished: 300 diff --git a/charts/clicker/tests/default_vaules/test-fixtures/golden/serviceaccount.yaml b/charts/clicker/tests/default_vaules/test-fixtures/golden/serviceaccount.yaml new file mode 100755 index 00000000..e6cec107 --- /dev/null +++ b/charts/clicker/tests/default_vaules/test-fixtures/golden/serviceaccount.yaml @@ -0,0 +1,14 @@ +--- +# Source: clicker/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: "clabernetes-clicker-service-account" + namespace: clabernetes + labels: + chart: "clicker-0.0.16" + release: release-name + heritage: Helm + clabernetes/app: clabernetes + clabernetes/name: "clabernetes-clicker-service-account" + clabernetes/component: service-account diff --git a/e2e/topology/containerlab/basic/containerlab_basic_test.go b/e2e/topology/containerlab/basic/containerlab_basic_test.go index f064d52c..46b8bf82 100644 --- a/e2e/topology/containerlab/basic/containerlab_basic_test.go +++ b/e2e/topology/containerlab/basic/containerlab_basic_test.go @@ -5,7 +5,7 @@ import ( "os" "testing" - clabernetese2esuite "github.com/srl-labs/clabernetes/e2e/suite" + clabernetestesthelpersuite "github.com/srl-labs/clabernetes/testhelper/suite" clabernetestesthelper "github.com/srl-labs/clabernetes/testhelper" ) @@ -21,12 +21,12 @@ func normalizeContainerlab(t *testing.T, objectData []byte) []byte { // unfortunately we need to remove the hash bits since any cluster may have no lb or get a // different lb address assigned than what we have stored in golden file(s) - objectData = clabernetese2esuite.YQCommand( + objectData = clabernetestesthelper.YQCommand( t, objectData, "del(.status.nodeExposedPortsHash)", ) - objectData = clabernetese2esuite.YQCommand( + objectData = clabernetestesthelper.YQCommand( t, objectData, "del(.status.nodeExposedPorts[].loadBalancerAddress)", @@ -39,14 +39,14 @@ func normalizeExposeService(t *testing.T, objectData []byte) []byte { t.Helper() // cluster ips obviously are going to be different all the time so we'll ignore them - objectData = clabernetese2esuite.YQCommand(t, objectData, "del(.spec.clusterIP)") - objectData = clabernetese2esuite.YQCommand(t, objectData, "del(.spec.clusterIPs)") + objectData = clabernetestesthelper.YQCommand(t, objectData, "del(.spec.clusterIP)") + objectData = clabernetestesthelper.YQCommand(t, objectData, "del(.spec.clusterIPs)") // remove node ports since they'll be random - objectData = clabernetese2esuite.YQCommand(t, objectData, "del(.spec.ports[].nodePort)") + objectData = clabernetestesthelper.YQCommand(t, objectData, "del(.spec.ports[].nodePort)") // and the lb ip in status because of course that may be different depending on cluster - objectData = clabernetese2esuite.YQCommand( + objectData = clabernetestesthelper.YQCommand( t, objectData, ".status.loadBalancer = {}", @@ -60,7 +60,7 @@ func TestContainerlabBasic(t *testing.T) { testName := "containerlab-basic" - steps := clabernetese2esuite.Steps{ + steps := clabernetestesthelpersuite.Steps{ { // this step, while obviously very "basic" does quite a bit of work for us... it ensures // that the default ports are allocated, the config is hashed and subdivided up, and our @@ -68,7 +68,7 @@ func TestContainerlabBasic(t *testing.T) { // setup as we'd expect. Index: 10, Description: "Create a simple containerlab topology with just one node", - AssertObjects: map[string][]clabernetese2esuite.AssertObject{ + AssertObjects: map[string][]clabernetestesthelpersuite.AssertObject{ "containerlab": { { Name: testName, @@ -89,5 +89,5 @@ func TestContainerlabBasic(t *testing.T) { }, } - clabernetese2esuite.Run(t, steps, testName) + clabernetestesthelpersuite.Run(t, steps, testName) } diff --git a/testhelper/command.go b/testhelper/command.go new file mode 100644 index 00000000..4ee1e168 --- /dev/null +++ b/testhelper/command.go @@ -0,0 +1,21 @@ +package testhelper + +import ( + "os/exec" + "testing" +) + +// Execute executes a command in the context of a test. +func Execute(t *testing.T, cmd *exec.Cmd) []byte { + t.Helper() + + output, err := cmd.CombinedOutput() + if err != nil { + t.Logf("error executing command, error: %q", err) + t.Logf("errored command: %s", cmd.String()) + t.Logf("errored command combined output: %s", output) + t.FailNow() + } + + return output +} diff --git a/testhelper/helm.go b/testhelper/helm.go new file mode 100644 index 00000000..e94b0e63 --- /dev/null +++ b/testhelper/helm.go @@ -0,0 +1,155 @@ +package testhelper + +import ( + "bytes" + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" + "testing" + + clabernetesconstants "github.com/srl-labs/clabernetes/constants" +) + +const ( + helm = "helm" +) + +// HelmTest executes a test against a helm chart -- this is a very simple/dumb test meant only to +// ensure that we don't accidentally screw up charts. We do this by storing the "golden" output of +// a rendered chart (and subcharts if applicable) with a given values file. +func HelmTest(t *testing.T, testName string) { + t.Helper() + + // we have to make the chartname/templates dir too since thats where helm wants to write things + actualRootDir := fmt.Sprintf("test-fixtures/%s-actual", testName) + actualDir := fmt.Sprintf("%s/clabernetes/templates", actualRootDir) + + valuesFile, err := filepath.Abs(fmt.Sprintf("test-fixtures/%s-values.yaml", testName)) + if err != nil { + t.Fatalf( + "failed getting abspath for values file, error: %s", err, + ) + } + + err = os.MkdirAll(actualDir, clabernetesconstants.PermissionsEveryoneRead) + if err != nil { + t.Fatalf( + "failed creating actual output directory %q, error: %s", actualDir, err, + ) + } + + defer func() { + if !*SkipCleanup { + err = os.RemoveAll(actualRootDir) + if err != nil { + t.Logf("failed cleaning up actual output directory %q, error: %s", actualDir, err) + } + } + }() + + HelmCommand( + t, + "template", + "../../.", + "--output-dir", + actualRootDir, + "--values", + valuesFile, + ) + + renderedTemplates := ReadAllRenderedTemplates(t, actualRootDir) + + if *Update { + for expectedFileName, expectedFileContent := range renderedTemplates { + WriteTestFixtureFile( + t, + fmt.Sprintf("golden/%s", filepath.Base(expectedFileName)), + expectedFileContent, + ) + } + + // we just wrote the golden file of course it will match, no need to check + return + } + + for expectedFileName, actualContents := range renderedTemplates { + expected := ReadTestFixtureFile(t, fmt.Sprintf("golden/%s", expectedFileName)) + + if !bytes.Equal( + actualContents, + expected, + ) { + FailOutput(t, actualContents, expected) + } + } +} + +// HelmCommand executes helm with the given arguments. +func HelmCommand(t *testing.T, args ...string) []byte { + t.Helper() + + cmd := exec.Command( + helm, + args..., + ) + + return Execute(t, cmd) +} + +// ReadAllRenderedTemplates loads all rendered template content into a map -- sub-charts are loaded +// with a "_subchart--" prefix. +func ReadAllRenderedTemplates(t *testing.T, rootRenderDir string) map[string][]byte { + t.Helper() + + renderedTemplates := map[string][]byte{} + + parentChartFileNames, err := filepath.Glob(fmt.Sprintf("%s/*/templates/*.yaml", rootRenderDir)) + if err != nil { + t.Fatalf("failed globbing parent chart files, error: '%s'", err) + } + + subChartFileNames, err := filepath.Glob( + fmt.Sprintf("%s/*/charts/*/templates/*.yaml", rootRenderDir), + ) + if err != nil { + t.Fatalf("failed globbing dependency chart files, error: '%s'", err) + } + + for _, parentChartFileName := range parentChartFileNames { + var contents []byte + + contents, err = os.ReadFile(parentChartFileName) //nolint:gosec + if err != nil { + t.Fatalf( + "failed reading contents of actual output file %q, error: %s", + parentChartFileName, + err, + ) + } + + renderedTemplates[filepath.Base(parentChartFileName)] = contents + } + + for _, subChartFileName := range subChartFileNames { + subChartPathComponents := strings.Split(subChartFileName, string(filepath.Separator)) + + subChartName := subChartPathComponents[4] + + var contents []byte + + contents, err = os.ReadFile(subChartFileName) //nolint:gosec + if err != nil { + t.Fatalf( + "failed reading contents of actual output file %q, error: %s", + subChartFileName, + err, + ) + } + + renderedTemplates[fmt.Sprintf("_subchart-%s-%s", subChartName, filepath.Base(subChartFileName))] = contents //nolint:lll + } + + return renderedTemplates +} diff --git a/e2e/suite/command.go b/testhelper/kubectl.go similarity index 63% rename from e2e/suite/command.go rename to testhelper/kubectl.go index b18e8b72..5097eb7b 100644 --- a/e2e/suite/command.go +++ b/testhelper/kubectl.go @@ -1,7 +1,6 @@ -package suite +package testhelper import ( - "fmt" "os/exec" "testing" ) @@ -10,19 +9,19 @@ const ( kubectl = "kubectl" ) -func execute(t *testing.T, cmd *exec.Cmd) []byte { - t.Helper() - - output, err := cmd.CombinedOutput() - if err != nil { - t.Logf("error executing command, error: %q", err) - t.Logf("errored command: %s", cmd.String()) - t.Logf("errored command combined output: %s", output) - t.FailNow() - } +// Operation represents a kubectl operation type, i.e. apply or delete. +type Operation string - return output -} +const ( + // Apply is the apply kubectl operation. + Apply Operation = "apply" + // Delete is the delete kubectl operation. + Delete Operation = "delete" + // Create is the create kubectl operation. + Create Operation = "create" + // Get is the get kubectl operation. + Get Operation = "get" +) func kubectlNamespace(t *testing.T, operation Operation, namespace string) { t.Helper() @@ -62,7 +61,7 @@ func KubectlFileOp(t *testing.T, operation Operation, namespace, fileName string fileName, ) - _ = execute(t, cmd) + _ = Execute(t, cmd) } // KubectlGetOp runs get on the given object, returning the yaml output. @@ -80,21 +79,5 @@ func KubectlGetOp(t *testing.T, kind, namespace, name string) []byte { "yaml", ) - return execute(t, cmd) -} - -// YQCommand accepts some yaml content and returns it after executing the given yqPattern against -// it. -func YQCommand(t *testing.T, content []byte, yqPattern string) []byte { - t.Helper() - - yqCmd := fmt.Sprintf("echo '%s' | yq '%s'", string(content), yqPattern) - - cmd := exec.Command( //nolint:gosec - "bash", - "-c", - yqCmd, - ) - - return execute(t, cmd) + return Execute(t, cmd) } diff --git a/e2e/suite/kubernetes.go b/testhelper/kubernetes.go similarity index 99% rename from e2e/suite/kubernetes.go rename to testhelper/kubernetes.go index cbe99ad9..68a9c243 100644 --- a/e2e/suite/kubernetes.go +++ b/testhelper/kubernetes.go @@ -1,4 +1,4 @@ -package suite +package testhelper import ( "testing" diff --git a/e2e/suite/eventually.go b/testhelper/suite/eventually.go similarity index 100% rename from e2e/suite/eventually.go rename to testhelper/suite/eventually.go diff --git a/e2e/suite/files.go b/testhelper/suite/files.go similarity index 100% rename from e2e/suite/files.go rename to testhelper/suite/files.go diff --git a/e2e/suite/logging.go b/testhelper/suite/logging.go similarity index 68% rename from e2e/suite/logging.go rename to testhelper/suite/logging.go index 02a1f989..7a68fa62 100644 --- a/e2e/suite/logging.go +++ b/testhelper/suite/logging.go @@ -4,7 +4,6 @@ import "fmt" const ( green = "\u001B[32m" - red = "\u001B[31m" colorStop = "\033[0m" ) @@ -17,8 +16,3 @@ func LogStepDescr(idx int, description string) string { func LogStepSuccess(idx int) string { return fmt.Sprintf("Step %d: %sSUCCESS%s", idx, green, colorStop) } - -// LogStepFailure sends a pretty string to the test logger for a step failure. -func LogStepFailure(idx int) string { - return fmt.Sprintf("Step %d: %sFAILURE%s", idx, red, colorStop) -} diff --git a/e2e/suite/run.go b/testhelper/suite/run.go similarity index 81% rename from e2e/suite/run.go rename to testhelper/suite/run.go index 236acb26..3e2d98b2 100644 --- a/e2e/suite/run.go +++ b/testhelper/suite/run.go @@ -16,13 +16,13 @@ const ( // Run executes a clabernetes e2e test. func Run(t *testing.T, steps []Step, testName string) { //nolint: thelper - namespace := NewTestNamespace(testName) + namespace := clabernetestesthelper.NewTestNamespace(testName) - KubectlCreateNamespace(t, namespace) + clabernetestesthelper.KubectlCreateNamespace(t, namespace) defer func() { if !*clabernetestesthelper.SkipCleanup { - KubectlDeleteNamespace(t, namespace) + clabernetestesthelper.KubectlDeleteNamespace(t, namespace) } }() @@ -34,7 +34,7 @@ func Run(t *testing.T, steps []Step, testName string) { //nolint: thelper for _, stepFixture := range stepFixtures { stepFixtureOperationType := GetStepFixtureType(t, stepFixture) - KubectlFileOp(t, stepFixtureOperationType, namespace, stepFixture) + clabernetestesthelper.KubectlFileOp(t, stepFixtureOperationType, namespace, stepFixture) } if *clabernetestesthelper.Update { @@ -77,10 +77,10 @@ func Run(t *testing.T, steps []Step, testName string) { //nolint: thelper func getter(t *testing.T, namespace, kind, objectName string, object AssertObject) []byte { t.Helper() - objectData := KubectlGetOp(t, kind, namespace, objectName) + objectData := clabernetestesthelper.KubectlGetOp(t, kind, namespace, objectName) if !object.SkipDefaultNormalize { - objectData = NormalizeKubernetesObject(t, objectData) + objectData = clabernetestesthelper.NormalizeKubernetesObject(t, objectData) } for _, normalizeF := range object.NormalizeFuncs { diff --git a/e2e/suite/steps.go b/testhelper/suite/steps.go similarity index 74% rename from e2e/suite/steps.go rename to testhelper/suite/steps.go index a7f17c70..5b99ef7d 100644 --- a/e2e/suite/steps.go +++ b/testhelper/suite/steps.go @@ -4,20 +4,8 @@ import ( "regexp" "sync" "testing" -) - -// Operation represents a kubectl operation type, i.e. apply or delete. -type Operation string -const ( - // Apply is the apply kubectl operation. - Apply Operation = "apply" - // Delete is the delete kubectl operation. - Delete Operation = "delete" - // Create is the create kubectl operation. - Create Operation = "create" - // Get is the get kubectl operation. - Get Operation = "get" + clabernetestesthelper "github.com/srl-labs/clabernetes/testhelper" ) // AssertObject represents an object that we are looking to assert the state of in a test -- the @@ -59,7 +47,7 @@ func getStepPatterns() *stepPatterns { } // GetStepFixtureType returns the Operation type of the given test step fixture file. -func GetStepFixtureType(t *testing.T, stepFixtureName string) Operation { +func GetStepFixtureType(t *testing.T, stepFixtureName string) clabernetestesthelper.Operation { t.Helper() patterns := getStepPatterns() @@ -67,10 +55,13 @@ func GetStepFixtureType(t *testing.T, stepFixtureName string) Operation { matches := patterns.stepFixtureType.FindStringSubmatch(stepFixtureName) opIndex := patterns.stepFixtureType.SubexpIndex("fixtureType") - resolved := Operation(matches[opIndex]) + resolved := clabernetestesthelper.Operation(matches[opIndex]) switch resolved { - case Apply, Delete, Create, Get: + case clabernetestesthelper.Apply, + clabernetestesthelper.Delete, + clabernetestesthelper.Create, + clabernetestesthelper.Get: default: t.Fatalf("fixture type '%s' invalid", resolved) } diff --git a/testhelper/yq.go b/testhelper/yq.go new file mode 100644 index 00000000..a39b2640 --- /dev/null +++ b/testhelper/yq.go @@ -0,0 +1,23 @@ +package testhelper + +import ( + "fmt" + "os/exec" + "testing" +) + +// YQCommand accepts some yaml content and returns it after executing the given yqPattern against +// it. +func YQCommand(t *testing.T, content []byte, yqPattern string) []byte { + t.Helper() + + yqCmd := fmt.Sprintf("echo '%s' | yq '%s'", string(content), yqPattern) + + cmd := exec.Command( //nolint:gosec + "bash", + "-c", + yqCmd, + ) + + return Execute(t, cmd) +} From b5926cdf52032c147a6cd289fc80822e57347955 Mon Sep 17 00:00:00 2001 From: Carl Montanari Date: Tue, 17 Oct 2023 06:37:36 -0700 Subject: [PATCH 2/6] tests: clicker sub chart test --- .../tests/clicker/clicker_enabled_test.go | 3 +- .../test-fixtures/clicker-enabled-values.yaml | 16 +++++ .../golden/_subchart-clicker-clusterrole.yaml | 11 ++- .../_subchart-clicker-clusterrolebinding.yaml | 21 +++--- .../golden/_subchart-clicker-job.yaml | 28 +++++--- .../_subchart-clicker-serviceaccount.yaml | 11 ++- .../golden/certificate-secret.yaml | 11 ++- .../test-fixtures/golden/clusterrole.yaml | 11 ++- .../golden/clusterrolebinding.yaml | 13 ++-- .../test-fixtures/golden/configmap.yaml | 17 +++-- .../test-fixtures/golden/deployment.yaml | 36 ++++++---- .../test-fixtures/golden/serviceaccount.yaml | 11 ++- .../default_vaules/default_values_test.go | 67 +------------------ charts/clabernetes/values.yaml | 5 ++ testhelper/helm.go | 34 +++++++--- 15 files changed, 163 insertions(+), 132 deletions(-) diff --git a/charts/clabernetes/tests/clicker/clicker_enabled_test.go b/charts/clabernetes/tests/clicker/clicker_enabled_test.go index b6e40fa7..c9a60d97 100644 --- a/charts/clabernetes/tests/clicker/clicker_enabled_test.go +++ b/charts/clabernetes/tests/clicker/clicker_enabled_test.go @@ -1,6 +1,7 @@ package default_vaules_test import ( + "fmt" "os" "testing" @@ -21,5 +22,5 @@ func TestClickerEnabled(t *testing.T) { testName := "clicker-enabled" - clabernetestesthelper.HelmTest(t, testName) + clabernetestesthelper.HelmTest(t, testName, fmt.Sprintf("%s-values.yaml", testName)) } diff --git a/charts/clabernetes/tests/clicker/test-fixtures/clicker-enabled-values.yaml b/charts/clabernetes/tests/clicker/test-fixtures/clicker-enabled-values.yaml index c80f8c3a..da2c82fb 100644 --- a/charts/clabernetes/tests/clicker/test-fixtures/clicker-enabled-values.yaml +++ b/charts/clabernetes/tests/clicker/test-fixtures/clicker-enabled-values.yaml @@ -1,3 +1,19 @@ --- +# ensure that "global" values (not actually helm globals, but values we pass via yaml anchor) +# are non-default and passed to the clicker cahrt and render properly +appName: &_appName clabernetes-plus-clicker + +# extra labels/annotations that are added to all objects +globalAnnotations: &_globalAnnotations + someannotation: someannotationvalue + annotherannotation: anotherannotationvalue +globalLabels: &_globalLabels + somelabel: somelabelvalue + anotherlabel: anotherlabelvalue + +# ensure that when enabled clicker stuff is rendered clicker: enabled: true + appName: *_appName + globalAnnotations: *_globalAnnotations + globalLabels: *_globalLabels \ No newline at end of file diff --git a/charts/clabernetes/tests/clicker/test-fixtures/golden/_subchart-clicker-clusterrole.yaml b/charts/clabernetes/tests/clicker/test-fixtures/golden/_subchart-clicker-clusterrole.yaml index 3f03c8d2..9aad0bbf 100755 --- a/charts/clabernetes/tests/clicker/test-fixtures/golden/_subchart-clicker-clusterrole.yaml +++ b/charts/clabernetes/tests/clicker/test-fixtures/golden/_subchart-clicker-clusterrole.yaml @@ -7,10 +7,15 @@ metadata: chart: "clicker-0.0.16" release: release-name heritage: Helm - clabernetes/app: clabernetes - clabernetes/name: "clabernetes-clicker-cluster-role" + clabernetes/app: clabernetes-plus-clicker + clabernetes/name: "clabernetes-plus-clicker-clicker-cluster-role" clabernetes/component: cluster-role - name: "clabernetes-clicker-cluster-role" + anotherlabel: anotherlabelvalue + somelabel: somelabelvalue + annotations: + annotherannotation: anotherannotationvalue + someannotation: someannotationvalue + name: "clabernetes-plus-clicker-clicker-cluster-role" rules: - apiGroups: - "" diff --git a/charts/clabernetes/tests/clicker/test-fixtures/golden/_subchart-clicker-clusterrolebinding.yaml b/charts/clabernetes/tests/clicker/test-fixtures/golden/_subchart-clicker-clusterrolebinding.yaml index 7de39437..517c0941 100755 --- a/charts/clabernetes/tests/clicker/test-fixtures/golden/_subchart-clicker-clusterrolebinding.yaml +++ b/charts/clabernetes/tests/clicker/test-fixtures/golden/_subchart-clicker-clusterrolebinding.yaml @@ -8,16 +8,21 @@ metadata: chart: "clicker-0.0.16" release: release-name heritage: Helm - clabernetes/app: clabernetes - clabernetes/name: "clabernetes-clicker-cluster-role-binding" + clabernetes/app: clabernetes-plus-clicker + clabernetes/name: "clabernetes-plus-clicker-clicker-cluster-role-binding" clabernetes/component: cluster-role-binding + anotherlabel: anotherlabelvalue + somelabel: somelabelvalue + annotations: + annotherannotation: anotherannotationvalue + someannotation: someannotationvalue subjects: - kind: ServiceAccount - name: "clabernetes-clicker-service-account" + name: "clabernetes-plus-clicker-clicker-service-account" namespace: clabernetes roleRef: kind: ClusterRole - name: "clabernetes-cluster-role" + name: "clabernetes-plus-clicker-cluster-role" apiGroup: rbac.authorization.k8s.io --- # Source: clabernetes/charts/clicker/templates/clusterrolebinding.yaml @@ -29,14 +34,14 @@ metadata: chart: "clicker-0.0.16" release: release-name heritage: Helm - clabernetes/app: clabernetes - clabernetes/name: "clabernetes-clicker-cluster-role-binding" + clabernetes/app: clabernetes-plus-clicker + clabernetes/name: "clabernetes-plus-clicker-clicker-cluster-role-binding" clabernetes/component: cluster-role-binding subjects: - kind: ServiceAccount - name: "clabernetes-clicker-service-account" + name: "clabernetes-plus-clicker-clicker-service-account" namespace: clabernetes roleRef: kind: ClusterRole - name: "clabernetes-clicker-cluster-role" + name: "clabernetes-plus-clicker-clicker-cluster-role" apiGroup: rbac.authorization.k8s.io diff --git a/charts/clabernetes/tests/clicker/test-fixtures/golden/_subchart-clicker-job.yaml b/charts/clabernetes/tests/clicker/test-fixtures/golden/_subchart-clicker-job.yaml index 37f8e037..353e6c73 100755 --- a/charts/clabernetes/tests/clicker/test-fixtures/golden/_subchart-clicker-job.yaml +++ b/charts/clabernetes/tests/clicker/test-fixtures/golden/_subchart-clicker-job.yaml @@ -3,15 +3,20 @@ apiVersion: batch/v1 kind: Job metadata: - name: clabernetes-clicker + name: clabernetes-plus-clicker-clicker namespace: clabernetes labels: chart: "clicker-0.0.16" release: release-name heritage: Helm - clabernetes/app: clabernetes - clabernetes/name: "clabernetes-clicker" + clabernetes/app: clabernetes-plus-clicker + clabernetes/name: "clabernetes-plus-clicker-clicker" clabernetes/component: clicker + anotherlabel: anotherlabelvalue + somelabel: somelabelvalue + annotations: + annotherannotation: anotherannotationvalue + someannotation: someannotationvalue spec: template: metadata: @@ -19,9 +24,14 @@ spec: chart: "clicker-0.0.16" release: release-name heritage: Helm - clabernetes/app: clabernetes - clabernetes/name: "clabernetes-clicker" + clabernetes/app: clabernetes-plus-clicker + clabernetes/name: "clabernetes-plus-clicker-clicker" clabernetes/component: clicker + anotherlabel: anotherlabelvalue + somelabel: somelabelvalue + annotations: + annotherannotation: anotherannotationvalue + someannotation: someannotationvalue spec: containers: - name: clicker @@ -33,7 +43,7 @@ spec: ] env: - name: APP_NAME - value: clabernetes + value: clabernetes-plus-clicker - name: POD_NAME valueFrom: fieldRef: @@ -51,14 +61,14 @@ spec: - name: CLICKER_WORKER_RESOURCES value: "requests:\n cpu: 50m\n memory: 128Mi" - name: CLICKER_GLOBAL_ANNOTATIONS - value: "{}" + value: "annotherannotation: anotherannotationvalue\nsomeannotation: someannotationvalue" - name: CLICKER_GLOBAL_LABELS - value: "{}" + value: "anotherlabel: anotherlabelvalue\nsomelabel: somelabelvalue" resources: requests: memory: 128Mi cpu: 50m restartPolicy: Never - serviceAccountName: "clabernetes-clicker-service-account" + serviceAccountName: "clabernetes-plus-clicker-clicker-service-account" backoffLimit: 4 ttlSecondsAfterFinished: 300 diff --git a/charts/clabernetes/tests/clicker/test-fixtures/golden/_subchart-clicker-serviceaccount.yaml b/charts/clabernetes/tests/clicker/test-fixtures/golden/_subchart-clicker-serviceaccount.yaml index a77e0f57..33e62841 100755 --- a/charts/clabernetes/tests/clicker/test-fixtures/golden/_subchart-clicker-serviceaccount.yaml +++ b/charts/clabernetes/tests/clicker/test-fixtures/golden/_subchart-clicker-serviceaccount.yaml @@ -3,12 +3,17 @@ apiVersion: v1 kind: ServiceAccount metadata: - name: "clabernetes-clicker-service-account" + name: "clabernetes-plus-clicker-clicker-service-account" namespace: clabernetes labels: chart: "clicker-0.0.16" release: release-name heritage: Helm - clabernetes/app: clabernetes - clabernetes/name: "clabernetes-clicker-service-account" + clabernetes/app: clabernetes-plus-clicker + clabernetes/name: "clabernetes-plus-clicker-clicker-service-account" clabernetes/component: service-account + anotherlabel: anotherlabelvalue + somelabel: somelabelvalue + annotations: + annotherannotation: anotherannotationvalue + someannotation: someannotationvalue diff --git a/charts/clabernetes/tests/clicker/test-fixtures/golden/certificate-secret.yaml b/charts/clabernetes/tests/clicker/test-fixtures/golden/certificate-secret.yaml index 32bdf5cf..5ba46dc7 100755 --- a/charts/clabernetes/tests/clicker/test-fixtures/golden/certificate-secret.yaml +++ b/charts/clabernetes/tests/clicker/test-fixtures/golden/certificate-secret.yaml @@ -7,9 +7,14 @@ metadata: chart: "clabernetes-0.0.16" release: release-name heritage: Helm - clabernetes/app: clabernetes - clabernetes/name: "clabernetes-certificate" + clabernetes/app: clabernetes-plus-clicker + clabernetes/name: "clabernetes-plus-clicker-certificate" clabernetes/component: certificate clabernetes/part-of: manager - name: "clabernetes-certificate" + anotherlabel: anotherlabelvalue + somelabel: somelabelvalue + annotations: + annotherannotation: anotherannotationvalue + someannotation: someannotationvalue + name: "clabernetes-plus-clicker-certificate" data: {} diff --git a/charts/clabernetes/tests/clicker/test-fixtures/golden/clusterrole.yaml b/charts/clabernetes/tests/clicker/test-fixtures/golden/clusterrole.yaml index c19aff5a..11b7ea33 100755 --- a/charts/clabernetes/tests/clicker/test-fixtures/golden/clusterrole.yaml +++ b/charts/clabernetes/tests/clicker/test-fixtures/golden/clusterrole.yaml @@ -7,10 +7,15 @@ metadata: chart: "clabernetes-0.0.16" release: release-name heritage: Helm - clabernetes/app: clabernetes - clabernetes/name: "clabernetes-cluster-role" + clabernetes/app: clabernetes-plus-clicker + clabernetes/name: "clabernetes-plus-clicker-cluster-role" clabernetes/component: cluster-role - name: "clabernetes-cluster-role" + anotherlabel: anotherlabelvalue + somelabel: somelabelvalue + annotations: + annotherannotation: anotherannotationvalue + someannotation: someannotationvalue + name: "clabernetes-plus-clicker-cluster-role" rules: - apiGroups: - topology.clabernetes diff --git a/charts/clabernetes/tests/clicker/test-fixtures/golden/clusterrolebinding.yaml b/charts/clabernetes/tests/clicker/test-fixtures/golden/clusterrolebinding.yaml index 97fe8a81..44e65644 100755 --- a/charts/clabernetes/tests/clicker/test-fixtures/golden/clusterrolebinding.yaml +++ b/charts/clabernetes/tests/clicker/test-fixtures/golden/clusterrolebinding.yaml @@ -8,14 +8,19 @@ metadata: chart: "clabernetes-0.0.16" release: release-name heritage: Helm - clabernetes/app: clabernetes - clabernetes/name: "clabernetes-cluster-role-binding" + clabernetes/app: clabernetes-plus-clicker + clabernetes/name: "clabernetes-plus-clicker-cluster-role-binding" clabernetes/component: cluster-role-binding + anotherlabel: anotherlabelvalue + somelabel: somelabelvalue + annotations: + annotherannotation: anotherannotationvalue + someannotation: someannotationvalue subjects: - kind: ServiceAccount - name: "clabernetes-service-account" + name: "clabernetes-plus-clicker-service-account" namespace: clabernetes roleRef: kind: ClusterRole - name: "clabernetes-cluster-role" + name: "clabernetes-plus-clicker-cluster-role" apiGroup: rbac.authorization.k8s.io diff --git a/charts/clabernetes/tests/clicker/test-fixtures/golden/configmap.yaml b/charts/clabernetes/tests/clicker/test-fixtures/golden/configmap.yaml index a7d240f9..063dc7a3 100755 --- a/charts/clabernetes/tests/clicker/test-fixtures/golden/configmap.yaml +++ b/charts/clabernetes/tests/clicker/test-fixtures/golden/configmap.yaml @@ -3,22 +3,29 @@ apiVersion: v1 kind: ConfigMap metadata: - name: clabernetes-config + name: clabernetes-plus-clicker-config namespace: clabernetes labels: chart: "clabernetes-0.0.16" release: release-name heritage: Helm - clabernetes/app: clabernetes - clabernetes/name: "clabernetes-config" + clabernetes/app: clabernetes-plus-clicker + clabernetes/name: "clabernetes-plus-clicker-config" clabernetes/component: config + anotherlabel: anotherlabelvalue + somelabel: somelabelvalue + annotations: + annotherannotation: anotherannotationvalue + someannotation: someannotationvalue data: globalAnnotations: |- --- - {} + annotherannotation: anotherannotationvalue + someannotation: someannotationvalue globalLabels: |- --- - {} + anotherlabel: anotherlabelvalue + somelabel: somelabelvalue defaultResources: |- --- {} diff --git a/charts/clabernetes/tests/clicker/test-fixtures/golden/deployment.yaml b/charts/clabernetes/tests/clicker/test-fixtures/golden/deployment.yaml index 89ff66b6..c5899e6e 100755 --- a/charts/clabernetes/tests/clicker/test-fixtures/golden/deployment.yaml +++ b/charts/clabernetes/tests/clicker/test-fixtures/golden/deployment.yaml @@ -3,19 +3,24 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: clabernetes-manager + name: clabernetes-plus-clicker-manager namespace: clabernetes labels: chart: "clabernetes-0.0.16" release: release-name heritage: Helm - clabernetes/app: clabernetes - clabernetes/name: "clabernetes-manager" + clabernetes/app: clabernetes-plus-clicker + clabernetes/name: "clabernetes-plus-clicker-manager" clabernetes/component: manager + anotherlabel: anotherlabelvalue + somelabel: somelabelvalue + annotations: + annotherannotation: anotherannotationvalue + someannotation: someannotationvalue spec: selector: matchLabels: - clabernetes/app: clabernetes + clabernetes/app: clabernetes-plus-clicker release: release-name replicas: strategy: @@ -29,9 +34,14 @@ spec: chart: "clabernetes-0.0.16" release: release-name heritage: Helm - clabernetes/app: clabernetes - clabernetes/name: "clabernetes-manager" + clabernetes/app: clabernetes-plus-clicker + clabernetes/name: "clabernetes-plus-clicker-manager" clabernetes/component: manager + anotherlabel: anotherlabelvalue + somelabel: somelabelvalue + annotations: + annotherannotation: anotherannotationvalue + someannotation: someannotationvalue spec: affinity: podAntiAffinity: @@ -40,20 +50,20 @@ spec: podAffinityTerm: labelSelector: matchLabels: - clabernetes/app: clabernetes - clabernetes/name: "clabernetes-manager" + clabernetes/app: clabernetes-plus-clicker + clabernetes/name: "clabernetes-plus-clicker-manager" clabernetes/component: manager topologyKey: kubernetes.io/hostname - weight: 50 podAffinityTerm: labelSelector: matchLabels: - clabernetes/app: clabernetes - clabernetes/name: "clabernetes-manager" + clabernetes/app: clabernetes-plus-clicker + clabernetes/name: "clabernetes-plus-clicker-manager" clabernetes/component: manager topologyKey: topology.kubernetes.io/zone terminationGracePeriodSeconds: 10 - serviceAccountName: "clabernetes-service-account" + serviceAccountName: "clabernetes-plus-clicker-service-account" initContainers: - name: init image: "ghcr.io/srl-labs/clabernetes/clabernetes-manager:0.0.16" @@ -61,7 +71,7 @@ spec: command: ["/clabernetes/manager", "run", "--initializer"] env: - name: APP_NAME - value: clabernetes + value: clabernetes-plus-clicker - name: POD_NAME valueFrom: fieldRef: @@ -83,7 +93,7 @@ spec: command: ["/clabernetes/manager", "run"] env: - name: APP_NAME - value: clabernetes + value: clabernetes-plus-clicker - name: POD_NAME valueFrom: fieldRef: diff --git a/charts/clabernetes/tests/clicker/test-fixtures/golden/serviceaccount.yaml b/charts/clabernetes/tests/clicker/test-fixtures/golden/serviceaccount.yaml index 81dd4361..606bfed9 100755 --- a/charts/clabernetes/tests/clicker/test-fixtures/golden/serviceaccount.yaml +++ b/charts/clabernetes/tests/clicker/test-fixtures/golden/serviceaccount.yaml @@ -3,12 +3,17 @@ apiVersion: v1 kind: ServiceAccount metadata: - name: "clabernetes-service-account" + name: "clabernetes-plus-clicker-service-account" namespace: clabernetes labels: chart: "clabernetes-0.0.16" release: release-name heritage: Helm - clabernetes/app: clabernetes - clabernetes/name: "clabernetes-service-account" + clabernetes/app: clabernetes-plus-clicker + clabernetes/name: "clabernetes-plus-clicker-service-account" clabernetes/component: service-account + anotherlabel: anotherlabelvalue + somelabel: somelabelvalue + annotations: + annotherannotation: anotherannotationvalue + someannotation: someannotationvalue diff --git a/charts/clabernetes/tests/default_vaules/default_values_test.go b/charts/clabernetes/tests/default_vaules/default_values_test.go index 2a312722..ff61c816 100644 --- a/charts/clabernetes/tests/default_vaules/default_values_test.go +++ b/charts/clabernetes/tests/default_vaules/default_values_test.go @@ -1,13 +1,9 @@ package default_vaules_test import ( - "fmt" "os" - "path/filepath" "testing" - clabernetesconstants "github.com/srl-labs/clabernetes/constants" - clabernetestesthelper "github.com/srl-labs/clabernetes/testhelper" ) @@ -25,66 +21,5 @@ func TestDefaultValues(t *testing.T) { testName := "default-values" - // we have to make the chartname/templates dir too since thats where helm wants to write things - actualRootDir := fmt.Sprintf("test-fixtures/%s-actual", testName) - actualDir := fmt.Sprintf("%s/clabernetes/templates", actualRootDir) - - err := os.MkdirAll(actualDir, clabernetesconstants.PermissionsEveryoneRead) - if err != nil { - t.Fatalf( - "failed creating actual output directory %q, error: %s", actualDir, err, - ) - } - - defer func() { - if !*clabernetestesthelper.SkipCleanup { - err = os.RemoveAll(actualRootDir) - if err != nil { - t.Logf("failed cleaning up actual output directory %q, error: %s", actualDir, err) - } - } - }() - - clabernetestesthelper.HelmCommand( - t, - "template", - "../../.", - "--output-dir", - actualRootDir, - ) - - var actualFileNames []string - - actualFileNames, err = filepath.Glob(fmt.Sprintf("%s/*.yaml", actualDir)) - if err != nil { - t.Fatalf("failed globbing actual files, error: '%s'", err) - } - - actualFileContents := map[string][]byte{} - - for _, actualFileName := range actualFileNames { - var actualFileContent []byte - - actualFileContent, err = os.ReadFile(actualFileName) //nolint:gosec - if err != nil { - t.Fatalf( - "failed reading contents of actual output file %q, error: %s", actualFileName, err, - ) - } - - actualFileContents[actualFileName] = actualFileContent - } - - if *clabernetestesthelper.Update { - for actualFileName, actualFileContent := range actualFileContents { - clabernetestesthelper.WriteTestFixtureFile( - t, - fmt.Sprintf("golden/%s", filepath.Base(actualFileName)), - actualFileContent, - ) - } - - // we just wrote the golden file of course it will match, no need to check - return - } + clabernetestesthelper.HelmTest(t, testName, "") } diff --git a/charts/clabernetes/values.yaml b/charts/clabernetes/values.yaml index 232799dd..3f9199b6 100644 --- a/charts/clabernetes/values.yaml +++ b/charts/clabernetes/values.yaml @@ -2,6 +2,11 @@ # # global options # +# note the yaml anchors, we use these to easily pass the same values to the clicker sub-chart (if +# enabling); there is no magic here other than yaml anchor magic, if you expect the "global" things +# to be really global and applied to the clicker (or any other future) dependency then use anchors +# or pass things explicitly. this felt better than using actual helm "globals" +# appName: &_appName clabernetes diff --git a/testhelper/helm.go b/testhelper/helm.go index e94b0e63..406c9558 100644 --- a/testhelper/helm.go +++ b/testhelper/helm.go @@ -19,21 +19,27 @@ const ( // HelmTest executes a test against a helm chart -- this is a very simple/dumb test meant only to // ensure that we don't accidentally screw up charts. We do this by storing the "golden" output of // a rendered chart (and subcharts if applicable) with a given values file. -func HelmTest(t *testing.T, testName string) { +func HelmTest(t *testing.T, testName, valuesFileName string) { t.Helper() // we have to make the chartname/templates dir too since thats where helm wants to write things actualRootDir := fmt.Sprintf("test-fixtures/%s-actual", testName) actualDir := fmt.Sprintf("%s/clabernetes/templates", actualRootDir) - valuesFile, err := filepath.Abs(fmt.Sprintf("test-fixtures/%s-values.yaml", testName)) - if err != nil { - t.Fatalf( - "failed getting abspath for values file, error: %s", err, - ) + var valuesFile string + + if valuesFileName != "" { + var err error + + valuesFile, err = filepath.Abs(fmt.Sprintf("test-fixtures/%s-values.yaml", testName)) + if err != nil { + t.Fatalf( + "failed getting abspath for values file, error: %s", err, + ) + } } - err = os.MkdirAll(actualDir, clabernetesconstants.PermissionsEveryoneRead) + err := os.MkdirAll(actualDir, clabernetesconstants.PermissionsEveryoneRead) if err != nil { t.Fatalf( "failed creating actual output directory %q, error: %s", actualDir, err, @@ -49,14 +55,20 @@ func HelmTest(t *testing.T, testName string) { } }() - HelmCommand( - t, + args := []string{ "template", "../../.", "--output-dir", actualRootDir, - "--values", - valuesFile, + } + + if valuesFile != "" { + args = append(args, "--values", valuesFile) + } + + HelmCommand( + t, + args..., ) renderedTemplates := ReadAllRenderedTemplates(t, actualRootDir) From fd26ff56dd2b632e639ca0e75669975f36603151 Mon Sep 17 00:00:00 2001 From: Carl Montanari Date: Tue, 17 Oct 2023 06:46:33 -0700 Subject: [PATCH 3/6] tests: always pass namespace in helm tests --- charts/clabernetes/tests/clicker/clicker_enabled_test.go | 9 ++++++++- .../tests/default_vaules/default_values_test.go | 4 +++- testhelper/helm.go | 4 +++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/charts/clabernetes/tests/clicker/clicker_enabled_test.go b/charts/clabernetes/tests/clicker/clicker_enabled_test.go index c9a60d97..eba19474 100644 --- a/charts/clabernetes/tests/clicker/clicker_enabled_test.go +++ b/charts/clabernetes/tests/clicker/clicker_enabled_test.go @@ -5,6 +5,8 @@ import ( "os" "testing" + clabernetesconstants "github.com/srl-labs/clabernetes/constants" + clabernetestesthelper "github.com/srl-labs/clabernetes/testhelper" ) @@ -22,5 +24,10 @@ func TestClickerEnabled(t *testing.T) { testName := "clicker-enabled" - clabernetestesthelper.HelmTest(t, testName, fmt.Sprintf("%s-values.yaml", testName)) + clabernetestesthelper.HelmTest( + t, + testName, + clabernetesconstants.Clabernetes, + fmt.Sprintf("%s-values.yaml", testName), + ) } diff --git a/charts/clabernetes/tests/default_vaules/default_values_test.go b/charts/clabernetes/tests/default_vaules/default_values_test.go index ff61c816..288a6e9c 100644 --- a/charts/clabernetes/tests/default_vaules/default_values_test.go +++ b/charts/clabernetes/tests/default_vaules/default_values_test.go @@ -4,6 +4,8 @@ import ( "os" "testing" + clabernetesconstants "github.com/srl-labs/clabernetes/constants" + clabernetestesthelper "github.com/srl-labs/clabernetes/testhelper" ) @@ -21,5 +23,5 @@ func TestDefaultValues(t *testing.T) { testName := "default-values" - clabernetestesthelper.HelmTest(t, testName, "") + clabernetestesthelper.HelmTest(t, testName, clabernetesconstants.Clabernetes, "") } diff --git a/testhelper/helm.go b/testhelper/helm.go index 406c9558..0e206f84 100644 --- a/testhelper/helm.go +++ b/testhelper/helm.go @@ -19,7 +19,7 @@ const ( // HelmTest executes a test against a helm chart -- this is a very simple/dumb test meant only to // ensure that we don't accidentally screw up charts. We do this by storing the "golden" output of // a rendered chart (and subcharts if applicable) with a given values file. -func HelmTest(t *testing.T, testName, valuesFileName string) { +func HelmTest(t *testing.T, testName, namespace, valuesFileName string) { t.Helper() // we have to make the chartname/templates dir too since thats where helm wants to write things @@ -58,6 +58,8 @@ func HelmTest(t *testing.T, testName, valuesFileName string) { args := []string{ "template", "../../.", + "--namespace", + namespace, "--output-dir", actualRootDir, } From 60567321ded77a9808754a02f476153d854641d7 Mon Sep 17 00:00:00 2001 From: Carl Montanari Date: Thu, 19 Oct 2023 10:06:23 -0700 Subject: [PATCH 4/6] tests: regen helm test after fixing replicas and setting sane default for in cluster dns --- .../tests/clicker/test-fixtures/golden/deployment.yaml | 4 +++- .../tests/default_vaules/test-fixtures/golden/deployment.yaml | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/charts/clabernetes/tests/clicker/test-fixtures/golden/deployment.yaml b/charts/clabernetes/tests/clicker/test-fixtures/golden/deployment.yaml index c5899e6e..6fa8c435 100755 --- a/charts/clabernetes/tests/clicker/test-fixtures/golden/deployment.yaml +++ b/charts/clabernetes/tests/clicker/test-fixtures/golden/deployment.yaml @@ -22,7 +22,7 @@ spec: matchLabels: clabernetes/app: clabernetes-plus-clicker release: release-name - replicas: + replicas: 3 strategy: rollingUpdate: maxSurge: 1 @@ -104,6 +104,8 @@ spec: fieldPath: metadata.namespace - name: CLIENT_OPERATION_TIMEOUT_MULTIPLIER value: "1" + - name: IN_CLUSTER_DNS_SUFFIX + value: svc.cluster.local - name: MANAGER_LOGGER_LEVEL value: info - name: CONTROLLER_LOGGER_LEVEL diff --git a/charts/clabernetes/tests/default_vaules/test-fixtures/golden/deployment.yaml b/charts/clabernetes/tests/default_vaules/test-fixtures/golden/deployment.yaml index 89ff66b6..868ccaa0 100755 --- a/charts/clabernetes/tests/default_vaules/test-fixtures/golden/deployment.yaml +++ b/charts/clabernetes/tests/default_vaules/test-fixtures/golden/deployment.yaml @@ -17,7 +17,7 @@ spec: matchLabels: clabernetes/app: clabernetes release: release-name - replicas: + replicas: 3 strategy: rollingUpdate: maxSurge: 1 @@ -94,6 +94,8 @@ spec: fieldPath: metadata.namespace - name: CLIENT_OPERATION_TIMEOUT_MULTIPLIER value: "1" + - name: IN_CLUSTER_DNS_SUFFIX + value: svc.cluster.local - name: MANAGER_LOGGER_LEVEL value: info - name: CONTROLLER_LOGGER_LEVEL From b81032adf5ac7b4dab2a4c480c15eb4de699c91a Mon Sep 17 00:00:00 2001 From: Carl Montanari Date: Sat, 21 Oct 2023 09:56:22 -0700 Subject: [PATCH 5/6] chore: update some linter settings/pins --- .golangci.yaml | 8 +++++--- Makefile | 6 ++++++ controllers/base.go | 5 ++++- launcher/containerlab.go | 5 +++-- testhelper/fail.go | 2 +- util/hash.go | 4 ++-- 6 files changed, 21 insertions(+), 9 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index 823d137b..325c037a 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -77,6 +77,7 @@ linters: - gocheckcompilerdirectives - gochecknoglobals - gochecknoinits + - gochecksumtype - gocognit - goconst - gocritic @@ -95,6 +96,7 @@ linters: - grouper - importas - ineffassign + - inamedparam - lll - maintidx - makezero @@ -106,7 +108,7 @@ linters: - nlreturn - noctx - nolintlint - - nolintlint + - perfsprint - prealloc - predeclared - reassign @@ -163,7 +165,7 @@ issues: text: "package-comments" run: - go: '1.20' + go: '1.21' skip-dirs: - .private timeout: 5m @@ -172,4 +174,4 @@ output: uniq-by-line: false service: - golangci-lint-version: 1.52.x + golangci-lint-version: 1.55.x diff --git a/Makefile b/Makefile index 793c8307..67a1ae05 100644 --- a/Makefile +++ b/Makefile @@ -31,6 +31,12 @@ test-e2e: ## Run e2e tests cov: ## Produce html coverage report go tool cover -html=cover.out +install-tools: ## Install lint/test tools + go install mvdan.cc/gofumpt@latest + go install golang.org/x/tools/cmd/goimports@latest + go install github.com/segmentio/golines@latest + go install gotest.tools/gotestsum@latest + install-code-generators: ## Install latest code-generator tools go install k8s.io/code-generator/cmd/deepcopy-gen@latest go install k8s.io/code-generator/cmd/openapi-gen@latest diff --git a/controllers/base.go b/controllers/base.go index f0bc4594..57927524 100644 --- a/controllers/base.go +++ b/controllers/base.go @@ -29,7 +29,10 @@ type Controller interface { // SetupWithManager sets the given controller up with the controller-runtime manager. SetupWithManager(mgr ctrlruntime.Manager) error // Reconcile is the actual reconcile function of the controller. - Reconcile(context.Context, ctrlruntime.Request) (ctrlruntime.Result, error) + Reconcile( + ctx context.Context, + req ctrlruntime.Request, + ) (ctrlruntime.Result, error) } // NewBaseController returns a new BaseController object to embed in clabernetes controllers. diff --git a/launcher/containerlab.go b/launcher/containerlab.go index c0d180d2..0597a5e8 100644 --- a/launcher/containerlab.go +++ b/launcher/containerlab.go @@ -6,6 +6,7 @@ import ( "net" "os" "os/exec" + "strconv" clabernetesconstants "github.com/srl-labs/clabernetes/constants" claberneteserrors "github.com/srl-labs/clabernetes/errors" @@ -70,11 +71,11 @@ func (c *clabernetes) runContainerlabVxlanTools( "--remote", resolvedVxlanRemote, "--id", - fmt.Sprint(vxlanID), + strconv.Itoa(vxlanID), "--link", fmt.Sprintf("%s-%s", localNodeName, cntLink), "--port", - fmt.Sprint(clabernetesconstants.VXLANServicePort), + strconv.Itoa(clabernetesconstants.VXLANServicePort), ) _, err = cmd.Output() diff --git a/testhelper/fail.go b/testhelper/fail.go index aa2c07d0..8017dae3 100644 --- a/testhelper/fail.go +++ b/testhelper/fail.go @@ -20,7 +20,7 @@ func FailOutput(t *testing.T, actual, expected any) { "\n%s"+ "\n\033[0;36m<<< actual ***\033[0m"+ "\n\033[0;35m*** expected >>>\033[0m"+ - "\n%s"+ + "\n%s"+ //nolint:goconst "\n\033[0;35m<<< expected ***\033[0m", actual, expected, ) diff --git a/util/hash.go b/util/hash.go index ce16807c..f1db3975 100644 --- a/util/hash.go +++ b/util/hash.go @@ -2,7 +2,7 @@ package util import ( "crypto/sha256" - "fmt" + "encoding/hex" ) // HashBytes accepts a bytes object and returns a string sha256 hash representing that object. @@ -10,5 +10,5 @@ func HashBytes(b []byte) string { hash := sha256.New() hash.Write(b) - return fmt.Sprintf("%x", hash.Sum(nil)) + return hex.EncodeToString(hash.Sum(nil)) } From d2e04cafbe94cff98a58022d94b21427bb24e8bb Mon Sep 17 00:00:00 2001 From: Carl Montanari Date: Sat, 21 Oct 2023 09:57:23 -0700 Subject: [PATCH 6/6] tests: update golden chart data --- .../tests/clicker/test-fixtures/golden/configmap.yaml | 6 +++++- .../tests/clicker/test-fixtures/golden/deployment.yaml | 8 ++++++++ .../default_vaules/test-fixtures/golden/configmap.yaml | 6 +++++- .../default_vaules/test-fixtures/golden/deployment.yaml | 8 ++++++++ 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/charts/clabernetes/tests/clicker/test-fixtures/golden/configmap.yaml b/charts/clabernetes/tests/clicker/test-fixtures/golden/configmap.yaml index 063dc7a3..ab1b8bfc 100755 --- a/charts/clabernetes/tests/clicker/test-fixtures/golden/configmap.yaml +++ b/charts/clabernetes/tests/clicker/test-fixtures/golden/configmap.yaml @@ -28,4 +28,8 @@ data: somelabel: somelabelvalue defaultResources: |- --- - {} + byContainerlabKind: {} + default: + requests: + cpu: 200m + memory: 512Mi diff --git a/charts/clabernetes/tests/clicker/test-fixtures/golden/deployment.yaml b/charts/clabernetes/tests/clicker/test-fixtures/golden/deployment.yaml index 6fa8c435..c8bd4ee6 100755 --- a/charts/clabernetes/tests/clicker/test-fixtures/golden/deployment.yaml +++ b/charts/clabernetes/tests/clicker/test-fixtures/golden/deployment.yaml @@ -120,3 +120,11 @@ spec: requests: memory: 128Mi cpu: 50m + ports: + - name: readiness-port + containerPort: 8080 + readinessProbe: + httpGet: + path: /ready + port: readiness-port + successThreshold: 1 diff --git a/charts/clabernetes/tests/default_vaules/test-fixtures/golden/configmap.yaml b/charts/clabernetes/tests/default_vaules/test-fixtures/golden/configmap.yaml index a7d240f9..8ba2cc1e 100755 --- a/charts/clabernetes/tests/default_vaules/test-fixtures/golden/configmap.yaml +++ b/charts/clabernetes/tests/default_vaules/test-fixtures/golden/configmap.yaml @@ -21,4 +21,8 @@ data: {} defaultResources: |- --- - {} + byContainerlabKind: {} + default: + requests: + cpu: 200m + memory: 512Mi diff --git a/charts/clabernetes/tests/default_vaules/test-fixtures/golden/deployment.yaml b/charts/clabernetes/tests/default_vaules/test-fixtures/golden/deployment.yaml index 868ccaa0..49646989 100755 --- a/charts/clabernetes/tests/default_vaules/test-fixtures/golden/deployment.yaml +++ b/charts/clabernetes/tests/default_vaules/test-fixtures/golden/deployment.yaml @@ -110,3 +110,11 @@ spec: requests: memory: 128Mi cpu: 50m + ports: + - name: readiness-port + containerPort: 8080 + readinessProbe: + httpGet: + path: /ready + port: readiness-port + successThreshold: 1