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  }