...

Source file src/k8s.io/apimachinery/pkg/apis/meta/internalversion/validation/validation_test.go

Documentation: k8s.io/apimachinery/pkg/apis/meta/internalversion/validation

     1  /*
     2  Copyright 2020 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 validation
    18  
    19  import (
    20  	"testing"
    21  
    22  	"k8s.io/apimachinery/pkg/apis/meta/internalversion"
    23  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    24  )
    25  
    26  func TestValidateListOptions(t *testing.T) {
    27  	boolPtrFn := func(b bool) *bool {
    28  		return &b
    29  	}
    30  
    31  	cases := []struct {
    32  		name                    string
    33  		opts                    internalversion.ListOptions
    34  		watchListFeatureEnabled bool
    35  		expectErrors            []string
    36  	}{{
    37  		name: "valid-default",
    38  		opts: internalversion.ListOptions{},
    39  	}, {
    40  		name: "valid-resourceversionmatch-exact",
    41  		opts: internalversion.ListOptions{
    42  			ResourceVersion:      "1",
    43  			ResourceVersionMatch: metav1.ResourceVersionMatchExact,
    44  		},
    45  	}, {
    46  		name: "invalid-resourceversionmatch-exact",
    47  		opts: internalversion.ListOptions{
    48  			ResourceVersion:      "0",
    49  			ResourceVersionMatch: metav1.ResourceVersionMatchExact,
    50  		},
    51  		expectErrors: []string{"resourceVersionMatch: Forbidden: resourceVersionMatch \"exact\" is forbidden for resourceVersion \"0\""},
    52  	}, {
    53  		name: "valid-resourceversionmatch-notolderthan",
    54  		opts: internalversion.ListOptions{
    55  			ResourceVersion:      "0",
    56  			ResourceVersionMatch: metav1.ResourceVersionMatchNotOlderThan,
    57  		},
    58  	}, {
    59  		name: "invalid-resourceversionmatch",
    60  		opts: internalversion.ListOptions{
    61  			ResourceVersion:      "0",
    62  			ResourceVersionMatch: "foo",
    63  		},
    64  		expectErrors: []string{"resourceVersionMatch: Unsupported value: \"foo\": supported values: \"Exact\", \"NotOlderThan\", \"\""},
    65  	}, {
    66  		name: "list-sendInitialEvents-forbidden",
    67  		opts: internalversion.ListOptions{
    68  			SendInitialEvents: boolPtrFn(true),
    69  		},
    70  		expectErrors: []string{"sendInitialEvents: Forbidden: sendInitialEvents is forbidden for list"},
    71  	}, {
    72  		name: "valid-watch-default",
    73  		opts: internalversion.ListOptions{
    74  			Watch: true,
    75  		},
    76  	}, {
    77  		name: "valid-watch-sendInitialEvents-on",
    78  		opts: internalversion.ListOptions{
    79  			Watch:                true,
    80  			SendInitialEvents:    boolPtrFn(true),
    81  			ResourceVersionMatch: metav1.ResourceVersionMatchNotOlderThan,
    82  			AllowWatchBookmarks:  true,
    83  		},
    84  		watchListFeatureEnabled: true,
    85  	}, {
    86  		name: "valid-watch-sendInitialEvents-off",
    87  		opts: internalversion.ListOptions{
    88  			Watch:                true,
    89  			SendInitialEvents:    boolPtrFn(false),
    90  			ResourceVersionMatch: metav1.ResourceVersionMatchNotOlderThan,
    91  			AllowWatchBookmarks:  true,
    92  		},
    93  		watchListFeatureEnabled: true,
    94  	}, {
    95  		name: "watch-resourceversionmatch-without-sendInitialEvents-forbidden",
    96  		opts: internalversion.ListOptions{
    97  			Watch:                true,
    98  			ResourceVersionMatch: metav1.ResourceVersionMatchNotOlderThan,
    99  		},
   100  		expectErrors: []string{"resourceVersionMatch: Forbidden: resourceVersionMatch is forbidden for watch unless sendInitialEvents is provided"},
   101  	}, {
   102  		name: "watch-sendInitialEvents-without-resourceversionmatch-forbidden",
   103  		opts: internalversion.ListOptions{
   104  			Watch:             true,
   105  			SendInitialEvents: boolPtrFn(true),
   106  		},
   107  		expectErrors: []string{"resourceVersionMatch: Forbidden: sendInitialEvents requires setting resourceVersionMatch to NotOlderThan", "sendInitialEvents: Forbidden: sendInitialEvents is forbidden for watch unless the WatchList feature gate is enabled"},
   108  	}, {
   109  		name: "watch-sendInitialEvents-with-exact-resourceversionmatch-forbidden",
   110  		opts: internalversion.ListOptions{
   111  			Watch:                true,
   112  			SendInitialEvents:    boolPtrFn(true),
   113  			ResourceVersionMatch: metav1.ResourceVersionMatchExact,
   114  			AllowWatchBookmarks:  true,
   115  		},
   116  		watchListFeatureEnabled: true,
   117  		expectErrors:            []string{"resourceVersionMatch: Forbidden: sendInitialEvents requires setting resourceVersionMatch to NotOlderThan", "resourceVersionMatch: Unsupported value: \"Exact\": supported values: \"NotOlderThan\""},
   118  	}, {
   119  		name: "watch-sendInitialEvents-on-with-empty-resourceversionmatch-forbidden",
   120  		opts: internalversion.ListOptions{
   121  			Watch:                true,
   122  			SendInitialEvents:    boolPtrFn(true),
   123  			ResourceVersionMatch: "",
   124  		},
   125  		expectErrors: []string{"resourceVersionMatch: Forbidden: sendInitialEvents requires setting resourceVersionMatch to NotOlderThan", "sendInitialEvents: Forbidden: sendInitialEvents is forbidden for watch unless the WatchList feature gate is enabled"},
   126  	}, {
   127  		name: "watch-sendInitialEvents-off-with-empty-resourceversionmatch-forbidden",
   128  		opts: internalversion.ListOptions{
   129  			Watch:                true,
   130  			SendInitialEvents:    boolPtrFn(false),
   131  			ResourceVersionMatch: "",
   132  		},
   133  		expectErrors: []string{"resourceVersionMatch: Forbidden: sendInitialEvents requires setting resourceVersionMatch to NotOlderThan", "sendInitialEvents: Forbidden: sendInitialEvents is forbidden for watch unless the WatchList feature gate is enabled"},
   134  	}, {
   135  		name: "watch-sendInitialEvents-with-incorrect-resourceversionmatch-forbidden",
   136  		opts: internalversion.ListOptions{
   137  			Watch:                true,
   138  			SendInitialEvents:    boolPtrFn(true),
   139  			ResourceVersionMatch: "incorrect",
   140  			AllowWatchBookmarks:  true,
   141  		},
   142  		watchListFeatureEnabled: true,
   143  		expectErrors:            []string{"resourceVersionMatch: Forbidden: sendInitialEvents requires setting resourceVersionMatch to NotOlderThan", "resourceVersionMatch: Unsupported value: \"incorrect\": supported values: \"NotOlderThan\""},
   144  	}, {
   145  		// note that validating allowWatchBookmarks would break backward compatibility
   146  		// because it was possible to request initial events via resourceVersion=0 before this change
   147  		name: "watch-sendInitialEvents-no-allowWatchBookmark",
   148  		opts: internalversion.ListOptions{
   149  			Watch:                true,
   150  			SendInitialEvents:    boolPtrFn(true),
   151  			ResourceVersionMatch: metav1.ResourceVersionMatchNotOlderThan,
   152  		},
   153  		watchListFeatureEnabled: true,
   154  	}, {
   155  		name: "watch-sendInitialEvents-no-watchlist-fg-disabled",
   156  		opts: internalversion.ListOptions{
   157  			Watch:                true,
   158  			SendInitialEvents:    boolPtrFn(true),
   159  			ResourceVersionMatch: metav1.ResourceVersionMatchNotOlderThan,
   160  			AllowWatchBookmarks:  true,
   161  		},
   162  		expectErrors: []string{"sendInitialEvents: Forbidden: sendInitialEvents is forbidden for watch unless the WatchList feature gate is enabled"},
   163  	}, {
   164  		name: "watch-sendInitialEvents-no-watchlist-fg-disabled",
   165  		opts: internalversion.ListOptions{
   166  			Watch:                true,
   167  			SendInitialEvents:    boolPtrFn(true),
   168  			ResourceVersionMatch: metav1.ResourceVersionMatchNotOlderThan,
   169  			AllowWatchBookmarks:  true,
   170  			Continue:             "123",
   171  		},
   172  		watchListFeatureEnabled: true,
   173  		expectErrors:            []string{"resourceVersionMatch: Forbidden: resourceVersionMatch is forbidden when continue is provided"},
   174  	}}
   175  
   176  	for _, tc := range cases {
   177  		t.Run(tc.name, func(t *testing.T) {
   178  			errs := ValidateListOptions(&tc.opts, tc.watchListFeatureEnabled)
   179  			if len(tc.expectErrors) > 0 {
   180  				if len(errs) != len(tc.expectErrors) {
   181  					t.Errorf("expected %d errors but got %d errors", len(tc.expectErrors), len(errs))
   182  					return
   183  				}
   184  				for i, expectedErr := range tc.expectErrors {
   185  					if expectedErr != errs[i].Error() {
   186  						t.Errorf("expected error '%s' but got '%s'", expectedErr, errs[i].Error())
   187  					}
   188  				}
   189  				return
   190  			}
   191  			if len(errs) != 0 {
   192  				t.Errorf("expected no errors, but got: %v", errs)
   193  			}
   194  		})
   195  	}
   196  }
   197  

View as plain text