k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/cmd/kubeadm/app/util/marshal_test.go (about) 1 /* 2 Copyright 2017 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package util 18 19 import ( 20 "bytes" 21 "reflect" 22 "sort" 23 "testing" 24 25 corev1 "k8s.io/api/core/v1" 26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 "k8s.io/apimachinery/pkg/runtime/schema" 28 29 kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" 30 "k8s.io/kubernetes/cmd/kubeadm/app/constants" 31 ) 32 33 var files = map[string][]byte{ 34 "foo": []byte(` 35 kind: Foo 36 apiVersion: foo.k8s.io/v1 37 fooField: foo 38 `), 39 "bar": []byte(` 40 apiVersion: bar.k8s.io/v2 41 barField: bar 42 kind: Bar 43 `), 44 "baz": []byte(` 45 apiVersion: baz.k8s.io/v1 46 kind: Baz 47 baz: 48 foo: bar 49 `), 50 "nokind": []byte(` 51 apiVersion: baz.k8s.io/v1 52 foo: foo 53 bar: bar 54 `), 55 "noapiversion": []byte(` 56 kind: Bar 57 foo: foo 58 bar: bar 59 `), 60 } 61 62 func TestMarshalUnmarshalYaml(t *testing.T) { 63 pod := &corev1.Pod{ 64 ObjectMeta: metav1.ObjectMeta{ 65 Name: "someName", 66 Namespace: "testNamespace", 67 Labels: map[string]string{ 68 "test": "yes", 69 }, 70 }, 71 Spec: corev1.PodSpec{ 72 RestartPolicy: corev1.RestartPolicyAlways, 73 }, 74 } 75 76 bytes, err := MarshalToYaml(pod, corev1.SchemeGroupVersion) 77 if err != nil { 78 t.Fatalf("unexpected error marshalling: %v", err) 79 } 80 81 t.Logf("\n%s", bytes) 82 83 obj2, err := UniversalUnmarshal(bytes) 84 if err != nil { 85 t.Fatalf("unexpected error marshalling: %v", err) 86 } 87 88 pod2, ok := obj2.(*corev1.Pod) 89 if !ok { 90 t.Fatal("did not get a Pod") 91 } 92 93 if pod2.Name != pod.Name { 94 t.Errorf("expected %q, got %q", pod.Name, pod2.Name) 95 } 96 97 if pod2.Namespace != pod.Namespace { 98 t.Errorf("expected %q, got %q", pod.Namespace, pod2.Namespace) 99 } 100 101 if !reflect.DeepEqual(pod2.Labels, pod.Labels) { 102 t.Errorf("expected %v, got %v", pod.Labels, pod2.Labels) 103 } 104 105 if pod2.Spec.RestartPolicy != pod.Spec.RestartPolicy { 106 t.Errorf("expected %q, got %q", pod.Spec.RestartPolicy, pod2.Spec.RestartPolicy) 107 } 108 } 109 110 func TestUnmarshalJson(t *testing.T) { 111 bytes := []byte(string(`{ 112 "apiVersion": "v1", 113 "kind": "Pod", 114 "metadata": { 115 "name": "someName", 116 "namespace": "testNamespace", 117 "labels": { 118 "test": "yes" 119 } 120 }, 121 "spec": { 122 "restartPolicy": "Always" 123 } 124 }`)) 125 126 t.Logf("\n%s", bytes) 127 128 obj2, err := UniversalUnmarshal(bytes) 129 if err != nil { 130 t.Fatalf("unexpected error marshalling: %v", err) 131 } 132 133 pod2, ok := obj2.(*corev1.Pod) 134 if !ok { 135 t.Fatal("did not get a Pod") 136 } 137 138 if pod2.Name != "someName" { 139 t.Errorf("expected someName, got %q", pod2.Name) 140 } 141 142 if pod2.Namespace != "testNamespace" { 143 t.Errorf("expected testNamespace, got %q", pod2.Namespace) 144 } 145 146 if !reflect.DeepEqual(pod2.Labels, map[string]string{"test": "yes"}) { 147 t.Errorf("expected [test:yes], got %v", pod2.Labels) 148 } 149 150 if pod2.Spec.RestartPolicy != "Always" { 151 t.Errorf("expected Always, got %q", pod2.Spec.RestartPolicy) 152 } 153 } 154 155 func TestSplitYAMLDocuments(t *testing.T) { 156 var tests = []struct { 157 name string 158 fileContents []byte 159 gvkmap kubeadmapi.DocumentMap 160 expectedErr bool 161 }{ 162 { 163 name: "FooOnly", 164 fileContents: files["foo"], 165 gvkmap: kubeadmapi.DocumentMap{ 166 {Group: "foo.k8s.io", Version: "v1", Kind: "Foo"}: files["foo"], 167 }, 168 }, 169 { 170 name: "FooBar", 171 fileContents: bytes.Join([][]byte{files["foo"], files["bar"]}, []byte(constants.YAMLDocumentSeparator)), 172 gvkmap: kubeadmapi.DocumentMap{ 173 {Group: "foo.k8s.io", Version: "v1", Kind: "Foo"}: files["foo"], 174 {Group: "bar.k8s.io", Version: "v2", Kind: "Bar"}: files["bar"], 175 }, 176 }, 177 { 178 name: "FooTwiceInvalid", 179 fileContents: bytes.Join([][]byte{files["foo"], files["bar"], files["foo"]}, []byte(constants.YAMLDocumentSeparator)), 180 expectedErr: true, 181 }, 182 { 183 name: "InvalidBaz", 184 fileContents: bytes.Join([][]byte{files["foo"], files["baz"]}, []byte(constants.YAMLDocumentSeparator)), 185 expectedErr: true, 186 }, 187 { 188 name: "InvalidNoKind", 189 fileContents: files["nokind"], 190 expectedErr: true, 191 }, 192 { 193 name: "InvalidNoAPIVersion", 194 fileContents: files["noapiversion"], 195 expectedErr: true, 196 }, 197 } 198 199 for _, rt := range tests { 200 t.Run(rt.name, func(t2 *testing.T) { 201 202 gvkmap, err := SplitYAMLDocuments(rt.fileContents) 203 if (err != nil) != rt.expectedErr { 204 t2.Errorf("expected error: %t, actual: %t", rt.expectedErr, err != nil) 205 } 206 207 if !reflect.DeepEqual(gvkmap, rt.gvkmap) { 208 t2.Errorf("expected gvkmap: %s\n\tactual: %s\n", rt.gvkmap, gvkmap) 209 } 210 }) 211 } 212 } 213 214 func TestGroupVersionKindsFromBytes(t *testing.T) { 215 var tests = []struct { 216 name string 217 fileContents []byte 218 gvks []string 219 expectedErr bool 220 }{ 221 { 222 name: "FooOnly", 223 fileContents: files["foo"], 224 gvks: []string{ 225 "foo.k8s.io/v1, Kind=Foo", 226 }, 227 }, 228 { 229 name: "FooBar", 230 fileContents: bytes.Join([][]byte{files["foo"], files["bar"]}, []byte(constants.YAMLDocumentSeparator)), 231 gvks: []string{ 232 "foo.k8s.io/v1, Kind=Foo", 233 "bar.k8s.io/v2, Kind=Bar", 234 }, 235 }, 236 { 237 name: "FooTwiceInvalid", 238 fileContents: bytes.Join([][]byte{files["foo"], files["bar"], files["foo"]}, []byte(constants.YAMLDocumentSeparator)), 239 gvks: []string{}, 240 expectedErr: true, 241 }, 242 { 243 name: "InvalidBaz", 244 fileContents: bytes.Join([][]byte{files["foo"], files["baz"]}, []byte(constants.YAMLDocumentSeparator)), 245 gvks: []string{}, 246 expectedErr: true, 247 }, 248 { 249 name: "InvalidNoKind", 250 fileContents: files["nokind"], 251 gvks: []string{}, 252 expectedErr: true, 253 }, 254 { 255 name: "InvalidNoAPIVersion", 256 fileContents: files["noapiversion"], 257 gvks: []string{}, 258 expectedErr: true, 259 }, 260 } 261 262 for _, rt := range tests { 263 t.Run(rt.name, func(t2 *testing.T) { 264 265 gvks, err := GroupVersionKindsFromBytes(rt.fileContents) 266 if (err != nil) != rt.expectedErr { 267 t2.Errorf("expected error: %t, actual: %t", rt.expectedErr, err != nil) 268 } 269 270 strgvks := []string{} 271 for _, gvk := range gvks { 272 strgvks = append(strgvks, gvk.String()) 273 } 274 sort.Strings(strgvks) 275 sort.Strings(rt.gvks) 276 277 if !reflect.DeepEqual(strgvks, rt.gvks) { 278 t2.Errorf("expected gvks: %s\n\tactual: %s\n", rt.gvks, strgvks) 279 } 280 }) 281 } 282 } 283 284 func TestGroupVersionKindsHasKind(t *testing.T) { 285 var tests = []struct { 286 name string 287 gvks []schema.GroupVersionKind 288 kind string 289 expected bool 290 }{ 291 { 292 name: "FooOnly", 293 gvks: []schema.GroupVersionKind{ 294 {Group: "foo.k8s.io", Version: "v1", Kind: "Foo"}, 295 }, 296 kind: "Foo", 297 expected: true, 298 }, 299 { 300 name: "FooBar", 301 gvks: []schema.GroupVersionKind{ 302 {Group: "foo.k8s.io", Version: "v1", Kind: "Foo"}, 303 {Group: "bar.k8s.io", Version: "v2", Kind: "Bar"}, 304 }, 305 kind: "Bar", 306 expected: true, 307 }, 308 { 309 name: "FooBazNoBaz", 310 gvks: []schema.GroupVersionKind{ 311 {Group: "foo.k8s.io", Version: "v1", Kind: "Foo"}, 312 {Group: "bar.k8s.io", Version: "v2", Kind: "Bar"}, 313 }, 314 kind: "Baz", 315 expected: false, 316 }, 317 } 318 319 for _, rt := range tests { 320 t.Run(rt.name, func(t2 *testing.T) { 321 322 actual := GroupVersionKindsHasKind(rt.gvks, rt.kind) 323 if rt.expected != actual { 324 t2.Errorf("expected gvks has kind: %t\n\tactual: %t\n", rt.expected, actual) 325 } 326 }) 327 } 328 } 329 330 func TestGroupVersionKindsHasInitConfiguration(t *testing.T) { 331 var tests = []struct { 332 name string 333 gvks []schema.GroupVersionKind 334 kind string 335 expected bool 336 }{ 337 { 338 name: "NoInitConfiguration", 339 gvks: []schema.GroupVersionKind{ 340 {Group: "foo.k8s.io", Version: "v1", Kind: "Foo"}, 341 }, 342 expected: false, 343 }, 344 { 345 name: "InitConfigurationFound", 346 gvks: []schema.GroupVersionKind{ 347 {Group: "foo.k8s.io", Version: "v1", Kind: "Foo"}, 348 {Group: "bar.k8s.io", Version: "v2", Kind: "InitConfiguration"}, 349 }, 350 expected: true, 351 }, 352 } 353 354 for _, rt := range tests { 355 t.Run(rt.name, func(t2 *testing.T) { 356 357 actual := GroupVersionKindsHasInitConfiguration(rt.gvks...) 358 if rt.expected != actual { 359 t2.Errorf("expected gvks has InitConfiguration: %t\n\tactual: %t\n", rt.expected, actual) 360 } 361 }) 362 } 363 } 364 365 func TestGroupVersionKindsHasJoinConfiguration(t *testing.T) { 366 var tests = []struct { 367 name string 368 gvks []schema.GroupVersionKind 369 kind string 370 expected bool 371 }{ 372 { 373 name: "NoJoinConfiguration", 374 gvks: []schema.GroupVersionKind{ 375 {Group: "foo.k8s.io", Version: "v1", Kind: "Foo"}, 376 }, 377 expected: false, 378 }, 379 { 380 name: "JoinConfigurationFound", 381 gvks: []schema.GroupVersionKind{ 382 {Group: "foo.k8s.io", Version: "v1", Kind: "Foo"}, 383 {Group: "bar.k8s.io", Version: "v2", Kind: "JoinConfiguration"}, 384 }, 385 expected: true, 386 }, 387 } 388 389 for _, rt := range tests { 390 t.Run(rt.name, func(t2 *testing.T) { 391 392 actual := GroupVersionKindsHasJoinConfiguration(rt.gvks...) 393 if rt.expected != actual { 394 t2.Errorf("expected gvks has JoinConfiguration: %t\n\tactual: %t\n", rt.expected, actual) 395 } 396 }) 397 } 398 } 399 400 func TestGroupVersionKindsHasResetConfiguration(t *testing.T) { 401 var tests = []struct { 402 name string 403 gvks []schema.GroupVersionKind 404 kind string 405 expected bool 406 }{ 407 { 408 name: "NoResetConfiguration", 409 gvks: []schema.GroupVersionKind{ 410 {Group: "foo.k8s.io", Version: "v1", Kind: "Foo"}, 411 }, 412 expected: false, 413 }, 414 { 415 name: "ResetConfigurationFound", 416 gvks: []schema.GroupVersionKind{ 417 {Group: "foo.k8s.io", Version: "v1", Kind: "Foo"}, 418 {Group: "bar.k8s.io", Version: "v2", Kind: "ResetConfiguration"}, 419 }, 420 expected: true, 421 }, 422 } 423 424 for _, rt := range tests { 425 t.Run(rt.name, func(t2 *testing.T) { 426 427 actual := GroupVersionKindsHasResetConfiguration(rt.gvks...) 428 if rt.expected != actual { 429 t2.Errorf("expected gvks has ResetConfiguration: %t\n\tactual: %t\n", rt.expected, actual) 430 } 431 }) 432 } 433 } 434 435 func TestGroupVersionKindsHasClusterConfiguration(t *testing.T) { 436 tests := []struct { 437 name string 438 gvks []schema.GroupVersionKind 439 expected bool 440 }{ 441 { 442 name: "does not have ClusterConfiguraiton", 443 gvks: []schema.GroupVersionKind{ 444 {Group: "foo.k8s.io", Version: "v1", Kind: "Foo"}, 445 }, 446 expected: false, 447 }, 448 { 449 name: "has ClusterConfiguraiton", 450 gvks: []schema.GroupVersionKind{ 451 {Group: "foo.k8s.io", Version: "v1", Kind: "Foo"}, 452 {Group: "foo.k8s.io", Version: "v1", Kind: "ClusterConfiguration"}, 453 }, 454 expected: true, 455 }, 456 } 457 for _, rt := range tests { 458 t.Run(rt.name, func(t *testing.T) { 459 actual := GroupVersionKindsHasClusterConfiguration(rt.gvks...) 460 if rt.expected != actual { 461 t.Errorf("expected gvks to have a ClusterConfiguration: %t\n\tactual: %t\n", rt.expected, actual) 462 } 463 }) 464 } 465 } 466 467 func TestGroupVersionKindsHasUpgradeConfiguration(t *testing.T) { 468 var tests = []struct { 469 name string 470 gvks []schema.GroupVersionKind 471 kind string 472 expected bool 473 }{ 474 { 475 name: "no UpgradeConfiguration found", 476 gvks: []schema.GroupVersionKind{ 477 {Group: "foo.k8s.io", Version: "v1", Kind: "Foo"}, 478 }, 479 expected: false, 480 }, 481 { 482 name: "UpgradeConfiguration is found", 483 gvks: []schema.GroupVersionKind{ 484 {Group: "foo.k8s.io", Version: "v1", Kind: "Foo"}, 485 {Group: "bar.k8s.io", Version: "v2", Kind: "UpgradeConfiguration"}, 486 }, 487 expected: true, 488 }, 489 } 490 491 for _, rt := range tests { 492 t.Run(rt.name, func(t2 *testing.T) { 493 actual := GroupVersionKindsHasUpgradeConfiguration(rt.gvks...) 494 if rt.expected != actual { 495 t2.Errorf("expected gvks has UpgradeConfiguration: %t\n\tactual: %t\n", rt.expected, actual) 496 } 497 }) 498 } 499 }