k8s.io/apiserver@v0.31.1/pkg/admission/plugin/policy/generic/policy_source_test.go (about) 1 /* 2 Copyright 2024 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 generic_test 18 19 import ( 20 "testing" 21 22 "github.com/stretchr/testify/require" 23 "k8s.io/api/admissionregistration/v1" 24 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 25 "k8s.io/apimachinery/pkg/runtime" 26 "k8s.io/apimachinery/pkg/types" 27 "k8s.io/apiserver/pkg/admission/plugin/policy/generic" 28 "k8s.io/apiserver/pkg/admission/plugin/policy/matching" 29 "k8s.io/apiserver/pkg/authorization/authorizer" 30 "k8s.io/client-go/tools/cache" 31 ) 32 33 func makeTestDispatcher(authorizer.Authorizer, *matching.Matcher) generic.Dispatcher[generic.PolicyHook[*FakePolicy, *FakeBinding, generic.Evaluator]] { 34 return nil 35 } 36 37 func TestPolicySourceHasSyncedEmpty(t *testing.T) { 38 testContext, testCancel, err := generic.NewPolicyTestContext( 39 func(fp *FakePolicy) generic.PolicyAccessor { return fp }, 40 func(fb *FakeBinding) generic.BindingAccessor { return fb }, 41 func(fp *FakePolicy) generic.Evaluator { return nil }, 42 makeTestDispatcher, 43 nil, 44 nil, 45 ) 46 require.NoError(t, err) 47 defer testCancel() 48 require.NoError(t, testContext.Start()) 49 50 // Should be able to wait for cache sync 51 require.True(t, cache.WaitForCacheSync(testContext.Done(), testContext.Source.HasSynced), "cache should sync after informer running") 52 } 53 54 func TestPolicySourceHasSyncedInitialList(t *testing.T) { 55 // Create a list of fake policies 56 initialObjects := []runtime.Object{ 57 &FakePolicy{ 58 ObjectMeta: metav1.ObjectMeta{ 59 Name: "policy1", 60 }, 61 }, 62 &FakeBinding{ 63 ObjectMeta: metav1.ObjectMeta{ 64 Name: "binding1", 65 }, 66 PolicyName: "policy1", 67 }, 68 } 69 70 testContext, testCancel, err := generic.NewPolicyTestContext( 71 func(fp *FakePolicy) generic.PolicyAccessor { return fp }, 72 func(fb *FakeBinding) generic.BindingAccessor { return fb }, 73 func(fp *FakePolicy) generic.Evaluator { return nil }, 74 makeTestDispatcher, 75 initialObjects, 76 nil, 77 ) 78 require.NoError(t, err) 79 defer testCancel() 80 require.NoError(t, testContext.Start()) 81 // Should be able to wait for cache sync 82 require.Len(t, testContext.Source.Hooks(), 1, "should have one policy") 83 require.NoError(t, testContext.UpdateAndWait( 84 &FakePolicy{ 85 ObjectMeta: metav1.ObjectMeta{ 86 Name: "policy2", 87 }, 88 }, 89 &FakeBinding{ 90 ObjectMeta: metav1.ObjectMeta{ 91 Name: "binding2", 92 }, 93 PolicyName: "policy2", 94 }, 95 )) 96 require.Len(t, testContext.Source.Hooks(), 2, "should have two policies") 97 require.NoError(t, testContext.UpdateAndWait( 98 &FakePolicy{ 99 ObjectMeta: metav1.ObjectMeta{ 100 Name: "policy3", 101 }, 102 }, 103 &FakeBinding{ 104 ObjectMeta: metav1.ObjectMeta{ 105 Name: "binding3", 106 }, 107 PolicyName: "policy3", 108 }, 109 &FakePolicy{ 110 ObjectMeta: metav1.ObjectMeta{ 111 Name: "policy2", 112 }, 113 ParamKind: &v1.ParamKind{ 114 APIVersion: "policy.example.com/v1", 115 Kind: "FakeParam", 116 }, 117 }, 118 )) 119 require.Len(t, testContext.Source.Hooks(), 3, "should have 3 policies") 120 121 } 122 123 func TestPolicySourceBindsToPolicies(t *testing.T) { 124 // Create a list of fake policies 125 initialObjects := []runtime.Object{ 126 &FakePolicy{ 127 ObjectMeta: metav1.ObjectMeta{ 128 Name: "policy1", 129 }, 130 }, 131 &FakeBinding{ 132 ObjectMeta: metav1.ObjectMeta{ 133 Name: "binding1", 134 }, 135 PolicyName: "policy1", 136 }, 137 } 138 139 testContext, testCancel, err := generic.NewPolicyTestContext( 140 func(fp *FakePolicy) generic.PolicyAccessor { return fp }, 141 func(fb *FakeBinding) generic.BindingAccessor { return fb }, 142 func(fp *FakePolicy) generic.Evaluator { return nil }, 143 makeTestDispatcher, 144 initialObjects, 145 nil, 146 ) 147 require.NoError(t, err) 148 defer testCancel() 149 require.NoError(t, testContext.Start()) 150 151 require.Len(t, testContext.Source.Hooks(), 1, "should have one policy") 152 require.Len(t, testContext.Source.Hooks()[0].Bindings, 1, "should have one binding") 153 require.Equal(t, "binding1", testContext.Source.Hooks()[0].Bindings[0].GetName(), "should have one binding") 154 155 // Change the binding to another policy (policies without bindings should 156 // be ignored, so it should remove the first 157 require.NoError(t, testContext.UpdateAndWait( 158 &FakePolicy{ 159 ObjectMeta: metav1.ObjectMeta{ 160 Name: "policy2", 161 }, 162 }, 163 &FakeBinding{ 164 ObjectMeta: metav1.ObjectMeta{ 165 Name: "binding1", 166 }, 167 PolicyName: "policy2", 168 })) 169 require.Len(t, testContext.Source.Hooks(), 1, "should have one policy") 170 require.Equal(t, "policy2", testContext.Source.Hooks()[0].Policy.GetName(), "policy name should be policy2") 171 require.Len(t, testContext.Source.Hooks()[0].Bindings, 1, "should have one binding") 172 require.Equal(t, "binding1", testContext.Source.Hooks()[0].Bindings[0].GetName(), "binding name should be binding1") 173 174 } 175 176 type FakePolicy struct { 177 metav1.TypeMeta 178 metav1.ObjectMeta 179 180 ParamKind *v1.ParamKind 181 } 182 183 var _ generic.PolicyAccessor = &FakePolicy{} 184 185 type FakeBinding struct { 186 metav1.TypeMeta 187 metav1.ObjectMeta 188 189 PolicyName string 190 } 191 192 var _ generic.BindingAccessor = &FakeBinding{} 193 194 func (fp *FakePolicy) GetName() string { 195 return fp.Name 196 } 197 198 func (fp *FakePolicy) GetNamespace() string { 199 return fp.Namespace 200 } 201 202 func (fp *FakePolicy) GetParamKind() *v1.ParamKind { 203 return fp.ParamKind 204 } 205 206 func (fb *FakePolicy) GetMatchConstraints() *v1.MatchResources { 207 return nil 208 } 209 210 func (fb *FakeBinding) GetName() string { 211 return fb.Name 212 } 213 214 func (fb *FakeBinding) GetNamespace() string { 215 return fb.Namespace 216 } 217 218 func (fb *FakeBinding) GetPolicyName() types.NamespacedName { 219 return types.NamespacedName{ 220 Name: fb.PolicyName, 221 } 222 } 223 224 func (fb *FakeBinding) GetMatchResources() *v1.MatchResources { 225 return nil 226 } 227 228 func (fb *FakeBinding) GetParamRef() *v1.ParamRef { 229 return nil 230 } 231 232 func (fp *FakePolicy) DeepCopyObject() runtime.Object { 233 // totally fudged deepcopy 234 newFP := &FakePolicy{} 235 *newFP = *fp 236 return newFP 237 } 238 239 func (fb *FakeBinding) DeepCopyObject() runtime.Object { 240 // totally fudged deepcopy 241 newFB := &FakeBinding{} 242 *newFB = *fb 243 return newFB 244 }