k8s.io/apiserver@v0.31.1/pkg/admission/chain_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 admission 18 19 import ( 20 "context" 21 "fmt" 22 "testing" 23 24 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 25 "k8s.io/apimachinery/pkg/runtime" 26 "k8s.io/apimachinery/pkg/runtime/schema" 27 ) 28 29 type FakeHandler struct { 30 *Handler 31 name string 32 admit, admitCalled bool 33 validate, validateCalled bool 34 } 35 36 func (h *FakeHandler) Admit(ctx context.Context, a Attributes, o ObjectInterfaces) (err error) { 37 h.admitCalled = true 38 if h.admit { 39 return nil 40 } 41 return fmt.Errorf("Don't admit") 42 } 43 44 func (h *FakeHandler) Validate(ctx context.Context, a Attributes, o ObjectInterfaces) (err error) { 45 h.validateCalled = true 46 if h.validate { 47 return nil 48 } 49 return fmt.Errorf("Don't validate") 50 } 51 52 func makeHandler(name string, accept bool, ops ...Operation) *FakeHandler { 53 return &FakeHandler{ 54 name: name, 55 admit: accept, 56 validate: accept, 57 Handler: NewHandler(ops...), 58 } 59 } 60 61 func TestAdmitAndValidate(t *testing.T) { 62 sysns := metav1.NamespaceSystem 63 otherns := "default" 64 tests := []struct { 65 name string 66 ns string 67 operation Operation 68 options runtime.Object 69 chain chainAdmissionHandler 70 accept bool 71 calls map[string]bool 72 }{ 73 { 74 name: "all accept", 75 ns: sysns, 76 operation: Create, 77 options: &metav1.CreateOptions{}, 78 chain: []Interface{ 79 makeHandler("a", true, Update, Delete, Create), 80 makeHandler("b", true, Delete, Create), 81 makeHandler("c", true, Create), 82 }, 83 calls: map[string]bool{"a": true, "b": true, "c": true}, 84 accept: true, 85 }, 86 { 87 name: "ignore handler", 88 ns: otherns, 89 operation: Create, 90 options: &metav1.CreateOptions{}, 91 chain: []Interface{ 92 makeHandler("a", true, Update, Delete, Create), 93 makeHandler("b", false, Delete), 94 makeHandler("c", true, Create), 95 }, 96 calls: map[string]bool{"a": true, "c": true}, 97 accept: true, 98 }, 99 { 100 name: "ignore all", 101 ns: sysns, 102 operation: Connect, 103 options: nil, 104 chain: []Interface{ 105 makeHandler("a", true, Update, Delete, Create), 106 makeHandler("b", false, Delete), 107 makeHandler("c", true, Create), 108 }, 109 calls: map[string]bool{}, 110 accept: true, 111 }, 112 { 113 name: "reject one", 114 ns: otherns, 115 operation: Delete, 116 options: &metav1.DeleteOptions{}, 117 chain: []Interface{ 118 makeHandler("a", true, Update, Delete, Create), 119 makeHandler("b", false, Delete), 120 makeHandler("c", true, Create), 121 }, 122 calls: map[string]bool{"a": true, "b": true}, 123 accept: false, 124 }, 125 } 126 for _, test := range tests { 127 t.Logf("testcase = %s", test.name) 128 // call admit and check that validate was not called at all 129 err := test.chain.Admit(context.TODO(), NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, test.ns, "", schema.GroupVersionResource{}, "", test.operation, test.options, false, nil), nil) 130 accepted := (err == nil) 131 if accepted != test.accept { 132 t.Errorf("unexpected result of admit call: %v", accepted) 133 } 134 for _, h := range test.chain { 135 fake := h.(*FakeHandler) 136 _, shouldBeCalled := test.calls[fake.name] 137 if shouldBeCalled != fake.admitCalled { 138 t.Errorf("admit handler %s not called as expected: %v", fake.name, fake.admitCalled) 139 continue 140 } 141 if fake.validateCalled { 142 t.Errorf("validate handler %s called during admit", fake.name) 143 } 144 145 // reset value for validation test 146 fake.admitCalled = false 147 } 148 149 // call validate and check that admit was not called at all 150 err = test.chain.Validate(context.TODO(), NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, test.ns, "", schema.GroupVersionResource{}, "", test.operation, test.options, false, nil), nil) 151 accepted = (err == nil) 152 if accepted != test.accept { 153 t.Errorf("unexpected result of validate call: %v\n", accepted) 154 } 155 for _, h := range test.chain { 156 fake := h.(*FakeHandler) 157 158 _, shouldBeCalled := test.calls[fake.name] 159 if shouldBeCalled != fake.validateCalled { 160 t.Errorf("validate handler %s not called as expected: %v", fake.name, fake.validateCalled) 161 continue 162 } 163 164 if fake.admitCalled { 165 t.Errorf("mutating handler unexpectedly called: %s", fake.name) 166 } 167 } 168 } 169 } 170 171 func TestHandles(t *testing.T) { 172 chain := chainAdmissionHandler{ 173 makeHandler("a", true, Update, Delete, Create), 174 makeHandler("b", true, Delete, Create), 175 makeHandler("c", true, Create), 176 } 177 178 tests := []struct { 179 name string 180 operation Operation 181 chain chainAdmissionHandler 182 expected bool 183 }{ 184 { 185 name: "all handle", 186 operation: Create, 187 expected: true, 188 }, 189 { 190 name: "none handle", 191 operation: Connect, 192 expected: false, 193 }, 194 { 195 name: "some handle", 196 operation: Delete, 197 expected: true, 198 }, 199 } 200 for _, test := range tests { 201 handles := chain.Handles(test.operation) 202 if handles != test.expected { 203 t.Errorf("Unexpected handles result. Expected: %v. Actual: %v", test.expected, handles) 204 } 205 } 206 }