github.com/minio/controller-tools@v0.4.7/pkg/crd/parser_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  	"io/ioutil"
    21  	"os"
    22  
    23  	"github.com/google/go-cmp/cmp"
    24  	. "github.com/onsi/ginkgo"
    25  	. "github.com/onsi/gomega"
    26  	"golang.org/x/tools/go/packages"
    27  	apiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
    28  	"k8s.io/apimachinery/pkg/runtime/schema"
    29  	"sigs.k8s.io/yaml"
    30  
    31  	"github.com/minio/controller-tools/pkg/crd"
    32  	crdmarkers "github.com/minio/controller-tools/pkg/crd/markers"
    33  	"github.com/minio/controller-tools/pkg/loader"
    34  	"github.com/minio/controller-tools/pkg/markers"
    35  )
    36  
    37  func packageErrors(pkg *loader.Package, filterKinds ...packages.ErrorKind) error {
    38  	toSkip := make(map[packages.ErrorKind]struct{})
    39  	for _, errKind := range filterKinds {
    40  		toSkip[errKind] = struct{}{}
    41  	}
    42  	var outErr error
    43  	packages.Visit([]*packages.Package{pkg.Package}, nil, func(pkgRaw *packages.Package) {
    44  		for _, err := range pkgRaw.Errors {
    45  			if _, skip := toSkip[err.Kind]; skip {
    46  				continue
    47  			}
    48  			outErr = err
    49  		}
    50  	})
    51  	return outErr
    52  }
    53  
    54  var _ = Describe("CRD Generation From Parsing to CustomResourceDefinition", func() {
    55  	It("should properly generate and flatten the rewritten CronJob schema", func() {
    56  		// TODO(directxman12): test generation across multiple versions (right
    57  		// now, we're trusting k/k's conversion code, though, which is probably
    58  		// fine for the time being)
    59  		By("switching into testdata to appease go modules")
    60  		cwd, err := os.Getwd()
    61  		Expect(err).NotTo(HaveOccurred())
    62  		Expect(os.Chdir("./testdata")).To(Succeed()) // go modules are directory-sensitive
    63  		defer func() { Expect(os.Chdir(cwd)).To(Succeed()) }()
    64  
    65  		By("loading the roots")
    66  		pkgs, err := loader.LoadRoots(".")
    67  		Expect(err).NotTo(HaveOccurred())
    68  		Expect(pkgs).To(HaveLen(1))
    69  		cronJobPkg := pkgs[0]
    70  
    71  		By("setting up the parser")
    72  		reg := &markers.Registry{}
    73  		Expect(crdmarkers.Register(reg)).To(Succeed())
    74  		parser := &crd.Parser{
    75  			Collector: &markers.Collector{Registry: reg},
    76  			Checker:   &loader.TypeChecker{},
    77  		}
    78  		crd.AddKnownTypes(parser)
    79  
    80  		By("requesting that the package be parsed")
    81  		parser.NeedPackage(cronJobPkg)
    82  
    83  		By("requesting that the CRD be generated")
    84  		groupKind := schema.GroupKind{Kind: "CronJob", Group: "testdata.kubebuilder.io"}
    85  		parser.NeedCRDFor(groupKind, nil)
    86  
    87  		By("fixing top level ObjectMeta on the CRD")
    88  		crd.FixTopLevelMetadata(parser.CustomResourceDefinitions[groupKind])
    89  
    90  		By("checking that no errors occurred along the way (expect for type errors)")
    91  		Expect(packageErrors(cronJobPkg, packages.TypeError)).NotTo(HaveOccurred())
    92  
    93  		By("checking that the CRD is present")
    94  		Expect(parser.CustomResourceDefinitions).To(HaveKey(groupKind))
    95  
    96  		By("loading the desired YAML")
    97  		expectedFile, err := ioutil.ReadFile("testdata.kubebuilder.io_cronjobs.yaml")
    98  		Expect(err).NotTo(HaveOccurred())
    99  
   100  		By("parsing the desired YAML")
   101  		var crd apiext.CustomResourceDefinition
   102  		Expect(yaml.Unmarshal(expectedFile, &crd)).To(Succeed())
   103  		// clear the annotations -- we don't care about the attribution annotation
   104  		crd.Annotations = nil
   105  
   106  		By("comparing the two")
   107  		Expect(parser.CustomResourceDefinitions[groupKind]).To(Equal(crd), "type not as expected, check pkg/crd/testdata/README.md for more details.\n\nDiff:\n\n%s", cmp.Diff(parser.CustomResourceDefinitions[groupKind], crd))
   108  	})
   109  
   110  	It("should generate plural words for Kind correctly", func() {
   111  		By("switching into testdata to appease go modules")
   112  		cwd, err := os.Getwd()
   113  		Expect(err).NotTo(HaveOccurred())
   114  		Expect(os.Chdir("./testdata/plural")).To(Succeed())
   115  		defer func() { Expect(os.Chdir(cwd)).To(Succeed()) }()
   116  
   117  		By("loading the roots")
   118  		pkgs, err := loader.LoadRoots(".")
   119  		Expect(err).NotTo(HaveOccurred())
   120  		Expect(pkgs).To(HaveLen(1))
   121  		pkg := pkgs[0]
   122  
   123  		By("setting up the parser")
   124  		reg := &markers.Registry{}
   125  		Expect(crdmarkers.Register(reg)).To(Succeed())
   126  		parser := &crd.Parser{
   127  			Collector: &markers.Collector{Registry: reg},
   128  			Checker:   &loader.TypeChecker{},
   129  		}
   130  		crd.AddKnownTypes(parser)
   131  
   132  		By("requesting that the package be parsed")
   133  		parser.NeedPackage(pkg)
   134  
   135  		By("requesting that the CRD be generated")
   136  		groupKind := schema.GroupKind{Kind: "TestQuota", Group: "plural.example.com"}
   137  		parser.NeedCRDFor(groupKind, nil)
   138  
   139  		By("fixing top level ObjectMeta on the CRD")
   140  		crd.FixTopLevelMetadata(parser.CustomResourceDefinitions[groupKind])
   141  
   142  		By("loading the desired YAML")
   143  		expectedFile, err := ioutil.ReadFile("plural.example.com_testquotas.yaml")
   144  		Expect(err).NotTo(HaveOccurred())
   145  
   146  		By("parsing the desired YAML")
   147  		var crd apiext.CustomResourceDefinition
   148  		Expect(yaml.Unmarshal(expectedFile, &crd)).To(Succeed())
   149  		// clear the annotations -- we don't care about the attribution annotation
   150  		crd.Annotations = nil
   151  
   152  		By("comparing the two")
   153  		Expect(parser.CustomResourceDefinitions[groupKind]).To(Equal(crd), "type not as expected, check pkg/crd/testdata/README.md for more details.\n\nDiff:\n\n%s", cmp.Diff(parser.CustomResourceDefinitions[groupKind], crd))
   154  	})
   155  
   156  	It("should skip api internal package", func() {
   157  		By("switching into testdata to appease go modules")
   158  		cwd, err := os.Getwd()
   159  		Expect(err).NotTo(HaveOccurred())
   160  		Expect(os.Chdir("./testdata/internal_version")).To(Succeed()) // go modules are directory-sensitive
   161  		defer func() { Expect(os.Chdir(cwd)).To(Succeed()) }()
   162  
   163  		By("loading the roots")
   164  		pkgs, err := loader.LoadRoots(".")
   165  		Expect(err).NotTo(HaveOccurred())
   166  		Expect(pkgs).To(HaveLen(1))
   167  		cronJobPkg := pkgs[0]
   168  
   169  		By("setting up the parser")
   170  		reg := &markers.Registry{}
   171  		Expect(crdmarkers.Register(reg)).To(Succeed())
   172  		parser := &crd.Parser{
   173  			Collector: &markers.Collector{Registry: reg},
   174  			Checker:   &loader.TypeChecker{},
   175  		}
   176  		crd.AddKnownTypes(parser)
   177  
   178  		By("requesting that the package be parsed")
   179  		parser.NeedPackage(cronJobPkg)
   180  
   181  		By("checking that there is no GroupVersion")
   182  		Expect(parser.GroupVersions).To(BeEmpty())
   183  
   184  		By("checking that there are no Types")
   185  		Expect(parser.Types).To(BeEmpty())
   186  
   187  		By("checking that no errors occurred along the way (expect for type errors)")
   188  		Expect(packageErrors(cronJobPkg, packages.TypeError)).NotTo(HaveOccurred())
   189  
   190  	})
   191  })