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  }