marshal_test.go 10 KB

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