github.com/spotmaxtech/k8s-apimachinery-v0260@v0.0.1/pkg/test/apis_meta_v1_unstructed_unstructure_test.go (about) 1 /* 2 Copyright 2015 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 test 18 19 import ( 20 "fmt" 21 "reflect" 22 "strconv" 23 "strings" 24 "testing" 25 "time" 26 27 apitesting "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/api/apitesting" 28 metav1 "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/apis/meta/v1" 29 "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/apis/meta/v1/unstructured" 30 "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/apis/testapigroup" 31 "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/runtime" 32 "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/runtime/schema" 33 "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/types" 34 ) 35 36 func TestDecodeUnstructured(t *testing.T) { 37 groupVersionString := "v1" 38 rawJson := fmt.Sprintf(`{"kind":"Pod","apiVersion":"%s","metadata":{"name":"test"}}`, groupVersionString) 39 pl := &List{ 40 Items: []runtime.Object{ 41 &testapigroup.Carp{ObjectMeta: metav1.ObjectMeta{Name: "1"}}, 42 &runtime.Unknown{ 43 TypeMeta: runtime.TypeMeta{Kind: "Pod", APIVersion: groupVersionString}, 44 Raw: []byte(rawJson), 45 ContentType: runtime.ContentTypeJSON, 46 }, 47 &runtime.Unknown{ 48 TypeMeta: runtime.TypeMeta{Kind: "", APIVersion: groupVersionString}, 49 Raw: []byte(rawJson), 50 ContentType: runtime.ContentTypeJSON, 51 }, 52 &unstructured.Unstructured{ 53 Object: map[string]interface{}{ 54 "kind": "Foo", 55 "apiVersion": "Bar", 56 "test": "value", 57 }, 58 }, 59 }, 60 } 61 if errs := runtime.DecodeList(pl.Items, unstructured.UnstructuredJSONScheme); len(errs) == 1 { 62 t.Fatalf("unexpected error %v", errs) 63 } 64 if pod, ok := pl.Items[1].(*unstructured.Unstructured); !ok || pod.Object["kind"] != "Pod" || pod.Object["metadata"].(map[string]interface{})["name"] != "test" { 65 t.Errorf("object not converted: %#v", pl.Items[1]) 66 } 67 if pod, ok := pl.Items[2].(*unstructured.Unstructured); !ok || pod.Object["kind"] != "Pod" || pod.Object["metadata"].(map[string]interface{})["name"] != "test" { 68 t.Errorf("object not converted: %#v", pl.Items[2]) 69 } 70 } 71 72 func TestDecode(t *testing.T) { 73 tcs := []struct { 74 json []byte 75 want runtime.Object 76 }{ 77 { 78 json: []byte(`{"apiVersion": "test", "kind": "test_kind"}`), 79 want: &unstructured.Unstructured{ 80 Object: map[string]interface{}{"apiVersion": "test", "kind": "test_kind"}, 81 }, 82 }, 83 { 84 json: []byte(`{"apiVersion": "test", "kind": "test_list", "items": []}`), 85 want: &unstructured.UnstructuredList{ 86 Object: map[string]interface{}{"apiVersion": "test", "kind": "test_list"}, 87 Items: []unstructured.Unstructured{}, 88 }, 89 }, 90 { 91 json: []byte(`{"items": [{"metadata": {"name": "object1", "deletionGracePeriodSeconds": 10}, "apiVersion": "test", "kind": "test_kind"}, {"metadata": {"name": "object2"}, "apiVersion": "test", "kind": "test_kind"}], "apiVersion": "test", "kind": "test_list"}`), 92 want: &unstructured.UnstructuredList{ 93 Object: map[string]interface{}{"apiVersion": "test", "kind": "test_list"}, 94 Items: []unstructured.Unstructured{ 95 { 96 Object: map[string]interface{}{ 97 "metadata": map[string]interface{}{"name": "object1", "deletionGracePeriodSeconds": int64(10)}, 98 "apiVersion": "test", 99 "kind": "test_kind", 100 }, 101 }, 102 { 103 Object: map[string]interface{}{ 104 "metadata": map[string]interface{}{"name": "object2"}, 105 "apiVersion": "test", 106 "kind": "test_kind", 107 }, 108 }, 109 }, 110 }, 111 }, 112 } 113 114 for _, tc := range tcs { 115 got, _, err := unstructured.UnstructuredJSONScheme.Decode(tc.json, nil, nil) 116 if err != nil { 117 t.Errorf("Unexpected error for %q: %v", string(tc.json), err) 118 continue 119 } 120 121 if !reflect.DeepEqual(got, tc.want) { 122 t.Errorf("Decode(%q) want: %v\ngot: %v", string(tc.json), tc.want, got) 123 } 124 } 125 } 126 127 func TestUnstructuredGetters(t *testing.T) { 128 trueVar := true 129 ten := int64(10) 130 unstruct := unstructured.Unstructured{ 131 Object: map[string]interface{}{ 132 "kind": "test_kind", 133 "apiVersion": "test_version", 134 "metadata": map[string]interface{}{ 135 "name": "test_name", 136 "namespace": "test_namespace", 137 "generateName": "test_generateName", 138 "uid": "test_uid", 139 "resourceVersion": "test_resourceVersion", 140 "generation": ten, 141 "deletionGracePeriodSeconds": ten, 142 "selfLink": "test_selfLink", 143 "creationTimestamp": "2009-11-10T23:00:00Z", 144 "deletionTimestamp": "2010-11-10T23:00:00Z", 145 "labels": map[string]interface{}{ 146 "test_label": "test_value", 147 }, 148 "annotations": map[string]interface{}{ 149 "test_annotation": "test_value", 150 }, 151 "ownerReferences": []interface{}{ 152 map[string]interface{}{ 153 "kind": "Pod", 154 "name": "poda", 155 "apiVersion": "v1", 156 "uid": "1", 157 }, 158 map[string]interface{}{ 159 "kind": "Pod", 160 "name": "podb", 161 "apiVersion": "v1", 162 "uid": "2", 163 // though these fields are of type *bool, but when 164 // decoded from JSON, they are unmarshalled as bool. 165 "controller": true, 166 "blockOwnerDeletion": true, 167 }, 168 }, 169 "finalizers": []interface{}{ 170 "finalizer.1", 171 "finalizer.2", 172 }, 173 }, 174 }, 175 } 176 177 if got, want := unstruct.GetAPIVersion(), "test_version"; got != want { 178 t.Errorf("GetAPIVersions() = %s, want %s", got, want) 179 } 180 181 if got, want := unstruct.GetKind(), "test_kind"; got != want { 182 t.Errorf("GetKind() = %s, want %s", got, want) 183 } 184 185 if got, want := unstruct.GetNamespace(), "test_namespace"; got != want { 186 t.Errorf("GetNamespace() = %s, want %s", got, want) 187 } 188 189 if got, want := unstruct.GetName(), "test_name"; got != want { 190 t.Errorf("GetName() = %s, want %s", got, want) 191 } 192 193 if got, want := unstruct.GetGenerateName(), "test_generateName"; got != want { 194 t.Errorf("GetGenerateName() = %s, want %s", got, want) 195 } 196 197 if got, want := unstruct.GetUID(), types.UID("test_uid"); got != want { 198 t.Errorf("GetUID() = %s, want %s", got, want) 199 } 200 201 if got, want := unstruct.GetResourceVersion(), "test_resourceVersion"; got != want { 202 t.Errorf("GetResourceVersion() = %s, want %s", got, want) 203 } 204 205 if got, want := unstruct.GetSelfLink(), "test_selfLink"; got != want { 206 t.Errorf("GetSelfLink() = %s, want %s", got, want) 207 } 208 209 if got, want := unstruct.GetCreationTimestamp(), metav1.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC); !got.Equal(&want) { 210 t.Errorf("GetCreationTimestamp() = %s, want %s", got, want) 211 } 212 213 if got, want := unstruct.GetDeletionTimestamp(), metav1.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC); got == nil || !got.Equal(&want) { 214 t.Errorf("GetDeletionTimestamp() = %s, want %s", got, want) 215 } 216 217 if got, want := unstruct.GetLabels(), map[string]string{"test_label": "test_value"}; !reflect.DeepEqual(got, want) { 218 t.Errorf("GetLabels() = %s, want %s", got, want) 219 } 220 221 if got, want := unstruct.GetAnnotations(), map[string]string{"test_annotation": "test_value"}; !reflect.DeepEqual(got, want) { 222 t.Errorf("GetAnnotations() = %s, want %s", got, want) 223 } 224 refs := unstruct.GetOwnerReferences() 225 expectedOwnerReferences := []metav1.OwnerReference{ 226 { 227 Kind: "Pod", 228 Name: "poda", 229 APIVersion: "v1", 230 UID: "1", 231 }, 232 { 233 Kind: "Pod", 234 Name: "podb", 235 APIVersion: "v1", 236 UID: "2", 237 Controller: &trueVar, 238 BlockOwnerDeletion: &trueVar, 239 }, 240 } 241 if got, want := refs, expectedOwnerReferences; !reflect.DeepEqual(got, want) { 242 t.Errorf("GetOwnerReferences()=%v, want %v", got, want) 243 } 244 if got, want := unstruct.GetFinalizers(), []string{"finalizer.1", "finalizer.2"}; !reflect.DeepEqual(got, want) { 245 t.Errorf("GetFinalizers()=%v, want %v", got, want) 246 } 247 if got, want := unstruct.GetDeletionGracePeriodSeconds(), &ten; !reflect.DeepEqual(got, want) { 248 t.Errorf("GetDeletionGracePeriodSeconds()=%v, want %v", got, want) 249 } 250 if got, want := unstruct.GetGeneration(), ten; !reflect.DeepEqual(got, want) { 251 t.Errorf("GetGeneration()=%v, want %v", got, want) 252 } 253 } 254 255 func TestUnstructuredSetters(t *testing.T) { 256 unstruct := unstructured.Unstructured{} 257 trueVar := true 258 ten := int64(10) 259 260 want := unstructured.Unstructured{ 261 Object: map[string]interface{}{ 262 "kind": "test_kind", 263 "apiVersion": "test_version", 264 "metadata": map[string]interface{}{ 265 "name": "test_name", 266 "namespace": "test_namespace", 267 "generateName": "test_generateName", 268 "uid": "test_uid", 269 "resourceVersion": "test_resourceVersion", 270 "selfLink": "test_selfLink", 271 "creationTimestamp": "2009-11-10T23:00:00Z", 272 "deletionTimestamp": "2010-11-10T23:00:00Z", 273 "deletionGracePeriodSeconds": ten, 274 "generation": ten, 275 "labels": map[string]interface{}{ 276 "test_label": "test_value", 277 }, 278 "annotations": map[string]interface{}{ 279 "test_annotation": "test_value", 280 }, 281 "ownerReferences": []interface{}{ 282 map[string]interface{}{ 283 "kind": "Pod", 284 "name": "poda", 285 "apiVersion": "v1", 286 "uid": "1", 287 }, 288 map[string]interface{}{ 289 "kind": "Pod", 290 "name": "podb", 291 "apiVersion": "v1", 292 "uid": "2", 293 "controller": true, 294 "blockOwnerDeletion": true, 295 }, 296 }, 297 "finalizers": []interface{}{ 298 "finalizer.1", 299 "finalizer.2", 300 }, 301 }, 302 }, 303 } 304 305 unstruct.SetAPIVersion("test_version") 306 unstruct.SetKind("test_kind") 307 unstruct.SetNamespace("test_namespace") 308 unstruct.SetName("test_name") 309 unstruct.SetGenerateName("test_generateName") 310 unstruct.SetUID(types.UID("test_uid")) 311 unstruct.SetResourceVersion("test_resourceVersion") 312 unstruct.SetSelfLink("test_selfLink") 313 unstruct.SetCreationTimestamp(metav1.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)) 314 date := metav1.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC) 315 unstruct.SetDeletionTimestamp(&date) 316 unstruct.SetLabels(map[string]string{"test_label": "test_value"}) 317 unstruct.SetAnnotations(map[string]string{"test_annotation": "test_value"}) 318 newOwnerReferences := []metav1.OwnerReference{ 319 { 320 Kind: "Pod", 321 Name: "poda", 322 APIVersion: "v1", 323 UID: "1", 324 }, 325 { 326 Kind: "Pod", 327 Name: "podb", 328 APIVersion: "v1", 329 UID: "2", 330 Controller: &trueVar, 331 BlockOwnerDeletion: &trueVar, 332 }, 333 } 334 unstruct.SetOwnerReferences(newOwnerReferences) 335 unstruct.SetFinalizers([]string{"finalizer.1", "finalizer.2"}) 336 unstruct.SetDeletionGracePeriodSeconds(&ten) 337 unstruct.SetGeneration(ten) 338 339 if !reflect.DeepEqual(unstruct, want) { 340 t.Errorf("Wanted: \n%s\n Got:\n%s", want, unstruct) 341 } 342 } 343 344 func TestOwnerReferences(t *testing.T) { 345 t.Parallel() 346 trueVar := true 347 falseVar := false 348 refs := []metav1.OwnerReference{ 349 { 350 APIVersion: "v2", 351 Kind: "K2", 352 Name: "n2", 353 UID: types.UID("abc1"), 354 }, 355 { 356 APIVersion: "v1", 357 Kind: "K1", 358 Name: "n1", 359 UID: types.UID("abc2"), 360 Controller: &trueVar, 361 BlockOwnerDeletion: &falseVar, 362 }, 363 { 364 APIVersion: "v3", 365 Kind: "K3", 366 Name: "n3", 367 UID: types.UID("abc3"), 368 Controller: &falseVar, 369 BlockOwnerDeletion: &trueVar, 370 }, 371 } 372 for i, ref := range refs { 373 ref := ref 374 t.Run(strconv.Itoa(i), func(t *testing.T) { 375 t.Parallel() 376 u1 := unstructured.Unstructured{ 377 Object: make(map[string]interface{}), 378 } 379 refsX := []metav1.OwnerReference{ref} 380 u1.SetOwnerReferences(refsX) 381 382 have := u1.GetOwnerReferences() 383 if !reflect.DeepEqual(have, refsX) { 384 t.Errorf("Object references are not the same: %#v != %#v", have, refsX) 385 } 386 }) 387 } 388 } 389 390 func TestUnstructuredListGetters(t *testing.T) { 391 unstruct := unstructured.UnstructuredList{ 392 Object: map[string]interface{}{ 393 "kind": "test_kind", 394 "apiVersion": "test_version", 395 "metadata": map[string]interface{}{ 396 "resourceVersion": "test_resourceVersion", 397 "selfLink": "test_selfLink", 398 }, 399 }, 400 } 401 402 if got, want := unstruct.GetAPIVersion(), "test_version"; got != want { 403 t.Errorf("GetAPIVersions() = %s, want %s", got, want) 404 } 405 406 if got, want := unstruct.GetKind(), "test_kind"; got != want { 407 t.Errorf("GetKind() = %s, want %s", got, want) 408 } 409 410 if got, want := unstruct.GetResourceVersion(), "test_resourceVersion"; got != want { 411 t.Errorf("GetResourceVersion() = %s, want %s", got, want) 412 } 413 414 if got, want := unstruct.GetSelfLink(), "test_selfLink"; got != want { 415 t.Errorf("GetSelfLink() = %s, want %s", got, want) 416 } 417 } 418 419 func TestUnstructuredListSetters(t *testing.T) { 420 unstruct := unstructured.UnstructuredList{} 421 422 want := unstructured.UnstructuredList{ 423 Object: map[string]interface{}{ 424 "kind": "test_kind", 425 "apiVersion": "test_version", 426 "metadata": map[string]interface{}{ 427 "resourceVersion": "test_resourceVersion", 428 "selfLink": "test_selfLink", 429 }, 430 }, 431 } 432 433 unstruct.SetAPIVersion("test_version") 434 unstruct.SetKind("test_kind") 435 unstruct.SetResourceVersion("test_resourceVersion") 436 unstruct.SetSelfLink("test_selfLink") 437 438 if !reflect.DeepEqual(unstruct, want) { 439 t.Errorf("Wanted: \n%s\n Got:\n%s", unstruct, want) 440 } 441 } 442 443 func TestDecodeNumbers(t *testing.T) { 444 445 // Start with a valid pod 446 originalJSON := []byte(`{ 447 "kind":"Carp", 448 "apiVersion":"v1", 449 "metadata":{"name":"pod","namespace":"foo"}, 450 "spec":{ 451 "containers":[{"name":"container","image":"container"}], 452 "activeDeadlineSeconds":1000030003 453 } 454 }`) 455 456 pod := &testapigroup.Carp{} 457 458 _, codecs := TestScheme() 459 codec := apitesting.TestCodec(codecs, schema.GroupVersion{Group: "", Version: runtime.APIVersionInternal}) 460 461 err := runtime.DecodeInto(codec, originalJSON, pod) 462 if err != nil { 463 t.Fatalf("unexpected error: %v", err) 464 } 465 466 // Round-trip with unstructured codec 467 unstructuredObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, originalJSON) 468 if err != nil { 469 t.Fatalf("unexpected error: %v", err) 470 } 471 roundtripJSON, err := runtime.Encode(unstructured.UnstructuredJSONScheme, unstructuredObj) 472 if err != nil { 473 t.Fatalf("unexpected error: %v", err) 474 } 475 476 // Make sure we serialize back out in int form 477 if !strings.Contains(string(roundtripJSON), `"activeDeadlineSeconds":1000030003`) { 478 t.Errorf("Expected %s, got %s", `"activeDeadlineSeconds":1000030003`, string(roundtripJSON)) 479 } 480 481 // Decode with structured codec again 482 obj2, err := runtime.Decode(codec, roundtripJSON) 483 if err != nil { 484 t.Fatalf("unexpected error: %v", err) 485 } 486 // ensure pod is still valid 487 pod2, ok := obj2.(*testapigroup.Carp) 488 if !ok { 489 t.Fatalf("expected an *api.Pod, got %#v", obj2) 490 } 491 492 // ensure round-trip preserved large integers 493 if !reflect.DeepEqual(pod, pod2) { 494 t.Fatalf("Expected\n\t%#v, got \n\t%#v", pod, pod2) 495 } 496 } 497 498 // TestAccessorMethods does opaque roundtrip testing against an Unstructured 499 // instance's Object methods to ensure that what is "Set" matches what you 500 // subsequently "Get" without any assertions against internal state. 501 func TestAccessorMethods(t *testing.T) { 502 int64p := func(i int) *int64 { 503 v := int64(i) 504 return &v 505 } 506 tests := []struct { 507 accessor string 508 val interface{} 509 nilVal reflect.Value 510 }{ 511 {accessor: "Namespace", val: "foo"}, 512 {accessor: "Name", val: "bar"}, 513 {accessor: "GenerateName", val: "baz"}, 514 {accessor: "UID", val: types.UID("uid")}, 515 {accessor: "ResourceVersion", val: "1"}, 516 {accessor: "Generation", val: int64(5)}, 517 {accessor: "SelfLink", val: "/foo"}, 518 // TODO: Handle timestamps, which are being marshalled as UTC and 519 // unmarshalled as Local. 520 // https://github.com/kubernetes/kubernetes/issues/21402 521 // {accessor: "CreationTimestamp", val: someTime}, 522 // {accessor: "DeletionTimestamp", val: someTimeP}, 523 {accessor: "DeletionTimestamp", nilVal: reflect.ValueOf((*metav1.Time)(nil))}, 524 {accessor: "DeletionGracePeriodSeconds", val: int64p(10)}, 525 {accessor: "DeletionGracePeriodSeconds", val: int64p(0)}, 526 {accessor: "DeletionGracePeriodSeconds", nilVal: reflect.ValueOf((*int64)(nil))}, 527 {accessor: "Labels", val: map[string]string{"foo": "bar"}}, 528 {accessor: "Annotations", val: map[string]string{"foo": "bar"}}, 529 {accessor: "Finalizers", val: []string{"foo"}}, 530 {accessor: "OwnerReferences", val: []metav1.OwnerReference{{Name: "foo"}}}, 531 } 532 for i, test := range tests { 533 t.Logf("evaluating test %d (%s)", i, test.accessor) 534 535 u := &unstructured.Unstructured{} 536 setter := reflect.ValueOf(u).MethodByName("Set" + test.accessor) 537 getter := reflect.ValueOf(u).MethodByName("Get" + test.accessor) 538 539 args := []reflect.Value{} 540 if test.val != nil { 541 args = append(args, reflect.ValueOf(test.val)) 542 } else { 543 args = append(args, test.nilVal) 544 } 545 setter.Call(args) 546 547 ret := getter.Call([]reflect.Value{}) 548 actual := ret[0].Interface() 549 550 var expected interface{} 551 if test.val != nil { 552 expected = test.val 553 } else { 554 expected = test.nilVal.Interface() 555 } 556 557 if e, a := expected, actual; !reflect.DeepEqual(e, a) { 558 t.Fatalf("%s: expected %v (%T), got %v (%T)", test.accessor, e, e, a, a) 559 } 560 } 561 }