diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e60c9469c2..58ce503938 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -96,6 +96,25 @@ Then you can run the end-to-end tests with: make e2e ``` +When the output of the Flux CLI changes, to automatically update the golden +files used in the test, pass `-update` flag to the test as: + +```bash +make e2e TEST_ARGS="-update" +``` + +Since not all packages use golden files for testing, `-update` argument must be +passed only for the packages that use golden files. Use the variables +`TEST_PKG_PATH` for unit tests and `E2E_TEST_PKG_PATH` for e2e tests, to set the +path of the target test package: + +```bash +# Unit test +make test TEST_PKG_PATH="./cmd/flux" TEST_ARGS="-update" +# e2e test +make e2e E2E_TEST_PKG_PATH="./cmd/flux" TEST_ARGS="-update" +``` + Teardown the e2e environment with: ```bash diff --git a/Makefile b/Makefile index 29ca788a28..5fd6f05f8e 100644 --- a/Makefile +++ b/Makefile @@ -35,11 +35,13 @@ cleanup-kind: rm $(TEST_KUBECONFIG) KUBEBUILDER_ASSETS?="$(shell $(ENVTEST) --arch=$(ENVTEST_ARCH) use -i $(ENVTEST_KUBERNETES_VERSION) --bin-dir=$(ENVTEST_ASSETS_DIR) -p path)" +TEST_PKG_PATH="./..." test: $(EMBEDDED_MANIFESTS_TARGET) tidy fmt vet install-envtest - KUBEBUILDER_ASSETS="$(KUBEBUILDER_ASSETS)" go test ./... -coverprofile cover.out --tags=unit + KUBEBUILDER_ASSETS="$(KUBEBUILDER_ASSETS)" go test $(TEST_PKG_PATH) -coverprofile cover.out --tags=unit $(TEST_ARGS) +E2E_TEST_PKG_PATH="./cmd/flux/..." e2e: $(EMBEDDED_MANIFESTS_TARGET) tidy fmt vet - TEST_KUBECONFIG=$(TEST_KUBECONFIG) go test ./cmd/flux/... -coverprofile e2e.cover.out --tags=e2e -v -failfast + TEST_KUBECONFIG=$(TEST_KUBECONFIG) go test $(E2E_TEST_PKG_PATH) -coverprofile e2e.cover.out --tags=e2e -v -failfast $(TEST_ARGS) test-with-kind: install-envtest make setup-kind diff --git a/cmd/flux/get_alert.go b/cmd/flux/get_alert.go index 126dbe569a..b23a763742 100644 --- a/cmd/flux/get_alert.go +++ b/cmd/flux/get_alert.go @@ -77,11 +77,11 @@ func init() { func (s alertListAdapter) summariseItem(i int, includeNamespace bool, includeKind bool) []string { item := s.Items[i] status, msg := statusAndMessage(item.Status.Conditions) - return append(nameColumns(&item, includeNamespace, includeKind), status, msg, strings.Title(strconv.FormatBool(item.Spec.Suspend))) + return append(nameColumns(&item, includeNamespace, includeKind), strings.Title(strconv.FormatBool(item.Spec.Suspend)), status, msg) } func (s alertListAdapter) headers(includeNamespace bool) []string { - headers := []string{"Name", "Ready", "Message", "Suspended"} + headers := []string{"Name", "Suspended", "Ready", "Message"} if includeNamespace { return append(namespaceHeader, headers...) } diff --git a/cmd/flux/get_helmrelease.go b/cmd/flux/get_helmrelease.go index 5478e29c06..0689757ee3 100644 --- a/cmd/flux/get_helmrelease.go +++ b/cmd/flux/get_helmrelease.go @@ -75,11 +75,11 @@ func (a helmReleaseListAdapter) summariseItem(i int, includeNamespace bool, incl revision := item.Status.LastAppliedRevision status, msg := statusAndMessage(item.Status.Conditions) return append(nameColumns(&item, includeNamespace, includeKind), - status, msg, revision, strings.Title(strconv.FormatBool(item.Spec.Suspend))) + revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)), status, msg) } func (a helmReleaseListAdapter) headers(includeNamespace bool) []string { - headers := []string{"Name", "Ready", "Message", "Revision", "Suspended"} + headers := []string{"Name", "Revision", "Suspended", "Ready", "Message"} if includeNamespace { headers = append([]string{"Namespace"}, headers...) } diff --git a/cmd/flux/get_image_policy.go b/cmd/flux/get_image_policy.go index 7974c380e3..a853817e41 100644 --- a/cmd/flux/get_image_policy.go +++ b/cmd/flux/get_image_policy.go @@ -74,11 +74,11 @@ func init() { func (s imagePolicyListAdapter) summariseItem(i int, includeNamespace bool, includeKind bool) []string { item := s.Items[i] status, msg := statusAndMessage(item.Status.Conditions) - return append(nameColumns(&item, includeNamespace, includeKind), status, msg, item.Status.LatestImage) + return append(nameColumns(&item, includeNamespace, includeKind), item.Status.LatestImage, status, msg) } func (s imagePolicyListAdapter) headers(includeNamespace bool) []string { - headers := []string{"Name", "Ready", "Message", "Latest image"} + headers := []string{"Name", "Latest image", "Ready", "Message"} if includeNamespace { return append(namespaceHeader, headers...) } diff --git a/cmd/flux/get_image_repository.go b/cmd/flux/get_image_repository.go index 0878a29c01..3b190b7d5b 100644 --- a/cmd/flux/get_image_repository.go +++ b/cmd/flux/get_image_repository.go @@ -82,11 +82,11 @@ func (s imageRepositoryListAdapter) summariseItem(i int, includeNamespace bool, lastScan = item.Status.LastScanResult.ScanTime.Time.Format(time.RFC3339) } return append(nameColumns(&item, includeNamespace, includeKind), - status, msg, lastScan, strings.Title(strconv.FormatBool(item.Spec.Suspend))) + lastScan, strings.Title(strconv.FormatBool(item.Spec.Suspend)), status, msg) } func (s imageRepositoryListAdapter) headers(includeNamespace bool) []string { - headers := []string{"Name", "Ready", "Message", "Last scan", "Suspended"} + headers := []string{"Name", "Last scan", "Suspended", "Ready", "Message"} if includeNamespace { return append(namespaceHeader, headers...) } diff --git a/cmd/flux/get_image_update.go b/cmd/flux/get_image_update.go index da16c57611..dd84b6d8a9 100644 --- a/cmd/flux/get_image_update.go +++ b/cmd/flux/get_image_update.go @@ -81,11 +81,11 @@ func (s imageUpdateAutomationListAdapter) summariseItem(i int, includeNamespace if item.Status.LastAutomationRunTime != nil { lastRun = item.Status.LastAutomationRunTime.Time.Format(time.RFC3339) } - return append(nameColumns(&item, includeNamespace, includeKind), status, msg, lastRun, strings.Title(strconv.FormatBool(item.Spec.Suspend))) + return append(nameColumns(&item, includeNamespace, includeKind), lastRun, strings.Title(strconv.FormatBool(item.Spec.Suspend)), status, msg) } func (s imageUpdateAutomationListAdapter) headers(includeNamespace bool) []string { - headers := []string{"Name", "Ready", "Message", "Last run", "Suspended"} + headers := []string{"Name", "Last run", "Suspended", "Ready", "Message"} if includeNamespace { return append(namespaceHeader, headers...) } diff --git a/cmd/flux/get_kustomization.go b/cmd/flux/get_kustomization.go index d2991e9395..5d20f639c8 100644 --- a/cmd/flux/get_kustomization.go +++ b/cmd/flux/get_kustomization.go @@ -85,11 +85,11 @@ func (a kustomizationListAdapter) summariseItem(i int, includeNamespace bool, in msg = shortenCommitSha(msg) } return append(nameColumns(&item, includeNamespace, includeKind), - status, msg, revision, strings.Title(strconv.FormatBool(item.Spec.Suspend))) + revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)), status, msg) } func (a kustomizationListAdapter) headers(includeNamespace bool) []string { - headers := []string{"Name", "Ready", "Message", "Revision", "Suspended"} + headers := []string{"Name", "Revision", "Suspended", "Ready", "Message"} if includeNamespace { headers = append([]string{"Namespace"}, headers...) } diff --git a/cmd/flux/get_receiver.go b/cmd/flux/get_receiver.go index d2147d1b18..ef7eb37635 100644 --- a/cmd/flux/get_receiver.go +++ b/cmd/flux/get_receiver.go @@ -74,11 +74,11 @@ func init() { func (s receiverListAdapter) summariseItem(i int, includeNamespace bool, includeKind bool) []string { item := s.Items[i] status, msg := statusAndMessage(item.Status.Conditions) - return append(nameColumns(&item, includeNamespace, includeKind), status, msg, strings.Title(strconv.FormatBool(item.Spec.Suspend))) + return append(nameColumns(&item, includeNamespace, includeKind), strings.Title(strconv.FormatBool(item.Spec.Suspend)), status, msg) } func (s receiverListAdapter) headers(includeNamespace bool) []string { - headers := []string{"Name", "Ready", "Message", "Suspended"} + headers := []string{"Name", "Suspended", "Ready", "Message"} if includeNamespace { return append(namespaceHeader, headers...) } diff --git a/cmd/flux/get_source_bucket.go b/cmd/flux/get_source_bucket.go index 963a8ed416..87c7f86b76 100644 --- a/cmd/flux/get_source_bucket.go +++ b/cmd/flux/get_source_bucket.go @@ -81,11 +81,11 @@ func (a *bucketListAdapter) summariseItem(i int, includeNamespace bool, includeK } status, msg := statusAndMessage(item.Status.Conditions) return append(nameColumns(&item, includeNamespace, includeKind), - status, msg, revision, strings.Title(strconv.FormatBool(item.Spec.Suspend))) + revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)), status, msg) } func (a bucketListAdapter) headers(includeNamespace bool) []string { - headers := []string{"Name", "Ready", "Message", "Revision", "Suspended"} + headers := []string{"Name", "Revision", "Suspended", "Ready", "Message"} if includeNamespace { headers = append([]string{"Namespace"}, headers...) } diff --git a/cmd/flux/get_source_chart.go b/cmd/flux/get_source_chart.go index f5401791f3..5179dad3bc 100644 --- a/cmd/flux/get_source_chart.go +++ b/cmd/flux/get_source_chart.go @@ -81,11 +81,11 @@ func (a *helmChartListAdapter) summariseItem(i int, includeNamespace bool, inclu } status, msg := statusAndMessage(item.Status.Conditions) return append(nameColumns(&item, includeNamespace, includeKind), - status, msg, revision, strings.Title(strconv.FormatBool(item.Spec.Suspend))) + revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)), status, msg) } func (a helmChartListAdapter) headers(includeNamespace bool) []string { - headers := []string{"Name", "Ready", "Message", "Revision", "Suspended"} + headers := []string{"Name", "Revision", "Suspended", "Ready", "Message"} if includeNamespace { headers = append([]string{"Namespace"}, headers...) } diff --git a/cmd/flux/get_source_git.go b/cmd/flux/get_source_git.go index 95b8ab4f59..9690ee3ae6 100644 --- a/cmd/flux/get_source_git.go +++ b/cmd/flux/get_source_git.go @@ -86,11 +86,11 @@ func (a *gitRepositoryListAdapter) summariseItem(i int, includeNamespace bool, i msg = shortenCommitSha(msg) } return append(nameColumns(&item, includeNamespace, includeKind), - status, msg, revision, strings.Title(strconv.FormatBool(item.Spec.Suspend))) + revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)), status, msg) } func (a gitRepositoryListAdapter) headers(includeNamespace bool) []string { - headers := []string{"Name", "Ready", "Message", "Revision", "Suspended"} + headers := []string{"Name", "Revision", "Suspended", "Ready", "Message"} if includeNamespace { headers = append([]string{"Namespace"}, headers...) } diff --git a/cmd/flux/get_source_helm.go b/cmd/flux/get_source_helm.go index cf98246b59..d23ecd327b 100644 --- a/cmd/flux/get_source_helm.go +++ b/cmd/flux/get_source_helm.go @@ -81,11 +81,11 @@ func (a *helmRepositoryListAdapter) summariseItem(i int, includeNamespace bool, } status, msg := statusAndMessage(item.Status.Conditions) return append(nameColumns(&item, includeNamespace, includeKind), - status, msg, revision, strings.Title(strconv.FormatBool(item.Spec.Suspend))) + revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)), status, msg) } func (a helmRepositoryListAdapter) headers(includeNamespace bool) []string { - headers := []string{"Name", "Ready", "Message", "Revision", "Suspended"} + headers := []string{"Name", "Revision", "Suspended", "Ready", "Message"} if includeNamespace { headers = append([]string{"Namespace"}, headers...) } diff --git a/cmd/flux/main_test.go b/cmd/flux/main_test.go index c41eb3e681..4408c8d7f5 100644 --- a/cmd/flux/main_test.go +++ b/cmd/flux/main_test.go @@ -20,6 +20,7 @@ import ( "bufio" "bytes" "context" + "flag" "fmt" "io" "os" @@ -42,6 +43,9 @@ import ( var nextNamespaceId int64 +// update allows golden files to be updated based on the current output. +var update = flag.Bool("update", false, "update golden files") + // Return a unique namespace with the specified prefix, for tests to create // objects that won't collide with each other. func allocateNamespace(prefix string) string { @@ -298,6 +302,18 @@ func assertGoldenTemplateFile(goldenFile string, templateValues map[string]strin expectedOutput = string(goldenFileContents) } if assertErr := assertGoldenValue(expectedOutput)(output, err); assertErr != nil { + // Update the golden files if comparision fails and the update flag is set. + if *update && output != "" { + // Skip update if there are template values. + if len(templateValues) > 0 { + fmt.Println("NOTE: -update flag passed but golden template files can't be updated, please update it manually") + } else { + if err := os.WriteFile(goldenFile, []byte(output), 0644); err != nil { + return fmt.Errorf("failed to update golden file '%s': %v", goldenFile, err) + } + return nil + } + } return fmt.Errorf("Mismatch from golden file '%s': %v", goldenFile, assertErr) } return nil diff --git a/cmd/flux/testdata/helmrelease/get_helmrelease_from_git.golden b/cmd/flux/testdata/helmrelease/get_helmrelease_from_git.golden index 1cfeacc306..e802cb36e6 100644 --- a/cmd/flux/testdata/helmrelease/get_helmrelease_from_git.golden +++ b/cmd/flux/testdata/helmrelease/get_helmrelease_from_git.golden @@ -1,2 +1,2 @@ -NAME READY MESSAGE REVISION SUSPENDED -thrfg True Release reconciliation succeeded 6.0.0 False +NAME REVISION SUSPENDED READY MESSAGE +thrfg 6.0.0 False True Release reconciliation succeeded diff --git a/cmd/flux/testdata/image/get_image_policy_regex.golden b/cmd/flux/testdata/image/get_image_policy_regex.golden index 8486fb1fb9..b7cf40a94c 100644 --- a/cmd/flux/testdata/image/get_image_policy_regex.golden +++ b/cmd/flux/testdata/image/get_image_policy_regex.golden @@ -1,2 +1,2 @@ -NAME READY MESSAGE LATEST IMAGE -podinfo-regex True Latest image tag for 'ghcr.io/stefanprodan/podinfo' resolved to: 5.0.0 ghcr.io/stefanprodan/podinfo:5.0.0 +NAME LATEST IMAGE READY MESSAGE +podinfo-regex ghcr.io/stefanprodan/podinfo:5.0.0 True Latest image tag for 'ghcr.io/stefanprodan/podinfo' resolved to: 5.0.0 diff --git a/cmd/flux/testdata/image/get_image_policy_semver.golden b/cmd/flux/testdata/image/get_image_policy_semver.golden index 6f8a17dd88..30ce52b725 100644 --- a/cmd/flux/testdata/image/get_image_policy_semver.golden +++ b/cmd/flux/testdata/image/get_image_policy_semver.golden @@ -1,2 +1,2 @@ -NAME READY MESSAGE LATEST IMAGE -podinfo-semver True Latest image tag for 'ghcr.io/stefanprodan/podinfo' resolved to: 5.0.3 ghcr.io/stefanprodan/podinfo:5.0.3 +NAME LATEST IMAGE READY MESSAGE +podinfo-semver ghcr.io/stefanprodan/podinfo:5.0.3 True Latest image tag for 'ghcr.io/stefanprodan/podinfo' resolved to: 5.0.3 diff --git a/cmd/flux/testdata/kustomization/get_kustomization_from_git.golden b/cmd/flux/testdata/kustomization/get_kustomization_from_git.golden index a613aa3412..b4f7e31c11 100644 --- a/cmd/flux/testdata/kustomization/get_kustomization_from_git.golden +++ b/cmd/flux/testdata/kustomization/get_kustomization_from_git.golden @@ -1,2 +1,2 @@ -NAME READY MESSAGE REVISION SUSPENDED -tkfg True Applied revision: 6.0.0/627d5c4 6.0.0/627d5c4 False +NAME REVISION SUSPENDED READY MESSAGE +tkfg 6.0.0/627d5c4 False True Applied revision: 6.0.0/627d5c4