mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-07 03:03:59 +00:00
Add componentconfig package testing files
This commit is contained in:
parent
be4683ef9c
commit
c762fbfa2b
@ -24,6 +24,7 @@ filegroup(
|
|||||||
name = "all-srcs",
|
name = "all-srcs",
|
||||||
srcs = [
|
srcs = [
|
||||||
":package-srcs",
|
":package-srcs",
|
||||||
|
"//staging/src/k8s.io/component-base/config/testing:all-srcs",
|
||||||
"//staging/src/k8s.io/component-base/config/v1alpha1:all-srcs",
|
"//staging/src/k8s.io/component-base/config/v1alpha1:all-srcs",
|
||||||
"//staging/src/k8s.io/component-base/config/validation:all-srcs",
|
"//staging/src/k8s.io/component-base/config/validation:all-srcs",
|
||||||
],
|
],
|
||||||
|
44
staging/src/k8s.io/component-base/config/testing/BUILD
Normal file
44
staging/src/k8s.io/component-base/config/testing/BUILD
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||||
|
|
||||||
|
go_library(
|
||||||
|
name = "go_default_library",
|
||||||
|
srcs = [
|
||||||
|
"apigroup.go",
|
||||||
|
"defaulting.go",
|
||||||
|
"helpers.go",
|
||||||
|
"roundtrip.go",
|
||||||
|
],
|
||||||
|
importmap = "k8s.io/kubernetes/vendor/k8s.io/component-base/config/testing",
|
||||||
|
importpath = "k8s.io/component-base/config/testing",
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
deps = [
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/api/apitesting/naming:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||||
|
"//vendor/github.com/google/go-cmp/cmp: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_test(
|
||||||
|
name = "go_default_test",
|
||||||
|
srcs = ["apigroup_test.go"],
|
||||||
|
embed = [":go_default_library"],
|
||||||
|
)
|
207
staging/src/k8s.io/component-base/config/testing/apigroup.go
Normal file
207
staging/src/k8s.io/component-base/config/testing/apigroup.go
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
/*
|
||||||
|
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 testing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
apinamingtest "k8s.io/apimachinery/pkg/api/apitesting/naming"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
"k8s.io/apimachinery/pkg/util/errors"
|
||||||
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
|
)
|
||||||
|
|
||||||
|
// APIVersionRegexp is the regular expression that matches with valid apiversion
|
||||||
|
var APIVersionRegexp = regexp.MustCompile(`^v\d+((alpha|beta){1}\d+)?$`)
|
||||||
|
|
||||||
|
// ComponentConfigPackage is used in APIGroup Testing
|
||||||
|
type ComponentConfigPackage struct {
|
||||||
|
ComponentName string
|
||||||
|
GroupName string
|
||||||
|
SchemeGroupVersion schema.GroupVersion
|
||||||
|
AddToScheme func(*runtime.Scheme) error
|
||||||
|
SkipTests sets.String
|
||||||
|
AllowedTags map[reflect.Type]bool
|
||||||
|
AllowedNonstandardJSONNames map[reflect.Type]string
|
||||||
|
}
|
||||||
|
|
||||||
|
type testingFunc func(*runtime.Scheme, *ComponentConfigPackage) error
|
||||||
|
|
||||||
|
const (
|
||||||
|
verifyTagNaming = "verifyTagNaming"
|
||||||
|
verifyGroupNameSuffix = "verifyGroupNameSuffix"
|
||||||
|
verifyGroupNameMatch = "verifyGroupNameMatch"
|
||||||
|
verifyCorrectGroupName = "verifyCorrectGroupName"
|
||||||
|
verifyComponentConfigKindExists = "verifyComponentConfigKindExists"
|
||||||
|
verifyExternalAPIVersion = "verifyExternalAPIVersion"
|
||||||
|
verifyInternalAPIVersion = "verifyInternalAPIVersion"
|
||||||
|
)
|
||||||
|
|
||||||
|
var testingFuncs = map[string]testingFunc{
|
||||||
|
verifyTagNaming: verifyTagNamingFunc,
|
||||||
|
verifyGroupNameSuffix: verifyGroupNameSuffixFunc,
|
||||||
|
verifyGroupNameMatch: verifyGroupNameMatchFunc,
|
||||||
|
verifyCorrectGroupName: verifyCorrectGroupNameFunc,
|
||||||
|
verifyComponentConfigKindExists: verifyComponentConfigKindExistsFunc,
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyExternalTypePackage tests if external component config package is defined correctly
|
||||||
|
// Test tag naming (json name should match Go name)
|
||||||
|
// Test that GroupName has the k8s.io suffix
|
||||||
|
// Test that GroupName == SchemeGroupVersion.GroupName
|
||||||
|
// Test that the API version follows the right pattern and isn't internal
|
||||||
|
// Test that addKnownTypes and AddToScheme registers at least one type and doesn't error
|
||||||
|
// Test that the GroupName is named correctly (based on ComponentName), and there is a {Component}Configuration kind in the scheme
|
||||||
|
func VerifyExternalTypePackage(pkginfo *ComponentConfigPackage) error {
|
||||||
|
scheme, err := setup(pkginfo)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("test setup error: %v", err)
|
||||||
|
}
|
||||||
|
extraFns := map[string]testingFunc{
|
||||||
|
verifyExternalAPIVersion: verifyExternalAPIVersionFunc,
|
||||||
|
}
|
||||||
|
return runFuncs(scheme, pkginfo, extraFns)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyInternalTypePackage tests if internal component config package is defined correctly
|
||||||
|
// Test tag naming (no tags allowed)
|
||||||
|
// Test that GroupName has the k8s.io suffix
|
||||||
|
// Test that GroupName == SchemeGroupVersion.GroupName
|
||||||
|
// API version should be internal
|
||||||
|
// Test that addKnownTypes and AddToScheme registers at least one type and doesn't error
|
||||||
|
// Test that the GroupName is named correctly (based on ComponentName), and there is a {Component}Configuration kind in the scheme
|
||||||
|
func VerifyInternalTypePackage(pkginfo *ComponentConfigPackage) error {
|
||||||
|
scheme, err := setup(pkginfo)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("test setup error: %v", err)
|
||||||
|
}
|
||||||
|
extraFns := map[string]testingFunc{
|
||||||
|
verifyInternalAPIVersion: verifyInternalAPIVersionFunc,
|
||||||
|
}
|
||||||
|
return runFuncs(scheme, pkginfo, extraFns)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setup(pkginfo *ComponentConfigPackage) (*runtime.Scheme, error) {
|
||||||
|
if len(pkginfo.ComponentName) == 0 ||
|
||||||
|
len(pkginfo.GroupName) == 0 ||
|
||||||
|
pkginfo.SchemeGroupVersion.Empty() ||
|
||||||
|
pkginfo.AddToScheme == nil {
|
||||||
|
return nil, fmt.Errorf("invalid argument: not all parameters were passed correctly to the function")
|
||||||
|
}
|
||||||
|
|
||||||
|
scheme := runtime.NewScheme()
|
||||||
|
if err := pkginfo.AddToScheme(scheme); err != nil {
|
||||||
|
return nil, fmt.Errorf("AddToScheme must not return an error: %v", err)
|
||||||
|
}
|
||||||
|
if len(scheme.AllKnownTypes()) == 0 {
|
||||||
|
return nil, fmt.Errorf("AddToScheme doesn't register any type")
|
||||||
|
}
|
||||||
|
return scheme, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func runFuncs(scheme *runtime.Scheme, pkginfo *ComponentConfigPackage, extraFns map[string]testingFunc) error {
|
||||||
|
verifyFns := []testingFunc{}
|
||||||
|
for name, fn := range testingFuncs {
|
||||||
|
if pkginfo.SkipTests.Has(name) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
verifyFns = append(verifyFns, fn)
|
||||||
|
}
|
||||||
|
for name, fn := range extraFns {
|
||||||
|
if pkginfo.SkipTests.Has(name) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
verifyFns = append(verifyFns, fn)
|
||||||
|
}
|
||||||
|
errs := []error{}
|
||||||
|
for _, fn := range verifyFns {
|
||||||
|
if err := fn(scheme, pkginfo); err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return errors.NewAggregate(errs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func verifyTagNamingFunc(scheme *runtime.Scheme, pkginfo *ComponentConfigPackage) error {
|
||||||
|
return apinamingtest.VerifyTagNaming(scheme, pkginfo.AllowedTags, pkginfo.AllowedNonstandardJSONNames)
|
||||||
|
}
|
||||||
|
|
||||||
|
func verifyGroupNameSuffixFunc(scheme *runtime.Scheme, _ *ComponentConfigPackage) error {
|
||||||
|
return apinamingtest.VerifyGroupNames(scheme, sets.NewString())
|
||||||
|
}
|
||||||
|
|
||||||
|
func verifyGroupNameMatchFunc(_ *runtime.Scheme, pkginfo *ComponentConfigPackage) error {
|
||||||
|
if pkginfo.GroupName != pkginfo.SchemeGroupVersion.Group {
|
||||||
|
return fmt.Errorf("GroupName must be equal to SchemeGroupVersion.Group, GroupName: %v,SchemeGroupVersion.Group: %v",
|
||||||
|
pkginfo.GroupName, pkginfo.SchemeGroupVersion.Group)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func verifyCorrectGroupNameFunc(_ *runtime.Scheme, pkginfo *ComponentConfigPackage) error {
|
||||||
|
desiredGroupName := fmt.Sprintf("%s.config.k8s.io", lowercaseWithoutDashes(pkginfo.ComponentName))
|
||||||
|
if pkginfo.SchemeGroupVersion.Group != desiredGroupName {
|
||||||
|
return fmt.Errorf("got GroupName %q, want %q", pkginfo.SchemeGroupVersion.Group, desiredGroupName)
|
||||||
|
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func verifyComponentConfigKindExistsFunc(scheme *runtime.Scheme, pkginfo *ComponentConfigPackage) error {
|
||||||
|
expectedKind := fmt.Sprintf("%sConfiguration", dashesToCapitalCase(pkginfo.ComponentName))
|
||||||
|
expectedGVK := pkginfo.SchemeGroupVersion.WithKind(expectedKind)
|
||||||
|
if !scheme.Recognizes(expectedGVK) {
|
||||||
|
registeredKinds := sets.NewString()
|
||||||
|
for gvk := range scheme.AllKnownTypes() {
|
||||||
|
registeredKinds.Insert(gvk.Kind)
|
||||||
|
}
|
||||||
|
return fmt.Errorf("Kind %s not registered in the scheme, registered kinds are %v", expectedKind, registeredKinds.List())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func verifyExternalAPIVersionFunc(_ *runtime.Scheme, pkginfo *ComponentConfigPackage) error {
|
||||||
|
if !APIVersionRegexp.MatchString(pkginfo.SchemeGroupVersion.Version) {
|
||||||
|
return fmt.Errorf("invalid API version %q, must match %q", pkginfo.SchemeGroupVersion.Version, APIVersionRegexp.String())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func verifyInternalAPIVersionFunc(_ *runtime.Scheme, pkginfo *ComponentConfigPackage) error {
|
||||||
|
if pkginfo.SchemeGroupVersion.Version != runtime.APIVersionInternal {
|
||||||
|
return fmt.Errorf("internal API version must be %q, got %q",
|
||||||
|
runtime.APIVersionInternal, pkginfo.SchemeGroupVersion.Version)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func lowercaseWithoutDashes(str string) string {
|
||||||
|
return strings.Replace(strings.ToLower(str), "-", "", -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func dashesToCapitalCase(str string) string {
|
||||||
|
segments := strings.Split(str, "-")
|
||||||
|
result := ""
|
||||||
|
for _, segment := range segments {
|
||||||
|
result += strings.Title(segment)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
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 testing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAPIVersionRegexp(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
apiversion string
|
||||||
|
expected bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "v1",
|
||||||
|
apiversion: "v1",
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "v1alpha1",
|
||||||
|
apiversion: "v1alpha1",
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "v1beta1",
|
||||||
|
apiversion: "v1beta1",
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "doesn't start with v",
|
||||||
|
apiversion: "beta1",
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "doesn't end with digit",
|
||||||
|
apiversion: "v1alpha",
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "doesn't have digit after v",
|
||||||
|
apiversion: "valpha1",
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "both alpha beta",
|
||||||
|
apiversion: "v1alpha1beta1",
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
actual := APIVersionRegexp.MatchString(tc.apiversion)
|
||||||
|
if actual != tc.expected {
|
||||||
|
t.Errorf("APIVersionRegexp expected %v, got %v", tc.expected, actual)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
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 testing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DefaultingTest run defaulting tests for given scheme
|
||||||
|
func DefaultingTest(t *testing.T, scheme *runtime.Scheme, codecs serializer.CodecFactory) {
|
||||||
|
tc := GetDefaultingTestCases(scheme)
|
||||||
|
RunTestsOnYAMLData(t, scheme, tc, codecs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDefaultingTestCases returns defaulting testcases for given scheme
|
||||||
|
func GetDefaultingTestCases(scheme *runtime.Scheme) []TestCase {
|
||||||
|
cases := []TestCase{}
|
||||||
|
for gvk := range scheme.AllKnownTypes() {
|
||||||
|
beforeDir := fmt.Sprintf("testdata/%s/before", gvk.Kind)
|
||||||
|
afterDir := fmt.Sprintf("testdata/%s/after", gvk.Kind)
|
||||||
|
filename := fmt.Sprintf("%s.yaml", gvk.Version)
|
||||||
|
|
||||||
|
cases = append(cases, TestCase{
|
||||||
|
name: fmt.Sprintf("default_%s", gvk.Version),
|
||||||
|
in: filepath.Join(beforeDir, filename),
|
||||||
|
inGVK: gvk,
|
||||||
|
out: filepath.Join(afterDir, filename),
|
||||||
|
outGV: gvk.GroupVersion(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return cases
|
||||||
|
}
|
96
staging/src/k8s.io/component-base/config/testing/helpers.go
Normal file
96
staging/src/k8s.io/component-base/config/testing/helpers.go
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
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 testing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RunTestsOnYAMLData decodes the yaml file from specified path, encodes the object and matches
|
||||||
|
// with expected yaml in specified path
|
||||||
|
func RunTestsOnYAMLData(t *testing.T, scheme *runtime.Scheme, tests []TestCase, codecs serializer.CodecFactory) {
|
||||||
|
for _, rt := range tests {
|
||||||
|
t.Run(rt.name, func(t *testing.T) {
|
||||||
|
obj, err := decodeTestData(rt.in, scheme, rt.inGVK, codecs)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
const mediaType = runtime.ContentTypeYAML
|
||||||
|
info, ok := runtime.SerializerInfoForMediaType(codecs.SupportedMediaTypes(), mediaType)
|
||||||
|
if !ok {
|
||||||
|
t.Errorf("unable to locate encoder -- %q is not a supported media type", mediaType)
|
||||||
|
}
|
||||||
|
|
||||||
|
encoder := codecs.EncoderForVersion(info.Serializer, rt.outGV)
|
||||||
|
|
||||||
|
actual, err := runtime.Encode(encoder, obj)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to encode object: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected, err := ioutil.ReadFile(rt.out)
|
||||||
|
if err != nil && !os.IsNotExist(err) {
|
||||||
|
t.Fatalf("couldn't read test data: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
needsUpdate := false
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
needsUpdate = true
|
||||||
|
t.Error("couldn't find test data")
|
||||||
|
} else {
|
||||||
|
if !bytes.Equal(expected, actual) {
|
||||||
|
t.Errorf("Output does not match expected, diff (- want, + got):\n\tin: %s\n\tout: %s\n\tgroupversion: %s\n\tdiff: \n%s\n",
|
||||||
|
rt.in, rt.out, rt.outGV.String(), cmp.Diff(string(expected), string(actual)))
|
||||||
|
needsUpdate = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if needsUpdate {
|
||||||
|
const updateEnvVar = "UPDATE_COMPONENTCONFIG_FIXTURE_DATA"
|
||||||
|
if os.Getenv(updateEnvVar) == "true" {
|
||||||
|
if err := ioutil.WriteFile(rt.out, actual, 0755); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Logf("wrote expected test data... verify, commit, and rerun tests")
|
||||||
|
} else {
|
||||||
|
t.Logf("if the diff is expected because of a new type or a new field, re-run with %s=true to update the compatibility data", updateEnvVar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeTestData(path string, scheme *runtime.Scheme, gvk schema.GroupVersionKind, codecs serializer.CodecFactory) (runtime.Object, error) {
|
||||||
|
content, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
obj, _, err := codecs.DecoderToVersion(codecs.UniversalDecoder(), gvk.GroupVersion()).Decode(content, &gvk, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return obj, nil
|
||||||
|
}
|
@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
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 testing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||||
|
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RoundTripTest runs roundtrip tests for given scheme
|
||||||
|
func RoundTripTest(t *testing.T, scheme *runtime.Scheme, codecs serializer.CodecFactory) {
|
||||||
|
tc := GetRoundtripTestCases(scheme, nil)
|
||||||
|
RunTestsOnYAMLData(t, scheme, tc, codecs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestCase defines a testcase for roundtrip and defaulting tests
|
||||||
|
type TestCase struct {
|
||||||
|
name, in, out string
|
||||||
|
inGVK schema.GroupVersionKind
|
||||||
|
outGV schema.GroupVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRoundtripTestCases returns the testcases for roundtrip testing for given scheme
|
||||||
|
func GetRoundtripTestCases(scheme *runtime.Scheme, disallowMarshalGroupVersions sets.String) []TestCase {
|
||||||
|
cases := []TestCase{}
|
||||||
|
versionsForKind := map[schema.GroupKind][]string{}
|
||||||
|
for gvk := range scheme.AllKnownTypes() {
|
||||||
|
versionsForKind[gvk.GroupKind()] = append(versionsForKind[gvk.GroupKind()], gvk.Version)
|
||||||
|
}
|
||||||
|
|
||||||
|
for gk, versions := range versionsForKind {
|
||||||
|
for _, vin := range versions {
|
||||||
|
if vin == runtime.APIVersionInternal {
|
||||||
|
continue // Don't try to deserialize the internal version
|
||||||
|
}
|
||||||
|
for _, vout := range versions {
|
||||||
|
inGVK := schema.GroupVersionKind{Group: gk.Group, Version: vin, Kind: gk.Kind}
|
||||||
|
marshalGV := schema.GroupVersion{Group: gk.Group, Version: vout}
|
||||||
|
if disallowMarshalGroupVersions.Has(marshalGV.String()) {
|
||||||
|
continue // Don't marshal a gv that is blacklisted
|
||||||
|
}
|
||||||
|
testdir := filepath.Join("testdata", gk.Kind, fmt.Sprintf("%sTo%s", vin, vout))
|
||||||
|
utilruntime.Must(filepath.Walk(testdir, func(path string, info os.FileInfo, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if info.IsDir() {
|
||||||
|
if info.Name() == fmt.Sprintf("%sTo%s", vin, vout) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return filepath.SkipDir
|
||||||
|
}
|
||||||
|
if filepath.Ext(info.Name()) != ".yaml" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
cases = append(cases, TestCase{
|
||||||
|
name: fmt.Sprintf("%sTo%s", vin, vout),
|
||||||
|
in: filepath.Join(testdir, info.Name()),
|
||||||
|
inGVK: inGVK,
|
||||||
|
out: filepath.Join(testdir, fmt.Sprintf("%s.after_roundtrip", info.Name())),
|
||||||
|
outGV: marshalGV,
|
||||||
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cases
|
||||||
|
}
|
@ -6,6 +6,7 @@ go 1.12
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/blang/semver v3.5.0+incompatible
|
github.com/blang/semver v3.5.0+incompatible
|
||||||
|
github.com/google/go-cmp v0.3.0
|
||||||
github.com/prometheus/client_golang v1.0.0
|
github.com/prometheus/client_golang v1.0.0
|
||||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90
|
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90
|
||||||
github.com/prometheus/common v0.4.1
|
github.com/prometheus/common v0.4.1
|
||||||
|
Loading…
Reference in New Issue
Block a user