k8s.io/kubernetes@v1.29.3/test/images/agnhost/webhook/patch_test.go (about)

     1  /*
     2  Copyright 2018 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 webhook
    18  
    19  import (
    20  	"encoding/json"
    21  	"fmt"
    22  	"reflect"
    23  	"testing"
    24  
    25  	jsonpatch "github.com/evanphx/json-patch"
    26  	corev1 "k8s.io/api/core/v1"
    27  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    28  )
    29  
    30  func TestPatches(t *testing.T) {
    31  	sidecarImage = "test-image"
    32  	testCases := []struct {
    33  		patch    string
    34  		initial  interface{}
    35  		expected interface{}
    36  		toTest   interface{}
    37  	}{
    38  		{
    39  			patch: configMapPatch1,
    40  			initial: corev1.ConfigMap{
    41  				Data: map[string]string{
    42  					"mutation-start": "yes",
    43  				},
    44  			},
    45  			expected: &corev1.ConfigMap{
    46  				Data: map[string]string{
    47  					"mutation-start":   "yes",
    48  					"mutation-stage-1": "yes",
    49  				},
    50  			},
    51  		},
    52  		{
    53  			patch: configMapPatch2,
    54  			initial: corev1.ConfigMap{
    55  				Data: map[string]string{
    56  					"mutation-start": "yes",
    57  				},
    58  			},
    59  			expected: &corev1.ConfigMap{
    60  				Data: map[string]string{
    61  					"mutation-start":   "yes",
    62  					"mutation-stage-2": "yes",
    63  				},
    64  			},
    65  		},
    66  
    67  		{
    68  			patch: podsInitContainerPatch,
    69  			initial: corev1.Pod{
    70  				Spec: corev1.PodSpec{
    71  					InitContainers: []corev1.Container{},
    72  				},
    73  			},
    74  			expected: &corev1.Pod{
    75  				Spec: corev1.PodSpec{
    76  					InitContainers: []corev1.Container{
    77  						{
    78  							Image:     "webhook-added-image",
    79  							Name:      "webhook-added-init-container",
    80  							Resources: corev1.ResourceRequirements{},
    81  						},
    82  					},
    83  				},
    84  			},
    85  		},
    86  		{
    87  			patch: fmt.Sprintf(podsSidecarPatch, sidecarImage),
    88  			initial: corev1.Pod{
    89  				Spec: corev1.PodSpec{
    90  					Containers: []corev1.Container{
    91  						{
    92  							Image:     "image1",
    93  							Name:      "container1",
    94  							Resources: corev1.ResourceRequirements{},
    95  						},
    96  					},
    97  				},
    98  			},
    99  			expected: &corev1.Pod{
   100  				Spec: corev1.PodSpec{
   101  					Containers: []corev1.Container{
   102  						{
   103  							Image:     "image1",
   104  							Name:      "container1",
   105  							Resources: corev1.ResourceRequirements{},
   106  						},
   107  						{
   108  							Image:     sidecarImage,
   109  							Name:      "webhook-added-sidecar",
   110  							Resources: corev1.ResourceRequirements{},
   111  						},
   112  					},
   113  				},
   114  			},
   115  		},
   116  	}
   117  	for _, testcase := range testCases {
   118  		objJS, err := json.Marshal(testcase.initial)
   119  		if err != nil {
   120  			t.Fatal(err)
   121  		}
   122  		patchObj, err := jsonpatch.DecodePatch([]byte(testcase.patch))
   123  		if err != nil {
   124  			t.Fatal(err)
   125  		}
   126  
   127  		patchedJS, err := patchObj.Apply(objJS)
   128  		if err != nil {
   129  			t.Fatal(err)
   130  		}
   131  		objType := reflect.TypeOf(testcase.initial)
   132  		objTest := reflect.New(objType).Interface()
   133  		err = json.Unmarshal(patchedJS, objTest)
   134  		if err != nil {
   135  			t.Fatal(err)
   136  		}
   137  		if !reflect.DeepEqual(objTest, testcase.expected) {
   138  			t.Errorf("\nexpected %#v\n, got %#v", testcase.expected, objTest)
   139  		}
   140  	}
   141  
   142  }
   143  
   144  func TestJSONPatchForUnstructured(t *testing.T) {
   145  	cr := &unstructured.Unstructured{
   146  		Object: map[string]interface{}{
   147  			"kind":       "Something",
   148  			"apiVersion": "somegroup/v1",
   149  			"data": map[string]interface{}{
   150  				"mutation-start": "yes",
   151  			},
   152  		},
   153  	}
   154  	crJS, err := json.Marshal(cr)
   155  	if err != nil {
   156  		t.Fatal(err)
   157  	}
   158  
   159  	patchObj, err := jsonpatch.DecodePatch([]byte(configMapPatch1))
   160  	if err != nil {
   161  		t.Fatal(err)
   162  	}
   163  	patchedJS, err := patchObj.Apply(crJS)
   164  	if err != nil {
   165  		t.Fatal(err)
   166  	}
   167  	patchedObj := unstructured.Unstructured{}
   168  	err = json.Unmarshal(patchedJS, &patchedObj)
   169  	if err != nil {
   170  		t.Fatal(err)
   171  	}
   172  	expectedData := map[string]interface{}{
   173  		"mutation-start":   "yes",
   174  		"mutation-stage-1": "yes",
   175  	}
   176  
   177  	if !reflect.DeepEqual(patchedObj.Object["data"], expectedData) {
   178  		t.Errorf("\nexpected %#v\n, got %#v", expectedData, patchedObj.Object["data"])
   179  	}
   180  }