json_test.go 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  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 json_test
  14. import (
  15. "fmt"
  16. "reflect"
  17. "strings"
  18. "testing"
  19. "k8s.io/kubernetes/pkg/api/unversioned"
  20. "k8s.io/kubernetes/pkg/runtime"
  21. "k8s.io/kubernetes/pkg/runtime/serializer/json"
  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. func TestDecode(t *testing.T) {
  33. testCases := []struct {
  34. creater runtime.ObjectCreater
  35. typer runtime.ObjectTyper
  36. yaml bool
  37. pretty bool
  38. data []byte
  39. defaultGVK *unversioned.GroupVersionKind
  40. into runtime.Object
  41. errFn func(error) bool
  42. expectedObject runtime.Object
  43. expectedGVK *unversioned.GroupVersionKind
  44. }{
  45. {
  46. data: []byte("{}"),
  47. expectedGVK: &unversioned.GroupVersionKind{},
  48. errFn: func(err error) bool { return strings.Contains(err.Error(), "Object 'Kind' is missing in") },
  49. },
  50. {
  51. data: []byte("{}"),
  52. defaultGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
  53. creater: &mockCreater{err: fmt.Errorf("fake error")},
  54. expectedGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
  55. errFn: func(err error) bool { return err.Error() == "fake error" },
  56. },
  57. {
  58. data: []byte("{}"),
  59. defaultGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
  60. creater: &mockCreater{err: fmt.Errorf("fake error")},
  61. expectedGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
  62. errFn: func(err error) bool { return err.Error() == "fake error" },
  63. },
  64. {
  65. data: []byte("{}"),
  66. defaultGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
  67. creater: &mockCreater{obj: &testDecodable{}},
  68. expectedObject: &testDecodable{},
  69. expectedGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
  70. },
  71. // version without group is not defaulted
  72. {
  73. data: []byte(`{"apiVersion":"blah"}`),
  74. defaultGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
  75. creater: &mockCreater{obj: &testDecodable{}},
  76. expectedObject: &testDecodable{},
  77. expectedGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "", Version: "blah"},
  78. },
  79. // group without version is defaulted
  80. {
  81. data: []byte(`{"apiVersion":"other/"}`),
  82. defaultGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
  83. creater: &mockCreater{obj: &testDecodable{}},
  84. expectedObject: &testDecodable{},
  85. expectedGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
  86. },
  87. // accept runtime.Unknown as into and bypass creator
  88. {
  89. data: []byte(`{}`),
  90. into: &runtime.Unknown{},
  91. expectedGVK: &unversioned.GroupVersionKind{},
  92. expectedObject: &runtime.Unknown{
  93. Raw: []byte(`{}`),
  94. ContentType: runtime.ContentTypeJSON,
  95. },
  96. },
  97. {
  98. data: []byte(`{"test":"object"}`),
  99. into: &runtime.Unknown{},
  100. expectedGVK: &unversioned.GroupVersionKind{},
  101. expectedObject: &runtime.Unknown{
  102. Raw: []byte(`{"test":"object"}`),
  103. ContentType: runtime.ContentTypeJSON,
  104. },
  105. },
  106. {
  107. data: []byte(`{"test":"object"}`),
  108. into: &runtime.Unknown{},
  109. defaultGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
  110. expectedGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
  111. expectedObject: &runtime.Unknown{
  112. TypeMeta: runtime.TypeMeta{APIVersion: "other/blah", Kind: "Test"},
  113. Raw: []byte(`{"test":"object"}`),
  114. ContentType: runtime.ContentTypeJSON,
  115. },
  116. },
  117. // unregistered objects can be decoded into directly
  118. {
  119. data: []byte(`{"kind":"Test","apiVersion":"other/blah","value":1,"Other":"test"}`),
  120. into: &testDecodable{},
  121. typer: &mockTyper{err: runtime.NewNotRegisteredErr(unversioned.GroupVersionKind{}, nil)},
  122. expectedGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
  123. expectedObject: &testDecodable{
  124. Other: "test",
  125. Value: 1,
  126. },
  127. },
  128. // registered types get defaulted by the into object kind
  129. {
  130. data: []byte(`{"value":1,"Other":"test"}`),
  131. into: &testDecodable{},
  132. typer: &mockTyper{gvk: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}},
  133. expectedGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
  134. expectedObject: &testDecodable{
  135. Other: "test",
  136. Value: 1,
  137. },
  138. },
  139. // registered types get defaulted by the into object kind even without version, but return an error
  140. {
  141. data: []byte(`{"value":1,"Other":"test"}`),
  142. into: &testDecodable{},
  143. typer: &mockTyper{gvk: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: ""}},
  144. expectedGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: ""},
  145. errFn: func(err error) bool { return strings.Contains(err.Error(), "Object 'apiVersion' is missing in") },
  146. expectedObject: &testDecodable{
  147. Other: "test",
  148. Value: 1,
  149. },
  150. },
  151. // runtime.VersionedObjects are decoded
  152. {
  153. data: []byte(`{"value":1,"Other":"test"}`),
  154. into: &runtime.VersionedObjects{Objects: []runtime.Object{}},
  155. creater: &mockCreater{obj: &testDecodable{}},
  156. typer: &mockTyper{gvk: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}},
  157. defaultGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
  158. expectedGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
  159. expectedObject: &runtime.VersionedObjects{
  160. Objects: []runtime.Object{
  161. &testDecodable{
  162. Other: "test",
  163. Value: 1,
  164. },
  165. },
  166. },
  167. },
  168. // runtime.VersionedObjects with an object are decoded into
  169. {
  170. data: []byte(`{"Other":"test"}`),
  171. into: &runtime.VersionedObjects{Objects: []runtime.Object{&testDecodable{Value: 2}}},
  172. typer: &mockTyper{gvk: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}},
  173. expectedGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
  174. expectedObject: &runtime.VersionedObjects{
  175. Objects: []runtime.Object{
  176. &testDecodable{
  177. Other: "test",
  178. Value: 2,
  179. },
  180. },
  181. },
  182. },
  183. }
  184. for i, test := range testCases {
  185. var s runtime.Serializer
  186. if test.yaml {
  187. s = json.NewYAMLSerializer(json.DefaultMetaFactory, test.creater, test.typer)
  188. } else {
  189. s = json.NewSerializer(json.DefaultMetaFactory, test.creater, test.typer, test.pretty)
  190. }
  191. obj, gvk, err := s.Decode([]byte(test.data), test.defaultGVK, test.into)
  192. if !reflect.DeepEqual(test.expectedGVK, gvk) {
  193. t.Errorf("%d: unexpected GVK: %v", i, gvk)
  194. }
  195. switch {
  196. case err == nil && test.errFn != nil:
  197. t.Errorf("%d: failed: %v", i, err)
  198. continue
  199. case err != nil && test.errFn == nil:
  200. t.Errorf("%d: failed: %v", i, err)
  201. continue
  202. case err != nil:
  203. if !test.errFn(err) {
  204. t.Errorf("%d: failed: %v", i, err)
  205. }
  206. if obj != nil {
  207. t.Errorf("%d: should have returned nil object", i)
  208. }
  209. continue
  210. }
  211. if test.into != nil && test.into != obj {
  212. t.Errorf("%d: expected into to be returned: %v", i, obj)
  213. continue
  214. }
  215. if !reflect.DeepEqual(test.expectedObject, obj) {
  216. t.Errorf("%d: unexpected object:\n%s", i, diff.ObjectGoPrintSideBySide(test.expectedObject, obj))
  217. }
  218. }
  219. }
  220. type mockCreater struct {
  221. apiVersion string
  222. kind string
  223. err error
  224. obj runtime.Object
  225. }
  226. func (c *mockCreater) New(kind unversioned.GroupVersionKind) (runtime.Object, error) {
  227. c.apiVersion, c.kind = kind.GroupVersion().String(), kind.Kind
  228. return c.obj, c.err
  229. }
  230. type mockTyper struct {
  231. gvk *unversioned.GroupVersionKind
  232. err error
  233. }
  234. func (t *mockTyper) ObjectKinds(obj runtime.Object) ([]unversioned.GroupVersionKind, bool, error) {
  235. if t.gvk == nil {
  236. return nil, false, t.err
  237. }
  238. return []unversioned.GroupVersionKind{*t.gvk}, false, t.err
  239. }
  240. func (t *mockTyper) Recognizes(_ unversioned.GroupVersionKind) bool {
  241. return false
  242. }