func TestUnversionedTypes(t *testing.T) { internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal} externalGV := schema.GroupVersion{Group: "test.group", Version: "testExternal"} otherGV := schema.GroupVersion{Group: "group", Version: "other"} scheme := runtime.NewScheme() scheme.AddUnversionedTypes(externalGV, &InternalSimple{}) scheme.AddKnownTypeWithName(internalGV.WithKind("Simple"), &InternalSimple{}) scheme.AddKnownTypeWithName(externalGV.WithKind("Simple"), &ExternalSimple{}) scheme.AddKnownTypeWithName(otherGV.WithKind("Simple"), &ExternalSimple{}) codec := serializer.NewCodecFactory(scheme).LegacyCodec(externalGV) if unv, ok := scheme.IsUnversioned(&InternalSimple{}); !unv || !ok { t.Fatalf("type not unversioned and in scheme: %t %t", unv, ok) } kinds, _, err := scheme.ObjectKinds(&InternalSimple{}) if err != nil { t.Fatal(err) } kind := kinds[0] if kind != externalGV.WithKind("InternalSimple") { t.Fatalf("unexpected: %#v", kind) } test := &InternalSimple{ TestString: "I'm the same", } obj := runtime.Object(test) data, err := runtime.Encode(codec, obj) if err != nil { t.Fatal(err) } obj2, gvk, err := codec.Decode(data, nil, nil) if err != nil { t.Fatal(err) } if _, ok := obj2.(*InternalSimple); !ok { t.Fatalf("Got wrong type") } if !reflect.DeepEqual(obj2, test) { t.Errorf("Expected:\n %#v,\n Got:\n %#v", test, obj2) } // object is serialized as an unversioned object (in the group and version it was defined in) if !reflect.DeepEqual(gvk, &schema.GroupVersionKind{Group: "test.group", Version: "testExternal", Kind: "InternalSimple"}) { t.Errorf("unexpected gvk returned by decode: %#v", gvk) } // when serialized to a different group, the object is kept in its preferred name codec = serializer.NewCodecFactory(scheme).LegacyCodec(otherGV) data, err = runtime.Encode(codec, obj) if err != nil { t.Fatal(err) } if string(data) != `{"apiVersion":"test.group/testExternal","kind":"InternalSimple","testString":"I'm the same"}`+"\n" { t.Errorf("unexpected data: %s", data) } }
func TestExternalToInternalMapping(t *testing.T) { internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal} externalGV := schema.GroupVersion{Group: "test.group", Version: "testExternal"} scheme := runtime.NewScheme() scheme.AddKnownTypeWithName(internalGV.WithKind("OptionalExtensionType"), &InternalOptionalExtensionType{}) scheme.AddKnownTypeWithName(externalGV.WithKind("OptionalExtensionType"), &ExternalOptionalExtensionType{}) codec := serializer.NewCodecFactory(scheme).LegacyCodec(externalGV) table := []struct { obj runtime.Object encoded string }{ { &InternalOptionalExtensionType{Extension: nil}, `{"kind":"OptionalExtensionType","apiVersion":"` + externalGV.String() + `"}`, }, } for i, item := range table { gotDecoded, err := runtime.Decode(codec, []byte(item.encoded)) if err != nil { t.Errorf("unexpected error '%v' (%v)", err, item.encoded) } else if e, a := item.obj, gotDecoded; !reflect.DeepEqual(e, a) { t.Errorf("%d: unexpected objects:\n%s", i, diff.ObjectGoPrintSideBySide(e, a)) } } }
func TestEncode(t *testing.T) { internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal} externalGV := schema.GroupVersion{Group: "test.group", Version: "testExternal"} scheme := runtime.NewScheme() scheme.AddKnownTypeWithName(internalGV.WithKind("Simple"), &InternalSimple{}) scheme.AddKnownTypeWithName(externalGV.WithKind("Simple"), &ExternalSimple{}) codec := serializer.NewCodecFactory(scheme).LegacyCodec(externalGV) test := &InternalSimple{ TestString: "I'm the same", } obj := runtime.Object(test) data, err := runtime.Encode(codec, obj) obj2, gvk, err2 := codec.Decode(data, nil, nil) if err != nil || err2 != nil { t.Fatalf("Failure: '%v' '%v'", err, err2) } if _, ok := obj2.(*InternalSimple); !ok { t.Fatalf("Got wrong type") } if !reflect.DeepEqual(obj2, test) { t.Errorf("Expected:\n %#v,\n Got:\n %#v", test, obj2) } if !reflect.DeepEqual(gvk, &schema.GroupVersionKind{Group: "test.group", Version: "testExternal", Kind: "Simple"}) { t.Errorf("unexpected gvk returned by decode: %#v", gvk) } }
func TestDecodeEmptyRawExtensionAsObject(t *testing.T) { internalGV := unversioned.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal} externalGV := unversioned.GroupVersion{Group: "test.group", Version: "v1test"} externalGVK := externalGV.WithKind("ObjectTest") s := runtime.NewScheme() s.AddKnownTypes(internalGV, &ObjectTest{}) s.AddKnownTypeWithName(externalGVK, &ObjectTestExternal{}) codec := serializer.NewCodecFactory(s).LegacyCodec(externalGV) obj, gvk, err := codec.Decode([]byte(`{"kind":"`+externalGVK.Kind+`","apiVersion":"`+externalGV.String()+`","items":[{}]}`), nil, nil) if err != nil { t.Fatalf("unexpected error: %v", err) } test := obj.(*ObjectTest) if unk, ok := test.Items[0].(*runtime.Unknown); !ok || unk.Kind != "" || unk.APIVersion != "" || string(unk.Raw) != "{}" || unk.ContentType != runtime.ContentTypeJSON { t.Fatalf("unexpected object: %#v", test.Items[0]) } if *gvk != externalGVK { t.Fatalf("unexpected kind: %#v", gvk) } obj, gvk, err = codec.Decode([]byte(`{"kind":"`+externalGVK.Kind+`","apiVersion":"`+externalGV.String()+`","items":[{"kind":"Other","apiVersion":"v1"}]}`), nil, nil) if err != nil { t.Fatalf("unexpected error: %v", err) } test = obj.(*ObjectTest) if unk, ok := test.Items[0].(*runtime.Unknown); !ok || unk.Kind != "" || unk.APIVersion != "" || string(unk.Raw) != `{"kind":"Other","apiVersion":"v1"}` || unk.ContentType != runtime.ContentTypeJSON { t.Fatalf("unexpected object: %#v", test.Items[0]) } if *gvk != externalGVK { t.Fatalf("unexpected kind: %#v", gvk) } }
func newExternalScheme() (*runtime.Scheme, meta.RESTMapper, runtime.Codec) { scheme := runtime.NewScheme() scheme.AddKnownTypeWithName(internalGV.WithKind("Type"), &internalType{}) scheme.AddKnownTypeWithName(unlikelyGV.WithKind("Type"), &externalType{}) //This tests that kubectl will not confuse the external scheme with the internal scheme, even when they accidentally have versions of the same name. scheme.AddKnownTypeWithName(validVersionGV.WithKind("Type"), &ExternalType2{}) codecs := serializer.NewCodecFactory(scheme) codec := codecs.LegacyCodec(unlikelyGV) mapper := meta.NewDefaultRESTMapper([]unversioned.GroupVersion{unlikelyGV, validVersionGV}, func(version unversioned.GroupVersion) (*meta.VersionInterfaces, error) { return &meta.VersionInterfaces{ ObjectConvertor: scheme, MetadataAccessor: meta.NewAccessor(), }, versionErrIfFalse(version == validVersionGV || version == unlikelyGV) }) for _, gv := range []unversioned.GroupVersion{unlikelyGV, validVersionGV} { for kind := range scheme.KnownTypes(gv) { gvk := gv.WithKind(kind) scope := meta.RESTScopeNamespace mapper.Add(gvk, scope) } } return scheme, mapper, codec }
func writeYAML(obj runtime.Object) ([]byte, error) { json, err := runtime.Encode(serializer.NewCodecFactory(internal.Scheme).LegacyCodec(v1.SchemeGroupVersion), obj) if err != nil { return nil, err } content, err := yaml.JSONToYAML(json) if err != nil { return nil, err } return content, err }
func TestStringSourceMarshaling(t *testing.T) { codec := serializer.NewCodecFactory(configapi.Scheme).LegacyCodec(SchemeGroupVersion) testcases := map[string]struct { Object configapi.StringSource ExpectedJSON string }{ "empty string": { Object: configapi.StringSource{}, ExpectedJSON: `""`, }, "string": { Object: configapi.StringSource{StringSourceSpec: configapi.StringSourceSpec{Value: "foo"}}, ExpectedJSON: `"foo"`, }, "struct value+keyFile": { Object: configapi.StringSource{StringSourceSpec: configapi.StringSourceSpec{Value: "foo", KeyFile: "bar"}}, ExpectedJSON: `{"value":"foo","env":"","file":"","keyFile":"bar"}`, }, "struct env": { Object: configapi.StringSource{StringSourceSpec: configapi.StringSourceSpec{Env: "foo"}}, ExpectedJSON: `{"value":"","env":"foo","file":"","keyFile":""}`, }, "struct file": { Object: configapi.StringSource{StringSourceSpec: configapi.StringSourceSpec{File: "foo"}}, ExpectedJSON: `{"value":"","env":"","file":"foo","keyFile":""}`, }, "struct file+keyFile": { Object: configapi.StringSource{StringSourceSpec: configapi.StringSourceSpec{File: "foo", KeyFile: "bar"}}, ExpectedJSON: `{"value":"","env":"","file":"foo","keyFile":"bar"}`, }, } for k, tc := range testcases { provider := &configapi.GitHubIdentityProvider{ClientSecret: tc.Object} json, err := runtime.Encode(codec, provider) if err != nil { t.Errorf("%s: unexpected error: %v", k, err) } // Wrap in a dummy JSON from the surrounding object input := fmt.Sprintf(`{"kind":"GitHubIdentityProvider","apiVersion":"v1","clientID":"","clientSecret":%s,"organizations":null,"teams":null}`, tc.ExpectedJSON) if strings.TrimSpace(string(json)) != input { t.Log(len(input), len(json)) t.Errorf("%s: expected\n%s\ngot\n%s", k, input, string(json)) } } }
func NewMetadataCodecFactory() serializer.CodecFactory { // populating another scheme from api.Scheme, registering every kind with // MetadataOnlyObject (or MetadataOnlyObjectList). scheme := runtime.NewScheme() allTypes := api.Scheme.AllKnownTypes() for kind := range allTypes { if kind.Version == runtime.APIVersionInternal { continue } metaOnlyObject := gvkToMetadataOnlyObject(kind) scheme.AddKnownTypeWithName(kind, metaOnlyObject) } scheme.AddUnversionedTypes(api.Unversioned, &unversioned.Status{}) return serializer.NewCodecFactory(scheme) }
// For debugging problems func TestSpecificKind(t *testing.T) { configapi.Scheme.Log(t) defer configapi.Scheme.Log(nil) kind := "MasterConfig" item, err := configapi.Scheme.New(configapi.SchemeGroupVersion.WithKind(kind)) if err != nil { t.Errorf("Couldn't make a %v? %v", kind, err) return } seed := int64(2703387474910584091) //rand.Int63() for i := 0; i < fuzzIters; i++ { fuzzInternalObject(t, configapiv1.SchemeGroupVersion, item, seed) roundTrip(t, serializer.NewCodecFactory(configapi.Scheme).LegacyCodec(configapiv1.SchemeGroupVersion), item) } }
func TestBadJSONRejection(t *testing.T) { scheme := runtime.NewScheme() codecs := serializer.NewCodecFactory(scheme) jsonserializer, _ := codecs.SerializerForFileExtension("json") badJSONMissingKind := []byte(`{ }`) if _, err := runtime.Decode(jsonserializer, badJSONMissingKind); err == nil { t.Errorf("Did not reject despite lack of kind field: %s", badJSONMissingKind) } badJSONUnknownType := []byte(`{"kind": "bar"}`) if _, err1 := runtime.Decode(jsonserializer, badJSONUnknownType); err1 == nil { t.Errorf("Did not reject despite use of unknown type: %s", badJSONUnknownType) } /*badJSONKindMismatch := []byte(`{"kind": "Pod"}`) if err2 := DecodeInto(badJSONKindMismatch, &Node{}); err2 == nil { t.Errorf("Kind is set but doesn't match the object type: %s", badJSONKindMismatch) }*/ }
// TestTypes will try to roundtrip all OpenShift and Kubernetes stable api types func TestTypes(t *testing.T) { for kind := range configapi.Scheme.KnownTypes(configapi.SchemeGroupVersion) { // Try a few times, since runTest uses random values. for i := 0; i < fuzzIters; i++ { item, err := configapi.Scheme.New(configapi.SchemeGroupVersion.WithKind(kind)) if err != nil { t.Errorf("Couldn't make a %v? %v", kind, err) continue } if _, err := meta.TypeAccessor(item); err != nil { t.Fatalf("%q is not a TypeMeta and cannot be tested - add it to nonRoundTrippableTypes: %v", kind, err) } seed := rand.Int63() fuzzInternalObject(t, configapiv1.SchemeGroupVersion, item, seed) roundTrip(t, serializer.NewCodecFactory(configapi.Scheme).LegacyCodec(configapiv1.SchemeGroupVersion), item) } } }
func testScheme(t *testing.T) (*runtime.Scheme, runtime.Codec) { scheme := runtime.NewScheme() scheme.Log(t) scheme.AddKnownTypes(*testapi.Default.GroupVersion(), &storagetesting.TestResource{}) scheme.AddKnownTypes(testapi.Default.InternalGroupVersion(), &storagetesting.TestResource{}) if err := scheme.AddConversionFuncs( func(in *storagetesting.TestResource, out *storagetesting.TestResource, s conversion.Scope) error { *out = *in return nil }, func(in, out *time.Time, s conversion.Scope) error { *out = *in return nil }, ); err != nil { panic(err) } codec := serializer.NewCodecFactory(scheme).LegacyCodec(*testapi.Default.GroupVersion()) return scheme, codec }
// TestDeepCopyOfRuntimeObject checks to make sure that runtime.Objects's can be passed through DeepCopy with fidelity func TestDeepCopyOfRuntimeObject(t *testing.T) { internalGV := unversioned.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal} externalGV := unversioned.GroupVersion{Group: "test.group", Version: "v1test"} embeddedTestExternalGVK := externalGV.WithKind("EmbeddedTest") s := runtime.NewScheme() s.AddKnownTypes(internalGV, &EmbeddedTest{}) s.AddKnownTypeWithName(embeddedTestExternalGVK, &EmbeddedTestExternal{}) original := &EmbeddedTest{ ID: "outer", Object: &EmbeddedTest{ ID: "inner", }, } codec := serializer.NewCodecFactory(s).LegacyCodec(externalGV) originalData, err := runtime.Encode(codec, original) if err != nil { t.Errorf("unexpected error: %v", err) } t.Logf("originalRole = %v\n", string(originalData)) copyOfOriginal, err := s.DeepCopy(original) if err != nil { t.Fatalf("unexpected error: %v", err) } copiedData, err := runtime.Encode(codec, copyOfOriginal.(runtime.Object)) if err != nil { t.Errorf("unexpected error: %v", err) } t.Logf("copyOfRole = %v\n", string(copiedData)) if !reflect.DeepEqual(original, copyOfOriginal) { t.Errorf("expected \n%v\n, got \n%v", string(originalData), string(copiedData)) } }
package latest import ( "k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/runtime/serializer" configapi "github.com/openshift/origin/pkg/cmd/server/api" ) // HACK TO ELIMINATE CYCLE UNTIL WE KILL THIS PACKAGE // Version is the string that represents the current external default version. var Version = unversioned.GroupVersion{Group: "", Version: "v1"} // OldestVersion is the string that represents the oldest server version supported, // for client code that wants to hardcode the lowest common denominator. var OldestVersion = unversioned.GroupVersion{Group: "", Version: "v1"} // Versions is the list of versions that are recognized in code. The order provided // may be assumed to be least feature rich to most feature rich, and clients may // choose to prefer the latter items in the list over the former items when presented // with a set of versions to choose. var Versions = []unversioned.GroupVersion{{Group: "", Version: "v1"}} var Codec = serializer.NewCodecFactory(configapi.Scheme).LegacyCodec(unversioned.GroupVersion{Group: "", Version: "v1"})
func TestScheme(t *testing.T) { internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal} externalGV := schema.GroupVersion{Group: "test.group", Version: "testExternal"} scheme := runtime.NewScheme() scheme.AddKnownTypeWithName(internalGV.WithKind("Simple"), &InternalSimple{}) scheme.AddKnownTypeWithName(externalGV.WithKind("Simple"), &ExternalSimple{}) // If set, would clear TypeMeta during conversion. //scheme.AddIgnoredConversionType(&TypeMeta{}, &TypeMeta{}) // test that scheme is an ObjectTyper var _ runtime.ObjectTyper = scheme internalToExternalCalls := 0 externalToInternalCalls := 0 // Register functions to verify that scope.Meta() gets set correctly. err := scheme.AddConversionFuncs( func(in *InternalSimple, out *ExternalSimple, scope conversion.Scope) error { scope.Convert(&in.TypeMeta, &out.TypeMeta, 0) scope.Convert(&in.TestString, &out.TestString, 0) internalToExternalCalls++ return nil }, func(in *ExternalSimple, out *InternalSimple, scope conversion.Scope) error { scope.Convert(&in.TypeMeta, &out.TypeMeta, 0) scope.Convert(&in.TestString, &out.TestString, 0) externalToInternalCalls++ return nil }, ) if err != nil { t.Fatalf("unexpected error: %v", err) } codecs := serializer.NewCodecFactory(scheme) codec := codecs.LegacyCodec(externalGV) info, _ := runtime.SerializerInfoForMediaType(codecs.SupportedMediaTypes(), runtime.ContentTypeJSON) jsonserializer := info.Serializer simple := &InternalSimple{ TestString: "foo", } // Test Encode, Decode, DecodeInto, and DecodeToVersion obj := runtime.Object(simple) data, err := runtime.Encode(codec, obj) if err != nil { t.Fatal(err) } obj2, err := runtime.Decode(codec, data) if err != nil { t.Fatal(err) } if _, ok := obj2.(*InternalSimple); !ok { t.Fatalf("Got wrong type") } if e, a := simple, obj2; !reflect.DeepEqual(e, a) { t.Errorf("Expected:\n %#v,\n Got:\n %#v", e, a) } obj3 := &InternalSimple{} if err := runtime.DecodeInto(codec, data, obj3); err != nil { t.Fatal(err) } // clearing TypeMeta is a function of the scheme, which we do not test here (ConvertToVersion // does not automatically clear TypeMeta anymore). simple.TypeMeta = runtime.TypeMeta{Kind: "Simple", APIVersion: externalGV.String()} if e, a := simple, obj3; !reflect.DeepEqual(e, a) { t.Errorf("Expected:\n %#v,\n Got:\n %#v", e, a) } obj4, err := runtime.Decode(jsonserializer, data) if err != nil { t.Fatal(err) } if _, ok := obj4.(*ExternalSimple); !ok { t.Fatalf("Got wrong type") } // Test Convert external := &ExternalSimple{} err = scheme.Convert(simple, external, nil) if err != nil { t.Fatalf("Unexpected error: %v", err) } if e, a := simple.TestString, external.TestString; e != a { t.Errorf("Expected %v, got %v", e, a) } // Encode and Convert should each have caused an increment. if e, a := 2, internalToExternalCalls; e != a { t.Errorf("Expected %v, got %v", e, a) } // DecodeInto and Decode should each have caused an increment because of a conversion if e, a := 2, externalToInternalCalls; e != a { t.Errorf("Expected %v, got %v", e, a) } }
func TestExtensionMapping(t *testing.T) { internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal} externalGV := schema.GroupVersion{Group: "test.group", Version: "testExternal"} scheme := runtime.NewScheme() scheme.AddKnownTypeWithName(internalGV.WithKind("ExtensionType"), &InternalExtensionType{}) scheme.AddKnownTypeWithName(internalGV.WithKind("OptionalExtensionType"), &InternalOptionalExtensionType{}) scheme.AddKnownTypeWithName(externalGV.WithKind("ExtensionType"), &ExternalExtensionType{}) scheme.AddKnownTypeWithName(externalGV.WithKind("OptionalExtensionType"), &ExternalOptionalExtensionType{}) // register external first when the object is the same in both schemes, so ObjectVersionAndKind reports the // external version. scheme.AddKnownTypeWithName(externalGV.WithKind("A"), &ExtensionA{}) scheme.AddKnownTypeWithName(externalGV.WithKind("B"), &ExtensionB{}) scheme.AddKnownTypeWithName(internalGV.WithKind("A"), &ExtensionA{}) scheme.AddKnownTypeWithName(internalGV.WithKind("B"), &ExtensionB{}) codec := serializer.NewCodecFactory(scheme).LegacyCodec(externalGV) table := []struct { obj runtime.Object expected runtime.Object encoded string }{ { &InternalExtensionType{ Extension: runtime.NewEncodable(codec, &ExtensionA{TestString: "foo"}), }, &InternalExtensionType{ Extension: &runtime.Unknown{ Raw: []byte(`{"apiVersion":"test.group/testExternal","kind":"A","testString":"foo"}`), ContentType: runtime.ContentTypeJSON, }, }, // apiVersion is set in the serialized object for easier consumption by clients `{"apiVersion":"` + externalGV.String() + `","kind":"ExtensionType","extension":{"apiVersion":"test.group/testExternal","kind":"A","testString":"foo"}} `, }, { &InternalExtensionType{Extension: runtime.NewEncodable(codec, &ExtensionB{TestString: "bar"})}, &InternalExtensionType{ Extension: &runtime.Unknown{ Raw: []byte(`{"apiVersion":"test.group/testExternal","kind":"B","testString":"bar"}`), ContentType: runtime.ContentTypeJSON, }, }, // apiVersion is set in the serialized object for easier consumption by clients `{"apiVersion":"` + externalGV.String() + `","kind":"ExtensionType","extension":{"apiVersion":"test.group/testExternal","kind":"B","testString":"bar"}} `, }, { &InternalExtensionType{Extension: nil}, &InternalExtensionType{ Extension: nil, }, `{"apiVersion":"` + externalGV.String() + `","kind":"ExtensionType","extension":null} `, }, } for i, item := range table { gotEncoded, err := runtime.Encode(codec, item.obj) if err != nil { t.Errorf("unexpected error '%v' (%#v)", err, item.obj) } else if e, a := item.encoded, string(gotEncoded); e != a { t.Errorf("expected\n%#v\ngot\n%#v\n", e, a) } gotDecoded, err := runtime.Decode(codec, []byte(item.encoded)) if err != nil { t.Errorf("unexpected error '%v' (%v)", err, item.encoded) } else if e, a := item.expected, gotDecoded; !reflect.DeepEqual(e, a) { t.Errorf("%d: unexpected objects:\n%s", i, diff.ObjectGoPrintSideBySide(e, a)) } } }
func TestSpecificRoundTrips(t *testing.T) { boolFalse := false testCases := []struct { mediaType string in, out runtime.Object to, from unversioned.GroupVersion }{ { in: &configapi.MasterConfig{ AdmissionConfig: configapi.AdmissionConfig{ PluginConfig: map[string]configapi.AdmissionPluginConfig{ "test1": {Configuration: &configapi.LDAPSyncConfig{BindDN: "first"}}, "test2": {Configuration: &runtime.Unknown{Raw: []byte(`{"kind":"LDAPSyncConfig","apiVersion":"v1","bindDN":"second"}`)}}, "test3": {Configuration: &runtime.Unknown{Raw: []byte(`{"kind":"Unknown","apiVersion":"some/version"}`)}}, "test4": {Configuration: nil}, }, }, }, to: configapiv1.SchemeGroupVersion, out: &configapiv1.MasterConfig{ TypeMeta: unversioned.TypeMeta{Kind: "MasterConfig", APIVersion: "v1"}, AdmissionConfig: configapiv1.AdmissionConfig{ PluginConfig: map[string]configapiv1.AdmissionPluginConfig{ "test1": {Configuration: runtime.RawExtension{ Object: &configapiv1.LDAPSyncConfig{BindDN: "first"}, Raw: []byte(`{"kind":"LDAPSyncConfig","apiVersion":"v1","url":"","bindDN":"first","bindPassword":"","insecure":false,"ca":"","groupUIDNameMapping":null}`), }}, "test2": {Configuration: runtime.RawExtension{ Object: &configapiv1.LDAPSyncConfig{BindDN: "second"}, Raw: []byte(`{"kind":"LDAPSyncConfig","apiVersion":"v1","bindDN":"second"}`), }}, "test3": {Configuration: runtime.RawExtension{ Object: &runtime.Unknown{TypeMeta: runtime.TypeMeta{Kind: "Unknown", APIVersion: "some/version"}, ContentType: "application/json", Raw: []byte(`{"kind":"Unknown","apiVersion":"some/version"}`)}, Raw: []byte(`{"kind":"Unknown","apiVersion":"some/version"}`), }}, "test4": {}, }, }, VolumeConfig: configapiv1.MasterVolumeConfig{DynamicProvisioningEnabled: &boolFalse}, }, from: configapiv1.SchemeGroupVersion, }, } f := serializer.NewCodecFactory(configapi.Scheme) for i, test := range testCases { var s runtime.Serializer if len(test.mediaType) != 0 { info, _ := f.SerializerForMediaType(test.mediaType, nil) s = info.Serializer } else { info, _ := f.SerializerForMediaType(f.SupportedMediaTypes()[0], nil) s = info.Serializer } data, err := runtime.Encode(f.LegacyCodec(test.to), test.in) if err != nil { t.Errorf("%d: unable to encode: %v", i, err) continue } result, err := runtime.Decode(f.DecoderToVersion(s, test.from), data) if err != nil { t.Errorf("%d: unable to decode: %v", i, err) continue } if !reflect.DeepEqual(test.out, result) { t.Errorf("%d: result did not match: %s", i, diff.ObjectReflectDiff(test.out, result)) continue } } }
func TestArrayOfRuntimeObject(t *testing.T) { internalGV := unversioned.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal} externalGV := unversioned.GroupVersion{Group: "test.group", Version: "v1test"} s := runtime.NewScheme() s.AddKnownTypes(internalGV, &EmbeddedTest{}) s.AddKnownTypeWithName(externalGV.WithKind("EmbeddedTest"), &EmbeddedTestExternal{}) s.AddKnownTypes(internalGV, &ObjectTest{}) s.AddKnownTypeWithName(externalGV.WithKind("ObjectTest"), &ObjectTestExternal{}) codec := serializer.NewCodecFactory(s).LegacyCodec(externalGV) innerItems := []runtime.Object{ &EmbeddedTest{ID: "baz"}, } items := []runtime.Object{ &EmbeddedTest{ID: "foo"}, &EmbeddedTest{ID: "bar"}, // TODO: until YAML is removed, this JSON must be in ascending key order to ensure consistent roundtrip serialization &runtime.Unknown{ Raw: []byte(`{"apiVersion":"unknown.group/unknown","foo":"bar","kind":"OtherTest"}`), ContentType: runtime.ContentTypeJSON, }, &ObjectTest{ Items: runtime.NewEncodableList(codec, innerItems), }, } internal := &ObjectTest{ Items: runtime.NewEncodableList(codec, items), } wire, err := runtime.Encode(codec, internal) if err != nil { t.Fatalf("unexpected error: %v", err) } t.Logf("Wire format is:\n%s\n", string(wire)) obj := &ObjectTestExternal{} if err := json.Unmarshal(wire, obj); err != nil { t.Fatalf("unexpected error: %v", err) } t.Logf("exact wire is: %s", string(obj.Items[0].Raw)) items[3] = &ObjectTest{Items: innerItems} internal.Items = items decoded, err := runtime.Decode(codec, wire) if err != nil { t.Fatalf("unexpected error: %v", err) } list, err := meta.ExtractList(decoded) if err != nil { t.Fatalf("unexpected error: %v", err) } if errs := runtime.DecodeList(list, codec); len(errs) > 0 { t.Fatalf("unexpected error: %v", errs) } list2, err := meta.ExtractList(list[3]) if err != nil { t.Fatalf("unexpected error: %v", err) } if errs := runtime.DecodeList(list2, codec); len(errs) > 0 { t.Fatalf("unexpected error: %v", errs) } if err := meta.SetList(list[3], list2); err != nil { t.Fatalf("unexpected error: %v", err) } // we want DecodeList to set type meta if possible, even on runtime.Unknown objects internal.Items[2].(*runtime.Unknown).TypeMeta = runtime.TypeMeta{Kind: "OtherTest", APIVersion: "unknown.group/unknown"} if e, a := internal.Items, list; !reflect.DeepEqual(e, a) { t.Errorf("mismatched decoded: %s", diff.ObjectGoPrintSideBySide(e, a)) } }
package api import ( "k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime/serializer" ) var Scheme = runtime.NewScheme() var Codecs = serializer.NewCodecFactory(Scheme) const GroupName = "" // SchemeGroupVersion is group version used to register these objects var SchemeGroupVersion = unversioned.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal} // Kind takes an unqualified kind and returns back a Group qualified GroupKind func Kind(kind string) unversioned.GroupKind { return SchemeGroupVersion.WithKind(kind).GroupKind() } // Resource takes an unqualified resource and returns back a Group qualified GroupResource func Resource(resource string) unversioned.GroupResource { return SchemeGroupVersion.WithResource(resource).GroupResource() } func AddToScheme(scheme *runtime.Scheme) { // Add the API to Scheme. addKnownTypes(scheme) }
func TestStringSourceUnmarshaling(t *testing.T) { codec := serializer.NewCodecFactory(configapi.Scheme).LegacyCodec(SchemeGroupVersion) testcases := map[string]struct { JSON string ExpectedObject configapi.StringSource ExpectedError string }{ "bool": { JSON: `true`, ExpectedObject: configapi.StringSource{}, ExpectedError: "cannot unmarshal", }, "number": { JSON: `1`, ExpectedObject: configapi.StringSource{}, ExpectedError: "cannot unmarshal", }, "empty string": { JSON: `""`, ExpectedObject: configapi.StringSource{}, ExpectedError: "", }, "string": { JSON: `"foo"`, ExpectedObject: configapi.StringSource{StringSourceSpec: configapi.StringSourceSpec{Value: "foo"}}, ExpectedError: "", }, "empty struct": { JSON: `{}`, ExpectedObject: configapi.StringSource{}, ExpectedError: "", }, "struct value": { JSON: `{"value":"foo"}`, ExpectedObject: configapi.StringSource{StringSourceSpec: configapi.StringSourceSpec{Value: "foo"}}, ExpectedError: "", }, "struct env": { JSON: `{"env":"foo"}`, ExpectedObject: configapi.StringSource{StringSourceSpec: configapi.StringSourceSpec{Env: "foo"}}, ExpectedError: "", }, "struct file": { JSON: `{"file":"foo"}`, ExpectedObject: configapi.StringSource{StringSourceSpec: configapi.StringSourceSpec{File: "foo"}}, ExpectedError: "", }, "struct file+keyFile": { JSON: `{"file":"foo","keyFile":"bar"}`, ExpectedObject: configapi.StringSource{StringSourceSpec: configapi.StringSourceSpec{File: "foo", KeyFile: "bar"}}, ExpectedError: "", }, } for k, tc := range testcases { // Wrap in a dummy object we can deserialize input := fmt.Sprintf(`{"kind":"GitHubIdentityProvider","apiVersion":"v1","clientSecret":%s}`, tc.JSON) obj, err := runtime.Decode(codec, []byte(input)) if len(tc.ExpectedError) > 0 && (err == nil || !strings.Contains(err.Error(), tc.ExpectedError)) { t.Errorf("%s: expected error containing %q, got %q", k, tc.ExpectedError, err.Error()) } if len(tc.ExpectedError) == 0 && err != nil { t.Errorf("%s: got unexpected error: %v", k, err) } if err != nil { continue } githubProvider, ok := obj.(*configapi.GitHubIdentityProvider) if !ok { t.Errorf("%s: wrapper object was not a GitHubIdentityProvider as expected: %#v", k, obj) continue } if !reflect.DeepEqual(tc.ExpectedObject, githubProvider.ClientSecret) { t.Errorf("%s: expected\n%#v\ngot\n%#v", k, tc.ExpectedObject, githubProvider.ClientSecret) } } }
return nil }, func(in *internal.MasterVolumeConfig, out *MasterVolumeConfig, s conversion.Scope) error { enabled := in.DynamicProvisioningEnabled out.DynamicProvisioningEnabled = &enabled return nil }, api.Convert_resource_Quantity_To_resource_Quantity, ) if err != nil { // If one of the conversion functions is malformed, detect it immediately. panic(err) } } var codec = serializer.NewCodecFactory(internal.Scheme).LegacyCodec(SchemeGroupVersion) // Convert_runtime_Object_To_runtime_RawExtension is conversion function that assumes that the runtime.Object you've embedded is in // the same GroupVersion that your containing type is in. This is signficantly better than simply breaking. // Given an ordered list of preferred external versions for a given encode or conversion call, the behavior of this function could be // made generic, predictable, and controllable. func convert_runtime_Object_To_runtime_RawExtension(in runtime.Object, out *runtime.RawExtension, s conversion.Scope) error { if in == nil { return nil } externalObject, err := internal.Scheme.ConvertToVersion(in, s.Meta().DestVersion) if runtime.IsNotRegisteredError(err) { switch cast := in.(type) { case *runtime.Unknown: out.Raw = cast.Raw
func TestNestedObject(t *testing.T) { internalGV := unversioned.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal} externalGV := unversioned.GroupVersion{Group: "test.group", Version: "v1test"} embeddedTestExternalGVK := externalGV.WithKind("EmbeddedTest") s := runtime.NewScheme() s.AddKnownTypes(internalGV, &EmbeddedTest{}) s.AddKnownTypeWithName(embeddedTestExternalGVK, &EmbeddedTestExternal{}) codec := serializer.NewCodecFactory(s).LegacyCodec(externalGV) inner := &EmbeddedTest{ ID: "inner", } outer := &EmbeddedTest{ ID: "outer", Object: runtime.NewEncodable(codec, inner), } wire, err := runtime.Encode(codec, outer) if err != nil { t.Fatalf("Unexpected encode error '%v'", err) } t.Logf("Wire format is:\n%v\n", string(wire)) decoded, err := runtime.Decode(codec, wire) if err != nil { t.Fatalf("Unexpected decode error %v", err) } // for later tests outer.Object = inner if e, a := outer, decoded; reflect.DeepEqual(e, a) { t.Errorf("Expected unequal %#v %#v", e, a) } obj, err := runtime.Decode(codec, decoded.(*EmbeddedTest).Object.(*runtime.Unknown).Raw) if err != nil { t.Fatal(err) } decoded.(*EmbeddedTest).Object = obj if e, a := outer, decoded; !reflect.DeepEqual(e, a) { t.Errorf("Expected equal %#v %#v", e, a) } // test JSON decoding of the external object, which should preserve // raw bytes var externalViaJSON EmbeddedTestExternal err = json.Unmarshal(wire, &externalViaJSON) if err != nil { t.Fatalf("Unexpected decode error %v", err) } if externalViaJSON.Kind == "" || externalViaJSON.APIVersion == "" || externalViaJSON.ID != "outer" { t.Errorf("Expected objects to have type info set, got %#v", externalViaJSON) } if !reflect.DeepEqual(externalViaJSON.EmptyObject.Raw, []byte("null")) || len(externalViaJSON.Object.Raw) == 0 { t.Errorf("Expected deserialization of nested objects into bytes, got %#v", externalViaJSON) } // test JSON decoding, too, since Decode uses yaml unmarshalling. // Generic Unmarshalling of JSON cannot load the nested objects because there is // no default schema set. Consumers wishing to get direct JSON decoding must use // the external representation var decodedViaJSON EmbeddedTest err = json.Unmarshal(wire, &decodedViaJSON) if err == nil || !strings.Contains(err.Error(), "unmarshal object into Go value of type runtime.Object") { t.Fatalf("Unexpected decode error %v", err) } if a := decodedViaJSON; a.Object != nil || a.EmptyObject != nil { t.Errorf("Expected embedded objects to be nil: %#v", a) } }