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  }