Skip to content

Commit 557687a

Browse files
test: Improve registry+v1 render regression test
1 parent 8cf5bda commit 557687a

File tree

57 files changed

+154
-18
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+154
-18
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,6 @@ site
4242
.tiltbuild/
4343
.catalogd-tmp/
4444
.vscode
45+
46+
# Tmporary files and directories
47+
/test/regression/convert/testdata/tmp/*

Makefile

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -172,15 +172,9 @@ generate: $(CONTROLLER_GEN) #EXHELP Generate code containing DeepCopy, DeepCopyI
172172
$(CONTROLLER_GEN) --load-build-tags=$(GO_BUILD_TAGS) object:headerFile="hack/boilerplate.go.txt" paths="./..."
173173

174174
.PHONY: verify
175-
verify: k8s-pin kind-verify-versions fmt generate manifests crd-ref-docs generate-test-data #HELP Verify all generated code is up-to-date. Runs k8s-pin instead of just tidy.
175+
verify: k8s-pin kind-verify-versions fmt generate manifests crd-ref-docs #HELP Verify all generated code is up-to-date. Runs k8s-pin instead of just tidy.
176176
git diff --exit-code
177177

178-
# Renders registry+v1 bundles in test/convert
179-
# Used by CI in verify to catch regressions in the registry+v1 -> plain conversion code
180-
.PHONY: generate-test-data
181-
generate-test-data:
182-
go run test/convert/generate-manifests.go
183-
184178
.PHONY: fix-lint
185179
fix-lint: $(GOLANGCI_LINT) #EXHELP Fix lint issues
186180
$(GOLANGCI_LINT) run --fix --build-tags $(GO_BUILD_TAGS) $(GOLANGCI_LINT_ARGS)
@@ -209,7 +203,7 @@ verify-crd-compatibility: $(CRD_DIFF) manifests
209203
#SECTION Test
210204

211205
.PHONY: test
212-
test: manifests generate fmt lint test-unit test-e2e #HELP Run all tests.
206+
test: manifests generate fmt lint test-unit test-e2e test-regression #HELP Run all tests.
213207

214208
.PHONY: e2e
215209
e2e: #EXHELP Run the e2e tests.
@@ -252,6 +246,10 @@ test-unit: $(SETUP_ENVTEST) envtest-k8s-bins #HELP Run the unit tests
252246
$(UNIT_TEST_DIRS) \
253247
-test.gocoverdir=$(COVERAGE_UNIT_DIR)
254248

249+
.PHONY: test-regression
250+
test-regression: #HELP Run regression test
251+
go test -count=1 -v ./test/regression/...
252+
255253
.PHONY: image-registry
256254
E2E_REGISTRY_IMAGE=localhost/e2e-test-registry:devel
257255
image-registry: export GOOS=linux

test/convert/README.md

Lines changed: 0 additions & 7 deletions
This file was deleted.
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/*
2+
## registry+v1 bundle regression test
3+
4+
This test in convert_test.go verifies that rendering registry+v1 bundles to manifests
5+
always produces the same files and content.
6+
7+
It runs: go run generate-manifests.go -output-dir=./testdata/tmp/rendered/
8+
Then compares: ./testdata/tmp/rendered/ vs ./testdata/expected-manifests/
9+
10+
Files are sorted by kind/namespace/name for consistency.
11+
12+
To update expected output (only on purpose), run:
13+
14+
go run generate-manifests.go -output-dir=./testdata/expected-manifests/
15+
*/
16+
package main
17+
18+
import (
19+
"bytes"
20+
"fmt"
21+
"os"
22+
"os/exec"
23+
"path/filepath"
24+
"testing"
25+
26+
"github.com/stretchr/testify/require"
27+
)
28+
29+
// Test_RenderedOutputMatchesExpected runs generate-manifests.go,
30+
// then compares the generated files in ./testdata/tmp/rendered/
31+
// against expected-manifests/.
32+
// It fails if any file differs or is missing.
33+
// TMP dir is cleaned up after test ends.
34+
func Test_RenderedOutput_MatchesExpected(t *testing.T) {
35+
tmpRoot := "./testdata/tmp/rendered/"
36+
expectedRoot := "./testdata/expected-manifests/"
37+
38+
// Remove the temporary output directory always
39+
t.Cleanup(func() {
40+
_ = os.RemoveAll("./testdata/tmp")
41+
})
42+
43+
// Call the generate-manifests.go script to generate the manifests
44+
// in the temporary directory.
45+
cmd := exec.Command("go", "run", "generate-manifests.go", "-output-dir="+tmpRoot)
46+
cmd.Stderr = os.Stderr
47+
cmd.Stdout = os.Stdout
48+
49+
err := cmd.Run()
50+
require.NoError(t, err, "failed to generate manifests")
51+
52+
// Compare structure + contents
53+
err = compareDirs(expectedRoot, tmpRoot)
54+
require.NoError(t, err, "rendered output differs from expected")
55+
}
56+
func compareDirs(expectedRoot, actualRoot string) error {
57+
// Step 1: Ensure every expected file exists in actual and contents match
58+
err := filepath.Walk(expectedRoot, func(expectedPath string, info os.FileInfo, err error) error {
59+
if err != nil {
60+
return err
61+
}
62+
if info.IsDir() {
63+
return nil
64+
}
65+
66+
relPath, err := filepath.Rel(expectedRoot, expectedPath)
67+
if err != nil {
68+
return err
69+
}
70+
actualPath := filepath.Join(actualRoot, relPath)
71+
72+
expectedBytes, err := os.ReadFile(expectedPath)
73+
if err != nil {
74+
return fmt.Errorf("failed to read expected file: %s", expectedPath)
75+
}
76+
actualBytes, err := os.ReadFile(actualPath)
77+
if err != nil {
78+
return fmt.Errorf("missing file: %s", relPath)
79+
}
80+
81+
if !bytes.Equal(expectedBytes, actualBytes) {
82+
return fmt.Errorf("file content mismatch at: %s", relPath)
83+
}
84+
return nil
85+
})
86+
if err != nil {
87+
return err
88+
}
89+
90+
// Step 1: Ensure actual does not contain unexpected files
91+
err = filepath.Walk(actualRoot, func(actualPath string, info os.FileInfo, err error) error {
92+
if err != nil {
93+
return err
94+
}
95+
if info.IsDir() {
96+
return nil
97+
}
98+
99+
relPath, err := filepath.Rel(actualRoot, actualPath)
100+
if err != nil {
101+
return err
102+
}
103+
expectedPath := filepath.Join(expectedRoot, relPath)
104+
105+
_, err = os.Stat(expectedPath)
106+
if os.IsNotExist(err) {
107+
return fmt.Errorf("unexpected extra file: %s", relPath)
108+
} else if err != nil {
109+
return fmt.Errorf("error checking expected file: %s", expectedPath)
110+
}
111+
return nil
112+
})
113+
return err
114+
}

test/convert/generate-manifests.go renamed to test/regression/convert/generate-manifests.go

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,20 @@
1+
// generate-manifests.go
2+
//
3+
// Renders registry+v1 bundles into YAML manifests for regression testing.
4+
// Used by tests to make sure output from the BundleRenderer stays consistent.
5+
//
6+
// By default, writes to ./testdata/tmp/generate/.
7+
// To update expected output, run:
8+
//
9+
// go run generate-manifests.go -output-dir=./testdata/expected-manifests/
10+
//
11+
// Only re-generate if you intentionally change rendering behavior.
12+
// Note that if the test fails is likely a regression in the renderer.
113
package main
214

315
import (
416
"cmp"
17+
"flag"
518
"fmt"
619
"os"
720
"path/filepath"
@@ -16,11 +29,26 @@ import (
1629
"github.com/operator-framework/operator-controller/internal/operator-controller/rukpak/render/registryv1"
1730
)
1831

32+
// This is a helper for a regression test to make sure the renderer output doesn't change.
33+
//
34+
// It renders known bundles into YAML files and writes them to a target output dir.
35+
// By default, it writes to a temp path used in tests:
36+
//
37+
// ./testdata/tmp/rendered/
38+
//
39+
// If you want to update the expected output, run it with:
40+
//
41+
// go run generate-manifests.go -output-dir=./testdata/expected-manifests/
42+
//
43+
// Note: Expected output should never change unless the renderer changes which is unlikely.
44+
// If the convert_test.go test fails, it likely means a regression was introduced in the renderer.
1945
func main() {
2046
bundleRootDir := "testdata/bundles/"
21-
outputRootDir := "test/convert/expected-manifests/"
47+
defaultOutputDir := "./testdata/tmp/rendered/"
48+
outputRootDir := flag.String("output-dir", defaultOutputDir, "path to write rendered manifests to")
49+
flag.Parse()
2250

23-
if err := os.RemoveAll(outputRootDir); err != nil {
51+
if err := os.RemoveAll(*outputRootDir); err != nil {
2452
fmt.Printf("error removing output directory: %v\n", err)
2553
os.Exit(1)
2654
}
@@ -52,7 +80,7 @@ func main() {
5280
},
5381
} {
5482
bundlePath := filepath.Join(bundleRootDir, tc.bundle)
55-
generatedManifestPath := filepath.Join(outputRootDir, tc.bundle, tc.testCaseName)
83+
generatedManifestPath := filepath.Join(*outputRootDir, tc.bundle, tc.testCaseName)
5684
if err := generateManifests(generatedManifestPath, bundlePath, tc.installNamespace, tc.watchNamespace); err != nil {
5785
fmt.Printf("Error generating manifests: %v", err)
5886
os.Exit(1)

0 commit comments

Comments
 (0)