Skip to content

Commit 0b23935

Browse files
committed
Add test to check generated content against generated master
1 parent c7f3de2 commit 0b23935

File tree

17 files changed

+777
-7
lines changed

17 files changed

+777
-7
lines changed
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
/*
2+
Copyright 2019 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package applyconfigurations
18+
19+
import (
20+
"fmt"
21+
"io"
22+
"io/fs"
23+
"os"
24+
"strings"
25+
26+
. "github.com/onsi/ginkgo"
27+
. "github.com/onsi/gomega"
28+
"k8s.io/apimachinery/pkg/util/sets"
29+
30+
"sigs.k8s.io/controller-tools/pkg/crd"
31+
"sigs.k8s.io/controller-tools/pkg/genall"
32+
"sigs.k8s.io/controller-tools/pkg/loader"
33+
"sigs.k8s.io/controller-tools/pkg/markers"
34+
)
35+
36+
type outputToMap map[string]*outputFile
37+
38+
// Open implements genall.OutputRule.
39+
func (m outputToMap) Open(_ *loader.Package, path string) (io.WriteCloser, error) {
40+
if _, ok := m[path]; !ok {
41+
m[path] = &outputFile{}
42+
}
43+
return m[path], nil
44+
}
45+
46+
type outputFile struct {
47+
contents []byte
48+
}
49+
50+
func (o *outputFile) Write(p []byte) (int, error) {
51+
o.contents = append(o.contents, p...)
52+
return len(p), nil
53+
}
54+
55+
func (o *outputFile) Close() error {
56+
return nil
57+
}
58+
59+
var _ = Describe("CRD Generation From Parsing to CustomResourceDefinition", func() {
60+
It("should be able to verify generated ApplyConfiguration types for the CronJob schema", func() {
61+
By("switching into testdata to appease go modules")
62+
cwd, err := os.Getwd()
63+
Expect(err).NotTo(HaveOccurred())
64+
Expect(os.Chdir("./testdata/cronjob")).To(Succeed()) // go modules are directory-sensitive
65+
defer func() { Expect(os.Chdir(cwd)).To(Succeed()) }()
66+
67+
output := make(outputToMap)
68+
69+
By("initializing the runtime")
70+
optionsRegistry := &markers.Registry{}
71+
Expect(optionsRegistry.Register(markers.Must(markers.MakeDefinition("crd", markers.DescribesPackage, crd.Generator{})))).To(Succeed())
72+
// Add the applyconfigurations generator but set it to verify only.
73+
// This allows us to check if there's a diff between the checked in generated data and what it would generate now.
74+
Expect(optionsRegistry.Register(markers.Must(markers.MakeDefinition("apply", markers.DescribesPackage, Generator{})))).To(Succeed())
75+
rt, err := genall.FromOptions(optionsRegistry, []string{
76+
"crd", // Run another generator first to make sure they don't interfere; see also: the comment on cronjob_types.go:UntypedBlob
77+
"apply",
78+
})
79+
Expect(err).NotTo(HaveOccurred())
80+
rt.OutputRules = genall.OutputRules{Default: output}
81+
82+
By("running the generator and checking for errors")
83+
hadErrs := rt.Run()
84+
85+
By("checking for errors")
86+
Expect(hadErrs).To(BeFalse(), "Generator should run without errors")
87+
88+
filesInMaster := make(map[string][]byte)
89+
masterFileNames := sets.New[string]()
90+
cronJobFS := os.DirFS(".")
91+
masterPath := "applyconfiguration-master"
92+
Expect(fs.WalkDir(cronJobFS, masterPath, func(path string, d fs.DirEntry, err error) error {
93+
if err != nil {
94+
return err
95+
}
96+
97+
if d.IsDir() {
98+
return nil
99+
}
100+
101+
data, err := os.ReadFile(path)
102+
if err != nil {
103+
return fmt.Errorf("error reading file %s: %w", path, err)
104+
}
105+
106+
// Record the path without the path prefix for comparison later.
107+
path = strings.TrimPrefix(path, masterPath+"/")
108+
masterFileNames.Insert(path)
109+
filesInMaster[path] = data
110+
return nil
111+
})).To(Succeed())
112+
113+
filesInOutput := make(map[string][]byte)
114+
outputFileNames := sets.New[string]()
115+
outputPath := "applyconfiguration"
116+
Expect(fs.WalkDir(cronJobFS, outputPath, func(path string, d fs.DirEntry, err error) error {
117+
if err != nil {
118+
return err
119+
}
120+
121+
if d.IsDir() {
122+
return nil
123+
}
124+
125+
data, err := os.ReadFile(path)
126+
if err != nil {
127+
return fmt.Errorf("error reading file %s: %w", path, err)
128+
}
129+
130+
// Record the path without the path prefix for comparison later.
131+
path = strings.TrimPrefix(path, outputPath+"/")
132+
outputFileNames.Insert(path)
133+
filesInOutput[path] = data
134+
return nil
135+
})).To(Succeed())
136+
137+
// Every file should be in both sets, check for files not in both sets.
138+
Expect(masterFileNames.SymmetricDifference(outputFileNames).UnsortedList()).To(BeEmpty(), "Generated files should match the checked in files")
139+
140+
for name, content := range filesInMaster {
141+
Expect(string(filesInOutput[name])).To(Equal(string(content)), "Generated files should match the checked in files, diff found in %s", name)
142+
}
143+
})
144+
})
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
Copyright 2019 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package applyconfigurations
18+
19+
import (
20+
"testing"
21+
22+
. "github.com/onsi/ginkgo"
23+
. "github.com/onsi/gomega"
24+
)
25+
26+
func TestObjectGeneration(t *testing.T) {
27+
RegisterFailHandler(Fail)
28+
RunSpecs(t, "ApplyConfiguration Generation Suite")
29+
}

pkg/applyconfigurations/gen.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,9 @@ func (ctx *ObjectGenCtx) generateForPackage(root *loader.Package) error {
200200
genericArgs.OutputPackagePath = filepath.Join(root.PkgPath, importPathSuffix)
201201
genericArgs.GoHeaderFilePath = ctx.HeaderFilePath
202202

203+
// Make the generated header static so that it doesn't rely on the compiled binary name.
204+
genericArgs.GeneratedByCommentTemplate = "// Code generated by applyconfiguration-gen. DO NOT EDIT.\n"
205+
203206
if err := generatorargs.Validate(genericArgs); err != nil {
204207
return err
205208
}

pkg/applyconfigurations/testdata/cronjob/applyconfiguration-master/internal/internal.go

Lines changed: 46 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/applyconfigurations/testdata/cronjob/applyconfiguration-master/testdata/cronjob/associativetype.go

Lines changed: 41 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)