diff --git a/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/customresource_handler.go b/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/customresource_handler.go index c756ec46610..8f38b17643a 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/customresource_handler.go +++ b/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/customresource_handler.go @@ -28,10 +28,12 @@ import ( "github.com/go-openapi/spec" "github.com/go-openapi/strfmt" "github.com/go-openapi/validate" + "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions" "k8s.io/apiextensions-apiserver/pkg/apiserver/conversion" structuralschema "k8s.io/apiextensions-apiserver/pkg/apiserver/schema" structuraldefaulting "k8s.io/apiextensions-apiserver/pkg/apiserver/schema/defaulting" + schemaobjectmeta "k8s.io/apiextensions-apiserver/pkg/apiserver/schema/objectmeta" structuralpruning "k8s.io/apiextensions-apiserver/pkg/apiserver/schema/pruning" apiservervalidation "k8s.io/apiextensions-apiserver/pkg/apiserver/validation" informers "k8s.io/apiextensions-apiserver/pkg/client/informers/internalversion/apiextensions/internalversion" @@ -1022,7 +1024,7 @@ func (v *unstructuredSchemaCoercer) apply(u *unstructured.Unstructured) error { if err != nil { return err } - objectMeta, foundObjectMeta, err := getObjectMeta(u, v.dropInvalidMetadata) + objectMeta, foundObjectMeta, err := schemaobjectmeta.GetObjectMeta(u, v.dropInvalidMetadata) if err != nil { return err } @@ -1044,72 +1046,10 @@ func (v *unstructuredSchemaCoercer) apply(u *unstructured.Unstructured) error { u.SetAPIVersion(apiVersion) } if foundObjectMeta { - if err := setObjectMeta(u, objectMeta); err != nil { + if err := schemaobjectmeta.SetObjectMeta(u, objectMeta); err != nil { return err } } return nil } - -var encodingjson = json.CaseSensitiveJsonIterator() - -func getObjectMeta(u *unstructured.Unstructured, dropMalformedFields bool) (*metav1.ObjectMeta, bool, error) { - metadata, found := u.UnstructuredContent()["metadata"] - if !found { - return nil, false, nil - } - - // round-trip through JSON first, hoping that unmarshaling just works - objectMeta := &metav1.ObjectMeta{} - metadataBytes, err := encodingjson.Marshal(metadata) - if err != nil { - return nil, false, err - } - if err = encodingjson.Unmarshal(metadataBytes, objectMeta); err == nil { - // if successful, return - return objectMeta, true, nil - } - if !dropMalformedFields { - // if we're not trying to drop malformed fields, return the error - return nil, true, err - } - - metadataMap, ok := metadata.(map[string]interface{}) - if !ok { - return nil, false, fmt.Errorf("invalid metadata: expected object, got %T", metadata) - } - - // Go field by field accumulating into the metadata object. - // This takes advantage of the fact that you can repeatedly unmarshal individual fields into a single struct, - // each iteration preserving the old key-values. - accumulatedObjectMeta := &metav1.ObjectMeta{} - testObjectMeta := &metav1.ObjectMeta{} - for k, v := range metadataMap { - // serialize a single field - if singleFieldBytes, err := encodingjson.Marshal(map[string]interface{}{k: v}); err == nil { - // do a test unmarshal - if encodingjson.Unmarshal(singleFieldBytes, testObjectMeta) == nil { - // if that succeeds, unmarshal for real - encodingjson.Unmarshal(singleFieldBytes, accumulatedObjectMeta) - } - } - } - - return accumulatedObjectMeta, true, nil -} - -func setObjectMeta(u *unstructured.Unstructured, objectMeta *metav1.ObjectMeta) error { - if objectMeta == nil { - unstructured.RemoveNestedField(u.UnstructuredContent(), "metadata") - return nil - } - - metadata, err := runtime.DefaultUnstructuredConverter.ToUnstructured(objectMeta) - if err != nil { - return err - } - - u.UnstructuredContent()["metadata"] = metadata - return nil -} diff --git a/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/customresource_handler_test.go b/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/customresource_handler_test.go index 62ed7cca25d..550a52a0f90 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/customresource_handler_test.go +++ b/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/customresource_handler_test.go @@ -17,24 +17,11 @@ limitations under the License. package apiserver import ( - "math/rand" - "reflect" "testing" - corev1 "k8s.io/api/core/v1" "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions" "k8s.io/apiextensions-apiserver/pkg/apiserver/conversion" - "k8s.io/apimachinery/pkg/api/apitesting/fuzzer" - "k8s.io/apimachinery/pkg/api/equality" - metafuzzer "k8s.io/apimachinery/pkg/apis/meta/fuzzer" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/runtime/serializer" - "k8s.io/apimachinery/pkg/runtime/serializer/json" - "k8s.io/apimachinery/pkg/util/diff" - clientgoscheme "k8s.io/client-go/kubernetes/scheme" ) func TestConvertFieldLabel(t *testing.T) { @@ -118,202 +105,3 @@ func TestConvertFieldLabel(t *testing.T) { }) } } - -func TestRoundtripObjectMeta(t *testing.T) { - scheme := runtime.NewScheme() - codecs := serializer.NewCodecFactory(scheme) - codec := json.NewSerializer(json.DefaultMetaFactory, scheme, scheme, false) - seed := rand.Int63() - fuzzer := fuzzer.FuzzerFor(metafuzzer.Funcs, rand.NewSource(seed), codecs) - - N := 1000 - for i := 0; i < N; i++ { - u := &unstructured.Unstructured{Object: map[string]interface{}{}} - original := &metav1.ObjectMeta{} - fuzzer.Fuzz(original) - if err := setObjectMeta(u, original); err != nil { - t.Fatalf("unexpected error setting ObjectMeta: %v", err) - } - o, _, err := getObjectMeta(u, false) - if err != nil { - t.Fatalf("unexpected error getting the Objectmeta: %v", err) - } - - if !equality.Semantic.DeepEqual(original, o) { - t.Errorf("diff: %v\nCodec: %#v", diff.ObjectReflectDiff(original, o), codec) - } - } -} - -// TestMalformedObjectMetaFields sets a number of different random values and types for all -// metadata fields. If json.Unmarshal accepts them, compare that getObjectMeta -// gives the same result. Otherwise, drop malformed fields. -func TestMalformedObjectMetaFields(t *testing.T) { - fuzzer := fuzzer.FuzzerFor(metafuzzer.Funcs, rand.NewSource(rand.Int63()), serializer.NewCodecFactory(runtime.NewScheme())) - spuriousValues := func() []interface{} { - return []interface{}{ - // primitives - nil, - int64(1), - float64(1.5), - true, - "a", - // well-formed complex values - []interface{}{"a", "b"}, - map[string]interface{}{"a": "1", "b": "2"}, - []interface{}{int64(1), int64(2)}, - []interface{}{float64(1.5), float64(2.5)}, - // known things json decoding tolerates - map[string]interface{}{"a": "1", "b": nil}, - // malformed things - map[string]interface{}{"a": "1", "b": []interface{}{"nested"}}, - []interface{}{"a", int64(1), float64(1.5), true, []interface{}{"nested"}}, - } - } - N := 100 - for i := 0; i < N; i++ { - fuzzedObjectMeta := &metav1.ObjectMeta{} - fuzzer.Fuzz(fuzzedObjectMeta) - goodMetaMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(fuzzedObjectMeta.DeepCopy()) - if err != nil { - t.Fatal(err) - } - for _, pth := range jsonPaths(nil, goodMetaMap) { - for _, v := range spuriousValues() { - // skip values of same type, because they can only cause decoding errors further insides - orig, err := JsonPathValue(goodMetaMap, pth, 0) - if err != nil { - t.Fatalf("unexpected to not find something at %v: %v", pth, err) - } - if reflect.TypeOf(v) == reflect.TypeOf(orig) { - continue - } - - // make a spurious map - spuriousMetaMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(fuzzedObjectMeta.DeepCopy()) - if err != nil { - t.Fatal(err) - } - if err := SetJsonPath(spuriousMetaMap, pth, 0, v); err != nil { - t.Fatal(err) - } - - // See if it can unmarshal to object meta - spuriousJSON, err := encodingjson.Marshal(spuriousMetaMap) - if err != nil { - t.Fatalf("error on %v=%#v: %v", pth, v, err) - } - expectedObjectMeta := &metav1.ObjectMeta{} - if err := encodingjson.Unmarshal(spuriousJSON, expectedObjectMeta); err != nil { - // if standard json unmarshal would fail decoding this field, drop the field entirely - truncatedMetaMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(fuzzedObjectMeta.DeepCopy()) - if err != nil { - t.Fatal(err) - } - - // we expect this logic for the different fields: - switch { - default: - // delete complete top-level field by default - DeleteJsonPath(truncatedMetaMap, pth[:1], 0) - } - - truncatedJSON, err := encodingjson.Marshal(truncatedMetaMap) - if err != nil { - t.Fatalf("error on %v=%#v: %v", pth, v, err) - } - expectedObjectMeta = &metav1.ObjectMeta{} - if err := encodingjson.Unmarshal(truncatedJSON, expectedObjectMeta); err != nil { - t.Fatalf("error on %v=%#v: %v", pth, v, err) - } - } - - // make sure dropInvalidTypedFields+getObjectMeta matches what we expect - u := &unstructured.Unstructured{Object: map[string]interface{}{"metadata": spuriousMetaMap}} - actualObjectMeta, _, err := getObjectMeta(u, true) - if err != nil { - t.Errorf("got unexpected error after dropping invalid typed fields on %v=%#v: %v", pth, v, err) - continue - } - - if !equality.Semantic.DeepEqual(expectedObjectMeta, actualObjectMeta) { - t.Errorf("%v=%#v, diff: %v\n", pth, v, diff.ObjectReflectDiff(expectedObjectMeta, actualObjectMeta)) - t.Errorf("expectedObjectMeta %#v", expectedObjectMeta) - } - } - } - } -} - -func TestGetObjectMetaNils(t *testing.T) { - u := &unstructured.Unstructured{ - Object: map[string]interface{}{ - "kind": "Pod", - "apiVersion": "v1", - "metadata": map[string]interface{}{ - "generateName": nil, - "labels": map[string]interface{}{ - "foo": nil, - }, - }, - }, - } - - o, _, err := getObjectMeta(u, true) - if err != nil { - t.Fatal(err) - } - if o.GenerateName != "" { - t.Errorf("expected null json value to be read as \"\" string, but got: %q", o.GenerateName) - } - if got, expected := o.Labels, map[string]string{"foo": ""}; !reflect.DeepEqual(got, expected) { - t.Errorf("unexpected labels, expected=%#v, got=%#v", expected, got) - } - - // double check this what the kube JSON decode is doing - bs, _ := encodingjson.Marshal(u.UnstructuredContent()) - kubeObj, _, err := clientgoscheme.Codecs.UniversalDecoder(corev1.SchemeGroupVersion).Decode(bs, nil, nil) - if err != nil { - t.Fatal(err) - } - pod, ok := kubeObj.(*corev1.Pod) - if !ok { - t.Fatalf("expected v1 Pod, got: %T", pod) - } - if got, expected := o.GenerateName, pod.ObjectMeta.GenerateName; got != expected { - t.Errorf("expected generatedName to be %q, got %q", expected, got) - } - if got, expected := o.Labels, pod.ObjectMeta.Labels; !reflect.DeepEqual(got, expected) { - t.Errorf("expected labels to be %v, got %v", expected, got) - } -} - -func TestGetObjectMeta(t *testing.T) { - for i := 0; i < 100; i++ { - u := &unstructured.Unstructured{Object: map[string]interface{}{ - "metadata": map[string]interface{}{ - "name": "good", - "Name": "bad1", - "nAme": "bad2", - "naMe": "bad3", - "namE": "bad4", - - "namespace": "good", - "Namespace": "bad1", - "nAmespace": "bad2", - "naMespace": "bad3", - "namEspace": "bad4", - - "creationTimestamp": "a", - }, - }} - - meta, _, err := getObjectMeta(u, true) - if err != nil { - t.Fatal(err) - } - if meta.Name != "good" || meta.Namespace != "good" { - t.Fatalf("got %#v", meta) - } - } -} diff --git a/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/objectmeta/coerce.go b/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/objectmeta/coerce.go new file mode 100644 index 00000000000..6a2932dc325 --- /dev/null +++ b/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/objectmeta/coerce.go @@ -0,0 +1,88 @@ +/* +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 objectmeta + +import ( + "fmt" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/serializer/json" +) + +var encodingjson = json.CaseSensitiveJsonIterator() + +func GetObjectMeta(u *unstructured.Unstructured, dropMalformedFields bool) (*metav1.ObjectMeta, bool, error) { + metadata, found := u.UnstructuredContent()["metadata"] + if !found { + return nil, false, nil + } + + // round-trip through JSON first, hoping that unmarshaling just works + objectMeta := &metav1.ObjectMeta{} + metadataBytes, err := encodingjson.Marshal(metadata) + if err != nil { + return nil, false, err + } + if err = encodingjson.Unmarshal(metadataBytes, objectMeta); err == nil { + // if successful, return + return objectMeta, true, nil + } + if !dropMalformedFields { + // if we're not trying to drop malformed fields, return the error + return nil, true, err + } + + metadataMap, ok := metadata.(map[string]interface{}) + if !ok { + return nil, false, fmt.Errorf("invalid metadata: expected object, got %T", metadata) + } + + // Go field by field accumulating into the metadata object. + // This takes advantage of the fact that you can repeatedly unmarshal individual fields into a single struct, + // each iteration preserving the old key-values. + accumulatedObjectMeta := &metav1.ObjectMeta{} + testObjectMeta := &metav1.ObjectMeta{} + for k, v := range metadataMap { + // serialize a single field + if singleFieldBytes, err := encodingjson.Marshal(map[string]interface{}{k: v}); err == nil { + // do a test unmarshal + if encodingjson.Unmarshal(singleFieldBytes, testObjectMeta) == nil { + // if that succeeds, unmarshal for real + encodingjson.Unmarshal(singleFieldBytes, accumulatedObjectMeta) + } + } + } + + return accumulatedObjectMeta, true, nil +} + +func SetObjectMeta(u *unstructured.Unstructured, objectMeta *metav1.ObjectMeta) error { + if objectMeta == nil { + unstructured.RemoveNestedField(u.UnstructuredContent(), "metadata") + return nil + } + + metadata, err := runtime.DefaultUnstructuredConverter.ToUnstructured(objectMeta) + if err != nil { + return err + } + + u.UnstructuredContent()["metadata"] = metadata + return nil +} diff --git a/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/objectmeta/coerce_test.go b/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/objectmeta/coerce_test.go new file mode 100644 index 00000000000..41bb2caabdd --- /dev/null +++ b/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/objectmeta/coerce_test.go @@ -0,0 +1,234 @@ +/* +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 objectmeta + +import ( + "math/rand" + "reflect" + "testing" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/apitesting/fuzzer" + "k8s.io/apimachinery/pkg/api/equality" + metafuzzer "k8s.io/apimachinery/pkg/apis/meta/fuzzer" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/apimachinery/pkg/runtime/serializer/json" + "k8s.io/apimachinery/pkg/util/diff" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" +) + +func TestRoundtripObjectMeta(t *testing.T) { + scheme := runtime.NewScheme() + codecs := serializer.NewCodecFactory(scheme) + codec := json.NewSerializer(json.DefaultMetaFactory, scheme, scheme, false) + seed := rand.Int63() + fuzzer := fuzzer.FuzzerFor(metafuzzer.Funcs, rand.NewSource(seed), codecs) + + N := 1000 + for i := 0; i < N; i++ { + u := &unstructured.Unstructured{Object: map[string]interface{}{}} + original := &metav1.ObjectMeta{} + fuzzer.Fuzz(original) + if err := SetObjectMeta(u, original); err != nil { + t.Fatalf("unexpected error setting ObjectMeta: %v", err) + } + o, _, err := GetObjectMeta(u, false) + if err != nil { + t.Fatalf("unexpected error getting the Objectmeta: %v", err) + } + + if !equality.Semantic.DeepEqual(original, o) { + t.Errorf("diff: %v\nCodec: %#v", diff.ObjectReflectDiff(original, o), codec) + } + } +} + +// TestMalformedObjectMetaFields sets a number of different random values and types for all +// metadata fields. If json.Unmarshal accepts them, compare that getObjectMeta +// gives the same result. Otherwise, drop malformed fields. +func TestMalformedObjectMetaFields(t *testing.T) { + fuzzer := fuzzer.FuzzerFor(metafuzzer.Funcs, rand.NewSource(rand.Int63()), serializer.NewCodecFactory(runtime.NewScheme())) + spuriousValues := func() []interface{} { + return []interface{}{ + // primitives + nil, + int64(1), + float64(1.5), + true, + "a", + // well-formed complex values + []interface{}{"a", "b"}, + map[string]interface{}{"a": "1", "b": "2"}, + []interface{}{int64(1), int64(2)}, + []interface{}{float64(1.5), float64(2.5)}, + // known things json decoding tolerates + map[string]interface{}{"a": "1", "b": nil}, + // malformed things + map[string]interface{}{"a": "1", "b": []interface{}{"nested"}}, + []interface{}{"a", int64(1), float64(1.5), true, []interface{}{"nested"}}, + } + } + N := 100 + for i := 0; i < N; i++ { + fuzzedObjectMeta := &metav1.ObjectMeta{} + fuzzer.Fuzz(fuzzedObjectMeta) + goodMetaMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(fuzzedObjectMeta.DeepCopy()) + if err != nil { + t.Fatal(err) + } + for _, pth := range jsonPaths(nil, goodMetaMap) { + for _, v := range spuriousValues() { + // skip values of same type, because they can only cause decoding errors further insides + orig, err := JsonPathValue(goodMetaMap, pth, 0) + if err != nil { + t.Fatalf("unexpected to not find something at %v: %v", pth, err) + } + if reflect.TypeOf(v) == reflect.TypeOf(orig) { + continue + } + + // make a spurious map + spuriousMetaMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(fuzzedObjectMeta.DeepCopy()) + if err != nil { + t.Fatal(err) + } + if err := SetJsonPath(spuriousMetaMap, pth, 0, v); err != nil { + t.Fatal(err) + } + + // See if it can unmarshal to object meta + spuriousJSON, err := encodingjson.Marshal(spuriousMetaMap) + if err != nil { + t.Fatalf("error on %v=%#v: %v", pth, v, err) + } + expectedObjectMeta := &metav1.ObjectMeta{} + if err := encodingjson.Unmarshal(spuriousJSON, expectedObjectMeta); err != nil { + // if standard json unmarshal would fail decoding this field, drop the field entirely + truncatedMetaMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(fuzzedObjectMeta.DeepCopy()) + if err != nil { + t.Fatal(err) + } + + // we expect this logic for the different fields: + switch { + default: + // delete complete top-level field by default + DeleteJsonPath(truncatedMetaMap, pth[:1], 0) + } + + truncatedJSON, err := encodingjson.Marshal(truncatedMetaMap) + if err != nil { + t.Fatalf("error on %v=%#v: %v", pth, v, err) + } + expectedObjectMeta = &metav1.ObjectMeta{} + if err := encodingjson.Unmarshal(truncatedJSON, expectedObjectMeta); err != nil { + t.Fatalf("error on %v=%#v: %v", pth, v, err) + } + } + + // make sure dropInvalidTypedFields+getObjectMeta matches what we expect + u := &unstructured.Unstructured{Object: map[string]interface{}{"metadata": spuriousMetaMap}} + actualObjectMeta, _, err := GetObjectMeta(u, true) + if err != nil { + t.Errorf("got unexpected error after dropping invalid typed fields on %v=%#v: %v", pth, v, err) + continue + } + + if !equality.Semantic.DeepEqual(expectedObjectMeta, actualObjectMeta) { + t.Errorf("%v=%#v, diff: %v\n", pth, v, diff.ObjectReflectDiff(expectedObjectMeta, actualObjectMeta)) + t.Errorf("expectedObjectMeta %#v", expectedObjectMeta) + } + } + } + } +} + +func TestGetObjectMetaNils(t *testing.T) { + u := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "kind": "Pod", + "apiVersion": "v1", + "metadata": map[string]interface{}{ + "generateName": nil, + "labels": map[string]interface{}{ + "foo": nil, + }, + }, + }, + } + + o, _, err := GetObjectMeta(u, true) + if err != nil { + t.Fatal(err) + } + if o.GenerateName != "" { + t.Errorf("expected null json value to be read as \"\" string, but got: %q", o.GenerateName) + } + if got, expected := o.Labels, map[string]string{"foo": ""}; !reflect.DeepEqual(got, expected) { + t.Errorf("unexpected labels, expected=%#v, got=%#v", expected, got) + } + + // double check this what the kube JSON decode is doing + bs, _ := encodingjson.Marshal(u.UnstructuredContent()) + kubeObj, _, err := clientgoscheme.Codecs.UniversalDecoder(corev1.SchemeGroupVersion).Decode(bs, nil, nil) + if err != nil { + t.Fatal(err) + } + pod, ok := kubeObj.(*corev1.Pod) + if !ok { + t.Fatalf("expected v1 Pod, got: %T", pod) + } + if got, expected := o.GenerateName, pod.ObjectMeta.GenerateName; got != expected { + t.Errorf("expected generatedName to be %q, got %q", expected, got) + } + if got, expected := o.Labels, pod.ObjectMeta.Labels; !reflect.DeepEqual(got, expected) { + t.Errorf("expected labels to be %v, got %v", expected, got) + } +} + +func TestGetObjectMeta(t *testing.T) { + for i := 0; i < 100; i++ { + u := &unstructured.Unstructured{Object: map[string]interface{}{ + "metadata": map[string]interface{}{ + "name": "good", + "Name": "bad1", + "nAme": "bad2", + "naMe": "bad3", + "namE": "bad4", + + "namespace": "good", + "Namespace": "bad1", + "nAmespace": "bad2", + "naMespace": "bad3", + "namEspace": "bad4", + + "creationTimestamp": "a", + }, + }} + + meta, _, err := GetObjectMeta(u, true) + if err != nil { + t.Fatal(err) + } + if meta.Name != "good" || meta.Namespace != "good" { + t.Fatalf("got %#v", meta) + } + } +} diff --git a/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/jsonpath_test.go b/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/objectmeta/jsonpath_test.go similarity index 99% rename from staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/jsonpath_test.go rename to staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/objectmeta/jsonpath_test.go index 8d9bb24f877..f6aa74743de 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/jsonpath_test.go +++ b/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/objectmeta/jsonpath_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package apiserver +package objectmeta import ( "bytes"