diff --git a/test/images/agnhost/webhook/BUILD b/test/images/agnhost/webhook/BUILD index 5e2c0995e78..84959a2d627 100644 --- a/test/images/agnhost/webhook/BUILD +++ b/test/images/agnhost/webhook/BUILD @@ -46,11 +46,17 @@ filegroup( go_test( name = "go_default_test", - srcs = ["patch_test.go"], + srcs = [ + "addlabel_test.go", + "patch_test.go", + ], embed = [":go_default_library"], deps = [ + "//staging/src/k8s.io/api/admission/v1beta1:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", "//vendor/github.com/evanphx/json-patch:go_default_library", ], ) diff --git a/test/images/agnhost/webhook/addlabel.go b/test/images/agnhost/webhook/addlabel.go index 7dec62b771f..6e61625a96c 100644 --- a/test/images/agnhost/webhook/addlabel.go +++ b/test/images/agnhost/webhook/addlabel.go @@ -31,14 +31,16 @@ const ( addAdditionalLabelPatch string = `[ { "op": "add", "path": "/metadata/labels/added-label", "value": "yes" } ]` + updateLabelPatch string = `[ + { "op": "replace", "path": "/metadata/labels/added-label", "value": "yes" } + ]` ) // Add a label {"added-label": "yes"} to the object func addLabel(ar v1beta1.AdmissionReview) *v1beta1.AdmissionResponse { klog.V(2).Info("calling add-label") obj := struct { - metav1.ObjectMeta - Data map[string]string + metav1.ObjectMeta `json:"metadata,omitempty"` }{} raw := ar.Request.Object.Raw err := json.Unmarshal(raw, &obj) @@ -49,12 +51,21 @@ func addLabel(ar v1beta1.AdmissionReview) *v1beta1.AdmissionResponse { reviewResponse := v1beta1.AdmissionResponse{} reviewResponse.Allowed = true - if len(obj.ObjectMeta.Labels) == 0 { - reviewResponse.Patch = []byte(addFirstLabelPatch) - } else { - reviewResponse.Patch = []byte(addAdditionalLabelPatch) - } + pt := v1beta1.PatchTypeJSONPatch - reviewResponse.PatchType = &pt + labelValue, hasLabel := obj.ObjectMeta.Labels["added-label"] + switch { + case len(obj.ObjectMeta.Labels) == 0: + reviewResponse.Patch = []byte(addFirstLabelPatch) + reviewResponse.PatchType = &pt + case !hasLabel: + reviewResponse.Patch = []byte(addAdditionalLabelPatch) + reviewResponse.PatchType = &pt + case labelValue != "yes": + reviewResponse.Patch = []byte(updateLabelPatch) + reviewResponse.PatchType = &pt + default: + // already set + } return &reviewResponse } diff --git a/test/images/agnhost/webhook/addlabel_test.go b/test/images/agnhost/webhook/addlabel_test.go new file mode 100644 index 00000000000..08a6dbdabc9 --- /dev/null +++ b/test/images/agnhost/webhook/addlabel_test.go @@ -0,0 +1,86 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package webhook + +import ( + "encoding/json" + "reflect" + "testing" + + jsonpatch "github.com/evanphx/json-patch" + "k8s.io/api/admission/v1beta1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +func TestAddLabel(t *testing.T) { + testCases := []struct { + name string + initialLabels map[string]string + expectedLabels map[string]string + }{ + { + name: "add first label", + initialLabels: nil, + expectedLabels: map[string]string{"added-label": "yes"}, + }, + { + name: "add second label", + initialLabels: map[string]string{"other-label": "yes"}, + expectedLabels: map[string]string{"other-label": "yes", "added-label": "yes"}, + }, + { + name: "idempotent update label", + initialLabels: map[string]string{"added-label": "yes"}, + expectedLabels: map[string]string{"added-label": "yes"}, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + request := corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Labels: tc.initialLabels}} + raw, err := json.Marshal(request) + if err != nil { + t.Fatal(err) + } + review := v1beta1.AdmissionReview{Request: &v1beta1.AdmissionRequest{Object: runtime.RawExtension{Raw: raw}}} + response := addLabel(review) + if response.Patch != nil { + patchObj, err := jsonpatch.DecodePatch([]byte(response.Patch)) + if err != nil { + t.Fatal(err) + } + raw, err = patchObj.Apply(raw) + if err != nil { + t.Fatal(err) + } + } + + objType := reflect.TypeOf(request) + objTest := reflect.New(objType).Interface() + err = json.Unmarshal(raw, objTest) + if err != nil { + t.Fatal(err) + } + actual := objTest.(*corev1.ConfigMap) + if !reflect.DeepEqual(actual.Labels, tc.expectedLabels) { + t.Errorf("\nexpected %#v, got %#v, patch: %v", actual.Labels, tc.expectedLabels, string(response.Patch)) + } + }) + } +}