Skip to content

Commit 53bc28d

Browse files
test: Improve registry+v1 render regression test
1 parent b5a475a commit 53bc28d

File tree

56 files changed

+152
-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.

56 files changed

+152
-18
lines changed

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: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/*
2+
## registry+v1 bundle regression test
3+
4+
This test 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 against expected-manifests/.
31+
//
32+
// It fails if any file differs or is missing.
33+
//
34+
// TMP dir is cleaned up after test ends.
35+
func Test_RenderedOutput_MatchesExpected(t *testing.T) {
36+
tmpRoot := "./testdata/tmp/rendered/"
37+
expectedRoot := "./testdata/expected-manifests/"
38+
39+
// Remove the temporary output directory always
40+
t.Cleanup(func() {
41+
_ = os.RemoveAll("./testdata/tmp")
42+
})
43+
44+
// Call the generate-manifests.go script to generate the manifests
45+
// in the temporary directory.
46+
cmd := exec.Command("go", "run", "generate-manifests.go", "-output-dir="+tmpRoot)
47+
cmd.Stderr = os.Stderr
48+
cmd.Stdout = os.Stdout
49+
50+
err := cmd.Run()
51+
require.NoError(t, err, "failed to generate manifests")
52+
53+
// Compare structure + contents
54+
err = compareDirs(expectedRoot, tmpRoot)
55+
require.NoError(t, err, "rendered output differs from expected")
56+
}
57+
func compareDirs(expectedRoot, actualRoot string) error {
58+
// Step 1: Ensure every expected file exists in actual and contents match
59+
err := filepath.Walk(expectedRoot, func(expectedPath string, info os.FileInfo, err error) error {
60+
if err != nil {
61+
return err
62+
}
63+
if info.IsDir() {
64+
return nil
65+
}
66+
67+
relPath, err := filepath.Rel(expectedRoot, expectedPath)
68+
if err != nil {
69+
return err
70+
}
71+
actualPath := filepath.Join(actualRoot, relPath)
72+
73+
expectedBytes, err := os.ReadFile(expectedPath)
74+
if err != nil {
75+
return fmt.Errorf("failed to read expected file: %s", expectedPath)
76+
}
77+
actualBytes, err := os.ReadFile(actualPath)
78+
if err != nil {
79+
return fmt.Errorf("missing file: %s", relPath)
80+
}
81+
82+
if !bytes.Equal(expectedBytes, actualBytes) {
83+
return fmt.Errorf("file content mismatch at: %s", relPath)
84+
}
85+
return nil
86+
})
87+
if err != nil {
88+
return err
89+
}
90+
91+
// Step 1: Ensure actual does not contain unexpected files
92+
err = filepath.Walk(actualRoot, func(actualPath string, info os.FileInfo, err error) error {
93+
if err != nil {
94+
return err
95+
}
96+
if info.IsDir() {
97+
return nil
98+
}
99+
100+
relPath, err := filepath.Rel(actualRoot, actualPath)
101+
if err != nil {
102+
return err
103+
}
104+
expectedPath := filepath.Join(expectedRoot, relPath)
105+
106+
_, err = os.Stat(expectedPath)
107+
if os.IsNotExist(err) {
108+
return fmt.Errorf("unexpected extra file: %s", relPath)
109+
} else if err != nil {
110+
return fmt.Errorf("error checking expected file: %s", expectedPath)
111+
}
112+
return nil
113+
})
114+
return err
115+
}

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/generate/
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 covert_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/generate/"
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)