...

Source file src/k8s.io/cli-runtime/pkg/resource/fallback_query_param_verifier_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  	"fmt"
    21  	"testing"
    22  
    23  	"k8s.io/apimachinery/pkg/api/errors"
    24  	"k8s.io/apimachinery/pkg/runtime/schema"
    25  	"k8s.io/client-go/discovery"
    26  	"k8s.io/client-go/openapi/cached"
    27  	"k8s.io/client-go/openapi/openapitest"
    28  	"k8s.io/client-go/openapi3"
    29  )
    30  
    31  func TestFallbackQueryParamVerifier_PrimaryNoFallback(t *testing.T) {
    32  	tests := map[string]struct {
    33  		crds             []schema.GroupKind      // CRDFinder returns these CRD's
    34  		gvk              schema.GroupVersionKind // GVK whose OpenAPI spec is checked
    35  		queryParam       VerifiableQueryParam    // Usually "fieldValidation"
    36  		expectedSupports bool
    37  	}{
    38  		"Field validation query param is supported for batch/v1/Job, primary verifier": {
    39  			crds: []schema.GroupKind{},
    40  			gvk: schema.GroupVersionKind{
    41  				Group:   "batch",
    42  				Version: "v1",
    43  				Kind:    "Job",
    44  			},
    45  			queryParam:       QueryParamFieldValidation,
    46  			expectedSupports: true,
    47  		},
    48  		"Field validation query param supported for core/v1/Namespace, primary verifier": {
    49  			crds: []schema.GroupKind{},
    50  			gvk: schema.GroupVersionKind{
    51  				Group:   "",
    52  				Version: "v1",
    53  				Kind:    "Namespace",
    54  			},
    55  			queryParam:       QueryParamFieldValidation,
    56  			expectedSupports: true,
    57  		},
    58  		"Field validation unsupported for unknown GVK in primary verifier": {
    59  			crds: []schema.GroupKind{},
    60  			gvk: schema.GroupVersionKind{
    61  				Group:   "bad",
    62  				Version: "v1",
    63  				Kind:    "Uknown",
    64  			},
    65  			queryParam:       QueryParamFieldValidation,
    66  			expectedSupports: false,
    67  		},
    68  		"Unknown query param unsupported (for all GVK's) in primary verifier": {
    69  			crds: []schema.GroupKind{},
    70  			gvk: schema.GroupVersionKind{
    71  				Group:   "apps",
    72  				Version: "v1",
    73  				Kind:    "Deployment",
    74  			},
    75  			queryParam:       "UnknownQueryParam",
    76  			expectedSupports: false,
    77  		},
    78  		"Field validation query param supported for found CRD in primary verifier": {
    79  			crds: []schema.GroupKind{
    80  				{
    81  					Group: "example.com",
    82  					Kind:  "ExampleCRD",
    83  				},
    84  			},
    85  			// GVK matches above CRD GroupKind
    86  			gvk: schema.GroupVersionKind{
    87  				Group:   "example.com",
    88  				Version: "v1",
    89  				Kind:    "ExampleCRD",
    90  			},
    91  			queryParam:       QueryParamFieldValidation,
    92  			expectedSupports: true,
    93  		},
    94  		"Field validation query param unsupported for missing CRD in primary verifier": {
    95  			crds: []schema.GroupKind{
    96  				{
    97  					Group: "different.com",
    98  					Kind:  "DifferentCRD",
    99  				},
   100  			},
   101  			// GVK does NOT match above CRD GroupKind
   102  			gvk: schema.GroupVersionKind{
   103  				Group:   "example.com",
   104  				Version: "v1",
   105  				Kind:    "ExampleCRD",
   106  			},
   107  			queryParam:       QueryParamFieldValidation,
   108  			expectedSupports: false,
   109  		},
   110  		"List GVK is specifically unsupported in primary verfier": {
   111  			crds: []schema.GroupKind{},
   112  			gvk: schema.GroupVersionKind{
   113  				Group:   "",
   114  				Version: "v1",
   115  				Kind:    "List",
   116  			},
   117  			queryParam:       QueryParamFieldValidation,
   118  			expectedSupports: false,
   119  		},
   120  	}
   121  
   122  	root := openapi3.NewRoot(cached.NewClient(openapitest.NewEmbeddedFileClient()))
   123  	for tn, tc := range tests {
   124  		t.Run(tn, func(t *testing.T) {
   125  			primary := createFakeV3Verifier(tc.crds, root, tc.queryParam)
   126  			// secondary verifier should not be called.
   127  			secondary := &failingVerifier{name: "secondary", t: t}
   128  			verifier := NewFallbackQueryParamVerifier(primary, secondary)
   129  			err := verifier.HasSupport(tc.gvk)
   130  			if tc.expectedSupports && err != nil {
   131  				t.Errorf("Expected supports, but returned err for GVK (%s)", tc.gvk)
   132  			} else if !tc.expectedSupports && err == nil {
   133  				t.Errorf("Expected not supports, but returned no err for GVK (%s)", tc.gvk)
   134  			}
   135  		})
   136  	}
   137  }
   138  
   139  func TestFallbackQueryParamVerifier_SecondaryFallback(t *testing.T) {
   140  	tests := map[string]struct {
   141  		crds             []schema.GroupKind      // CRDFinder returns these CRD's
   142  		gvk              schema.GroupVersionKind // GVK whose OpenAPI spec is checked
   143  		queryParam       VerifiableQueryParam    // Usually "fieldValidation"
   144  		primaryError     error
   145  		expectedSupports bool
   146  	}{
   147  		"Field validation query param is supported for batch/v1/Job, secondary verifier": {
   148  			crds: []schema.GroupKind{},
   149  			gvk: schema.GroupVersionKind{
   150  				Group:   "batch",
   151  				Version: "v1",
   152  				Kind:    "Job",
   153  			},
   154  			queryParam:       QueryParamFieldValidation,
   155  			primaryError:     errors.NewNotFound(schema.GroupResource{}, "OpenAPI V3 endpoint not found"),
   156  			expectedSupports: true,
   157  		},
   158  		"Field validation query param is supported for batch/v1/Job, invalid v3 document error": {
   159  			crds: []schema.GroupKind{},
   160  			gvk: schema.GroupVersionKind{
   161  				Group:   "batch",
   162  				Version: "v1",
   163  				Kind:    "Job",
   164  			},
   165  			queryParam:       QueryParamFieldValidation,
   166  			primaryError:     fmt.Errorf("Invalid OpenAPI V3 document"),
   167  			expectedSupports: true,
   168  		},
   169  		"Field validation query param is supported for batch/v1/Job, timeout error": {
   170  			crds: []schema.GroupKind{},
   171  			gvk: schema.GroupVersionKind{
   172  				Group:   "batch",
   173  				Version: "v1",
   174  				Kind:    "Job",
   175  			},
   176  			queryParam:       QueryParamFieldValidation,
   177  			primaryError:     fmt.Errorf("timeout"),
   178  			expectedSupports: true,
   179  		},
   180  		"Field validation query param supported for core/v1/Namespace, secondary verifier": {
   181  			crds: []schema.GroupKind{},
   182  			gvk: schema.GroupVersionKind{
   183  				Group:   "",
   184  				Version: "v1",
   185  				Kind:    "Namespace",
   186  			},
   187  			queryParam:       QueryParamFieldValidation,
   188  			primaryError:     errors.NewNotFound(schema.GroupResource{}, "OpenAPI V3 endpoint not found"),
   189  			expectedSupports: true,
   190  		},
   191  		"Field validation unsupported for unknown GVK, secondary verifier": {
   192  			crds: []schema.GroupKind{},
   193  			gvk: schema.GroupVersionKind{
   194  				Group:   "bad",
   195  				Version: "v1",
   196  				Kind:    "Uknown",
   197  			},
   198  			queryParam:       QueryParamFieldValidation,
   199  			primaryError:     errors.NewNotFound(schema.GroupResource{}, "OpenAPI V3 endpoint not found"),
   200  			expectedSupports: false,
   201  		},
   202  		"Field validation unsupported for unknown GVK, invalid document causes secondary verifier": {
   203  			crds: []schema.GroupKind{},
   204  			gvk: schema.GroupVersionKind{
   205  				Group:   "bad",
   206  				Version: "v1",
   207  				Kind:    "Uknown",
   208  			},
   209  			queryParam:       QueryParamFieldValidation,
   210  			primaryError:     fmt.Errorf("Invalid OpenAPI V3 document"),
   211  			expectedSupports: false,
   212  		},
   213  		"Unknown query param unsupported (for all GVK's), secondary verifier": {
   214  			crds: []schema.GroupKind{},
   215  			gvk: schema.GroupVersionKind{
   216  				Group:   "apps",
   217  				Version: "v1",
   218  				Kind:    "Deployment",
   219  			},
   220  			queryParam:       "UnknownQueryParam",
   221  			primaryError:     errors.NewNotFound(schema.GroupResource{}, "OpenAPI V3 endpoint not found"),
   222  			expectedSupports: false,
   223  		},
   224  		"Field validation query param supported for found CRD, secondary verifier": {
   225  			crds: []schema.GroupKind{
   226  				{
   227  					Group: "example.com",
   228  					Kind:  "ExampleCRD",
   229  				},
   230  			},
   231  			// GVK matches above CRD GroupKind
   232  			gvk: schema.GroupVersionKind{
   233  				Group:   "example.com",
   234  				Version: "v1",
   235  				Kind:    "ExampleCRD",
   236  			},
   237  			queryParam:       QueryParamFieldValidation,
   238  			primaryError:     errors.NewNotFound(schema.GroupResource{}, "OpenAPI V3 endpoint not found"),
   239  			expectedSupports: true,
   240  		},
   241  		"Field validation query param unsupported for missing CRD, secondary verifier": {
   242  			crds: []schema.GroupKind{
   243  				{
   244  					Group: "different.com",
   245  					Kind:  "DifferentCRD",
   246  				},
   247  			},
   248  			// GVK does NOT match above CRD GroupKind
   249  			gvk: schema.GroupVersionKind{
   250  				Group:   "example.com",
   251  				Version: "v1",
   252  				Kind:    "ExampleCRD",
   253  			},
   254  			queryParam:       QueryParamFieldValidation,
   255  			primaryError:     errors.NewNotFound(schema.GroupResource{}, "OpenAPI V3 endpoint not found"),
   256  			expectedSupports: false,
   257  		},
   258  		"List GVK is specifically unsupported": {
   259  			crds: []schema.GroupKind{},
   260  			gvk: schema.GroupVersionKind{
   261  				Group:   "",
   262  				Version: "v1",
   263  				Kind:    "List",
   264  			},
   265  			queryParam:       QueryParamFieldValidation,
   266  			primaryError:     errors.NewNotFound(schema.GroupResource{}, "OpenAPI V3 endpoint not found"),
   267  			expectedSupports: false,
   268  		},
   269  	}
   270  
   271  	// Primary OpenAPI client always returns "NotFound" error, so secondary verifier is used.
   272  	fakeOpenAPIClient := openapitest.NewFakeClient()
   273  	root := openapi3.NewRoot(fakeOpenAPIClient)
   274  	for tn, tc := range tests {
   275  		t.Run(tn, func(t *testing.T) {
   276  			fakeOpenAPIClient.ForcedErr = tc.primaryError
   277  			primary := createFakeV3Verifier(tc.crds, root, tc.queryParam)
   278  			secondary := createFakeLegacyVerifier(tc.crds, &fakeSchema, tc.queryParam)
   279  			verifier := NewFallbackQueryParamVerifier(primary, secondary)
   280  			err := verifier.HasSupport(tc.gvk)
   281  			if tc.expectedSupports && err != nil {
   282  				t.Errorf("Expected supports, but returned err for GVK (%s)", tc.gvk)
   283  			} else if !tc.expectedSupports && err == nil {
   284  				t.Errorf("Expected not supports, but returned no err for GVK (%s)", tc.gvk)
   285  			}
   286  		})
   287  	}
   288  }
   289  
   290  // createFakeV3Verifier returns a fake OpenAPI V3 queryParamVerifierV3 struct
   291  // filled in with passed values; implements Verifier interface.
   292  func createFakeV3Verifier(crds []schema.GroupKind, root openapi3.Root, queryParam VerifiableQueryParam) Verifier {
   293  	return &queryParamVerifierV3{
   294  		finder: NewCRDFinder(func() ([]schema.GroupKind, error) {
   295  			return crds, nil
   296  		}),
   297  		root:       root,
   298  		queryParam: queryParam,
   299  	}
   300  }
   301  
   302  // createFakeLegacyVerifier returns a fake QueryParamVerifier struct for legacy
   303  // OpenAPI V2; implements Verifier interface.
   304  func createFakeLegacyVerifier(crds []schema.GroupKind, fakeSchema discovery.OpenAPISchemaInterface, queryParam VerifiableQueryParam) Verifier {
   305  	return &QueryParamVerifier{
   306  		finder: NewCRDFinder(func() ([]schema.GroupKind, error) {
   307  			return crds, nil
   308  		}),
   309  		openAPIGetter: fakeSchema,
   310  		queryParam:    queryParam,
   311  	}
   312  }
   313  
   314  // failingVerifier always crashes when called; implements Verifier
   315  type failingVerifier struct {
   316  	name string
   317  	t    *testing.T
   318  }
   319  
   320  func (c *failingVerifier) HasSupport(gvk schema.GroupVersionKind) error {
   321  	c.t.Fatalf("%s verifier should not be called", c.name)
   322  	return nil
   323  }
   324  

View as plain text