1/* 2Copyright 2014 The Kubernetes Authors. 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package clientcmd 18 19import ( 20 "fmt" 21 "testing" 22 23 restclient "k8s.io/client-go/rest" 24 clientcmdapi "k8s.io/client-go/tools/clientcmd/api" 25) 26 27type testLoader struct { 28 ClientConfigLoader 29 30 called bool 31 config *clientcmdapi.Config 32 err error 33} 34 35func (l *testLoader) Load() (*clientcmdapi.Config, error) { 36 l.called = true 37 return l.config, l.err 38} 39 40type testClientConfig struct { 41 rawconfig *clientcmdapi.Config 42 config *restclient.Config 43 namespace string 44 namespaceSpecified bool 45 err error 46} 47 48func (c *testClientConfig) RawConfig() (clientcmdapi.Config, error) { 49 if c.rawconfig == nil { 50 return clientcmdapi.Config{}, fmt.Errorf("unexpected call") 51 } 52 return *c.rawconfig, nil 53} 54func (c *testClientConfig) ClientConfig() (*restclient.Config, error) { 55 return c.config, c.err 56} 57func (c *testClientConfig) Namespace() (string, bool, error) { 58 return c.namespace, c.namespaceSpecified, c.err 59} 60func (c *testClientConfig) ConfigAccess() ConfigAccess { 61 return nil 62} 63 64type testICC struct { 65 testClientConfig 66 67 possible bool 68 called bool 69} 70 71func (icc *testICC) Possible() bool { 72 icc.called = true 73 return icc.possible 74} 75 76func TestInClusterConfig(t *testing.T) { 77 default1 := &DirectClientConfig{ 78 config: *createValidTestConfig(), 79 contextName: "clean", 80 overrides: &ConfigOverrides{}, 81 } 82 invalidDefaultConfig := clientcmdapi.NewConfig() 83 invalidDefaultConfig.Clusters["clean"] = &clientcmdapi.Cluster{ 84 Server: "http://localhost:8080", 85 } 86 invalidDefaultConfig.Contexts["other"] = &clientcmdapi.Context{ 87 Cluster: "clean", 88 } 89 invalidDefaultConfig.CurrentContext = "clean" 90 91 defaultInvalid := &DirectClientConfig{ 92 config: *invalidDefaultConfig, 93 overrides: &ConfigOverrides{}, 94 } 95 if _, err := defaultInvalid.ClientConfig(); err == nil || !IsConfigurationInvalid(err) { 96 t.Fatal(err) 97 } 98 config1, err := default1.ClientConfig() 99 if err != nil { 100 t.Fatal(err) 101 } 102 config2 := &restclient.Config{Host: "config2"} 103 err1 := fmt.Errorf("unique error") 104 105 testCases := map[string]struct { 106 clientConfig *testClientConfig 107 icc *testICC 108 defaultConfig *DirectClientConfig 109 110 checkedICC bool 111 result *restclient.Config 112 err error 113 }{ 114 "in-cluster checked on other error": { 115 clientConfig: &testClientConfig{err: ErrEmptyConfig}, 116 icc: &testICC{}, 117 118 checkedICC: true, 119 result: nil, 120 err: ErrEmptyConfig, 121 }, 122 123 "in-cluster not checked on non-empty error": { 124 clientConfig: &testClientConfig{err: ErrEmptyCluster}, 125 icc: &testICC{}, 126 127 checkedICC: false, 128 result: nil, 129 err: ErrEmptyCluster, 130 }, 131 132 "in-cluster checked when config is default": { 133 defaultConfig: default1, 134 clientConfig: &testClientConfig{config: config1}, 135 icc: &testICC{}, 136 137 checkedICC: true, 138 result: config1, 139 err: nil, 140 }, 141 142 "in-cluster not checked when default config is invalid": { 143 defaultConfig: defaultInvalid, 144 clientConfig: &testClientConfig{config: config1}, 145 icc: &testICC{}, 146 147 checkedICC: false, 148 result: config1, 149 err: nil, 150 }, 151 152 "in-cluster not checked when config is not equal to default": { 153 defaultConfig: default1, 154 clientConfig: &testClientConfig{config: config2}, 155 icc: &testICC{}, 156 157 checkedICC: false, 158 result: config2, 159 err: nil, 160 }, 161 162 "in-cluster checked when config is not equal to default and error is empty": { 163 clientConfig: &testClientConfig{config: config2, err: ErrEmptyConfig}, 164 icc: &testICC{}, 165 166 checkedICC: true, 167 result: config2, 168 err: ErrEmptyConfig, 169 }, 170 171 "in-cluster error returned when config is empty": { 172 clientConfig: &testClientConfig{err: ErrEmptyConfig}, 173 icc: &testICC{ 174 possible: true, 175 testClientConfig: testClientConfig{ 176 err: err1, 177 }, 178 }, 179 180 checkedICC: true, 181 result: nil, 182 err: err1, 183 }, 184 185 "in-cluster config returned when config is empty": { 186 clientConfig: &testClientConfig{err: ErrEmptyConfig}, 187 icc: &testICC{ 188 possible: true, 189 testClientConfig: testClientConfig{ 190 config: config2, 191 }, 192 }, 193 194 checkedICC: true, 195 result: config2, 196 err: nil, 197 }, 198 199 "in-cluster not checked when standard default is invalid": { 200 defaultConfig: &DefaultClientConfig, 201 clientConfig: &testClientConfig{config: config2}, 202 icc: &testICC{}, 203 204 checkedICC: false, 205 result: config2, 206 err: nil, 207 }, 208 } 209 210 for name, test := range testCases { 211 c := &DeferredLoadingClientConfig{icc: test.icc} 212 c.loader = &ClientConfigLoadingRules{DefaultClientConfig: test.defaultConfig} 213 c.clientConfig = test.clientConfig 214 215 cfg, err := c.ClientConfig() 216 if test.icc.called != test.checkedICC { 217 t.Errorf("%s: unexpected in-cluster-config call %t", name, test.icc.called) 218 } 219 if err != test.err || cfg != test.result { 220 t.Errorf("%s: unexpected result: %v %#v", name, err, cfg) 221 } 222 } 223} 224 225func TestInClusterConfigNamespace(t *testing.T) { 226 err1 := fmt.Errorf("unique error") 227 228 testCases := map[string]struct { 229 clientConfig *testClientConfig 230 icc *testICC 231 overrides *ConfigOverrides 232 233 checkedICC bool 234 result string 235 overridden bool 236 err error 237 }{ 238 "in-cluster checked on empty error": { 239 clientConfig: &testClientConfig{err: ErrEmptyConfig}, 240 icc: &testICC{}, 241 242 checkedICC: true, 243 err: ErrEmptyConfig, 244 }, 245 246 "in-cluster not checked on non-empty error": { 247 clientConfig: &testClientConfig{err: ErrEmptyCluster}, 248 icc: &testICC{}, 249 250 err: ErrEmptyCluster, 251 }, 252 253 "in-cluster checked when config is default": { 254 clientConfig: &testClientConfig{}, 255 icc: &testICC{}, 256 257 checkedICC: true, 258 }, 259 260 "in-cluster not checked when config is not equal to default": { 261 clientConfig: &testClientConfig{namespace: "test", namespaceSpecified: true}, 262 icc: &testICC{}, 263 264 result: "test", 265 overridden: true, 266 }, 267 268 "in-cluster checked when namespace is not specified, but is defaulted": { 269 clientConfig: &testClientConfig{namespace: "test", namespaceSpecified: false}, 270 icc: &testICC{}, 271 272 checkedICC: true, 273 result: "test", 274 overridden: false, 275 }, 276 277 "in-cluster error returned when config is empty": { 278 clientConfig: &testClientConfig{err: ErrEmptyConfig}, 279 icc: &testICC{ 280 possible: true, 281 testClientConfig: testClientConfig{ 282 err: err1, 283 }, 284 }, 285 286 checkedICC: true, 287 err: err1, 288 }, 289 290 "in-cluster config returned when config is empty": { 291 clientConfig: &testClientConfig{err: ErrEmptyConfig}, 292 icc: &testICC{ 293 possible: true, 294 testClientConfig: testClientConfig{ 295 namespace: "test", 296 namespaceSpecified: true, 297 }, 298 }, 299 300 checkedICC: true, 301 result: "test", 302 overridden: true, 303 }, 304 305 "in-cluster config returned when config is empty and namespace is defaulted but not explicitly set": { 306 clientConfig: &testClientConfig{err: ErrEmptyConfig}, 307 icc: &testICC{ 308 possible: true, 309 testClientConfig: testClientConfig{ 310 namespace: "test", 311 namespaceSpecified: false, 312 }, 313 }, 314 315 checkedICC: true, 316 result: "test", 317 overridden: false, 318 }, 319 320 "overridden context used to verify explicit namespace in config": { 321 clientConfig: &testClientConfig{ 322 namespace: "default", 323 namespaceSpecified: false, // a namespace that comes from a context is not considered overridden 324 rawconfig: &clientcmdapi.Config{Contexts: map[string]*clientcmdapi.Context{"overridden-context": {Namespace: "default"}}}, 325 }, 326 overrides: &ConfigOverrides{CurrentContext: "overridden-context"}, 327 icc: &testICC{ 328 possible: true, 329 testClientConfig: testClientConfig{ 330 namespace: "icc", 331 namespaceSpecified: false, // a namespace that comes from icc is not considered overridden 332 }, 333 }, 334 checkedICC: true, 335 result: "default", 336 overridden: false, // a namespace that comes from a context is not considered overridden 337 }, 338 } 339 340 for name, test := range testCases { 341 t.Run(name, func(t *testing.T) { 342 c := &DeferredLoadingClientConfig{icc: test.icc, overrides: test.overrides} 343 c.clientConfig = test.clientConfig 344 345 ns, overridden, err := c.Namespace() 346 if test.icc.called != test.checkedICC { 347 t.Errorf("%s: unexpected in-cluster-config call %t", name, test.icc.called) 348 } 349 if err != test.err || ns != test.result || overridden != test.overridden { 350 t.Errorf("%s: unexpected result: %v %s %t", name, err, ns, overridden) 351 } 352 }) 353 } 354} 355