...

Source file src/k8s.io/cli-runtime/pkg/resource/query_param_verifier_v3_test.go

Documentation: k8s.io/cli-runtime/pkg/resource

     1  /*
     2  Copyright 2023 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 resource
    18  
    19  import (
    20  	"strings"
    21  	"testing"
    22  
    23  	"k8s.io/apimachinery/pkg/runtime/schema"
    24  	"k8s.io/client-go/openapi/cached"
    25  	"k8s.io/client-go/openapi/openapitest"
    26  	"k8s.io/client-go/openapi3"
    27  	"k8s.io/kube-openapi/pkg/spec3"
    28  )
    29  
    30  func TestV3SupportsQueryParamBatchV1(t *testing.T) {
    31  	tests := map[string]struct {
    32  		crds             []schema.GroupKind      // CRDFinder returns these CRD's
    33  		gvk              schema.GroupVersionKind // GVK whose OpenAPI V3 spec is checked
    34  		queryParam       VerifiableQueryParam    // Usually "fieldValidation"
    35  		expectedSupports bool
    36  	}{
    37  		"Field validation query param is supported for batch/v1/Job": {
    38  			crds: []schema.GroupKind{},
    39  			gvk: schema.GroupVersionKind{
    40  				Group:   "batch",
    41  				Version: "v1",
    42  				Kind:    "Job",
    43  			},
    44  			queryParam:       QueryParamFieldValidation,
    45  			expectedSupports: true,
    46  		},
    47  		"Field validation query param supported for core/v1/Namespace": {
    48  			crds: []schema.GroupKind{},
    49  			gvk: schema.GroupVersionKind{
    50  				Group:   "",
    51  				Version: "v1",
    52  				Kind:    "Namespace",
    53  			},
    54  			queryParam:       QueryParamFieldValidation,
    55  			expectedSupports: true,
    56  		},
    57  		"Field validation unsupported for unknown GVK": {
    58  			crds: []schema.GroupKind{},
    59  			gvk: schema.GroupVersionKind{
    60  				Group:   "bad",
    61  				Version: "v1",
    62  				Kind:    "Uknown",
    63  			},
    64  			queryParam:       QueryParamFieldValidation,
    65  			expectedSupports: false,
    66  		},
    67  		"Unknown query param unsupported (for all GVK's)": {
    68  			crds: []schema.GroupKind{},
    69  			gvk: schema.GroupVersionKind{
    70  				Group:   "apps",
    71  				Version: "v1",
    72  				Kind:    "Deployment",
    73  			},
    74  			queryParam:       "UnknownQueryParam",
    75  			expectedSupports: false,
    76  		},
    77  		"Field validation query param supported for found CRD": {
    78  			crds: []schema.GroupKind{
    79  				{
    80  					Group: "example.com",
    81  					Kind:  "ExampleCRD",
    82  				},
    83  			},
    84  			// GVK matches above CRD GroupKind
    85  			gvk: schema.GroupVersionKind{
    86  				Group:   "example.com",
    87  				Version: "v1",
    88  				Kind:    "ExampleCRD",
    89  			},
    90  			queryParam:       QueryParamFieldValidation,
    91  			expectedSupports: true,
    92  		},
    93  		"Field validation query param unsupported for missing CRD": {
    94  			crds: []schema.GroupKind{
    95  				{
    96  					Group: "different.com",
    97  					Kind:  "DifferentCRD",
    98  				},
    99  			},
   100  			// GVK does NOT match above CRD GroupKind
   101  			gvk: schema.GroupVersionKind{
   102  				Group:   "example.com",
   103  				Version: "v1",
   104  				Kind:    "ExampleCRD",
   105  			},
   106  			queryParam:       QueryParamFieldValidation,
   107  			expectedSupports: false,
   108  		},
   109  		"List GVK is specifically unsupported": {
   110  			crds: []schema.GroupKind{},
   111  			gvk: schema.GroupVersionKind{
   112  				Group:   "",
   113  				Version: "v1",
   114  				Kind:    "List",
   115  			},
   116  			queryParam:       QueryParamFieldValidation,
   117  			expectedSupports: false,
   118  		},
   119  	}
   120  
   121  	root := openapi3.NewRoot(cached.NewClient(openapitest.NewEmbeddedFileClient()))
   122  	for tn, tc := range tests {
   123  		t.Run(tn, func(t *testing.T) {
   124  			verifier := &queryParamVerifierV3{
   125  				finder: NewCRDFinder(func() ([]schema.GroupKind, error) {
   126  					return tc.crds, nil
   127  				}),
   128  				root:       root,
   129  				queryParam: tc.queryParam,
   130  			}
   131  			err := verifier.HasSupport(tc.gvk)
   132  			if tc.expectedSupports && err != nil {
   133  				t.Errorf("Expected supports, but returned err for GVK (%s)", tc.gvk)
   134  			} else if !tc.expectedSupports && err == nil {
   135  				t.Errorf("Expected not supports, but returned no err for GVK (%s)", tc.gvk)
   136  			}
   137  		})
   138  	}
   139  }
   140  
   141  func TestInvalidOpenAPIV3Document(t *testing.T) {
   142  	tests := map[string]struct {
   143  		spec *spec3.OpenAPI
   144  		err  string
   145  	}{
   146  		"nil document returns error": {
   147  			spec: nil,
   148  			err:  "Invalid OpenAPI V3 document",
   149  		},
   150  		"empty document returns error": {
   151  			spec: &spec3.OpenAPI{},
   152  			err:  "Invalid OpenAPI V3 document",
   153  		},
   154  		"minimal document returns error": {
   155  			spec: &spec3.OpenAPI{
   156  				Version: "openapi 3.0.0",
   157  				Paths:   nil,
   158  			},
   159  			err: "Invalid OpenAPI V3 document",
   160  		},
   161  		"empty Paths returns error": {
   162  			spec: &spec3.OpenAPI{
   163  				Version: "openapi 3.0.0",
   164  				Paths:   &spec3.Paths{},
   165  			},
   166  			err: "Path not found for GVK",
   167  		},
   168  		"nil Path returns error": {
   169  			spec: &spec3.OpenAPI{
   170  				Version: "openapi 3.0.0",
   171  				Paths:   &spec3.Paths{Paths: map[string]*spec3.Path{"/version": nil}},
   172  			},
   173  			err: "Path not found for GVK",
   174  		},
   175  		"empty Path returns error": {
   176  			spec: &spec3.OpenAPI{
   177  				Version: "openapi 3.0.0",
   178  				Paths:   &spec3.Paths{Paths: map[string]*spec3.Path{"/version": {}}},
   179  			},
   180  			err: "Path not found for GVK",
   181  		},
   182  	}
   183  
   184  	gvk := schema.GroupVersionKind{
   185  		Group:   "batch",
   186  		Version: "v1",
   187  		Kind:    "Job",
   188  	}
   189  	for tn, tc := range tests {
   190  		t.Run(tn, func(t *testing.T) {
   191  
   192  			verifier := &queryParamVerifierV3{
   193  				finder: NewCRDFinder(func() ([]schema.GroupKind, error) {
   194  					return []schema.GroupKind{}, nil
   195  				}),
   196  				root:       &fakeRoot{tc.spec},
   197  				queryParam: QueryParamFieldValidation,
   198  			}
   199  			err := verifier.HasSupport(gvk)
   200  			if !strings.Contains(err.Error(), tc.err) {
   201  				t.Errorf("Expected error (%s), but received (%s)", tc.err, err.Error())
   202  			}
   203  		})
   204  	}
   205  }
   206  
   207  // fakeRoot implements Root interface; manually specifies the returned OpenAPI V3 document.
   208  type fakeRoot struct {
   209  	spec *spec3.OpenAPI
   210  }
   211  
   212  func (f *fakeRoot) GroupVersions() ([]schema.GroupVersion, error) {
   213  	// Unused
   214  	return nil, nil
   215  }
   216  
   217  // GVSpec returns hard-coded OpenAPI V3 document.
   218  func (f *fakeRoot) GVSpec(gv schema.GroupVersion) (*spec3.OpenAPI, error) {
   219  	return f.spec, nil
   220  }
   221  
   222  func (f *fakeRoot) GVSpecAsMap(gv schema.GroupVersion) (map[string]interface{}, error) {
   223  	// Unused
   224  	return nil, nil
   225  }
   226  

View as plain text