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  }