marshal_test.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. /*
  2. Copyright 2017 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 util
  14. import (
  15. "bytes"
  16. "reflect"
  17. "sort"
  18. "testing"
  19. corev1 "k8s.io/api/core/v1"
  20. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  21. "k8s.io/apimachinery/pkg/runtime"
  22. "k8s.io/apimachinery/pkg/runtime/schema"
  23. "k8s.io/apimachinery/pkg/runtime/serializer"
  24. kubeadmapiv1beta2 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta2"
  25. "k8s.io/kubernetes/cmd/kubeadm/app/constants"
  26. )
  27. var files = map[string][]byte{
  28. "foo": []byte(`
  29. kind: Foo
  30. apiVersion: foo.k8s.io/v1
  31. fooField: foo
  32. `),
  33. "bar": []byte(`
  34. apiVersion: bar.k8s.io/v2
  35. barField: bar
  36. kind: Bar
  37. `),
  38. "baz": []byte(`
  39. apiVersion: baz.k8s.io/v1
  40. kind: Baz
  41. baz:
  42. foo: bar
  43. `),
  44. "nokind": []byte(`
  45. apiVersion: baz.k8s.io/v1
  46. foo: foo
  47. bar: bar
  48. `),
  49. "noapiversion": []byte(`
  50. kind: Bar
  51. foo: foo
  52. bar: bar
  53. `),
  54. }
  55. func TestMarshalUnmarshalYaml(t *testing.T) {
  56. pod := &corev1.Pod{
  57. ObjectMeta: metav1.ObjectMeta{
  58. Name: "someName",
  59. Namespace: "testNamespace",
  60. Labels: map[string]string{
  61. "test": "yes",
  62. },
  63. },
  64. Spec: corev1.PodSpec{
  65. RestartPolicy: corev1.RestartPolicyAlways,
  66. },
  67. }
  68. bytes, err := MarshalToYaml(pod, corev1.SchemeGroupVersion)
  69. if err != nil {
  70. t.Fatalf("unexpected error marshalling: %v", err)
  71. }
  72. t.Logf("\n%s", bytes)
  73. obj2, err := UnmarshalFromYaml(bytes, corev1.SchemeGroupVersion)
  74. if err != nil {
  75. t.Fatalf("unexpected error marshalling: %v", err)
  76. }
  77. pod2, ok := obj2.(*corev1.Pod)
  78. if !ok {
  79. t.Fatal("did not get a Pod")
  80. }
  81. if pod2.Name != pod.Name {
  82. t.Errorf("expected %q, got %q", pod.Name, pod2.Name)
  83. }
  84. if pod2.Namespace != pod.Namespace {
  85. t.Errorf("expected %q, got %q", pod.Namespace, pod2.Namespace)
  86. }
  87. if !reflect.DeepEqual(pod2.Labels, pod.Labels) {
  88. t.Errorf("expected %v, got %v", pod.Labels, pod2.Labels)
  89. }
  90. if pod2.Spec.RestartPolicy != pod.Spec.RestartPolicy {
  91. t.Errorf("expected %q, got %q", pod.Spec.RestartPolicy, pod2.Spec.RestartPolicy)
  92. }
  93. }
  94. func TestMarshalUnmarshalToYamlForCodecs(t *testing.T) {
  95. cfg := &kubeadmapiv1beta2.InitConfiguration{
  96. TypeMeta: metav1.TypeMeta{
  97. Kind: constants.InitConfigurationKind,
  98. APIVersion: kubeadmapiv1beta2.SchemeGroupVersion.String(),
  99. },
  100. NodeRegistration: kubeadmapiv1beta2.NodeRegistrationOptions{
  101. Name: "testNode",
  102. CRISocket: "/var/run/cri.sock",
  103. },
  104. BootstrapTokens: []kubeadmapiv1beta2.BootstrapToken{
  105. {
  106. Token: &kubeadmapiv1beta2.BootstrapTokenString{ID: "abcdef", Secret: "abcdef0123456789"},
  107. },
  108. },
  109. // NOTE: Using MarshalToYamlForCodecs and UnmarshalFromYamlForCodecs for ClusterConfiguration fields here won't work
  110. // by design. This is because we have a `json:"-"` annotation in order to avoid struct duplication. See the comment
  111. // at the kubeadmapiv1beta2.InitConfiguration definition.
  112. }
  113. kubeadmapiv1beta2.SetDefaults_InitConfiguration(cfg)
  114. scheme := runtime.NewScheme()
  115. if err := kubeadmapiv1beta2.AddToScheme(scheme); err != nil {
  116. t.Fatal(err)
  117. }
  118. codecs := serializer.NewCodecFactory(scheme)
  119. bytes, err := MarshalToYamlForCodecs(cfg, kubeadmapiv1beta2.SchemeGroupVersion, codecs)
  120. if err != nil {
  121. t.Fatalf("unexpected error marshalling InitConfiguration: %v", err)
  122. }
  123. t.Logf("\n%s", bytes)
  124. obj, err := UnmarshalFromYamlForCodecs(bytes, kubeadmapiv1beta2.SchemeGroupVersion, codecs)
  125. if err != nil {
  126. t.Fatalf("unexpected error unmarshalling InitConfiguration: %v", err)
  127. }
  128. cfg2, ok := obj.(*kubeadmapiv1beta2.InitConfiguration)
  129. if !ok || cfg2 == nil {
  130. t.Fatal("did not get InitConfiguration back")
  131. }
  132. if !reflect.DeepEqual(*cfg, *cfg2) {
  133. t.Errorf("expected %v, got %v", *cfg, *cfg2)
  134. }
  135. }
  136. func TestSplitYAMLDocuments(t *testing.T) {
  137. var tests = []struct {
  138. name string
  139. fileContents []byte
  140. gvkmap map[schema.GroupVersionKind][]byte
  141. expectedErr bool
  142. }{
  143. {
  144. name: "FooOnly",
  145. fileContents: files["foo"],
  146. gvkmap: map[schema.GroupVersionKind][]byte{
  147. {Group: "foo.k8s.io", Version: "v1", Kind: "Foo"}: files["foo"],
  148. },
  149. },
  150. {
  151. name: "FooBar",
  152. fileContents: bytes.Join([][]byte{files["foo"], files["bar"]}, []byte(constants.YAMLDocumentSeparator)),
  153. gvkmap: map[schema.GroupVersionKind][]byte{
  154. {Group: "foo.k8s.io", Version: "v1", Kind: "Foo"}: files["foo"],
  155. {Group: "bar.k8s.io", Version: "v2", Kind: "Bar"}: files["bar"],
  156. },
  157. },
  158. {
  159. name: "FooTwiceInvalid",
  160. fileContents: bytes.Join([][]byte{files["foo"], files["bar"], files["foo"]}, []byte(constants.YAMLDocumentSeparator)),
  161. expectedErr: true,
  162. },
  163. {
  164. name: "InvalidBaz",
  165. fileContents: bytes.Join([][]byte{files["foo"], files["baz"]}, []byte(constants.YAMLDocumentSeparator)),
  166. expectedErr: true,
  167. },
  168. {
  169. name: "InvalidNoKind",
  170. fileContents: files["nokind"],
  171. expectedErr: true,
  172. },
  173. {
  174. name: "InvalidNoAPIVersion",
  175. fileContents: files["noapiversion"],
  176. expectedErr: true,
  177. },
  178. }
  179. for _, rt := range tests {
  180. t.Run(rt.name, func(t2 *testing.T) {
  181. gvkmap, err := SplitYAMLDocuments(rt.fileContents)
  182. if (err != nil) != rt.expectedErr {
  183. t2.Errorf("expected error: %t, actual: %t", rt.expectedErr, err != nil)
  184. }
  185. if !reflect.DeepEqual(gvkmap, rt.gvkmap) {
  186. t2.Errorf("expected gvkmap: %s\n\tactual: %s\n", rt.gvkmap, gvkmap)
  187. }
  188. })
  189. }
  190. }
  191. func TestGroupVersionKindsFromBytes(t *testing.T) {
  192. var tests = []struct {
  193. name string
  194. fileContents []byte
  195. gvks []string
  196. expectedErr bool
  197. }{
  198. {
  199. name: "FooOnly",
  200. fileContents: files["foo"],
  201. gvks: []string{
  202. "foo.k8s.io/v1, Kind=Foo",
  203. },
  204. },
  205. {
  206. name: "FooBar",
  207. fileContents: bytes.Join([][]byte{files["foo"], files["bar"]}, []byte(constants.YAMLDocumentSeparator)),
  208. gvks: []string{
  209. "foo.k8s.io/v1, Kind=Foo",
  210. "bar.k8s.io/v2, Kind=Bar",
  211. },
  212. },
  213. {
  214. name: "FooTwiceInvalid",
  215. fileContents: bytes.Join([][]byte{files["foo"], files["bar"], files["foo"]}, []byte(constants.YAMLDocumentSeparator)),
  216. gvks: []string{},
  217. expectedErr: true,
  218. },
  219. {
  220. name: "InvalidBaz",
  221. fileContents: bytes.Join([][]byte{files["foo"], files["baz"]}, []byte(constants.YAMLDocumentSeparator)),
  222. gvks: []string{},
  223. expectedErr: true,
  224. },
  225. {
  226. name: "InvalidNoKind",
  227. fileContents: files["nokind"],
  228. gvks: []string{},
  229. expectedErr: true,
  230. },
  231. {
  232. name: "InvalidNoAPIVersion",
  233. fileContents: files["noapiversion"],
  234. gvks: []string{},
  235. expectedErr: true,
  236. },
  237. }
  238. for _, rt := range tests {
  239. t.Run(rt.name, func(t2 *testing.T) {
  240. gvks, err := GroupVersionKindsFromBytes(rt.fileContents)
  241. if (err != nil) != rt.expectedErr {
  242. t2.Errorf("expected error: %t, actual: %t", rt.expectedErr, err != nil)
  243. }
  244. strgvks := []string{}
  245. for _, gvk := range gvks {
  246. strgvks = append(strgvks, gvk.String())
  247. }
  248. sort.Strings(strgvks)
  249. sort.Strings(rt.gvks)
  250. if !reflect.DeepEqual(strgvks, rt.gvks) {
  251. t2.Errorf("expected gvks: %s\n\tactual: %s\n", rt.gvks, strgvks)
  252. }
  253. })
  254. }
  255. }
  256. func TestGroupVersionKindsHasKind(t *testing.T) {
  257. var tests = []struct {
  258. name string
  259. gvks []schema.GroupVersionKind
  260. kind string
  261. expected bool
  262. }{
  263. {
  264. name: "FooOnly",
  265. gvks: []schema.GroupVersionKind{
  266. {Group: "foo.k8s.io", Version: "v1", Kind: "Foo"},
  267. },
  268. kind: "Foo",
  269. expected: true,
  270. },
  271. {
  272. name: "FooBar",
  273. gvks: []schema.GroupVersionKind{
  274. {Group: "foo.k8s.io", Version: "v1", Kind: "Foo"},
  275. {Group: "bar.k8s.io", Version: "v2", Kind: "Bar"},
  276. },
  277. kind: "Bar",
  278. expected: true,
  279. },
  280. {
  281. name: "FooBazNoBaz",
  282. gvks: []schema.GroupVersionKind{
  283. {Group: "foo.k8s.io", Version: "v1", Kind: "Foo"},
  284. {Group: "bar.k8s.io", Version: "v2", Kind: "Bar"},
  285. },
  286. kind: "Baz",
  287. expected: false,
  288. },
  289. }
  290. for _, rt := range tests {
  291. t.Run(rt.name, func(t2 *testing.T) {
  292. actual := GroupVersionKindsHasKind(rt.gvks, rt.kind)
  293. if rt.expected != actual {
  294. t2.Errorf("expected gvks has kind: %t\n\tactual: %t\n", rt.expected, actual)
  295. }
  296. })
  297. }
  298. }
  299. func TestGroupVersionKindsHasInitConfiguration(t *testing.T) {
  300. var tests = []struct {
  301. name string
  302. gvks []schema.GroupVersionKind
  303. kind string
  304. expected bool
  305. }{
  306. {
  307. name: "NoInitConfiguration",
  308. gvks: []schema.GroupVersionKind{
  309. {Group: "foo.k8s.io", Version: "v1", Kind: "Foo"},
  310. },
  311. expected: false,
  312. },
  313. {
  314. name: "InitConfigurationFound",
  315. gvks: []schema.GroupVersionKind{
  316. {Group: "foo.k8s.io", Version: "v1", Kind: "Foo"},
  317. {Group: "bar.k8s.io", Version: "v2", Kind: "InitConfiguration"},
  318. },
  319. expected: true,
  320. },
  321. }
  322. for _, rt := range tests {
  323. t.Run(rt.name, func(t2 *testing.T) {
  324. actual := GroupVersionKindsHasInitConfiguration(rt.gvks...)
  325. if rt.expected != actual {
  326. t2.Errorf("expected gvks has InitConfiguration: %t\n\tactual: %t\n", rt.expected, actual)
  327. }
  328. })
  329. }
  330. }
  331. func TestGroupVersionKindsHasJoinConfiguration(t *testing.T) {
  332. var tests = []struct {
  333. name string
  334. gvks []schema.GroupVersionKind
  335. kind string
  336. expected bool
  337. }{
  338. {
  339. name: "NoJoinConfiguration",
  340. gvks: []schema.GroupVersionKind{
  341. {Group: "foo.k8s.io", Version: "v1", Kind: "Foo"},
  342. },
  343. expected: false,
  344. },
  345. {
  346. name: "JoinConfigurationFound",
  347. gvks: []schema.GroupVersionKind{
  348. {Group: "foo.k8s.io", Version: "v1", Kind: "Foo"},
  349. {Group: "bar.k8s.io", Version: "v2", Kind: "JoinConfiguration"},
  350. },
  351. expected: true,
  352. },
  353. }
  354. for _, rt := range tests {
  355. t.Run(rt.name, func(t2 *testing.T) {
  356. actual := GroupVersionKindsHasJoinConfiguration(rt.gvks...)
  357. if rt.expected != actual {
  358. t2.Errorf("expected gvks has JoinConfiguration: %t\n\tactual: %t\n", rt.expected, actual)
  359. }
  360. })
  361. }
  362. }