From 39506d22193c05c2e76f7d1904eaf6b1ffdf13d3 Mon Sep 17 00:00:00 2001 From: Wojciech Tyczynski Date: Fri, 30 Dec 2016 09:28:28 +0100 Subject: [PATCH 1/2] Fix incorrect testapi groups --- pkg/api/testapi/testapi.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/api/testapi/testapi.go b/pkg/api/testapi/testapi.go index 0772b18c33a..6abbd527a70 100644 --- a/pkg/api/testapi/testapi.go +++ b/pkg/api/testapi/testapi.go @@ -200,8 +200,8 @@ func init() { externalGroupVersion := schema.GroupVersion{Group: apps.GroupName, Version: api.Registry.GroupOrDie(apps.GroupName).GroupVersion.Version} Groups[apps.GroupName] = TestGroup{ externalGroupVersion: externalGroupVersion, - internalGroupVersion: extensions.SchemeGroupVersion, - internalTypes: api.Scheme.KnownTypes(extensions.SchemeGroupVersion), + internalGroupVersion: apps.SchemeGroupVersion, + internalTypes: api.Scheme.KnownTypes(apps.SchemeGroupVersion), externalTypes: api.Scheme.KnownTypes(externalGroupVersion), } } From 91f8dcf44a70231c3527f46683b47752bc7d20d0 Mon Sep 17 00:00:00 2001 From: Wojciech Tyczynski Date: Thu, 29 Dec 2016 10:07:39 +0100 Subject: [PATCH 2/2] Test runtime.Object <-> map[string]interface{} conversion --- pkg/api/BUILD | 2 + pkg/api/serialization_test.go | 2 +- pkg/api/unstructured_test.go | 180 ++++++++++++++++++++++++++++++++++ 3 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 pkg/api/unstructured_test.go diff --git a/pkg/api/BUILD b/pkg/api/BUILD index 85ee59f3f59..4533230827b 100644 --- a/pkg/api/BUILD +++ b/pkg/api/BUILD @@ -74,6 +74,7 @@ go_test( "meta_test.go", "serialization_proto_test.go", "serialization_test.go", + "unstructured_test.go", ], tags = ["automanaged"], deps = [ @@ -99,6 +100,7 @@ go_test( "//vendor:k8s.io/apimachinery/pkg/runtime/serializer/streaming", "//vendor:k8s.io/apimachinery/pkg/types", "//vendor:k8s.io/apimachinery/pkg/util/diff", + "//vendor:k8s.io/apimachinery/pkg/util/json", "//vendor:k8s.io/apimachinery/pkg/util/sets", "//vendor:k8s.io/apimachinery/pkg/watch", ], diff --git a/pkg/api/serialization_test.go b/pkg/api/serialization_test.go index e2660cfb1b0..f209e016ce5 100644 --- a/pkg/api/serialization_test.go +++ b/pkg/api/serialization_test.go @@ -518,7 +518,7 @@ const benchmarkSeed = 100 func benchmarkItems() []v1.Pod { apiObjectFuzzer := apitesting.FuzzerFor(nil, api.SchemeGroupVersion, rand.NewSource(benchmarkSeed)) - items := make([]v1.Pod, 2) + items := make([]v1.Pod, 10) for i := range items { var pod api.Pod apiObjectFuzzer.Fuzz(&pod) diff --git a/pkg/api/unstructured_test.go b/pkg/api/unstructured_test.go new file mode 100644 index 00000000000..17ea662183b --- /dev/null +++ b/pkg/api/unstructured_test.go @@ -0,0 +1,180 @@ +/* +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 api_test + +import ( + "math/rand" + "reflect" + "testing" + + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/testapi" + apitesting "k8s.io/kubernetes/pkg/api/testing" + "k8s.io/kubernetes/pkg/api/v1" + + "k8s.io/apimachinery/pkg/util/diff" + "k8s.io/apimachinery/pkg/util/json" + + "github.com/google/gofuzz" +) + +func doRoundTrip(t *testing.T, group testapi.TestGroup, kind string) { + // We do fuzzing on the internal version of the object, and only then + // convert to the external version. This is because custom fuzzing + // function are only supported for internal objects. + internalObj, err := api.Scheme.New(group.InternalGroupVersion().WithKind(kind)) + if err != nil { + t.Fatalf("Couldn't create internal object %v: %v", kind, err) + } + seed := rand.Int63() + apitesting.FuzzerFor(t, group.InternalGroupVersion(), rand.NewSource(seed)). + // We are explicitly overwriting custom fuzzing functions, to ensure + // that InitContainers and their statuses are not generated. This is + // because in thise test we are simply doing json operations, in which + // those disappear. + Funcs( + func(s *api.PodSpec, c fuzz.Continue) { + c.FuzzNoCustom(s) + s.InitContainers = nil + }, + func(s *api.PodStatus, c fuzz.Continue) { + c.FuzzNoCustom(s) + s.InitContainerStatuses = nil + }, + ).Fuzz(internalObj) + + item, err := api.Scheme.New(group.GroupVersion().WithKind(kind)) + if err != nil { + t.Fatalf("Couldn't create external object %v: %v", kind, err) + } + if err := api.Scheme.Convert(internalObj, item, nil); err != nil { + t.Fatalf("Conversion for %v failed: %v", kind, err) + } + + data, err := json.Marshal(item) + if err != nil { + t.Errorf("Error when marshaling object: %v", err) + return + } + unstr := make(map[string]interface{}) + err = json.Unmarshal(data, &unstr) + if err != nil { + t.Errorf("Error when unmarshaling to unstructured: %v", err) + return + } + + data, err = json.Marshal(unstr) + if err != nil { + t.Errorf("Error when marshaling unstructured: %v", err) + return + } + unmarshalledObj := reflect.New(reflect.TypeOf(item).Elem()).Interface() + err = json.Unmarshal(data, &unmarshalledObj) + if err != nil { + t.Errorf("Error when unmarshaling to object: %v", err) + return + } + if !api.Semantic.DeepEqual(item, unmarshalledObj) { + t.Errorf("Object changed during JSON operations, diff: %v", diff.ObjectReflectDiff(item, unmarshalledObj)) + return + } + + // TODO; Enable the following part of test once to/from unstructured + // format conversions are implemented. + /* + newUnstr := make(map[string]interface{}) + err = unstructured.NewConverter().ToUnstructured(item, &newUnstr) + if err != nil { + t.Errorf("ToUnstructured failed: %v", err) + return + } + + newObj := reflect.New(reflect.TypeOf(item).Elem()).Interface().(runtime.Object) + err = unstructured.NewConverter().FromUnstructured(newUnstr, newObj) + if err != nil { + t.Errorf("FromUnstructured failed: %v", err) + return + } + + if !api.Semantic.DeepEqual(item, newObj) { + t.Errorf("Object changed, diff: %v", diff.ObjectReflectDiff(item, newObj)) + } + */ +} + +func TestRoundTrip(t *testing.T) { + for groupKey, group := range testapi.Groups { + for kind := range group.ExternalTypes() { + if nonRoundTrippableTypes.Has(kind) { + continue + } + t.Logf("Testing: %v in %v", kind, groupKey) + for i := 0; i < 50; i++ { + doRoundTrip(t, group, kind) + if t.Failed() { + break + } + } + } + } +} + +// TODO; Enable the following benchmark once to/from unstructured +// format conversions are implemented. +/* +func BenchmarkToFromUnstructured(b *testing.B) { + items := benchmarkItems() + size := len(items) + b.ResetTimer() + for i := 0; i < b.N; i++ { + unstr := map[string]interface{}{} + if err := unstructured.NewConverter().ToUnstructured(&items[i%size], &unstr); err != nil { + b.Fatalf("unexpected error: %v", err) + } + obj := v1.Pod{} + if err := unstructured.NewConverter().FromUnstructured(unstr, &obj); err != nil { + b.Fatalf("unexpected error: %v", err) + } + } + b.StopTimer() +} +*/ + +func BenchmarkToFromUnstructuredViaJSON(b *testing.B) { + items := benchmarkItems() + size := len(items) + b.ResetTimer() + for i := 0; i < b.N; i++ { + data, err := json.Marshal(&items[i%size]) + if err != nil { + b.Fatalf("unexpected error: %v", err) + } + unstr := map[string]interface{}{} + if err := json.Unmarshal(data, &unstr); err != nil { + b.Fatalf("unexpected error: %v", err) + } + data, err = json.Marshal(unstr) + if err != nil { + b.Fatalf("unexpected error: %v", err) + } + obj := v1.Pod{} + if err := json.Unmarshal(data, &obj); err != nil { + b.Fatalf("unexpected error: %v", err) + } + } + b.StopTimer() +}