diff --git a/go.mod b/go.mod index 70bedb3cb30..c567f1777aa 100644 --- a/go.mod +++ b/go.mod @@ -44,7 +44,6 @@ require ( github.com/evanphx/json-patch v4.9.0+incompatible github.com/fsnotify/fsnotify v1.4.9 github.com/go-bindata/go-bindata v3.1.1+incompatible - github.com/go-openapi/analysis v0.19.5 github.com/go-openapi/loads v0.19.4 github.com/go-openapi/spec v0.19.3 github.com/go-openapi/strfmt v0.19.3 diff --git a/test/conformance/BUILD b/test/conformance/BUILD index a387ab2c366..21bf50e2e15 100644 --- a/test/conformance/BUILD +++ b/test/conformance/BUILD @@ -32,7 +32,6 @@ filegroup( srcs = [ ":package-srcs", "//test/conformance/behaviors:all-srcs", - "//test/conformance/kubeconform:all-srcs", "//test/conformance/testdata:all-srcs", ], tags = ["automanaged"], diff --git a/test/conformance/kubeconform/.gitignore b/test/conformance/kubeconform/.gitignore deleted file mode 100644 index 0af3e9fa8fa..00000000000 --- a/test/conformance/kubeconform/.gitignore +++ /dev/null @@ -1 +0,0 @@ -kubetestgen diff --git a/test/conformance/kubeconform/BUILD b/test/conformance/kubeconform/BUILD deleted file mode 100644 index 20e7fefa374..00000000000 --- a/test/conformance/kubeconform/BUILD +++ /dev/null @@ -1,40 +0,0 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") - -go_library( - name = "go_default_library", - srcs = [ - "gen.go", - "kubeconform.go", - "link.go", - ], - importpath = "k8s.io/kubernetes/test/conformance/kubeconform", - visibility = ["//visibility:private"], - deps = [ - "//test/conformance/behaviors:go_default_library", - "//vendor/github.com/go-openapi/analysis:go_default_library", - "//vendor/github.com/go-openapi/loads:go_default_library", - "//vendor/github.com/go-openapi/spec:go_default_library", - "//vendor/gopkg.in/yaml.v2:go_default_library", - ], -) - -filegroup( - name = "package-srcs", - srcs = glob(["**"]), - tags = ["automanaged"], - visibility = ["//visibility:private"], -) - -filegroup( - name = "all-srcs", - srcs = [":package-srcs"], - tags = ["automanaged"], - visibility = ["//visibility:public"], -) - -go_binary( - name = "kubeconform", - data = ["//api/openapi-spec"], - embed = [":go_default_library"], - visibility = ["//visibility:public"], -) diff --git a/test/conformance/kubeconform/README.md b/test/conformance/kubeconform/README.md deleted file mode 100644 index 4b27497fbe3..00000000000 --- a/test/conformance/kubeconform/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# kubeconform - -`kubeconform` is used to manage the creation and coverage analysis of conformance behaviors and tests. Currently it performs two functions: - -* `gen`. This command generates a list of behaviors for a resource based on the OpenAPI schema. The purpose is to bootstrap a list of behaviors, and not to produce the final list of behaviors. We expect that the resulting files will be curated to identify a meaningful set of behaviors for the conformance requirements of the targeted resource. This may include addition, modification, and removal of behaviors from the generated list. -* `link`. This command prints the defined behaviors not covered by any test. - -## gen -**Example usage for PodSpec:** - -From the root directory of the k/k repo, will produce `pod.yaml` in -`test/conformance/behaviors`. The `pwd` is needed because of how bazel handles -working directories with `run`. - -``` -$ bazel run //test/conformance/kubeconform:kubeconform -- --resource io.k8s.api.core.v1.PodSpec --area pod --schema api/openapi-spec/swagger.json --dir `pwd`/test/conformance/behaviors/ gen -``` - -**Flags:** - -- `schema` - a URL or local file name pointing to the JSON OpenAPI schema -- `resource` - the specific OpenAPI definition for which to generate behaviors -- `area` - the name to use for the area -- `dir` - the path to the behaviors directory (default current directory) - -**Note**: The tool automatically generates suites based on the object type for a field. All primitive data types are grouped into a default suite, while object data types are grouped into their own suite, one per object. - -## link - -``` -$ bazel run //test/conformance/kubeconform:kubeconform -- -dir `pwd`/test/conformance/behaviors/sig-node -testdata `pwd`/test/conformance/testdata/conformance.yaml link -``` diff --git a/test/conformance/kubeconform/gen.go b/test/conformance/kubeconform/gen.go deleted file mode 100644 index 520cdf6f3a7..00000000000 --- a/test/conformance/kubeconform/gen.go +++ /dev/null @@ -1,218 +0,0 @@ -/* -Copyright 2019 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package main - -import ( - "fmt" - "os" - "path/filepath" - "sort" - "strings" - - "github.com/go-openapi/analysis" - "github.com/go-openapi/loads" - "github.com/go-openapi/spec" - "gopkg.in/yaml.v2" - "k8s.io/kubernetes/test/conformance/behaviors" -) - -var defMap map[string]analysis.SchemaRef - -func gen(o *options) error { - defMap = make(map[string]analysis.SchemaRef) - d, err := loads.JSONSpec(o.schemaPath) - if err != nil { - return err - } - defs := d.Analyzer.AllDefinitions() - sort.Slice(defs, func(i, j int) bool { return defs[i].Name < defs[j].Name }) - - for _, d := range defs { - if !d.TopLevel { - continue - } - defMap[d.Ref.String()] = d - } - - var suites []behaviors.Suite - var suiteMapping = make(map[string]*behaviors.Suite) - - for _, v := range defs { - if !v.TopLevel || o.resource != v.Name { - continue - } - name := trimObjectName(v.Name) - - defaultsuite := behaviors.Suite{ - Suite: o.area + "/spec", - Description: "Base suite for " + o.area, - Behaviors: []behaviors.Behavior{}, - } - - _ = defaultsuite - - for p, propSchema := range v.Schema.Properties { - id := o.area + p + "/" - - if propSchema.Ref.String() != "" || propSchema.Type[0] == "array" { - if _, ok := suiteMapping[id]; !ok { - newsuite := behaviors.Suite{ - Suite: o.area + "/" + p, - Description: "Suite for " + o.area + "/" + p, - Behaviors: []behaviors.Behavior{}, - } - suiteMapping[id] = &newsuite - } - behaviors := suiteMapping[id].Behaviors - behaviors = append(behaviors, schemaBehavior(o.area, name, p, propSchema)...) - suiteMapping[id].Behaviors = behaviors - } else { - if _, ok := suiteMapping["default"]; !ok { - newsuite := behaviors.Suite{ - Suite: o.area + "/spec", - Description: "Base suite for " + o.area, - Behaviors: []behaviors.Behavior{}, - } - suiteMapping["default"] = &newsuite - } - - behaviors := suiteMapping["default"].Behaviors - behaviors = append(behaviors, schemaBehavior(o.area, name, p, propSchema)...) - suiteMapping["default"].Behaviors = behaviors - - } - } - for _, v := range suiteMapping { - suites = append(suites, *v) - } - - break - } - - var area behaviors.Area = behaviors.Area{Area: o.area, Suites: suites} - countFields(suites) - return printYAML(filepath.Join(o.behaviorsDir, o.area), area) -} - -func printYAML(fileName string, areaO behaviors.Area) error { - f, err := os.Create(fileName + ".yaml") - if err != nil { - return err - } - defer f.Close() - y, err := yaml.Marshal(areaO) - if err != nil { - return err - } - - _, err = f.WriteString(string(y)) - if err != nil { - return err - } - return nil -} - -func countFields(suites []behaviors.Suite) { - var fieldsMapping map[string]int - fieldsMapping = make(map[string]int) - for _, suite := range suites { - for _, behavior := range suite.Behaviors { - if _, exists := fieldsMapping[behavior.APIType]; exists { - fieldsMapping[behavior.APIType]++ - } else { - fieldsMapping[behavior.APIType] = 1 - } - } - } - for k, v := range fieldsMapping { - fmt.Printf("Type %v, Count %v\n", k, v) - } -} - -func trimObjectName(name string) string { - if strings.Index(name, "#/definitions/") == 0 { - name = name[len("#/definitions/"):] - } - if strings.Index(name, "io.k8s.api.") == 0 { - return name[len("io.k8s.api."):] - } - return name -} - -func objectBehaviors(id string, s *spec.Schema) []behaviors.Behavior { - if strings.Contains(id, "openAPIV3Schema") || strings.Contains(id, "JSONSchema") || strings.Contains(s.Ref.String(), "JSONSchema") { - return []behaviors.Behavior{} - } - - ref, ok := defMap[s.Ref.String()] - if !ok { - return []behaviors.Behavior{} - } - - return schemaBehaviors(id, trimObjectName(ref.Name), ref.Schema) -} - -func schemaBehaviors(base, apiObject string, s *spec.Schema) []behaviors.Behavior { - var behaviors []behaviors.Behavior - for p, propSchema := range s.Properties { - b := schemaBehavior(base, apiObject, p, propSchema) - behaviors = append(behaviors, b...) - } - return behaviors -} - -func schemaBehavior(base, apiObject, p string, propSchema spec.Schema) []behaviors.Behavior { - - id := strings.Join([]string{base, p}, "/") - if propSchema.Ref.String() != "" { - if apiObject == trimObjectName(propSchema.Ref.String()) { - return []behaviors.Behavior{} - } - return objectBehaviors(id, &propSchema) - } - var b []behaviors.Behavior - switch propSchema.Type[0] { - case "array": - b = objectBehaviors(id, propSchema.Items.Schema) - case "boolean": - b = []behaviors.Behavior{ - { - ID: id, - APIObject: apiObject, - APIField: p, - APIType: propSchema.Type[0], - Description: "Boolean set to true. " + propSchema.Description, - }, - { - ID: id, - APIObject: apiObject, - APIField: p, - APIType: propSchema.Type[0], - Description: "Boolean set to false. " + propSchema.Description, - }, - } - default: - b = []behaviors.Behavior{{ - ID: id, - APIObject: apiObject, - APIField: p, - APIType: propSchema.Type[0], - Description: propSchema.Description, - }} - } - return b -} diff --git a/test/conformance/kubeconform/kubeconform.go b/test/conformance/kubeconform/kubeconform.go deleted file mode 100644 index b7925df9372..00000000000 --- a/test/conformance/kubeconform/kubeconform.go +++ /dev/null @@ -1,119 +0,0 @@ -/* -Copyright 2020 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package main - -import ( - "flag" - "fmt" - "os" -) - -// homegrown command structures now but if this grows we may -// want to adopt whatever kubectl uses -type options struct { - // Flags only used for generating behaviors - schemaPath string - resource string - area string - - // Flags only used for linking behaviors - testdata string - listAll bool - - // Flags shared between CLI tools - behaviorsDir string -} - -type actionFunc func(*options) error - -func parseFlags() (actionFunc, *options) { - o := &options{} - - f := flag.NewFlagSet(os.Args[0], flag.ExitOnError) - f.StringVar(&o.schemaPath, "schema", "", "Path to the OpenAPI schema") - f.StringVar(&o.resource, "resource", "", "Resource name") - f.StringVar(&o.area, "area", "", "Area name to use") - - f.StringVar(&o.testdata, "testdata", "test/conformance/testdata/conformance.yaml", "YAML file containing test linkage data") - f.BoolVar(&o.listAll, "all", false, "List all behaviors, not just those missing tests") - - f.StringVar(&o.behaviorsDir, "dir", "test/conformance/behaviors/", "Path to the behaviors directory") - - f.Usage = func() { - fmt.Fprintf(os.Stderr, - "USAGE\n-----\n%s [ options ] { link | gen }\n", - os.Args[0]) - fmt.Fprintf(os.Stderr, "\nOPTIONS\n-------\n") - flag.PrintDefaults() - fmt.Fprintf(os.Stderr, "\nACTIONS\n------------") - fmt.Fprintf(os.Stderr, ` - 'link' lists behaviors associated with tests - 'gen' generates behaviors based on the API schema -`) - } - - flag.CommandLine = f - flag.Parse() - if len(flag.Args()) != 1 { - flag.CommandLine.Usage() - os.Exit(2) - } - - var action actionFunc - switch flag.Args()[0] { - case "gen": - action = gen - if o.schemaPath == "" { - action = nil - fmt.Fprintf(os.Stderr, "-schema is required for 'gen'\n") - } - if o.resource == "" { - action = nil - fmt.Fprintf(os.Stderr, "-resource is required for 'gen'\n") - } - if o.area == "" { - action = nil - fmt.Fprintf(os.Stderr, "-area is required for 'gen'\n") - } - case "link": - action = link - if o.testdata == "" { - action = nil - fmt.Fprintf(os.Stderr, "-testdata is required for 'link'\n") - } - } - - if o.behaviorsDir == "" { - action = nil - fmt.Fprintf(os.Stderr, "-dir is required\n") - } - - if action == nil { - flag.CommandLine.Usage() - os.Exit(2) - } - return action, o -} - -func main() { - action, o := parseFlags() - err := action(o) - if err != nil { - fmt.Printf("Error: %s\n", err) - os.Exit(1) - } -} diff --git a/test/conformance/kubeconform/link.go b/test/conformance/kubeconform/link.go deleted file mode 100644 index eadb5e8c5b0..00000000000 --- a/test/conformance/kubeconform/link.go +++ /dev/null @@ -1,92 +0,0 @@ -/* -Copyright 2020 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package main - -import ( - "fmt" - "io/ioutil" - - "gopkg.in/yaml.v2" - - "k8s.io/kubernetes/test/conformance/behaviors" -) - -func link(o *options) error { - behaviorsMapping := make(map[string][]string) - var conformanceDataList []behaviors.ConformanceData - - behaviorFiles, err := behaviors.BehaviorFileList(o.behaviorsDir) - if err != nil { - return err - } - - fmt.Println() - fmt.Printf("Using behaviors from these %d files:\n", len(behaviorFiles)) - for _, f := range behaviorFiles { - fmt.Println(" ", f) - } - fmt.Println() - - if o.listAll { - fmt.Println("All behaviors:") - } else { - fmt.Println("Behaviors not covered by any conformance test:") - } - - for _, behaviorFile := range behaviorFiles { - suite, err := behaviors.LoadSuite(behaviorFile) - if err != nil { - return err - } - err = behaviors.ValidateSuite(suite) - if err != nil { - return fmt.Errorf("error validating %s: %q", behaviorFile, err.Error()) - } - for _, behavior := range suite.Behaviors { - behaviorsMapping[behavior.ID] = nil - } - } - - conformanceYaml, err := ioutil.ReadFile(o.testdata) - if err != nil { - return fmt.Errorf("%s: %v", o.testdata, err) - } - - err = yaml.Unmarshal(conformanceYaml, &conformanceDataList) - if err != nil { - return fmt.Errorf("%s: %v", o.testdata, err) - } - - for _, data := range conformanceDataList { - for _, behaviorID := range data.Behaviors { - if _, ok := behaviorsMapping[behaviorID]; !ok { - return fmt.Errorf("cannot find behavior %q", behaviorID) - } - behaviorsMapping[behaviorID] = append(behaviorsMapping[behaviorID], data.CodeName) - } - } - printBehaviorsMapping(behaviorsMapping, o) - return nil -} - -func printBehaviorsMapping(behaviorsMapping map[string][]string, o *options) { - for behaviorID, tests := range behaviorsMapping { - if o.listAll || tests == nil { - fmt.Println(" ", behaviorID) - } - } -} diff --git a/vendor/modules.txt b/vendor/modules.txt index 21b48c70443..0306bd68618 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -408,7 +408,6 @@ github.com/go-bindata/go-bindata/go-bindata github.com/go-logr/logr # github.com/go-logr/logr => github.com/go-logr/logr v0.2.0 # github.com/go-openapi/analysis v0.19.5 => github.com/go-openapi/analysis v0.19.5 -## explicit github.com/go-openapi/analysis # github.com/go-openapi/analysis => github.com/go-openapi/analysis v0.19.5 github.com/go-openapi/analysis/internal