Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not serialize internal types in ComponentConfig tests #86144

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view

This file was deleted.

Empty file.
@@ -0,0 +1,2 @@
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
File renamed without changes.

This file was deleted.

2 changes: 1 addition & 1 deletion staging/src/k8s.io/component-base/config/testing/BUILD
Expand Up @@ -13,11 +13,11 @@ go_library(
visibility = ["//visibility:public"],
deps = [
"//staging/src/k8s.io/apimachinery/pkg/api/apitesting/naming:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/equality: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",
],
Expand Down
17 changes: 12 additions & 5 deletions staging/src/k8s.io/component-base/config/testing/defaulting.go
Expand Up @@ -27,24 +27,31 @@ import (

// 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)
cases := GetDefaultingTestCases(t, scheme, codecs)
RunTestsOnYAMLData(t, cases)
}

// GetDefaultingTestCases returns defaulting testcases for given scheme
func GetDefaultingTestCases(scheme *runtime.Scheme) []TestCase {
func GetDefaultingTestCases(t *testing.T, scheme *runtime.Scheme, codecs serializer.CodecFactory) []TestCase {
cases := []TestCase{}
for gvk := range scheme.AllKnownTypes() {
if gvk.Version == runtime.APIVersionInternal {
continue
}
beforeDir := fmt.Sprintf("testdata/%s/before", gvk.Kind)
afterDir := fmt.Sprintf("testdata/%s/after", gvk.Kind)
filename := fmt.Sprintf("%s.yaml", gvk.Version)

codec, err := getCodecForGV(codecs, gvk.GroupVersion())
if err != nil {
t.Fatal(err)
}

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(),
codec: codec,
})
}
return cases
Expand Down
115 changes: 62 additions & 53 deletions staging/src/k8s.io/component-base/config/testing/helpers.go
Expand Up @@ -18,6 +18,7 @@ package testing

import (
"bytes"
"fmt"
"io/ioutil"
"os"
"testing"
Expand All @@ -28,69 +29,77 @@ import (
"k8s.io/apimachinery/pkg/runtime/serializer"
)

// TestCase defines a testcase for roundtrip and defaulting tests
type TestCase struct {
name, in, out string
codec runtime.Codec
}

// 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 RunTestsOnYAMLData(t *testing.T, tests []TestCase) {
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
roundTrip(t, tc)
})
}
}

func decodeTestData(path string, scheme *runtime.Scheme, gvk schema.GroupVersionKind, codecs serializer.CodecFactory) (runtime.Object, error) {
func decodeYAML(t *testing.T, path string, codec runtime.Codec) runtime.Object {
content, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
t.Fatal(err)
}

obj, _, err := codecs.DecoderToVersion(codecs.UniversalDecoder(), gvk.GroupVersion()).Decode(content, &gvk, nil)
// decode to internal type
object, err := runtime.Decode(codec, content)
if err != nil {
return nil, err
t.Fatal(err)
}

return object
}

func getCodecForGV(codecs serializer.CodecFactory, gv schema.GroupVersion) (runtime.Codec, error) {
mediaType := runtime.ContentTypeYAML
serializerInfo, ok := runtime.SerializerInfoForMediaType(codecs.SupportedMediaTypes(), mediaType)
if !ok {
return nil, fmt.Errorf("unable to locate encoder -- %q is not a supported media type", mediaType)
}
codec := codecs.CodecForVersions(serializerInfo.Serializer, codecs.UniversalDeserializer(), gv, nil)
return codec, nil
}

func matchOutputFile(t *testing.T, actual []byte, expectedFilePath string) {
expected, err := ioutil.ReadFile(expectedFilePath)
if err != nil && !os.IsNotExist(err) {
t.Fatalf("couldn't read test data: %v", err)
}

needsUpdate := false
const updateEnvVar = "UPDATE_COMPONENTCONFIG_FIXTURE_DATA"

if os.IsNotExist(err) {
needsUpdate = true
if os.Getenv(updateEnvVar) != "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%s\n",
cmp.Diff(string(expected), string(actual)))
needsUpdate = true
}
}
if needsUpdate {
if os.Getenv(updateEnvVar) == "true" {
if err := ioutil.WriteFile(expectedFilePath, actual, 0644); err != nil {
t.Fatal(err)
}
t.Error("wrote expected test data... verify, commit, and rerun tests")
} else {
t.Errorf("if the diff is expected because of a new type or a new field, "+
"re-run with %s=true to update the compatibility data or generate missing files", updateEnvVar)
}
}
return obj, nil
}