meta_test.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. /*
  2. Copyright 2014 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package meta_test
  14. import (
  15. "reflect"
  16. "testing"
  17. "github.com/google/gofuzz"
  18. "k8s.io/kubernetes/pkg/api"
  19. "k8s.io/kubernetes/pkg/api/meta"
  20. "k8s.io/kubernetes/pkg/api/meta/metatypes"
  21. "k8s.io/kubernetes/pkg/api/unversioned"
  22. "k8s.io/kubernetes/pkg/api/v1"
  23. "k8s.io/kubernetes/pkg/runtime"
  24. "k8s.io/kubernetes/pkg/types"
  25. )
  26. func TestAPIObjectMeta(t *testing.T) {
  27. j := &api.Pod{
  28. TypeMeta: unversioned.TypeMeta{APIVersion: "/a", Kind: "b"},
  29. ObjectMeta: api.ObjectMeta{
  30. Namespace: "bar",
  31. Name: "foo",
  32. GenerateName: "prefix",
  33. UID: "uid",
  34. ResourceVersion: "1",
  35. SelfLink: "some/place/only/we/know",
  36. Labels: map[string]string{"foo": "bar"},
  37. Annotations: map[string]string{"x": "y"},
  38. Finalizers: []string{
  39. "finalizer.1",
  40. "finalizer.2",
  41. },
  42. },
  43. }
  44. var _ meta.Object = &j.ObjectMeta
  45. var _ meta.ObjectMetaAccessor = j
  46. accessor, err := meta.Accessor(j)
  47. if err != nil {
  48. t.Fatalf("unexpected error: %v", err)
  49. }
  50. if accessor != meta.Object(j) {
  51. t.Fatalf("should have returned the same pointer: %#v\n\n%#v", accessor, j)
  52. }
  53. if e, a := "bar", accessor.GetNamespace(); e != a {
  54. t.Errorf("expected %v, got %v", e, a)
  55. }
  56. if e, a := "foo", accessor.GetName(); e != a {
  57. t.Errorf("expected %v, got %v", e, a)
  58. }
  59. if e, a := "prefix", accessor.GetGenerateName(); e != a {
  60. t.Errorf("expected %v, got %v", e, a)
  61. }
  62. if e, a := "uid", string(accessor.GetUID()); e != a {
  63. t.Errorf("expected %v, got %v", e, a)
  64. }
  65. if e, a := "1", accessor.GetResourceVersion(); e != a {
  66. t.Errorf("expected %v, got %v", e, a)
  67. }
  68. if e, a := "some/place/only/we/know", accessor.GetSelfLink(); e != a {
  69. t.Errorf("expected %v, got %v", e, a)
  70. }
  71. if e, a := []string{"finalizer.1", "finalizer.2"}, accessor.GetFinalizers(); !reflect.DeepEqual(e, a) {
  72. t.Errorf("expected %v, got %v", e, a)
  73. }
  74. typeAccessor, err := meta.TypeAccessor(j)
  75. if err != nil {
  76. t.Fatalf("unexpected error: %v", err)
  77. }
  78. if e, a := "a", typeAccessor.GetAPIVersion(); e != a {
  79. t.Errorf("expected %v, got %v", e, a)
  80. }
  81. if e, a := "b", typeAccessor.GetKind(); e != a {
  82. t.Errorf("expected %v, got %v", e, a)
  83. }
  84. accessor.SetNamespace("baz")
  85. accessor.SetName("bar")
  86. accessor.SetGenerateName("generate")
  87. accessor.SetUID("other")
  88. typeAccessor.SetAPIVersion("c")
  89. typeAccessor.SetKind("d")
  90. accessor.SetResourceVersion("2")
  91. accessor.SetSelfLink("google.com")
  92. accessor.SetFinalizers([]string{"finalizer.3"})
  93. // Prove that accessor changes the original object.
  94. if e, a := "baz", j.Namespace; e != a {
  95. t.Errorf("expected %v, got %v", e, a)
  96. }
  97. if e, a := "bar", j.Name; e != a {
  98. t.Errorf("expected %v, got %v", e, a)
  99. }
  100. if e, a := "generate", j.GenerateName; e != a {
  101. t.Errorf("expected %v, got %v", e, a)
  102. }
  103. if e, a := types.UID("other"), j.UID; e != a {
  104. t.Errorf("expected %v, got %v", e, a)
  105. }
  106. if e, a := "c", j.APIVersion; e != a {
  107. t.Errorf("expected %v, got %v", e, a)
  108. }
  109. if e, a := "d", j.Kind; e != a {
  110. t.Errorf("expected %v, got %v", e, a)
  111. }
  112. if e, a := "2", j.ResourceVersion; e != a {
  113. t.Errorf("expected %v, got %v", e, a)
  114. }
  115. if e, a := "google.com", j.SelfLink; e != a {
  116. t.Errorf("expected %v, got %v", e, a)
  117. }
  118. if e, a := []string{"finalizer.3"}, j.Finalizers; !reflect.DeepEqual(e, a) {
  119. t.Errorf("expected %v, got %v", e, a)
  120. }
  121. typeAccessor.SetAPIVersion("d")
  122. typeAccessor.SetKind("e")
  123. if e, a := "d", j.APIVersion; e != a {
  124. t.Errorf("expected %v, got %v", e, a)
  125. }
  126. if e, a := "e", j.Kind; e != a {
  127. t.Errorf("expected %v, got %v", e, a)
  128. }
  129. }
  130. func TestGenericTypeMeta(t *testing.T) {
  131. type TypeMeta struct {
  132. Kind string `json:"kind,omitempty"`
  133. Namespace string `json:"namespace,omitempty"`
  134. Name string `json:"name,omitempty"`
  135. GenerateName string `json:"generateName,omitempty"`
  136. UID string `json:"uid,omitempty"`
  137. CreationTimestamp unversioned.Time `json:"creationTimestamp,omitempty"`
  138. SelfLink string `json:"selfLink,omitempty"`
  139. ResourceVersion string `json:"resourceVersion,omitempty"`
  140. APIVersion string `json:"apiVersion,omitempty"`
  141. Labels map[string]string `json:"labels,omitempty"`
  142. Annotations map[string]string `json:"annotations,omitempty"`
  143. OwnerReferences []api.OwnerReference `json:"ownerReferences,omitempty"`
  144. Finalizers []string `json:"finalizers,omitempty"`
  145. }
  146. j := struct{ TypeMeta }{TypeMeta{APIVersion: "a", Kind: "b"}}
  147. typeAccessor, err := meta.TypeAccessor(&j)
  148. if err != nil {
  149. t.Fatalf("unexpected error: %v", err)
  150. }
  151. if e, a := "a", typeAccessor.GetAPIVersion(); e != a {
  152. t.Errorf("expected %v, got %v", e, a)
  153. }
  154. if e, a := "b", typeAccessor.GetKind(); e != a {
  155. t.Errorf("expected %v, got %v", e, a)
  156. }
  157. typeAccessor.SetAPIVersion("c")
  158. typeAccessor.SetKind("d")
  159. if e, a := "c", j.APIVersion; e != a {
  160. t.Errorf("expected %v, got %v", e, a)
  161. }
  162. if e, a := "d", j.Kind; e != a {
  163. t.Errorf("expected %v, got %v", e, a)
  164. }
  165. typeAccessor.SetAPIVersion("d")
  166. typeAccessor.SetKind("e")
  167. if e, a := "d", j.APIVersion; e != a {
  168. t.Errorf("expected %v, got %v", e, a)
  169. }
  170. if e, a := "e", j.Kind; e != a {
  171. t.Errorf("expected %v, got %v", e, a)
  172. }
  173. }
  174. type InternalTypeMeta struct {
  175. Kind string `json:"kind,omitempty"`
  176. Namespace string `json:"namespace,omitempty"`
  177. Name string `json:"name,omitempty"`
  178. GenerateName string `json:"generateName,omitempty"`
  179. UID string `json:"uid,omitempty"`
  180. CreationTimestamp unversioned.Time `json:"creationTimestamp,omitempty"`
  181. SelfLink string `json:"selfLink,omitempty"`
  182. ResourceVersion string `json:"resourceVersion,omitempty"`
  183. APIVersion string `json:"apiVersion,omitempty"`
  184. Labels map[string]string `json:"labels,omitempty"`
  185. Annotations map[string]string `json:"annotations,omitempty"`
  186. Finalizers []string `json:"finalizers,omitempty"`
  187. OwnerReferences []api.OwnerReference `json:"ownerReferences,omitempty"`
  188. }
  189. func (m *InternalTypeMeta) GetResourceVersion() string { return m.ResourceVersion }
  190. func (m *InternalTypeMeta) SetResourceVersion(rv string) { m.ResourceVersion = rv }
  191. func (m *InternalTypeMeta) GetSelfLink() string { return m.SelfLink }
  192. func (m *InternalTypeMeta) SetSelfLink(link string) { m.SelfLink = link }
  193. type MyAPIObject struct {
  194. TypeMeta InternalTypeMeta `json:",inline"`
  195. }
  196. func (obj *MyAPIObject) GetListMeta() unversioned.List { return &obj.TypeMeta }
  197. func (obj *MyAPIObject) GetObjectKind() unversioned.ObjectKind { return obj }
  198. func (obj *MyAPIObject) SetGroupVersionKind(gvk unversioned.GroupVersionKind) {
  199. obj.TypeMeta.APIVersion, obj.TypeMeta.Kind = gvk.ToAPIVersionAndKind()
  200. }
  201. func (obj *MyAPIObject) GroupVersionKind() unversioned.GroupVersionKind {
  202. return unversioned.FromAPIVersionAndKind(obj.TypeMeta.APIVersion, obj.TypeMeta.Kind)
  203. }
  204. type MyIncorrectlyMarkedAsAPIObject struct{}
  205. func (obj *MyIncorrectlyMarkedAsAPIObject) GetObjectKind() unversioned.ObjectKind {
  206. return unversioned.EmptyObjectKind
  207. }
  208. func TestResourceVersionerOfAPI(t *testing.T) {
  209. type T struct {
  210. runtime.Object
  211. Expected string
  212. }
  213. testCases := map[string]T{
  214. "empty api object": {&MyAPIObject{}, ""},
  215. "api object with version": {&MyAPIObject{TypeMeta: InternalTypeMeta{ResourceVersion: "1"}}, "1"},
  216. "pointer to api object with version": {&MyAPIObject{TypeMeta: InternalTypeMeta{ResourceVersion: "1"}}, "1"},
  217. }
  218. versioning := meta.NewAccessor()
  219. for key, testCase := range testCases {
  220. actual, err := versioning.ResourceVersion(testCase.Object)
  221. if err != nil {
  222. t.Errorf("%s: unexpected error %#v", key, err)
  223. }
  224. if actual != testCase.Expected {
  225. t.Errorf("%s: expected %v, got %v", key, testCase.Expected, actual)
  226. }
  227. }
  228. failingCases := map[string]struct {
  229. runtime.Object
  230. Expected string
  231. }{
  232. "not a valid object to try": {&MyIncorrectlyMarkedAsAPIObject{}, "1"},
  233. }
  234. for key, testCase := range failingCases {
  235. _, err := versioning.ResourceVersion(testCase.Object)
  236. if err == nil {
  237. t.Errorf("%s: expected error, got nil", key)
  238. }
  239. }
  240. setCases := map[string]struct {
  241. runtime.Object
  242. Expected string
  243. }{
  244. "pointer to api object with version": {&MyAPIObject{TypeMeta: InternalTypeMeta{ResourceVersion: "1"}}, "1"},
  245. }
  246. for key, testCase := range setCases {
  247. if err := versioning.SetResourceVersion(testCase.Object, "5"); err != nil {
  248. t.Errorf("%s: unexpected error %#v", key, err)
  249. }
  250. actual, err := versioning.ResourceVersion(testCase.Object)
  251. if err != nil {
  252. t.Errorf("%s: unexpected error %#v", key, err)
  253. }
  254. if actual != "5" {
  255. t.Errorf("%s: expected %v, got %v", key, "5", actual)
  256. }
  257. }
  258. }
  259. func TestTypeMetaSelfLinker(t *testing.T) {
  260. table := map[string]struct {
  261. obj runtime.Object
  262. expect string
  263. try string
  264. succeed bool
  265. }{
  266. "normal": {
  267. obj: &MyAPIObject{TypeMeta: InternalTypeMeta{SelfLink: "foobar"}},
  268. expect: "foobar",
  269. try: "newbar",
  270. succeed: true,
  271. },
  272. "fail": {
  273. obj: &MyIncorrectlyMarkedAsAPIObject{},
  274. succeed: false,
  275. },
  276. }
  277. linker := runtime.SelfLinker(meta.NewAccessor())
  278. for name, item := range table {
  279. got, err := linker.SelfLink(item.obj)
  280. if e, a := item.succeed, err == nil; e != a {
  281. t.Errorf("%v: expected %v, got %v", name, e, a)
  282. }
  283. if e, a := item.expect, got; item.succeed && e != a {
  284. t.Errorf("%v: expected %v, got %v", name, e, a)
  285. }
  286. err = linker.SetSelfLink(item.obj, item.try)
  287. if e, a := item.succeed, err == nil; e != a {
  288. t.Errorf("%v: expected %v, got %v", name, e, a)
  289. }
  290. if item.succeed {
  291. got, err := linker.SelfLink(item.obj)
  292. if err != nil {
  293. t.Errorf("%v: expected no err, got %v", name, err)
  294. }
  295. if e, a := item.try, got; e != a {
  296. t.Errorf("%v: expected %v, got %v", name, e, a)
  297. }
  298. }
  299. }
  300. }
  301. type MyAPIObject2 struct {
  302. unversioned.TypeMeta
  303. v1.ObjectMeta
  304. }
  305. func getObjectMetaAndOwnerRefereneces() (myAPIObject2 MyAPIObject2, metaOwnerReferences []metatypes.OwnerReference) {
  306. fuzz.New().NilChance(.5).NumElements(1, 5).Fuzz(&myAPIObject2)
  307. references := myAPIObject2.ObjectMeta.OwnerReferences
  308. // This is necessary for the test to pass because the getter will return a
  309. // non-nil slice.
  310. metaOwnerReferences = make([]metatypes.OwnerReference, 0)
  311. for i := 0; i < len(references); i++ {
  312. metaOwnerReferences = append(metaOwnerReferences, metatypes.OwnerReference{
  313. Kind: references[i].Kind,
  314. Name: references[i].Name,
  315. UID: references[i].UID,
  316. APIVersion: references[i].APIVersion,
  317. Controller: references[i].Controller,
  318. })
  319. }
  320. if len(references) == 0 {
  321. // This is necessary for the test to pass because the setter will make a
  322. // non-nil slice.
  323. myAPIObject2.ObjectMeta.OwnerReferences = make([]v1.OwnerReference, 0)
  324. }
  325. return myAPIObject2, metaOwnerReferences
  326. }
  327. func testGetOwnerReferences(t *testing.T) {
  328. obj, expected := getObjectMetaAndOwnerRefereneces()
  329. accessor, err := meta.Accessor(&obj)
  330. if err != nil {
  331. t.Error(err)
  332. }
  333. references := accessor.GetOwnerReferences()
  334. if !reflect.DeepEqual(references, expected) {
  335. t.Errorf("expect %#v\n got %#v", expected, references)
  336. }
  337. }
  338. func testSetOwnerReferences(t *testing.T) {
  339. expected, references := getObjectMetaAndOwnerRefereneces()
  340. obj := MyAPIObject2{}
  341. accessor, err := meta.Accessor(&obj)
  342. if err != nil {
  343. t.Error(err)
  344. }
  345. accessor.SetOwnerReferences(references)
  346. if e, a := expected.ObjectMeta.OwnerReferences, obj.ObjectMeta.OwnerReferences; !reflect.DeepEqual(e, a) {
  347. t.Errorf("expect %#v\n got %#v", e, a)
  348. }
  349. }
  350. func TestAccessOwnerReferences(t *testing.T) {
  351. fuzzIter := 5
  352. for i := 0; i < fuzzIter; i++ {
  353. testGetOwnerReferences(t)
  354. testSetOwnerReferences(t)
  355. }
  356. }
  357. // BenchmarkAccessorSetFastPath shows the interface fast path
  358. func BenchmarkAccessorSetFastPath(b *testing.B) {
  359. obj := &api.Pod{
  360. TypeMeta: unversioned.TypeMeta{APIVersion: "/a", Kind: "b"},
  361. ObjectMeta: api.ObjectMeta{
  362. Namespace: "bar",
  363. Name: "foo",
  364. GenerateName: "prefix",
  365. UID: "uid",
  366. ResourceVersion: "1",
  367. SelfLink: "some/place/only/we/know",
  368. Labels: map[string]string{"foo": "bar"},
  369. Annotations: map[string]string{"x": "y"},
  370. },
  371. }
  372. b.ResetTimer()
  373. for i := 0; i < b.N; i++ {
  374. acc, err := meta.Accessor(obj)
  375. if err != nil {
  376. b.Fatal(err)
  377. }
  378. acc.SetNamespace("something")
  379. }
  380. b.StopTimer()
  381. }