sigs.k8s.io/controller-tools@v0.15.1-0.20240515195456-85686cb69316/pkg/crd/gen_integration_test.go (about) 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 crd_test 18 19 import ( 20 "bytes" 21 "io" 22 "os" 23 "path/filepath" 24 25 "github.com/google/go-cmp/cmp" 26 . "github.com/onsi/ginkgo" 27 . "github.com/onsi/gomega" 28 29 "sigs.k8s.io/controller-tools/pkg/crd" 30 crdmarkers "sigs.k8s.io/controller-tools/pkg/crd/markers" 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 var _ = Describe("CRD Generation proper defaulting", func() { 37 var ( 38 ctx, ctx2 *genall.GenerationContext 39 out *outputRule 40 41 genDir = filepath.Join("testdata", "gen") 42 ) 43 44 BeforeEach(func() { 45 By("switching into testdata to appease go modules") 46 cwd, err := os.Getwd() 47 Expect(err).NotTo(HaveOccurred()) 48 Expect(os.Chdir(genDir)).To(Succeed()) // go modules are directory-sensitive 49 defer func() { Expect(os.Chdir(cwd)).To(Succeed()) }() 50 51 By("loading the roots") 52 pkgs, err := loader.LoadRoots(".") 53 Expect(err).NotTo(HaveOccurred()) 54 Expect(pkgs).To(HaveLen(1)) 55 pkgs2, err := loader.LoadRoots("./...") 56 Expect(err).NotTo(HaveOccurred()) 57 Expect(pkgs2).To(HaveLen(2)) 58 59 By("setup up the context") 60 reg := &markers.Registry{} 61 Expect(crdmarkers.Register(reg)).To(Succeed()) 62 out = &outputRule{ 63 buf: &bytes.Buffer{}, 64 } 65 ctx = &genall.GenerationContext{ 66 Collector: &markers.Collector{Registry: reg}, 67 Roots: pkgs, 68 Checker: &loader.TypeChecker{}, 69 OutputRule: out, 70 } 71 ctx2 = &genall.GenerationContext{ 72 Collector: &markers.Collector{Registry: reg}, 73 Roots: pkgs2, 74 Checker: &loader.TypeChecker{}, 75 OutputRule: out, 76 } 77 }) 78 79 It("should fail to generate v1beta1 CRDs", func() { 80 By("calling Generate") 81 gen := &crd.Generator{ 82 CRDVersions: []string{"v1beta1"}, 83 } 84 Expect(gen.Generate(ctx)).To(MatchError(`apiVersion "apiextensions.k8s.io/v1beta1" is not supported`)) 85 }) 86 87 It("should not strip v1 CRDs of default fields and metadata description", func() { 88 By("calling Generate") 89 gen := &crd.Generator{ 90 CRDVersions: []string{"v1"}, 91 } 92 Expect(gen.Generate(ctx)).NotTo(HaveOccurred()) 93 94 By("loading the desired YAML") 95 expectedFile, err := os.ReadFile(filepath.Join(genDir, "bar.example.com_foos.yaml")) 96 Expect(err).NotTo(HaveOccurred()) 97 expectedFile = fixAnnotations(expectedFile) 98 99 By("comparing the two") 100 Expect(out.buf.String()).To(Equal(string(expectedFile)), cmp.Diff(out.buf.String(), string(expectedFile))) 101 }) 102 103 It("should have deterministic output", func() { 104 By("calling Generate on multple packages") 105 gen := &crd.Generator{ 106 CRDVersions: []string{"v1"}, 107 } 108 Expect(gen.Generate(ctx2)).NotTo(HaveOccurred()) 109 110 By("loading the desired YAMLs") 111 expectedFileFoos, err := os.ReadFile(filepath.Join(genDir, "bar.example.com_foos.yaml")) 112 Expect(err).NotTo(HaveOccurred()) 113 expectedFileFoos = fixAnnotations(expectedFileFoos) 114 expectedFileZoos, err := os.ReadFile(filepath.Join(genDir, "zoo", "bar.example.com_zoos.yaml")) 115 Expect(err).NotTo(HaveOccurred()) 116 expectedFileZoos = fixAnnotations(expectedFileZoos) 117 118 By("comparing the two, output must be deterministic because groupKinds are sorted") 119 expectedOut := string(expectedFileFoos) + string(expectedFileZoos) 120 Expect(out.buf.String()).To(Equal(expectedOut), cmp.Diff(out.buf.String(), expectedOut)) 121 }) 122 123 It("should add preserveUnknownFields=false when specified", func() { 124 By("calling Generate") 125 no := false 126 gen := &crd.Generator{ 127 CRDVersions: []string{"v1"}, 128 DeprecatedV1beta1CompatibilityPreserveUnknownFields: &no, 129 } 130 Expect(gen.Generate(ctx)).NotTo(HaveOccurred()) 131 132 By("searching preserveUnknownFields") 133 Expect(out.buf.String()).To(ContainSubstring("preserveUnknownFields: false")) 134 }) 135 136 It("should add preserveUnknownFields=true when specified", func() { 137 By("calling Generate") 138 yes := true 139 gen := &crd.Generator{ 140 CRDVersions: []string{"v1"}, 141 DeprecatedV1beta1CompatibilityPreserveUnknownFields: &yes, 142 } 143 Expect(gen.Generate(ctx)).NotTo(HaveOccurred()) 144 145 By("searching preserveUnknownFields") 146 Expect(out.buf.String()).To(ContainSubstring("preserveUnknownFields: true")) 147 }) 148 149 It("should not add preserveUnknownFields when not specified", func() { 150 By("calling Generate") 151 gen := &crd.Generator{ 152 CRDVersions: []string{"v1"}, 153 } 154 Expect(gen.Generate(ctx)).NotTo(HaveOccurred()) 155 156 By("searching preserveUnknownFields") 157 Expect(out.buf.String()).NotTo(ContainSubstring("preserveUnknownFields")) 158 }) 159 }) 160 161 // fixAnnotations fixes the attribution annotation for tests. 162 func fixAnnotations(crdBytes []byte) []byte { 163 return bytes.Replace(crdBytes, []byte("(devel)"), []byte("(unknown)"), 1) 164 } 165 166 type outputRule struct { 167 buf *bytes.Buffer 168 } 169 170 func (o *outputRule) Open(_ *loader.Package, _ string) (io.WriteCloser, error) { 171 return nopCloser{o.buf}, nil 172 } 173 174 type nopCloser struct { 175 io.Writer 176 } 177 178 func (n nopCloser) Close() error { 179 return nil 180 }