123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420 |
- /*
- Copyright 2014 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 meta_test
- import (
- "reflect"
- "testing"
- "github.com/google/gofuzz"
- "k8s.io/kubernetes/pkg/api"
- "k8s.io/kubernetes/pkg/api/meta"
- "k8s.io/kubernetes/pkg/api/meta/metatypes"
- "k8s.io/kubernetes/pkg/api/unversioned"
- "k8s.io/kubernetes/pkg/api/v1"
- "k8s.io/kubernetes/pkg/runtime"
- "k8s.io/kubernetes/pkg/types"
- )
- func TestAPIObjectMeta(t *testing.T) {
- j := &api.Pod{
- TypeMeta: unversioned.TypeMeta{APIVersion: "/a", Kind: "b"},
- ObjectMeta: api.ObjectMeta{
- Namespace: "bar",
- Name: "foo",
- GenerateName: "prefix",
- UID: "uid",
- ResourceVersion: "1",
- SelfLink: "some/place/only/we/know",
- Labels: map[string]string{"foo": "bar"},
- Annotations: map[string]string{"x": "y"},
- Finalizers: []string{
- "finalizer.1",
- "finalizer.2",
- },
- },
- }
- var _ meta.Object = &j.ObjectMeta
- var _ meta.ObjectMetaAccessor = j
- accessor, err := meta.Accessor(j)
- if err != nil {
- t.Fatalf("unexpected error: %v", err)
- }
- if accessor != meta.Object(j) {
- t.Fatalf("should have returned the same pointer: %#v\n\n%#v", accessor, j)
- }
- if e, a := "bar", accessor.GetNamespace(); e != a {
- t.Errorf("expected %v, got %v", e, a)
- }
- if e, a := "foo", accessor.GetName(); e != a {
- t.Errorf("expected %v, got %v", e, a)
- }
- if e, a := "prefix", accessor.GetGenerateName(); e != a {
- t.Errorf("expected %v, got %v", e, a)
- }
- if e, a := "uid", string(accessor.GetUID()); e != a {
- t.Errorf("expected %v, got %v", e, a)
- }
- if e, a := "1", accessor.GetResourceVersion(); e != a {
- t.Errorf("expected %v, got %v", e, a)
- }
- if e, a := "some/place/only/we/know", accessor.GetSelfLink(); e != a {
- t.Errorf("expected %v, got %v", e, a)
- }
- if e, a := []string{"finalizer.1", "finalizer.2"}, accessor.GetFinalizers(); !reflect.DeepEqual(e, a) {
- t.Errorf("expected %v, got %v", e, a)
- }
- typeAccessor, err := meta.TypeAccessor(j)
- if err != nil {
- t.Fatalf("unexpected error: %v", err)
- }
- if e, a := "a", typeAccessor.GetAPIVersion(); e != a {
- t.Errorf("expected %v, got %v", e, a)
- }
- if e, a := "b", typeAccessor.GetKind(); e != a {
- t.Errorf("expected %v, got %v", e, a)
- }
- accessor.SetNamespace("baz")
- accessor.SetName("bar")
- accessor.SetGenerateName("generate")
- accessor.SetUID("other")
- typeAccessor.SetAPIVersion("c")
- typeAccessor.SetKind("d")
- accessor.SetResourceVersion("2")
- accessor.SetSelfLink("google.com")
- accessor.SetFinalizers([]string{"finalizer.3"})
- // Prove that accessor changes the original object.
- if e, a := "baz", j.Namespace; e != a {
- t.Errorf("expected %v, got %v", e, a)
- }
- if e, a := "bar", j.Name; e != a {
- t.Errorf("expected %v, got %v", e, a)
- }
- if e, a := "generate", j.GenerateName; e != a {
- t.Errorf("expected %v, got %v", e, a)
- }
- if e, a := types.UID("other"), j.UID; e != a {
- t.Errorf("expected %v, got %v", e, a)
- }
- if e, a := "c", j.APIVersion; e != a {
- t.Errorf("expected %v, got %v", e, a)
- }
- if e, a := "d", j.Kind; e != a {
- t.Errorf("expected %v, got %v", e, a)
- }
- if e, a := "2", j.ResourceVersion; e != a {
- t.Errorf("expected %v, got %v", e, a)
- }
- if e, a := "google.com", j.SelfLink; e != a {
- t.Errorf("expected %v, got %v", e, a)
- }
- if e, a := []string{"finalizer.3"}, j.Finalizers; !reflect.DeepEqual(e, a) {
- t.Errorf("expected %v, got %v", e, a)
- }
- typeAccessor.SetAPIVersion("d")
- typeAccessor.SetKind("e")
- if e, a := "d", j.APIVersion; e != a {
- t.Errorf("expected %v, got %v", e, a)
- }
- if e, a := "e", j.Kind; e != a {
- t.Errorf("expected %v, got %v", e, a)
- }
- }
- func TestGenericTypeMeta(t *testing.T) {
- type TypeMeta struct {
- Kind string `json:"kind,omitempty"`
- Namespace string `json:"namespace,omitempty"`
- Name string `json:"name,omitempty"`
- GenerateName string `json:"generateName,omitempty"`
- UID string `json:"uid,omitempty"`
- CreationTimestamp unversioned.Time `json:"creationTimestamp,omitempty"`
- SelfLink string `json:"selfLink,omitempty"`
- ResourceVersion string `json:"resourceVersion,omitempty"`
- APIVersion string `json:"apiVersion,omitempty"`
- Labels map[string]string `json:"labels,omitempty"`
- Annotations map[string]string `json:"annotations,omitempty"`
- OwnerReferences []api.OwnerReference `json:"ownerReferences,omitempty"`
- Finalizers []string `json:"finalizers,omitempty"`
- }
- j := struct{ TypeMeta }{TypeMeta{APIVersion: "a", Kind: "b"}}
- typeAccessor, err := meta.TypeAccessor(&j)
- if err != nil {
- t.Fatalf("unexpected error: %v", err)
- }
- if e, a := "a", typeAccessor.GetAPIVersion(); e != a {
- t.Errorf("expected %v, got %v", e, a)
- }
- if e, a := "b", typeAccessor.GetKind(); e != a {
- t.Errorf("expected %v, got %v", e, a)
- }
- typeAccessor.SetAPIVersion("c")
- typeAccessor.SetKind("d")
- if e, a := "c", j.APIVersion; e != a {
- t.Errorf("expected %v, got %v", e, a)
- }
- if e, a := "d", j.Kind; e != a {
- t.Errorf("expected %v, got %v", e, a)
- }
- typeAccessor.SetAPIVersion("d")
- typeAccessor.SetKind("e")
- if e, a := "d", j.APIVersion; e != a {
- t.Errorf("expected %v, got %v", e, a)
- }
- if e, a := "e", j.Kind; e != a {
- t.Errorf("expected %v, got %v", e, a)
- }
- }
- type InternalTypeMeta struct {
- Kind string `json:"kind,omitempty"`
- Namespace string `json:"namespace,omitempty"`
- Name string `json:"name,omitempty"`
- GenerateName string `json:"generateName,omitempty"`
- UID string `json:"uid,omitempty"`
- CreationTimestamp unversioned.Time `json:"creationTimestamp,omitempty"`
- SelfLink string `json:"selfLink,omitempty"`
- ResourceVersion string `json:"resourceVersion,omitempty"`
- APIVersion string `json:"apiVersion,omitempty"`
- Labels map[string]string `json:"labels,omitempty"`
- Annotations map[string]string `json:"annotations,omitempty"`
- Finalizers []string `json:"finalizers,omitempty"`
- OwnerReferences []api.OwnerReference `json:"ownerReferences,omitempty"`
- }
- func (m *InternalTypeMeta) GetResourceVersion() string { return m.ResourceVersion }
- func (m *InternalTypeMeta) SetResourceVersion(rv string) { m.ResourceVersion = rv }
- func (m *InternalTypeMeta) GetSelfLink() string { return m.SelfLink }
- func (m *InternalTypeMeta) SetSelfLink(link string) { m.SelfLink = link }
- type MyAPIObject struct {
- TypeMeta InternalTypeMeta `json:",inline"`
- }
- func (obj *MyAPIObject) GetListMeta() unversioned.List { return &obj.TypeMeta }
- func (obj *MyAPIObject) GetObjectKind() unversioned.ObjectKind { return obj }
- func (obj *MyAPIObject) SetGroupVersionKind(gvk unversioned.GroupVersionKind) {
- obj.TypeMeta.APIVersion, obj.TypeMeta.Kind = gvk.ToAPIVersionAndKind()
- }
- func (obj *MyAPIObject) GroupVersionKind() unversioned.GroupVersionKind {
- return unversioned.FromAPIVersionAndKind(obj.TypeMeta.APIVersion, obj.TypeMeta.Kind)
- }
- type MyIncorrectlyMarkedAsAPIObject struct{}
- func (obj *MyIncorrectlyMarkedAsAPIObject) GetObjectKind() unversioned.ObjectKind {
- return unversioned.EmptyObjectKind
- }
- func TestResourceVersionerOfAPI(t *testing.T) {
- type T struct {
- runtime.Object
- Expected string
- }
- testCases := map[string]T{
- "empty api object": {&MyAPIObject{}, ""},
- "api object with version": {&MyAPIObject{TypeMeta: InternalTypeMeta{ResourceVersion: "1"}}, "1"},
- "pointer to api object with version": {&MyAPIObject{TypeMeta: InternalTypeMeta{ResourceVersion: "1"}}, "1"},
- }
- versioning := meta.NewAccessor()
- for key, testCase := range testCases {
- actual, err := versioning.ResourceVersion(testCase.Object)
- if err != nil {
- t.Errorf("%s: unexpected error %#v", key, err)
- }
- if actual != testCase.Expected {
- t.Errorf("%s: expected %v, got %v", key, testCase.Expected, actual)
- }
- }
- failingCases := map[string]struct {
- runtime.Object
- Expected string
- }{
- "not a valid object to try": {&MyIncorrectlyMarkedAsAPIObject{}, "1"},
- }
- for key, testCase := range failingCases {
- _, err := versioning.ResourceVersion(testCase.Object)
- if err == nil {
- t.Errorf("%s: expected error, got nil", key)
- }
- }
- setCases := map[string]struct {
- runtime.Object
- Expected string
- }{
- "pointer to api object with version": {&MyAPIObject{TypeMeta: InternalTypeMeta{ResourceVersion: "1"}}, "1"},
- }
- for key, testCase := range setCases {
- if err := versioning.SetResourceVersion(testCase.Object, "5"); err != nil {
- t.Errorf("%s: unexpected error %#v", key, err)
- }
- actual, err := versioning.ResourceVersion(testCase.Object)
- if err != nil {
- t.Errorf("%s: unexpected error %#v", key, err)
- }
- if actual != "5" {
- t.Errorf("%s: expected %v, got %v", key, "5", actual)
- }
- }
- }
- func TestTypeMetaSelfLinker(t *testing.T) {
- table := map[string]struct {
- obj runtime.Object
- expect string
- try string
- succeed bool
- }{
- "normal": {
- obj: &MyAPIObject{TypeMeta: InternalTypeMeta{SelfLink: "foobar"}},
- expect: "foobar",
- try: "newbar",
- succeed: true,
- },
- "fail": {
- obj: &MyIncorrectlyMarkedAsAPIObject{},
- succeed: false,
- },
- }
- linker := runtime.SelfLinker(meta.NewAccessor())
- for name, item := range table {
- got, err := linker.SelfLink(item.obj)
- if e, a := item.succeed, err == nil; e != a {
- t.Errorf("%v: expected %v, got %v", name, e, a)
- }
- if e, a := item.expect, got; item.succeed && e != a {
- t.Errorf("%v: expected %v, got %v", name, e, a)
- }
- err = linker.SetSelfLink(item.obj, item.try)
- if e, a := item.succeed, err == nil; e != a {
- t.Errorf("%v: expected %v, got %v", name, e, a)
- }
- if item.succeed {
- got, err := linker.SelfLink(item.obj)
- if err != nil {
- t.Errorf("%v: expected no err, got %v", name, err)
- }
- if e, a := item.try, got; e != a {
- t.Errorf("%v: expected %v, got %v", name, e, a)
- }
- }
- }
- }
- type MyAPIObject2 struct {
- unversioned.TypeMeta
- v1.ObjectMeta
- }
- func getObjectMetaAndOwnerRefereneces() (myAPIObject2 MyAPIObject2, metaOwnerReferences []metatypes.OwnerReference) {
- fuzz.New().NilChance(.5).NumElements(1, 5).Fuzz(&myAPIObject2)
- references := myAPIObject2.ObjectMeta.OwnerReferences
- // This is necessary for the test to pass because the getter will return a
- // non-nil slice.
- metaOwnerReferences = make([]metatypes.OwnerReference, 0)
- for i := 0; i < len(references); i++ {
- metaOwnerReferences = append(metaOwnerReferences, metatypes.OwnerReference{
- Kind: references[i].Kind,
- Name: references[i].Name,
- UID: references[i].UID,
- APIVersion: references[i].APIVersion,
- Controller: references[i].Controller,
- })
- }
- if len(references) == 0 {
- // This is necessary for the test to pass because the setter will make a
- // non-nil slice.
- myAPIObject2.ObjectMeta.OwnerReferences = make([]v1.OwnerReference, 0)
- }
- return myAPIObject2, metaOwnerReferences
- }
- func testGetOwnerReferences(t *testing.T) {
- obj, expected := getObjectMetaAndOwnerRefereneces()
- accessor, err := meta.Accessor(&obj)
- if err != nil {
- t.Error(err)
- }
- references := accessor.GetOwnerReferences()
- if !reflect.DeepEqual(references, expected) {
- t.Errorf("expect %#v\n got %#v", expected, references)
- }
- }
- func testSetOwnerReferences(t *testing.T) {
- expected, references := getObjectMetaAndOwnerRefereneces()
- obj := MyAPIObject2{}
- accessor, err := meta.Accessor(&obj)
- if err != nil {
- t.Error(err)
- }
- accessor.SetOwnerReferences(references)
- if e, a := expected.ObjectMeta.OwnerReferences, obj.ObjectMeta.OwnerReferences; !reflect.DeepEqual(e, a) {
- t.Errorf("expect %#v\n got %#v", e, a)
- }
- }
- func TestAccessOwnerReferences(t *testing.T) {
- fuzzIter := 5
- for i := 0; i < fuzzIter; i++ {
- testGetOwnerReferences(t)
- testSetOwnerReferences(t)
- }
- }
- // BenchmarkAccessorSetFastPath shows the interface fast path
- func BenchmarkAccessorSetFastPath(b *testing.B) {
- obj := &api.Pod{
- TypeMeta: unversioned.TypeMeta{APIVersion: "/a", Kind: "b"},
- ObjectMeta: api.ObjectMeta{
- Namespace: "bar",
- Name: "foo",
- GenerateName: "prefix",
- UID: "uid",
- ResourceVersion: "1",
- SelfLink: "some/place/only/we/know",
- Labels: map[string]string{"foo": "bar"},
- Annotations: map[string]string{"x": "y"},
- },
- }
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- acc, err := meta.Accessor(obj)
- if err != nil {
- b.Fatal(err)
- }
- acc.SetNamespace("something")
- }
- b.StopTimer()
- }
|