k8s.io/apiserver@v0.31.1/pkg/server/options/admission_test.go (about)

     1  /*
     2  Copyright 2017 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 options
    18  
    19  import (
    20  	"fmt"
    21  	"io"
    22  	"testing"
    23  
    24  	"k8s.io/apimachinery/pkg/util/sets"
    25  	"k8s.io/apiserver/pkg/admission"
    26  )
    27  
    28  func TestEnabledPluginNames(t *testing.T) {
    29  	scenarios := []struct {
    30  		expectedPluginNames       []string
    31  		setDefaultOffPlugins      sets.Set[string]
    32  		setRecommendedPluginOrder []string
    33  		setEnablePlugins          []string
    34  		setDisablePlugins         []string
    35  		setAdmissionControl       []string
    36  	}{
    37  		// scenario 0: check if a call to enabledPluginNames sets expected values.
    38  		{
    39  			expectedPluginNames: []string{"NamespaceLifecycle", "MutatingAdmissionWebhook", "ValidatingAdmissionPolicy", "ValidatingAdmissionWebhook"},
    40  		},
    41  
    42  		// scenario 1: use default off plugins if no specified
    43  		{
    44  			expectedPluginNames:       []string{"pluginB"},
    45  			setRecommendedPluginOrder: []string{"pluginA", "pluginB", "pluginC", "pluginD"},
    46  			setDefaultOffPlugins:      sets.New("pluginA", "pluginC", "pluginD"),
    47  		},
    48  
    49  		// scenario 2: use default off plugins and with RecommendedPluginOrder
    50  		{
    51  			expectedPluginNames:       []string{"pluginA", "pluginB", "pluginC", "pluginD"},
    52  			setRecommendedPluginOrder: []string{"pluginA", "pluginB", "pluginC", "pluginD"},
    53  			setDefaultOffPlugins:      sets.Set[string]{},
    54  		},
    55  
    56  		// scenario 3: use default off plugins and specified by enable-admission-plugins with RecommendedPluginOrder
    57  		{
    58  			expectedPluginNames:       []string{"pluginA", "pluginB", "pluginC", "pluginD"},
    59  			setRecommendedPluginOrder: []string{"pluginA", "pluginB", "pluginC", "pluginD"},
    60  			setDefaultOffPlugins:      sets.New("pluginC", "pluginD"),
    61  			setEnablePlugins:          []string{"pluginD", "pluginC"},
    62  		},
    63  
    64  		// scenario 4: use default off plugins and specified by disable-admission-plugins with RecommendedPluginOrder
    65  		{
    66  			expectedPluginNames:       []string{"pluginB"},
    67  			setRecommendedPluginOrder: []string{"pluginA", "pluginB", "pluginC", "pluginD"},
    68  			setDefaultOffPlugins:      sets.New("pluginC", "pluginD"),
    69  			setDisablePlugins:         []string{"pluginA"},
    70  		},
    71  
    72  		// scenario 5: use default off plugins and specified by enable-admission-plugins and disable-admission-plugins with RecommendedPluginOrder
    73  		{
    74  			expectedPluginNames:       []string{"pluginA", "pluginC"},
    75  			setRecommendedPluginOrder: []string{"pluginA", "pluginB", "pluginC", "pluginD"},
    76  			setDefaultOffPlugins:      sets.New("pluginC", "pluginD"),
    77  			setEnablePlugins:          []string{"pluginC"},
    78  			setDisablePlugins:         []string{"pluginB"},
    79  		},
    80  
    81  		// scenario 6: use default off plugins and specified by admission-control with RecommendedPluginOrder
    82  		{
    83  			expectedPluginNames:       []string{"pluginA", "pluginB", "pluginC"},
    84  			setRecommendedPluginOrder: []string{"pluginA", "pluginB", "pluginC", "pluginD"},
    85  			setDefaultOffPlugins:      sets.New("pluginD"),
    86  			setAdmissionControl:       []string{"pluginA", "pluginB"},
    87  		},
    88  
    89  		// scenario 7: use default off plugins and specified by admission-control with RecommendedPluginOrder
    90  		{
    91  			expectedPluginNames:       []string{"pluginA", "pluginB", "pluginC"},
    92  			setRecommendedPluginOrder: []string{"pluginA", "pluginB", "pluginC", "pluginD"},
    93  			setDefaultOffPlugins:      sets.New("pluginC", "pluginD"),
    94  			setAdmissionControl:       []string{"pluginA", "pluginB", "pluginC"},
    95  		},
    96  	}
    97  
    98  	// act
    99  	for index, scenario := range scenarios {
   100  		t.Run(fmt.Sprintf("scenario %d", index), func(t *testing.T) {
   101  			target := NewAdmissionOptions()
   102  
   103  			if scenario.setDefaultOffPlugins != nil {
   104  				target.DefaultOffPlugins = scenario.setDefaultOffPlugins
   105  			}
   106  			if scenario.setRecommendedPluginOrder != nil {
   107  				target.RecommendedPluginOrder = scenario.setRecommendedPluginOrder
   108  			}
   109  			if scenario.setEnablePlugins != nil {
   110  				target.EnablePlugins = scenario.setEnablePlugins
   111  			}
   112  			if scenario.setDisablePlugins != nil {
   113  				target.DisablePlugins = scenario.setDisablePlugins
   114  			}
   115  			if scenario.setAdmissionControl != nil {
   116  				target.EnablePlugins = scenario.setAdmissionControl
   117  			}
   118  
   119  			actualPluginNames := target.enabledPluginNames()
   120  
   121  			if len(actualPluginNames) != len(scenario.expectedPluginNames) {
   122  				t.Fatalf("incorrect number of items, got %d, expected = %d", len(actualPluginNames), len(scenario.expectedPluginNames))
   123  			}
   124  			for i := range actualPluginNames {
   125  				if scenario.expectedPluginNames[i] != actualPluginNames[i] {
   126  					t.Errorf("missmatch at index = %d, got = %s, expected = %s", i, actualPluginNames[i], scenario.expectedPluginNames[i])
   127  				}
   128  			}
   129  		})
   130  	}
   131  }
   132  
   133  func TestValidate(t *testing.T) {
   134  	scenarios := []struct {
   135  		setEnablePlugins           []string
   136  		setDisablePlugins          []string
   137  		setRecommendedPluginsOrder []string
   138  		expectedResult             bool
   139  	}{
   140  		// scenario 0: not set any flag
   141  		{
   142  			expectedResult: true,
   143  		},
   144  
   145  		// scenario 1: set both `--enable-admission-plugins` `--disable-admission-plugins`
   146  		{
   147  			setEnablePlugins:  []string{"pluginA", "pluginB"},
   148  			setDisablePlugins: []string{"pluginC"},
   149  			expectedResult:    true,
   150  		},
   151  
   152  		// scenario 2: set invalid `--enable-admission-plugins` `--disable-admission-plugins`
   153  		{
   154  			setEnablePlugins:  []string{"pluginA", "pluginB"},
   155  			setDisablePlugins: []string{"pluginB"},
   156  			expectedResult:    false,
   157  		},
   158  
   159  		// scenario 3: set only invalid `--enable-admission-plugins`
   160  		{
   161  			setEnablePlugins: []string{"pluginA", "pluginE"},
   162  			expectedResult:   false,
   163  		},
   164  
   165  		// scenario 4: set only invalid `--disable-admission-plugins`
   166  		{
   167  			setDisablePlugins: []string{"pluginA", "pluginE"},
   168  			expectedResult:    false,
   169  		},
   170  
   171  		// scenario 5: set valid `--enable-admission-plugins`
   172  		{
   173  			setEnablePlugins: []string{"pluginA", "pluginB"},
   174  			expectedResult:   true,
   175  		},
   176  
   177  		// scenario 6: set valid `--disable-admission-plugins`
   178  		{
   179  			setDisablePlugins: []string{"pluginA"},
   180  			expectedResult:    true,
   181  		},
   182  
   183  		// scenario 7: RecommendedPluginOrder has duplicated plugin
   184  		{
   185  			setRecommendedPluginsOrder: []string{"pluginA", "pluginB", "pluginB", "pluginC"},
   186  			expectedResult:             false,
   187  		},
   188  
   189  		// scenario 8: RecommendedPluginOrder not equal to registered
   190  		{
   191  			setRecommendedPluginsOrder: []string{"pluginA", "pluginB", "pluginC"},
   192  			expectedResult:             false,
   193  		},
   194  
   195  		// scenario 9: RecommendedPluginOrder equal to registered
   196  		{
   197  			setRecommendedPluginsOrder: []string{"pluginA", "pluginB", "pluginC", "pluginD"},
   198  			expectedResult:             true,
   199  		},
   200  
   201  		// scenario 10: RecommendedPluginOrder not equal to registered
   202  		{
   203  			setRecommendedPluginsOrder: []string{"pluginA", "pluginB", "pluginC", "pluginE"},
   204  			expectedResult:             false,
   205  		},
   206  	}
   207  
   208  	for index, scenario := range scenarios {
   209  		t.Run(fmt.Sprintf("scenario %d", index), func(t *testing.T) {
   210  			options := NewAdmissionOptions()
   211  			options.DefaultOffPlugins = sets.New("pluginC", "pluginD")
   212  			options.RecommendedPluginOrder = []string{"pluginA", "pluginB", "pluginC", "pluginD"}
   213  			options.Plugins = &admission.Plugins{}
   214  			for _, plugin := range options.RecommendedPluginOrder {
   215  				options.Plugins.Register(plugin, func(config io.Reader) (admission.Interface, error) {
   216  					return nil, nil
   217  				})
   218  			}
   219  
   220  			if scenario.setEnablePlugins != nil {
   221  				options.EnablePlugins = scenario.setEnablePlugins
   222  			}
   223  			if scenario.setDisablePlugins != nil {
   224  				options.DisablePlugins = scenario.setDisablePlugins
   225  			}
   226  			if scenario.setRecommendedPluginsOrder != nil {
   227  				options.RecommendedPluginOrder = scenario.setRecommendedPluginsOrder
   228  			}
   229  
   230  			err := options.Validate()
   231  			if len(err) > 0 && scenario.expectedResult {
   232  				t.Errorf("Unexpected err: %v", err)
   233  			}
   234  			if len(err) == 0 && !scenario.expectedResult {
   235  				t.Errorf("Expect error, but got none")
   236  			}
   237  		})
   238  	}
   239  }