From 094116ac9a0f5794881792db1be21099b510f4cf Mon Sep 17 00:00:00 2001 From: Antoine Pelisse Date: Thu, 28 Sep 2017 09:34:24 -0700 Subject: [PATCH] Add test for explain --- pkg/kubectl/explain/BUILD | 20 ++- pkg/kubectl/explain/field_lookup_test.go | 77 +++++++++++ pkg/kubectl/explain/fields_printer_test.go | 66 ++++++++++ pkg/kubectl/explain/formatter_test.go | 91 +++++++++++++ pkg/kubectl/explain/model_printer_test.go | 122 ++++++++++++++++++ .../explain/recursive_fields_printer_test.go | 61 +++++++++ pkg/kubectl/explain/test-swagger.json | 78 +++++++++++ pkg/kubectl/explain/typename_test.go | 80 ++++++++++++ 8 files changed, 594 insertions(+), 1 deletion(-) create mode 100644 pkg/kubectl/explain/field_lookup_test.go create mode 100644 pkg/kubectl/explain/fields_printer_test.go create mode 100644 pkg/kubectl/explain/formatter_test.go create mode 100644 pkg/kubectl/explain/model_printer_test.go create mode 100644 pkg/kubectl/explain/recursive_fields_printer_test.go create mode 100644 pkg/kubectl/explain/test-swagger.json create mode 100644 pkg/kubectl/explain/typename_test.go diff --git a/pkg/kubectl/explain/BUILD b/pkg/kubectl/explain/BUILD index 457ce2dd853..d55a25c5354 100644 --- a/pkg/kubectl/explain/BUILD +++ b/pkg/kubectl/explain/BUILD @@ -1,4 +1,4 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") go_library( name = "go_default_library", @@ -32,3 +32,21 @@ filegroup( tags = ["automanaged"], visibility = ["//visibility:public"], ) + +go_test( + name = "go_default_test", + srcs = [ + "field_lookup_test.go", + "fields_printer_test.go", + "formatter_test.go", + "model_printer_test.go", + "recursive_fields_printer_test.go", + "typename_test.go", + ], + data = ["test-swagger.json"], + library = ":go_default_library", + deps = [ + "//pkg/kubectl/cmd/util/openapi/testing:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", + ], +) diff --git a/pkg/kubectl/explain/field_lookup_test.go b/pkg/kubectl/explain/field_lookup_test.go new file mode 100644 index 00000000000..4120c31f336 --- /dev/null +++ b/pkg/kubectl/explain/field_lookup_test.go @@ -0,0 +1,77 @@ +/* +Copyright 2017 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 explain + +import ( + "testing" + + "k8s.io/apimachinery/pkg/runtime/schema" +) + +func TestFindField(t *testing.T) { + schema := resources.LookupResource(schema.GroupVersionKind{ + Group: "", + Version: "v1", + Kind: "OneKind", + }) + if schema == nil { + t.Fatal("Counldn't find schema v1.OneKind") + } + + tests := []struct { + path []string + + err string + expectedPath string + }{ + { + path: []string{}, + expectedPath: "OneKind", + }, + { + path: []string{"field1"}, + expectedPath: "OneKind.field1", + }, + { + path: []string{"field1", "array"}, + expectedPath: "OtherKind.array", + }, + { + path: []string{"field1", "what?"}, + err: `field "what?" does not exist`, + }, + } + + for _, test := range tests { + path, err := LookupSchemaForField(schema, test.path) + + gotErr := "" + if err != nil { + gotErr = err.Error() + } + + gotPath := "" + if path != nil { + gotPath = path.GetPath().String() + } + + if gotErr != test.err && gotPath != test.expectedPath { + t.Errorf("LookupSchemaForField(schema, %v) = (%v, %v), expected (%s, %v)", + test.path, gotErr, gotPath, test.expectedPath, test.err) + } + } +} diff --git a/pkg/kubectl/explain/fields_printer_test.go b/pkg/kubectl/explain/fields_printer_test.go new file mode 100644 index 00000000000..0e04c631f85 --- /dev/null +++ b/pkg/kubectl/explain/fields_printer_test.go @@ -0,0 +1,66 @@ +/* +Copyright 2017 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 explain + +import ( + "bytes" + "testing" + + "k8s.io/apimachinery/pkg/runtime/schema" +) + +func TestFields(t *testing.T) { + schema := resources.LookupResource(schema.GroupVersionKind{ + Group: "", + Version: "v1", + Kind: "OneKind", + }) + if schema == nil { + t.Fatal("Couldn't find schema v1.OneKind") + } + + want := `field1 -required- + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla ut lacus ac + enim vulputate imperdiet ac accumsan risus. Integer vel accumsan lectus. + Praesent tempus nulla id tortor luctus, quis varius nulla laoreet. Ut orci + nisi, suscipit id velit sed, blandit eleifend turpis. Curabitur tempus ante at + lectus viverra, a mattis augue euismod. Morbi quam ligula, porttitor sit amet + lacus non, interdum pulvinar tortor. Praesent accumsan risus et ipsum dictum, + vel ullamcorper lorem egestas. + +field2 <[]map[string]string> + This is an array of object of PrimitiveDef + +` + + buf := bytes.Buffer{} + f := Formatter{ + Writer: &buf, + Wrap: 80, + } + s, err := LookupSchemaForField(schema, []string{}) + if err != nil { + t.Fatalf("Invalid path %v: %v", []string{}, err) + } + if err := (fieldsPrinterBuilder{Recursive: false}).BuildFieldsPrinter(&f).PrintFields(s); err != nil { + t.Fatalf("Failed to print fields: %v", err) + } + got := buf.String() + if got != want { + t.Errorf("Got:\n%v\nWant:\n%v\n", buf.String(), want) + } +} diff --git a/pkg/kubectl/explain/formatter_test.go b/pkg/kubectl/explain/formatter_test.go new file mode 100644 index 00000000000..15aaf0a9873 --- /dev/null +++ b/pkg/kubectl/explain/formatter_test.go @@ -0,0 +1,91 @@ +/* +Copyright 2017 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 explain + +import ( + "bytes" + "testing" +) + +func TestFormatterWrite(t *testing.T) { + buf := bytes.Buffer{} + f := Formatter{ + Writer: &buf, + } + + f.Write("Lorem ipsum dolor sit amet, consectetur adipiscing elit.") + // Indent creates a new Formatter + f.Indent(5).Write("Morbi at turpis faucibus, gravida dolor ut, fringilla velit.") + // So Indent(2) doesn't indent to 7 here. + f.Indent(2).Write("Etiam maximus urna at tellus faucibus mattis.") + + want := `Lorem ipsum dolor sit amet, consectetur adipiscing elit. + Morbi at turpis faucibus, gravida dolor ut, fringilla velit. + Etiam maximus urna at tellus faucibus mattis. +` + + if buf.String() != want { + t.Errorf("Got:\n%v\nWant:\n%v\n", buf.String(), want) + } +} + +func TestFormatterWrappedWrite(t *testing.T) { + buf := bytes.Buffer{} + f := Formatter{ + Writer: &buf, + Wrap: 50, + } + + f.WriteWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi at turpis faucibus, gravida dolor ut, fringilla velit.") + f.Indent(10).WriteWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi at turpis faucibus, gravida dolor ut, fringilla velit.") + // Test long words (especially urls) on their own line. + f.Indent(20).WriteWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit. ThisIsAVeryLongWordThatDoesn'tFitOnALineOnItsOwn. Morbi at turpis faucibus, gravida dolor ut, fringilla velit.") + + want := `Lorem ipsum dolor sit amet, consectetur adipiscing +elit. Morbi at turpis faucibus, gravida dolor ut, +fringilla velit. + Lorem ipsum dolor sit amet, consectetur + adipiscing elit. Morbi at turpis + faucibus, gravida dolor ut, fringilla + velit. + Lorem ipsum dolor sit amet, + consectetur adipiscing elit. + ThisIsAVeryLongWordThatDoesn'tFitOnALineOnItsOwn. + Morbi at turpis faucibus, + gravida dolor ut, fringilla + velit. +` + + if buf.String() != want { + t.Errorf("Got:\n%v\nWant:\n%v\n", buf.String(), want) + } +} + +func TestDefaultWrap(t *testing.T) { + buf := bytes.Buffer{} + f := Formatter{ + Writer: &buf, + // Wrap is not set + } + + f.WriteWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi at turpis faucibus, gravida dolor ut, fringilla velit. Etiam maximus urna at tellus faucibus mattis.") + want := `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi at turpis faucibus, gravida dolor ut, fringilla velit. Etiam maximus urna at tellus faucibus mattis. +` + if buf.String() != want { + t.Errorf("Got:\n%v\nWant:\n%v\n", buf.String(), want) + } +} diff --git a/pkg/kubectl/explain/model_printer_test.go b/pkg/kubectl/explain/model_printer_test.go new file mode 100644 index 00000000000..66b9b07eafc --- /dev/null +++ b/pkg/kubectl/explain/model_printer_test.go @@ -0,0 +1,122 @@ +/* +Copyright 2017 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 explain + +import ( + "bytes" + "testing" + + "k8s.io/apimachinery/pkg/runtime/schema" +) + +func TestModel(t *testing.T) { + schema := resources.LookupResource(schema.GroupVersionKind{ + Group: "", + Version: "v1", + Kind: "OneKind", + }) + if schema == nil { + t.Fatal("Couldn't find schema v1.OneKind") + } + + tests := []struct { + path []string + want string + }{ + { + want: `DESCRIPTION: + OneKind has a short description + +FIELDS: + field1 -required- + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla ut lacus ac + enim vulputate imperdiet ac accumsan risus. Integer vel accumsan lectus. + Praesent tempus nulla id tortor luctus, quis varius nulla laoreet. Ut orci + nisi, suscipit id velit sed, blandit eleifend turpis. Curabitur tempus ante + at lectus viverra, a mattis augue euismod. Morbi quam ligula, porttitor sit + amet lacus non, interdum pulvinar tortor. Praesent accumsan risus et ipsum + dictum, vel ullamcorper lorem egestas. + + field2 <[]map[string]string> + This is an array of object of PrimitiveDef + +`, + path: []string{}, + }, + { + want: `RESOURCE: field1 + +DESCRIPTION: + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla ut lacus ac + enim vulputate imperdiet ac accumsan risus. Integer vel accumsan lectus. + Praesent tempus nulla id tortor luctus, quis varius nulla laoreet. Ut orci + nisi, suscipit id velit sed, blandit eleifend turpis. Curabitur tempus ante + at lectus viverra, a mattis augue euismod. Morbi quam ligula, porttitor sit + amet lacus non, interdum pulvinar tortor. Praesent accumsan risus et ipsum + dictum, vel ullamcorper lorem egestas. + + This is another kind of Kind + +FIELDS: + array <[]integer> + This array must be an array of int + + int + This int must be an int + + object + This is an object of string + + primitive + + string -required- + This string must be a string + +`, + path: []string{"field1"}, + }, + { + want: `FIELD: string + +DESCRIPTION: + This string must be a string +`, + path: []string{"field1", "string"}, + }, + { + want: `FIELD: array <[]integer> + +DESCRIPTION: + This array must be an array of int + + This is an int in an array +`, + path: []string{"field1", "array"}, + }, + } + + for _, test := range tests { + buf := bytes.Buffer{} + if err := PrintModelDescription(test.path, &buf, schema, false); err != nil { + t.Fatalf("Failed to PrintModelDescription for path %v: %v", test.path, err) + } + got := buf.String() + if got != test.want { + t.Errorf("Got:\n%v\nWant:\n%v\n", buf.String(), test.want) + } + } +} diff --git a/pkg/kubectl/explain/recursive_fields_printer_test.go b/pkg/kubectl/explain/recursive_fields_printer_test.go new file mode 100644 index 00000000000..75571ab4ee5 --- /dev/null +++ b/pkg/kubectl/explain/recursive_fields_printer_test.go @@ -0,0 +1,61 @@ +/* +Copyright 2017 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 explain + +import ( + "bytes" + "testing" + + "k8s.io/apimachinery/pkg/runtime/schema" +) + +func TestRecursiveFields(t *testing.T) { + schema := resources.LookupResource(schema.GroupVersionKind{ + Group: "", + Version: "v1", + Kind: "OneKind", + }) + if schema == nil { + t.Fatal("Couldn't find schema v1.OneKind") + } + + want := `field1 + array <[]integer> + int + object + primitive + string +field2 <[]map[string]string> +` + + buf := bytes.Buffer{} + f := Formatter{ + Writer: &buf, + Wrap: 80, + } + s, err := LookupSchemaForField(schema, []string{}) + if err != nil { + t.Fatalf("Invalid path %v: %v", []string{}, err) + } + if err := (fieldsPrinterBuilder{Recursive: true}).BuildFieldsPrinter(&f).PrintFields(s); err != nil { + t.Fatalf("Failed to print fields: %v", err) + } + got := buf.String() + if got != want { + t.Errorf("Got:\n%v\nWant:\n%v\n", buf.String(), want) + } +} diff --git a/pkg/kubectl/explain/test-swagger.json b/pkg/kubectl/explain/test-swagger.json new file mode 100644 index 00000000000..a7634b0679a --- /dev/null +++ b/pkg/kubectl/explain/test-swagger.json @@ -0,0 +1,78 @@ +{ + "swagger": "2.0", + "info": { + "title": "Kubernetes", + "version": "v1.9.0" + }, + "paths": {}, + "definitions": { + "PrimitiveDef": { + "type": "string" + }, + "OneKind": { + "description": "OneKind has a short description", + "required": [ + "field1", + ], + "properties": { + "field1": { + "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla ut lacus ac enim vulputate imperdiet ac accumsan risus. Integer vel accumsan lectus. Praesent tempus nulla id tortor luctus, quis varius nulla laoreet. Ut orci nisi, suscipit id velit sed, blandit eleifend turpis. Curabitur tempus ante at lectus viverra, a mattis augue euismod. Morbi quam ligula, porttitor sit amet lacus non, interdum pulvinar tortor. Praesent accumsan risus et ipsum dictum, vel ullamcorper lorem egestas.", + "$ref": "#/definitions/OtherKind" + }, + "field2": { + "description": "This is an array of object of PrimitiveDef", + "type": "array", + "items": { + "description": "This is an object of PrimitiveDef", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/PrimitiveDef" + } + } + } + }, + "x-kubernetes-group-version-kind": [ + { + "group": "", + "kind": "OneKind", + "version": "v1" + } + ] + }, + "OtherKind": { + "description": "This is another kind of Kind", + "required": [ + "string", + ], + "properties": { + "string": { + "description": "This string must be a string", + "type": "string", + }, + "int": { + "description": "This int must be an int", + "type": "integer", + }, + "array": { + "description": "This array must be an array of int", + "type": "array", + "items": { + "description": "This is an int in an array", + "type": "integer", + } + }, + "object": { + "description": "This is an object of string", + "type": "object", + "additionalProperties": { + "description": "this is a string in an object", + "type": "string", + } + }, + "primitive": { + "$ref": "#/definitions/PrimitiveDef" + } + } + } + } +} diff --git a/pkg/kubectl/explain/typename_test.go b/pkg/kubectl/explain/typename_test.go new file mode 100644 index 00000000000..aa3e5a2abeb --- /dev/null +++ b/pkg/kubectl/explain/typename_test.go @@ -0,0 +1,80 @@ +/* +Copyright 2017 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 explain + +import ( + "testing" + + "k8s.io/apimachinery/pkg/runtime/schema" + tst "k8s.io/kubernetes/pkg/kubectl/cmd/util/openapi/testing" +) + +var resources = tst.NewFakeResources("test-swagger.json") + +func TestReferenceTypename(t *testing.T) { + schema := resources.LookupResource(schema.GroupVersionKind{ + Group: "", + Version: "v1", + Kind: "OneKind", + }) + if schema == nil { + t.Fatal("Couldn't find schema v1.OneKind") + } + + tests := []struct { + path []string + expected string + }{ + { + // Kind is "Object" + path: []string{}, + expected: "Object", + }, + { + // Reference is equal to pointed type "Object" + path: []string{"field1"}, + expected: "Object", + }, + { + // Reference is equal to pointed type "string" + path: []string{"field1", "primitive"}, + expected: "string", + }, + { + // Array of object of reference to string + path: []string{"field2"}, + expected: "[]map[string]string", + }, + { + // Array of integer + path: []string{"field1", "array"}, + expected: "[]integer", + }, + } + + for _, test := range tests { + s, err := LookupSchemaForField(schema, test.path) + if err != nil { + t.Fatalf("Invalid test.path %v: %v", test.path, err) + } + got := GetTypeName(s) + if got != test.expected { + t.Errorf("Got %q, expected %q", got, test.expected) + } + } + +}