versioning_test.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. /*
  2. Copyright 2015 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 versioning
  14. import (
  15. "fmt"
  16. "io"
  17. "io/ioutil"
  18. "reflect"
  19. "testing"
  20. "k8s.io/kubernetes/pkg/api/unversioned"
  21. "k8s.io/kubernetes/pkg/runtime"
  22. "k8s.io/kubernetes/pkg/util/diff"
  23. )
  24. type testDecodable struct {
  25. Other string
  26. Value int `json:"value"`
  27. gvk unversioned.GroupVersionKind
  28. }
  29. func (d *testDecodable) GetObjectKind() unversioned.ObjectKind { return d }
  30. func (d *testDecodable) SetGroupVersionKind(gvk unversioned.GroupVersionKind) { d.gvk = gvk }
  31. func (d *testDecodable) GroupVersionKind() unversioned.GroupVersionKind { return d.gvk }
  32. type testNestedDecodable struct {
  33. Other string
  34. Value int `json:"value"`
  35. gvk unversioned.GroupVersionKind
  36. nestedCalled bool
  37. nestedErr error
  38. }
  39. func (d *testNestedDecodable) GetObjectKind() unversioned.ObjectKind { return d }
  40. func (d *testNestedDecodable) SetGroupVersionKind(gvk unversioned.GroupVersionKind) { d.gvk = gvk }
  41. func (d *testNestedDecodable) GroupVersionKind() unversioned.GroupVersionKind { return d.gvk }
  42. func (d *testNestedDecodable) EncodeNestedObjects(e runtime.Encoder) error {
  43. d.nestedCalled = true
  44. return d.nestedErr
  45. }
  46. func (d *testNestedDecodable) DecodeNestedObjects(_ runtime.Decoder) error {
  47. d.nestedCalled = true
  48. return d.nestedErr
  49. }
  50. func TestNestedDecode(t *testing.T) {
  51. n := &testNestedDecodable{nestedErr: fmt.Errorf("unable to decode")}
  52. decoder := &mockSerializer{obj: n}
  53. codec := NewCodec(nil, decoder, nil, nil, nil, nil, nil, nil)
  54. if _, _, err := codec.Decode([]byte(`{}`), nil, n); err != n.nestedErr {
  55. t.Errorf("unexpected error: %v", err)
  56. }
  57. if !n.nestedCalled {
  58. t.Errorf("did not invoke nested decoder")
  59. }
  60. }
  61. func TestNestedEncode(t *testing.T) {
  62. n := &testNestedDecodable{nestedErr: fmt.Errorf("unable to decode")}
  63. n2 := &testNestedDecodable{nestedErr: fmt.Errorf("unable to decode 2")}
  64. encoder := &mockSerializer{obj: n}
  65. codec := NewCodec(
  66. encoder, nil,
  67. &checkConvertor{obj: n2, groupVersion: unversioned.GroupVersion{Group: "other"}},
  68. nil, nil,
  69. &mockTyper{gvks: []unversioned.GroupVersionKind{{Kind: "test"}}},
  70. unversioned.GroupVersion{Group: "other"}, nil,
  71. )
  72. if err := codec.Encode(n, ioutil.Discard); err != n2.nestedErr {
  73. t.Errorf("unexpected error: %v", err)
  74. }
  75. if n.nestedCalled || !n2.nestedCalled {
  76. t.Errorf("did not invoke correct nested decoder")
  77. }
  78. }
  79. func TestDecode(t *testing.T) {
  80. gvk1 := &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}
  81. decodable1 := &testDecodable{}
  82. decodable2 := &testDecodable{}
  83. decodable3 := &testDecodable{}
  84. versionedDecodable1 := &runtime.VersionedObjects{Objects: []runtime.Object{decodable1}}
  85. testCases := []struct {
  86. serializer runtime.Serializer
  87. convertor runtime.ObjectConvertor
  88. creater runtime.ObjectCreater
  89. copier runtime.ObjectCopier
  90. typer runtime.ObjectTyper
  91. yaml bool
  92. pretty bool
  93. encodes, decodes runtime.GroupVersioner
  94. defaultGVK *unversioned.GroupVersionKind
  95. into runtime.Object
  96. errFn func(error) bool
  97. expectedObject runtime.Object
  98. sameObject runtime.Object
  99. expectedGVK *unversioned.GroupVersionKind
  100. }{
  101. {
  102. serializer: &mockSerializer{actual: gvk1},
  103. convertor: &checkConvertor{groupVersion: unversioned.GroupVersion{Group: "other", Version: "__internal"}},
  104. expectedGVK: gvk1,
  105. decodes: unversioned.GroupVersion{Group: "other", Version: "__internal"},
  106. },
  107. {
  108. serializer: &mockSerializer{actual: gvk1, obj: decodable1},
  109. convertor: &checkConvertor{in: decodable1, obj: decodable2, groupVersion: unversioned.GroupVersion{Group: "other", Version: "__internal"}},
  110. expectedGVK: gvk1,
  111. sameObject: decodable2,
  112. decodes: unversioned.GroupVersion{Group: "other", Version: "__internal"},
  113. },
  114. // defaultGVK.Group is allowed to force a conversion to the destination group
  115. {
  116. serializer: &mockSerializer{actual: gvk1, obj: decodable1},
  117. defaultGVK: &unversioned.GroupVersionKind{Group: "force"},
  118. convertor: &checkConvertor{in: decodable1, obj: decodable2, groupVersion: unversioned.GroupVersion{Group: "force", Version: "__internal"}},
  119. expectedGVK: gvk1,
  120. sameObject: decodable2,
  121. decodes: unversioned.GroupVersion{Group: "force", Version: "__internal"},
  122. },
  123. // uses direct conversion for into when objects differ
  124. {
  125. into: decodable3,
  126. serializer: &mockSerializer{actual: gvk1, obj: decodable1},
  127. convertor: &checkConvertor{in: decodable1, obj: decodable3, directConvert: true},
  128. expectedGVK: gvk1,
  129. sameObject: decodable3,
  130. },
  131. {
  132. into: versionedDecodable1,
  133. serializer: &mockSerializer{actual: gvk1, obj: decodable3},
  134. convertor: &checkConvertor{in: decodable3, obj: decodable1, directConvert: true},
  135. expectedGVK: gvk1,
  136. sameObject: versionedDecodable1,
  137. },
  138. // returns directly when serializer returns into
  139. {
  140. into: decodable3,
  141. serializer: &mockSerializer{actual: gvk1, obj: decodable3},
  142. expectedGVK: gvk1,
  143. sameObject: decodable3,
  144. },
  145. // returns directly when serializer returns into
  146. {
  147. into: versionedDecodable1,
  148. serializer: &mockSerializer{actual: gvk1, obj: decodable1},
  149. expectedGVK: gvk1,
  150. sameObject: versionedDecodable1,
  151. },
  152. // runtime.VersionedObjects are decoded
  153. {
  154. into: &runtime.VersionedObjects{Objects: []runtime.Object{}},
  155. serializer: &mockSerializer{actual: gvk1, obj: decodable1},
  156. copier: &checkCopy{in: decodable1, obj: decodable1},
  157. convertor: &checkConvertor{in: decodable1, obj: decodable2, groupVersion: unversioned.GroupVersion{Group: "other", Version: "__internal"}},
  158. expectedGVK: gvk1,
  159. expectedObject: &runtime.VersionedObjects{Objects: []runtime.Object{decodable1, decodable2}},
  160. decodes: unversioned.GroupVersion{Group: "other", Version: "__internal"},
  161. },
  162. {
  163. into: &runtime.VersionedObjects{Objects: []runtime.Object{}},
  164. serializer: &mockSerializer{actual: gvk1, obj: decodable1},
  165. copier: &checkCopy{in: decodable1, obj: nil, err: fmt.Errorf("error on copy")},
  166. convertor: &checkConvertor{in: decodable1, obj: decodable2, groupVersion: unversioned.GroupVersion{Group: "other", Version: "__internal"}},
  167. expectedGVK: gvk1,
  168. expectedObject: &runtime.VersionedObjects{Objects: []runtime.Object{decodable1, decodable2}},
  169. decodes: unversioned.GroupVersion{Group: "other", Version: "__internal"},
  170. },
  171. // decode into the same version as the serialized object
  172. {
  173. decodes: unversioned.GroupVersions{gvk1.GroupVersion()},
  174. serializer: &mockSerializer{actual: gvk1, obj: decodable1},
  175. convertor: &checkConvertor{in: decodable1, obj: decodable1, groupVersion: unversioned.GroupVersions{{Group: "other", Version: "blah"}}},
  176. expectedGVK: gvk1,
  177. expectedObject: decodable1,
  178. },
  179. {
  180. into: &runtime.VersionedObjects{Objects: []runtime.Object{}},
  181. decodes: unversioned.GroupVersions{gvk1.GroupVersion()},
  182. serializer: &mockSerializer{actual: gvk1, obj: decodable1},
  183. convertor: &checkConvertor{in: decodable1, obj: decodable1, groupVersion: unversioned.GroupVersions{{Group: "other", Version: "blah"}}},
  184. copier: &checkCopy{in: decodable1, obj: decodable1, err: nil},
  185. expectedGVK: gvk1,
  186. expectedObject: &runtime.VersionedObjects{Objects: []runtime.Object{decodable1}},
  187. },
  188. // codec with non matching version skips conversion altogether
  189. {
  190. decodes: unversioned.GroupVersions{{Group: "something", Version: "else"}},
  191. serializer: &mockSerializer{actual: gvk1, obj: decodable1},
  192. convertor: &checkConvertor{in: decodable1, obj: decodable1, groupVersion: unversioned.GroupVersions{{Group: "something", Version: "else"}}},
  193. expectedGVK: gvk1,
  194. expectedObject: decodable1,
  195. },
  196. {
  197. into: &runtime.VersionedObjects{Objects: []runtime.Object{}},
  198. decodes: unversioned.GroupVersions{{Group: "something", Version: "else"}},
  199. serializer: &mockSerializer{actual: gvk1, obj: decodable1},
  200. convertor: &checkConvertor{in: decodable1, obj: decodable1, groupVersion: unversioned.GroupVersions{{Group: "something", Version: "else"}}},
  201. copier: &checkCopy{in: decodable1, obj: decodable1, err: nil},
  202. expectedGVK: gvk1,
  203. expectedObject: &runtime.VersionedObjects{Objects: []runtime.Object{decodable1}},
  204. },
  205. }
  206. for i, test := range testCases {
  207. t.Logf("%d", i)
  208. s := NewCodec(test.serializer, test.serializer, test.convertor, test.creater, test.copier, test.typer, test.encodes, test.decodes)
  209. obj, gvk, err := s.Decode([]byte(`{}`), test.defaultGVK, test.into)
  210. if !reflect.DeepEqual(test.expectedGVK, gvk) {
  211. t.Errorf("%d: unexpected GVK: %v", i, gvk)
  212. }
  213. switch {
  214. case err == nil && test.errFn != nil:
  215. t.Errorf("%d: failed: %v", i, err)
  216. continue
  217. case err != nil && test.errFn == nil:
  218. t.Errorf("%d: failed: %v", i, err)
  219. continue
  220. case err != nil:
  221. if !test.errFn(err) {
  222. t.Errorf("%d: failed: %v", i, err)
  223. }
  224. if obj != nil {
  225. t.Errorf("%d: should have returned nil object", i)
  226. }
  227. continue
  228. }
  229. if test.into != nil && test.into != obj {
  230. t.Errorf("%d: expected into to be returned: %v", i, obj)
  231. continue
  232. }
  233. switch {
  234. case test.expectedObject != nil:
  235. if !reflect.DeepEqual(test.expectedObject, obj) {
  236. t.Errorf("%d: unexpected object:\n%s", i, diff.ObjectGoPrintSideBySide(test.expectedObject, obj))
  237. }
  238. case test.sameObject != nil:
  239. if test.sameObject != obj {
  240. t.Errorf("%d: unexpected object:\n%s", i, diff.ObjectGoPrintSideBySide(test.sameObject, obj))
  241. }
  242. case obj != nil:
  243. t.Errorf("%d: unexpected object: %#v", i, obj)
  244. }
  245. }
  246. }
  247. type checkCopy struct {
  248. in, obj runtime.Object
  249. err error
  250. }
  251. func (c *checkCopy) Copy(obj runtime.Object) (runtime.Object, error) {
  252. if c.in != nil && c.in != obj {
  253. return nil, fmt.Errorf("unexpected input to copy: %#v", obj)
  254. }
  255. return c.obj, c.err
  256. }
  257. type checkConvertor struct {
  258. err error
  259. in, obj runtime.Object
  260. groupVersion runtime.GroupVersioner
  261. directConvert bool
  262. }
  263. func (c *checkConvertor) Convert(in, out, context interface{}) error {
  264. if !c.directConvert {
  265. return fmt.Errorf("unexpected call to Convert")
  266. }
  267. if c.in != nil && c.in != in {
  268. return fmt.Errorf("unexpected in: %s", in)
  269. }
  270. if c.obj != nil && c.obj != out {
  271. return fmt.Errorf("unexpected out: %s", out)
  272. }
  273. return c.err
  274. }
  275. func (c *checkConvertor) ConvertToVersion(in runtime.Object, outVersion runtime.GroupVersioner) (out runtime.Object, err error) {
  276. if c.directConvert {
  277. return nil, fmt.Errorf("unexpected call to ConvertToVersion")
  278. }
  279. if c.in != nil && c.in != in {
  280. return nil, fmt.Errorf("unexpected in: %s", in)
  281. }
  282. if !reflect.DeepEqual(c.groupVersion, outVersion) {
  283. return nil, fmt.Errorf("unexpected outversion: %s (%s)", outVersion, c.groupVersion)
  284. }
  285. return c.obj, c.err
  286. }
  287. func (c *checkConvertor) ConvertFieldLabel(version, kind, label, value string) (string, string, error) {
  288. return "", "", fmt.Errorf("unexpected call to ConvertFieldLabel")
  289. }
  290. type mockSerializer struct {
  291. err error
  292. obj runtime.Object
  293. defaults, actual *unversioned.GroupVersionKind
  294. into runtime.Object
  295. }
  296. func (s *mockSerializer) Decode(data []byte, defaults *unversioned.GroupVersionKind, into runtime.Object) (runtime.Object, *unversioned.GroupVersionKind, error) {
  297. s.defaults = defaults
  298. s.into = into
  299. return s.obj, s.actual, s.err
  300. }
  301. func (s *mockSerializer) Encode(obj runtime.Object, w io.Writer) error {
  302. s.obj = obj
  303. return s.err
  304. }
  305. type mockCreater struct {
  306. err error
  307. obj runtime.Object
  308. }
  309. func (c *mockCreater) New(kind unversioned.GroupVersionKind) (runtime.Object, error) {
  310. return c.obj, c.err
  311. }
  312. type mockTyper struct {
  313. gvks []unversioned.GroupVersionKind
  314. unversioned bool
  315. err error
  316. }
  317. func (t *mockTyper) ObjectKinds(obj runtime.Object) ([]unversioned.GroupVersionKind, bool, error) {
  318. return t.gvks, t.unversioned, t.err
  319. }
  320. func (t *mockTyper) Recognizes(_ unversioned.GroupVersionKind) bool {
  321. return true
  322. }