k8s.io/apiserver@v0.31.1/pkg/cel/openapi/maplist_test.go (about) 1 /* 2 Copyright 2022 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 openapi 18 19 import ( 20 "reflect" 21 "testing" 22 23 "k8s.io/kube-openapi/pkg/validation/spec" 24 ) 25 26 func TestMapList(t *testing.T) { 27 for _, tc := range []struct { 28 name string 29 sts *spec.Schema 30 items []interface{} 31 warmUpQueries []interface{} 32 query interface{} 33 expected interface{} 34 }{ 35 { 36 name: "default list type", 37 sts: &spec.Schema{ 38 SchemaProps: spec.SchemaProps{ 39 Type: []string{"array"}, 40 }}, 41 query: map[string]interface{}{}, 42 expected: nil, 43 }, 44 { 45 name: "non list type", 46 sts: &spec.Schema{ 47 SchemaProps: spec.SchemaProps{ 48 Type: []string{"map"}, 49 }}, 50 query: map[string]interface{}{}, 51 expected: nil, 52 }, 53 { 54 name: "non-map list type", 55 sts: &spec.Schema{ 56 SchemaProps: spec.SchemaProps{ 57 Type: []string{"array"}, 58 }, 59 VendorExtensible: spec.VendorExtensible{Extensions: map[string]interface{}{ 60 extListType: listTypeSet, 61 }}}, 62 query: map[string]interface{}{}, 63 expected: nil, 64 }, 65 { 66 name: "no keys", 67 sts: &spec.Schema{ 68 SchemaProps: spec.SchemaProps{ 69 Type: []string{"array"}, 70 }}, 71 query: map[string]interface{}{}, 72 expected: nil, 73 }, 74 { 75 name: "single key", 76 sts: &spec.Schema{ 77 SchemaProps: spec.SchemaProps{ 78 Type: []string{"array"}, 79 }, 80 VendorExtensible: spec.VendorExtensible{Extensions: map[string]interface{}{ 81 extListType: listTypeMap, 82 extListMapKeys: []any{"k"}, 83 }}}, 84 items: []interface{}{ 85 map[string]interface{}{ 86 "k": "a", 87 "v1": "a", 88 }, 89 map[string]interface{}{ 90 "k": "b", 91 "v1": "b", 92 }, 93 }, 94 query: map[string]interface{}{ 95 "k": "b", 96 "v1": "B", 97 }, 98 expected: map[string]interface{}{ 99 "k": "b", 100 "v1": "b", 101 }, 102 }, 103 { 104 name: "single key ignoring non-map query", 105 sts: &spec.Schema{ 106 SchemaProps: spec.SchemaProps{ 107 Type: []string{"array"}, 108 }}, 109 items: []interface{}{ 110 map[string]interface{}{ 111 "k": "a", 112 "v1": "a", 113 }, 114 }, 115 query: 42, 116 expected: nil, 117 }, 118 { 119 name: "single key ignoring unkeyable query", 120 sts: &spec.Schema{ 121 SchemaProps: spec.SchemaProps{ 122 Type: []string{"array"}, 123 }, 124 VendorExtensible: spec.VendorExtensible{Extensions: map[string]interface{}{ 125 extListType: listTypeMap, 126 extListMapKeys: []any{"k"}, 127 }}}, 128 items: []interface{}{ 129 map[string]interface{}{ 130 "k": "a", 131 "v1": "a", 132 }, 133 }, 134 query: map[string]interface{}{ 135 "k": map[string]interface{}{ 136 "keys": "must", 137 "be": "scalars", 138 }, 139 "v1": "A", 140 }, 141 expected: nil, 142 }, 143 { 144 name: "ignores item of invalid type", 145 sts: &spec.Schema{ 146 SchemaProps: spec.SchemaProps{ 147 Type: []string{"array"}, 148 }, 149 VendorExtensible: spec.VendorExtensible{Extensions: map[string]interface{}{ 150 extListType: listTypeMap, 151 extListMapKeys: []any{"k"}, 152 }}}, 153 items: []interface{}{ 154 map[string]interface{}{ 155 "k": "a", 156 "v1": "a", 157 }, 158 5, 159 }, 160 query: map[string]interface{}{ 161 "k": "a", 162 "v1": "A", 163 }, 164 expected: map[string]interface{}{ 165 "k": "a", 166 "v1": "a", 167 }, 168 }, 169 { 170 name: "keep first entry when duplicated keys are encountered", 171 sts: &spec.Schema{ 172 SchemaProps: spec.SchemaProps{ 173 Type: []string{"array"}, 174 }, 175 VendorExtensible: spec.VendorExtensible{Extensions: map[string]interface{}{ 176 extListType: listTypeMap, 177 extListMapKeys: []any{"k"}, 178 }}}, 179 items: []interface{}{ 180 map[string]interface{}{ 181 "k": "a", 182 "v1": "a", 183 }, 184 map[string]interface{}{ 185 "k": "a", 186 "v1": "b", 187 }, 188 }, 189 query: map[string]interface{}{ 190 "k": "a", 191 "v1": "A", 192 }, 193 expected: map[string]interface{}{ 194 "k": "a", 195 "v1": "a", 196 }, 197 }, 198 { 199 name: "keep first entry when duplicated multi-keys are encountered", 200 sts: &spec.Schema{ 201 SchemaProps: spec.SchemaProps{ 202 Type: []string{"array"}, 203 }, 204 VendorExtensible: spec.VendorExtensible{Extensions: map[string]interface{}{ 205 extListType: listTypeMap, 206 extListMapKeys: []any{"k1", "k2"}, 207 }}}, 208 items: []interface{}{ 209 map[string]interface{}{ 210 "k1": "a", 211 "k2": "b", 212 "v1": "a", 213 }, 214 map[string]interface{}{ 215 "k1": "a", 216 "k2": "b", 217 "v1": "b", 218 }, 219 map[string]interface{}{ 220 "k1": "x", 221 "k2": "y", 222 "v1": "z", 223 }, 224 }, 225 warmUpQueries: []interface{}{ 226 map[string]interface{}{ 227 "k1": "x", 228 "k2": "y", 229 }, 230 }, 231 query: map[string]interface{}{ 232 "k1": "a", 233 "k2": "b", 234 }, 235 expected: map[string]interface{}{ 236 "k1": "a", 237 "k2": "b", 238 "v1": "a", 239 }, 240 }, 241 { 242 name: "multiple keys with defaults ignores item with nil value for key", 243 sts: &spec.Schema{ 244 SchemaProps: spec.SchemaProps{ 245 Type: []string{"array"}, 246 Properties: map[string]spec.Schema{ 247 "kb": {SchemaProps: spec.SchemaProps{ 248 Default: true, 249 }}, 250 "kf": {SchemaProps: spec.SchemaProps{ 251 Default: 2.0, 252 }}, 253 "ki": {SchemaProps: spec.SchemaProps{ 254 Default: int64(64), 255 }}, 256 "ks": { 257 SchemaProps: spec.SchemaProps{ 258 Default: "hello", 259 }}, 260 }, 261 }, 262 VendorExtensible: spec.VendorExtensible{Extensions: map[string]interface{}{ 263 extListType: listTypeMap, 264 extListMapKeys: []any{"kb", "kf", "ki", "ks"}, 265 }}}, 266 items: []interface{}{ 267 map[string]interface{}{ 268 "kb": nil, 269 "kf": float64(2.0), 270 "ki": int64(42), 271 "ks": "hello", 272 "v1": "a", 273 }, 274 map[string]interface{}{ 275 "kb": false, 276 "kf": float64(2.0), 277 "ki": int64(42), 278 "ks": "hello", 279 "v1": "b", 280 }, 281 }, 282 query: map[string]interface{}{ 283 "kb": false, 284 "kf": float64(2.0), 285 "ki": int64(42), 286 "ks": "hello", 287 "v1": "B", 288 }, 289 expected: map[string]interface{}{ 290 "kb": false, 291 "kf": float64(2.0), 292 "ki": int64(42), 293 "ks": "hello", 294 "v1": "b", 295 }, 296 }, 297 } { 298 t.Run(tc.name, func(t *testing.T) { 299 mapList := MakeMapList(tc.sts, tc.items) 300 for _, warmUp := range tc.warmUpQueries { 301 mapList.Get(warmUp) 302 } 303 actual := mapList.Get(tc.query) 304 if !reflect.DeepEqual(tc.expected, actual) { 305 t.Errorf("got: %v, expected %v", actual, tc.expected) 306 } 307 }) 308 } 309 }