1
16
17 package config
18
19 import (
20 "fmt"
21 "os"
22 "path"
23 "reflect"
24 "strings"
25 "testing"
26
27 "github.com/google/go-cmp/cmp"
28 apiequality "k8s.io/apimachinery/pkg/api/equality"
29 "k8s.io/cli-runtime/pkg/genericiooptions"
30 "k8s.io/client-go/tools/clientcmd"
31 clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
32 utiltesting "k8s.io/client-go/util/testing"
33 cmdutil "k8s.io/kubectl/pkg/cmd/util"
34 )
35
36 func newRedFederalCowHammerConfig() clientcmdapi.Config {
37 return clientcmdapi.Config{
38 AuthInfos: map[string]*clientcmdapi.AuthInfo{
39 "red-user": {Token: "red-token"}},
40 Clusters: map[string]*clientcmdapi.Cluster{
41 "cow-cluster": {Server: "http://cow.org:8080"}},
42 Contexts: map[string]*clientcmdapi.Context{
43 "federal-context": {AuthInfo: "red-user", Cluster: "cow-cluster"}},
44 CurrentContext: "federal-context",
45 }
46 }
47
48 func Example_view() {
49 expectedConfig := newRedFederalCowHammerConfig()
50 test := configCommandTest{
51 args: []string{"view"},
52 startingConfig: newRedFederalCowHammerConfig(),
53 expectedConfig: expectedConfig,
54 }
55
56 output := test.run(&testing.T{})
57 fmt.Printf("%v", output)
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76 }
77
78 func TestCurrentContext(t *testing.T) {
79 startingConfig := newRedFederalCowHammerConfig()
80 test := configCommandTest{
81 args: []string{"current-context"},
82 startingConfig: startingConfig,
83 expectedConfig: startingConfig,
84 expectedOutputs: []string{startingConfig.CurrentContext},
85 }
86 test.run(t)
87 }
88
89 func TestSetCurrentContext(t *testing.T) {
90 expectedConfig := newRedFederalCowHammerConfig()
91 startingConfig := newRedFederalCowHammerConfig()
92
93 newContextName := "the-new-context"
94
95 startingConfig.Contexts[newContextName] = clientcmdapi.NewContext()
96 expectedConfig.Contexts[newContextName] = clientcmdapi.NewContext()
97
98 expectedConfig.CurrentContext = newContextName
99
100 test := configCommandTest{
101 args: []string{"use-context", "the-new-context"},
102 startingConfig: startingConfig,
103 expectedConfig: expectedConfig,
104 }
105
106 test.run(t)
107 }
108
109 func TestSetNonExistentContext(t *testing.T) {
110 expectedConfig := newRedFederalCowHammerConfig()
111
112 test := configCommandTest{
113 args: []string{"use-context", "non-existent-config"},
114 startingConfig: expectedConfig,
115 expectedConfig: expectedConfig,
116 }
117
118 func() {
119 defer func() {
120
121 cmdutil.DefaultBehaviorOnFatal()
122 }()
123
124
125 cmdutil.BehaviorOnFatal(func(e string, code int) {
126 if code != 1 {
127 t.Errorf("The exit code is %d, expected 1", code)
128 }
129 expectedOutputs := []string{`no context exists with the name: "non-existent-config"`}
130 test.checkOutput(e, expectedOutputs, t)
131 })
132
133 test.run(t)
134 }()
135 }
136
137 func TestSetIntoExistingStruct(t *testing.T) {
138 expectedConfig := newRedFederalCowHammerConfig()
139 expectedConfig.AuthInfos["red-user"].Password = "new-path-value"
140 test := configCommandTest{
141 args: []string{"set", "users.red-user.password", "new-path-value"},
142 startingConfig: newRedFederalCowHammerConfig(),
143 expectedConfig: expectedConfig,
144 }
145
146 test.run(t)
147 }
148
149 func TestSetWithPathPrefixIntoExistingStruct(t *testing.T) {
150 expectedConfig := newRedFederalCowHammerConfig()
151 expectedConfig.Clusters["cow-cluster"].Server = "http://cow.org:8080/foo/baz"
152 test := configCommandTest{
153 args: []string{"set", "clusters.cow-cluster.server", "http://cow.org:8080/foo/baz"},
154 startingConfig: newRedFederalCowHammerConfig(),
155 expectedConfig: expectedConfig,
156 }
157
158 test.run(t)
159
160 dc := clientcmd.NewDefaultClientConfig(expectedConfig, &clientcmd.ConfigOverrides{})
161 dcc, err := dc.ClientConfig()
162 if err != nil {
163 t.Fatalf("unexpected error: %v", err)
164 }
165 expectedHost := "http://cow.org:8080/foo/baz"
166 if expectedHost != dcc.Host {
167 t.Fatalf("expected client.Config.Host = %q instead of %q", expectedHost, dcc.Host)
168 }
169 }
170
171 func TestUnsetStruct(t *testing.T) {
172 expectedConfig := newRedFederalCowHammerConfig()
173 delete(expectedConfig.AuthInfos, "red-user")
174 test := configCommandTest{
175 args: []string{"unset", "users.red-user"},
176 startingConfig: newRedFederalCowHammerConfig(),
177 expectedConfig: expectedConfig,
178 }
179
180 test.run(t)
181 }
182
183 func TestUnsetField(t *testing.T) {
184 expectedConfig := newRedFederalCowHammerConfig()
185 expectedConfig.AuthInfos["red-user"] = clientcmdapi.NewAuthInfo()
186 test := configCommandTest{
187 args: []string{"unset", "users.red-user.token"},
188 startingConfig: newRedFederalCowHammerConfig(),
189 expectedConfig: expectedConfig,
190 }
191
192 test.run(t)
193 }
194
195 func TestSetIntoNewStruct(t *testing.T) {
196 expectedConfig := newRedFederalCowHammerConfig()
197 cluster := clientcmdapi.NewCluster()
198 cluster.Server = "new-server-value"
199 expectedConfig.Clusters["big-cluster"] = cluster
200 test := configCommandTest{
201 args: []string{"set", "clusters.big-cluster.server", "new-server-value"},
202 startingConfig: newRedFederalCowHammerConfig(),
203 expectedConfig: expectedConfig,
204 }
205
206 test.run(t)
207 }
208
209 func TestSetBoolean(t *testing.T) {
210 expectedConfig := newRedFederalCowHammerConfig()
211 cluster := clientcmdapi.NewCluster()
212 cluster.InsecureSkipTLSVerify = true
213 expectedConfig.Clusters["big-cluster"] = cluster
214 test := configCommandTest{
215 args: []string{"set", "clusters.big-cluster.insecure-skip-tls-verify", "true"},
216 startingConfig: newRedFederalCowHammerConfig(),
217 expectedConfig: expectedConfig,
218 }
219
220 test.run(t)
221 }
222
223 func TestSetIntoNewConfig(t *testing.T) {
224 expectedConfig := *clientcmdapi.NewConfig()
225 context := clientcmdapi.NewContext()
226 context.AuthInfo = "fake-user"
227 expectedConfig.Contexts["new-context"] = context
228 test := configCommandTest{
229 args: []string{"set", "contexts.new-context.user", "fake-user"},
230 startingConfig: *clientcmdapi.NewConfig(),
231 expectedConfig: expectedConfig,
232 }
233
234 test.run(t)
235 }
236
237 func TestNewEmptyAuth(t *testing.T) {
238 expectedConfig := *clientcmdapi.NewConfig()
239 expectedConfig.AuthInfos["the-user-name"] = clientcmdapi.NewAuthInfo()
240 test := configCommandTest{
241 args: []string{"set-credentials", "the-user-name"},
242 startingConfig: *clientcmdapi.NewConfig(),
243 expectedConfig: expectedConfig,
244 }
245
246 test.run(t)
247 }
248
249 func TestAdditionalAuth(t *testing.T) {
250 expectedConfig := newRedFederalCowHammerConfig()
251 authInfo := clientcmdapi.NewAuthInfo()
252 authInfo.Token = "token"
253 expectedConfig.AuthInfos["another-user"] = authInfo
254 test := configCommandTest{
255 args: []string{"set-credentials", "another-user", "--" + clientcmd.FlagBearerToken + "=token"},
256 startingConfig: newRedFederalCowHammerConfig(),
257 expectedConfig: expectedConfig,
258 }
259
260 test.run(t)
261 }
262
263 func TestEmbedClientCert(t *testing.T) {
264 fakeCertFile, _ := os.CreateTemp(os.TempDir(), "")
265 defer utiltesting.CloseAndRemove(t, fakeCertFile)
266 fakeData := []byte("fake-data")
267 os.WriteFile(fakeCertFile.Name(), fakeData, 0600)
268 expectedConfig := newRedFederalCowHammerConfig()
269 authInfo := clientcmdapi.NewAuthInfo()
270 authInfo.ClientCertificateData = fakeData
271 expectedConfig.AuthInfos["another-user"] = authInfo
272
273 test := configCommandTest{
274 args: []string{"set-credentials", "another-user", "--" + clientcmd.FlagCertFile + "=" + fakeCertFile.Name(), "--" + clientcmd.FlagEmbedCerts + "=true"},
275 startingConfig: newRedFederalCowHammerConfig(),
276 expectedConfig: expectedConfig,
277 }
278
279 test.run(t)
280 }
281
282 func TestExecPlugin(t *testing.T) {
283 fakeCertFile, _ := os.CreateTemp(os.TempDir(), "")
284 defer utiltesting.CloseAndRemove(t, fakeCertFile)
285 fakeData := []byte("fake-data")
286 err := os.WriteFile(fakeCertFile.Name(), fakeData, 0600)
287 if err != nil {
288 t.Errorf("unexpected error %v", err)
289 }
290 expectedConfig := newRedFederalCowHammerConfig()
291 authInfo := clientcmdapi.NewAuthInfo()
292 authInfo.Exec = &clientcmdapi.ExecConfig{
293 Command: "example-client-go-exec-plugin",
294 Args: []string{"arg1", "arg2"},
295 Env: []clientcmdapi.ExecEnvVar{
296 {
297 Name: "FOO",
298 Value: "bar",
299 },
300 },
301 APIVersion: "client.authentication.k8s.io/v1",
302 ProvideClusterInfo: false,
303 InteractiveMode: "Never",
304 }
305 expectedConfig.AuthInfos["cred-exec-user"] = authInfo
306
307 test := configCommandTest{
308 args: []string{
309 "set-credentials",
310 "cred-exec-user",
311 "--exec-api-version=client.authentication.k8s.io/v1",
312 "--exec-command=example-client-go-exec-plugin",
313 "--exec-arg=arg1,arg2",
314 "--exec-env=FOO=bar",
315 "--exec-interactive-mode=Never",
316 },
317 startingConfig: newRedFederalCowHammerConfig(),
318 expectedConfig: expectedConfig,
319 }
320
321 test.run(t)
322 }
323
324 func TestExecPluginWithProveClusterInfo(t *testing.T) {
325 fakeCertFile, _ := os.CreateTemp(os.TempDir(), "")
326 defer utiltesting.CloseAndRemove(t, fakeCertFile)
327 fakeData := []byte("fake-data")
328 err := os.WriteFile(fakeCertFile.Name(), fakeData, 0600)
329 if err != nil {
330 t.Errorf("unexpected error %v", err)
331 }
332 expectedConfig := newRedFederalCowHammerConfig()
333 authInfo := clientcmdapi.NewAuthInfo()
334 authInfo.Exec = &clientcmdapi.ExecConfig{
335 Command: "example-client-go-exec-plugin",
336 Args: []string{"arg1", "arg2"},
337 Env: []clientcmdapi.ExecEnvVar{
338 {
339 Name: "FOO",
340 Value: "bar",
341 },
342 },
343 APIVersion: "client.authentication.k8s.io/v1",
344 ProvideClusterInfo: true,
345 InteractiveMode: "Always",
346 }
347 expectedConfig.AuthInfos["cred-exec-user"] = authInfo
348
349 test := configCommandTest{
350 args: []string{
351 "set-credentials",
352 "cred-exec-user",
353 "--exec-api-version=client.authentication.k8s.io/v1",
354 "--exec-command=example-client-go-exec-plugin",
355 "--exec-arg=arg1,arg2",
356 "--exec-env=FOO=bar",
357 "--exec-interactive-mode=Always",
358 "--exec-provide-cluster-info=true",
359 },
360 startingConfig: newRedFederalCowHammerConfig(),
361 expectedConfig: expectedConfig,
362 }
363
364 test.run(t)
365 }
366
367 func TestEmbedClientKey(t *testing.T) {
368 fakeKeyFile, _ := os.CreateTemp(os.TempDir(), "")
369 defer utiltesting.CloseAndRemove(t, fakeKeyFile)
370 fakeData := []byte("fake-data")
371 os.WriteFile(fakeKeyFile.Name(), fakeData, 0600)
372 expectedConfig := newRedFederalCowHammerConfig()
373 authInfo := clientcmdapi.NewAuthInfo()
374 authInfo.ClientKeyData = fakeData
375 expectedConfig.AuthInfos["another-user"] = authInfo
376
377 test := configCommandTest{
378 args: []string{"set-credentials", "another-user", "--" + clientcmd.FlagKeyFile + "=" + fakeKeyFile.Name(), "--" + clientcmd.FlagEmbedCerts + "=true"},
379 startingConfig: newRedFederalCowHammerConfig(),
380 expectedConfig: expectedConfig,
381 }
382
383 test.run(t)
384 }
385
386 func TestEmbedNoKeyOrCertDisallowed(t *testing.T) {
387 expectedConfig := newRedFederalCowHammerConfig()
388 test := configCommandTest{
389 args: []string{"set-credentials", "another-user", "--" + clientcmd.FlagEmbedCerts + "=true"},
390 startingConfig: newRedFederalCowHammerConfig(),
391 expectedConfig: expectedConfig,
392 }
393
394 func() {
395 defer func() {
396
397 cmdutil.DefaultBehaviorOnFatal()
398 }()
399
400
401 cmdutil.BehaviorOnFatal(func(e string, code int) {
402 if code != 1 {
403 t.Errorf("The exit code is %d, expected 1", code)
404 }
405 expectedOutputs := []string{"--client-certificate", "--client-key", "embed"}
406 test.checkOutput(e, expectedOutputs, t)
407 })
408
409 test.run(t)
410 }()
411 }
412
413 func TestEmptyTokenAndCertAllowed(t *testing.T) {
414 fakeCertFile, _ := os.CreateTemp(os.TempDir(), "cert-file")
415 defer utiltesting.CloseAndRemove(t, fakeCertFile)
416 expectedConfig := newRedFederalCowHammerConfig()
417 authInfo := clientcmdapi.NewAuthInfo()
418 authInfo.ClientCertificate = path.Base(fakeCertFile.Name())
419 expectedConfig.AuthInfos["another-user"] = authInfo
420
421 test := configCommandTest{
422 args: []string{"set-credentials", "another-user", "--" + clientcmd.FlagCertFile + "=" + fakeCertFile.Name(), "--" + clientcmd.FlagBearerToken + "="},
423 startingConfig: newRedFederalCowHammerConfig(),
424 expectedConfig: expectedConfig,
425 }
426
427 test.run(t)
428 }
429
430 func TestTokenAndCertAllowed(t *testing.T) {
431 expectedConfig := newRedFederalCowHammerConfig()
432 authInfo := clientcmdapi.NewAuthInfo()
433 authInfo.Token = "token"
434 authInfo.ClientCertificate = "/cert-file"
435 expectedConfig.AuthInfos["another-user"] = authInfo
436 test := configCommandTest{
437 args: []string{"set-credentials", "another-user", "--" + clientcmd.FlagCertFile + "=/cert-file", "--" + clientcmd.FlagBearerToken + "=token"},
438 startingConfig: newRedFederalCowHammerConfig(),
439 expectedConfig: expectedConfig,
440 }
441
442 test.run(t)
443 }
444
445 func TestTokenAndBasicDisallowed(t *testing.T) {
446 expectedConfig := newRedFederalCowHammerConfig()
447 test := configCommandTest{
448 args: []string{"set-credentials", "another-user", "--" + clientcmd.FlagUsername + "=myuser", "--" + clientcmd.FlagBearerToken + "=token"},
449 startingConfig: newRedFederalCowHammerConfig(),
450 expectedConfig: expectedConfig,
451 }
452
453 func() {
454 defer func() {
455
456 cmdutil.DefaultBehaviorOnFatal()
457 }()
458
459
460 cmdutil.BehaviorOnFatal(func(e string, code int) {
461 if code != 1 {
462 t.Errorf("The exit code is %d, expected 1", code)
463 }
464
465 expectedOutputs := []string{"--token", "--username"}
466 test.checkOutput(e, expectedOutputs, t)
467 })
468
469 test.run(t)
470 }()
471 }
472
473 func TestBasicClearsToken(t *testing.T) {
474 authInfoWithToken := clientcmdapi.NewAuthInfo()
475 authInfoWithToken.Token = "token"
476
477 authInfoWithBasic := clientcmdapi.NewAuthInfo()
478 authInfoWithBasic.Username = "myuser"
479 authInfoWithBasic.Password = "mypass"
480
481 startingConfig := newRedFederalCowHammerConfig()
482 startingConfig.AuthInfos["another-user"] = authInfoWithToken
483
484 expectedConfig := newRedFederalCowHammerConfig()
485 expectedConfig.AuthInfos["another-user"] = authInfoWithBasic
486
487 test := configCommandTest{
488 args: []string{"set-credentials", "another-user", "--" + clientcmd.FlagUsername + "=myuser", "--" + clientcmd.FlagPassword + "=mypass"},
489 startingConfig: startingConfig,
490 expectedConfig: expectedConfig,
491 }
492
493 test.run(t)
494 }
495
496 func TestTokenClearsBasic(t *testing.T) {
497 authInfoWithBasic := clientcmdapi.NewAuthInfo()
498 authInfoWithBasic.Username = "myuser"
499 authInfoWithBasic.Password = "mypass"
500
501 authInfoWithToken := clientcmdapi.NewAuthInfo()
502 authInfoWithToken.Token = "token"
503
504 startingConfig := newRedFederalCowHammerConfig()
505 startingConfig.AuthInfos["another-user"] = authInfoWithBasic
506
507 expectedConfig := newRedFederalCowHammerConfig()
508 expectedConfig.AuthInfos["another-user"] = authInfoWithToken
509
510 test := configCommandTest{
511 args: []string{"set-credentials", "another-user", "--" + clientcmd.FlagBearerToken + "=token"},
512 startingConfig: startingConfig,
513 expectedConfig: expectedConfig,
514 }
515
516 test.run(t)
517 }
518
519 func TestTokenLeavesCert(t *testing.T) {
520 authInfoWithCerts := clientcmdapi.NewAuthInfo()
521 authInfoWithCerts.ClientCertificate = "cert"
522 authInfoWithCerts.ClientCertificateData = []byte("certdata")
523 authInfoWithCerts.ClientKey = "key"
524 authInfoWithCerts.ClientKeyData = []byte("keydata")
525
526 authInfoWithTokenAndCerts := clientcmdapi.NewAuthInfo()
527 authInfoWithTokenAndCerts.Token = "token"
528 authInfoWithTokenAndCerts.ClientCertificate = "cert"
529 authInfoWithTokenAndCerts.ClientCertificateData = []byte("certdata")
530 authInfoWithTokenAndCerts.ClientKey = "key"
531 authInfoWithTokenAndCerts.ClientKeyData = []byte("keydata")
532
533 startingConfig := newRedFederalCowHammerConfig()
534 startingConfig.AuthInfos["another-user"] = authInfoWithCerts
535
536 expectedConfig := newRedFederalCowHammerConfig()
537 expectedConfig.AuthInfos["another-user"] = authInfoWithTokenAndCerts
538
539 test := configCommandTest{
540 args: []string{"set-credentials", "another-user", "--" + clientcmd.FlagBearerToken + "=token"},
541 startingConfig: startingConfig,
542 expectedConfig: expectedConfig,
543 }
544
545 test.run(t)
546 }
547
548 func TestCertLeavesToken(t *testing.T) {
549 authInfoWithToken := clientcmdapi.NewAuthInfo()
550 authInfoWithToken.Token = "token"
551
552 authInfoWithTokenAndCerts := clientcmdapi.NewAuthInfo()
553 authInfoWithTokenAndCerts.Token = "token"
554 authInfoWithTokenAndCerts.ClientCertificate = "/cert"
555 authInfoWithTokenAndCerts.ClientKey = "/key"
556
557 startingConfig := newRedFederalCowHammerConfig()
558 startingConfig.AuthInfos["another-user"] = authInfoWithToken
559
560 expectedConfig := newRedFederalCowHammerConfig()
561 expectedConfig.AuthInfos["another-user"] = authInfoWithTokenAndCerts
562
563 test := configCommandTest{
564 args: []string{"set-credentials", "another-user", "--" + clientcmd.FlagCertFile + "=/cert", "--" + clientcmd.FlagKeyFile + "=/key"},
565 startingConfig: startingConfig,
566 expectedConfig: expectedConfig,
567 }
568
569 test.run(t)
570 }
571
572 func TestSetBytesBad(t *testing.T) {
573 startingConfig := newRedFederalCowHammerConfig()
574 startingConfig.Clusters["another-cluster"] = clientcmdapi.NewCluster()
575
576 test := configCommandTest{
577 args: []string{"set", "clusters.another-cluster.certificate-authority-data", "cadata"},
578 startingConfig: startingConfig,
579 expectedConfig: startingConfig,
580 }
581
582 func() {
583 defer func() {
584
585 cmdutil.DefaultBehaviorOnFatal()
586 }()
587
588
589 cmdutil.BehaviorOnFatal(func(e string, code int) {
590 if code != 1 {
591 t.Errorf("The exit code is %d, expected 1", code)
592 }
593 })
594
595 test.run(t)
596 }()
597 }
598
599 func TestSetBytes(t *testing.T) {
600 clusterInfoWithCAData := clientcmdapi.NewCluster()
601 clusterInfoWithCAData.CertificateAuthorityData = []byte("cadata")
602
603 startingConfig := newRedFederalCowHammerConfig()
604 startingConfig.Clusters["another-cluster"] = clientcmdapi.NewCluster()
605
606 expectedConfig := newRedFederalCowHammerConfig()
607 expectedConfig.Clusters["another-cluster"] = clusterInfoWithCAData
608
609 test := configCommandTest{
610 args: []string{"set", "clusters.another-cluster.certificate-authority-data", "cadata", "--set-raw-bytes"},
611 startingConfig: startingConfig,
612 expectedConfig: expectedConfig,
613 }
614
615 test.run(t)
616 }
617
618 func TestSetBase64Bytes(t *testing.T) {
619 clusterInfoWithCAData := clientcmdapi.NewCluster()
620 clusterInfoWithCAData.CertificateAuthorityData = []byte("cadata")
621
622 startingConfig := newRedFederalCowHammerConfig()
623 startingConfig.Clusters["another-cluster"] = clientcmdapi.NewCluster()
624
625 expectedConfig := newRedFederalCowHammerConfig()
626 expectedConfig.Clusters["another-cluster"] = clusterInfoWithCAData
627
628 test := configCommandTest{
629 args: []string{"set", "clusters.another-cluster.certificate-authority-data", "Y2FkYXRh"},
630 startingConfig: startingConfig,
631 expectedConfig: expectedConfig,
632 }
633
634 test.run(t)
635 }
636
637 func TestUnsetBytes(t *testing.T) {
638 clusterInfoWithCAData := clientcmdapi.NewCluster()
639 clusterInfoWithCAData.CertificateAuthorityData = []byte("cadata")
640
641 startingConfig := newRedFederalCowHammerConfig()
642 startingConfig.Clusters["another-cluster"] = clusterInfoWithCAData
643
644 expectedConfig := newRedFederalCowHammerConfig()
645 expectedConfig.Clusters["another-cluster"] = clientcmdapi.NewCluster()
646
647 test := configCommandTest{
648 args: []string{"unset", "clusters.another-cluster.certificate-authority-data"},
649 startingConfig: startingConfig,
650 expectedConfig: expectedConfig,
651 }
652
653 test.run(t)
654 }
655
656 func TestCAClearsInsecure(t *testing.T) {
657 fakeCAFile, _ := os.CreateTemp(os.TempDir(), "ca-file")
658 defer utiltesting.CloseAndRemove(t, fakeCAFile)
659 clusterInfoWithInsecure := clientcmdapi.NewCluster()
660 clusterInfoWithInsecure.InsecureSkipTLSVerify = true
661
662 clusterInfoWithCA := clientcmdapi.NewCluster()
663 clusterInfoWithCA.CertificateAuthority = path.Base(fakeCAFile.Name())
664
665 startingConfig := newRedFederalCowHammerConfig()
666 startingConfig.Clusters["another-cluster"] = clusterInfoWithInsecure
667
668 expectedConfig := newRedFederalCowHammerConfig()
669 expectedConfig.Clusters["another-cluster"] = clusterInfoWithCA
670
671 test := configCommandTest{
672 args: []string{"set-cluster", "another-cluster", "--" + clientcmd.FlagCAFile + "=" + fakeCAFile.Name()},
673 startingConfig: startingConfig,
674 expectedConfig: expectedConfig,
675 }
676
677 test.run(t)
678 }
679
680 func TestCAClearsCAData(t *testing.T) {
681 clusterInfoWithCAData := clientcmdapi.NewCluster()
682 clusterInfoWithCAData.CertificateAuthorityData = []byte("cadata")
683
684 clusterInfoWithCA := clientcmdapi.NewCluster()
685 clusterInfoWithCA.CertificateAuthority = "/cafile"
686
687 startingConfig := newRedFederalCowHammerConfig()
688 startingConfig.Clusters["another-cluster"] = clusterInfoWithCAData
689
690 expectedConfig := newRedFederalCowHammerConfig()
691 expectedConfig.Clusters["another-cluster"] = clusterInfoWithCA
692
693 test := configCommandTest{
694 args: []string{"set-cluster", "another-cluster", "--" + clientcmd.FlagCAFile + "=/cafile", "--" + clientcmd.FlagInsecure + "=false"},
695 startingConfig: startingConfig,
696 expectedConfig: expectedConfig,
697 }
698
699 test.run(t)
700 }
701
702 func TestInsecureClearsCA(t *testing.T) {
703 clusterInfoWithInsecure := clientcmdapi.NewCluster()
704 clusterInfoWithInsecure.InsecureSkipTLSVerify = true
705
706 clusterInfoWithCA := clientcmdapi.NewCluster()
707 clusterInfoWithCA.CertificateAuthority = "cafile"
708 clusterInfoWithCA.CertificateAuthorityData = []byte("cadata")
709
710 startingConfig := newRedFederalCowHammerConfig()
711 startingConfig.Clusters["another-cluster"] = clusterInfoWithCA
712
713 expectedConfig := newRedFederalCowHammerConfig()
714 expectedConfig.Clusters["another-cluster"] = clusterInfoWithInsecure
715
716 test := configCommandTest{
717 args: []string{"set-cluster", "another-cluster", "--" + clientcmd.FlagInsecure + "=true"},
718 startingConfig: startingConfig,
719 expectedConfig: expectedConfig,
720 }
721
722 test.run(t)
723 }
724
725 func TestCADataClearsCA(t *testing.T) {
726 fakeCAFile, _ := os.CreateTemp(os.TempDir(), "")
727 defer utiltesting.CloseAndRemove(t, fakeCAFile)
728 fakeData := []byte("cadata")
729 os.WriteFile(fakeCAFile.Name(), fakeData, 0600)
730
731 clusterInfoWithCAData := clientcmdapi.NewCluster()
732 clusterInfoWithCAData.CertificateAuthorityData = fakeData
733
734 clusterInfoWithCA := clientcmdapi.NewCluster()
735 clusterInfoWithCA.CertificateAuthority = "cafile"
736
737 startingConfig := newRedFederalCowHammerConfig()
738 startingConfig.Clusters["another-cluster"] = clusterInfoWithCA
739
740 expectedConfig := newRedFederalCowHammerConfig()
741 expectedConfig.Clusters["another-cluster"] = clusterInfoWithCAData
742
743 test := configCommandTest{
744 args: []string{"set-cluster", "another-cluster", "--" + clientcmd.FlagCAFile + "=" + fakeCAFile.Name(), "--" + clientcmd.FlagEmbedCerts + "=true"},
745 startingConfig: startingConfig,
746 expectedConfig: expectedConfig,
747 }
748
749 test.run(t)
750 }
751
752 func TestEmbedNoCADisallowed(t *testing.T) {
753 expectedConfig := newRedFederalCowHammerConfig()
754 test := configCommandTest{
755 args: []string{"set-cluster", "another-cluster", "--" + clientcmd.FlagEmbedCerts + "=true"},
756 startingConfig: newRedFederalCowHammerConfig(),
757 expectedConfig: expectedConfig,
758 }
759
760 func() {
761 defer func() {
762
763 cmdutil.DefaultBehaviorOnFatal()
764 }()
765
766
767 cmdutil.BehaviorOnFatal(func(e string, code int) {
768 if code != 1 {
769 t.Errorf("The exit code is %d, expected 1", code)
770 }
771
772 expectedOutputs := []string{"--certificate-authority", "embed"}
773 test.checkOutput(e, expectedOutputs, t)
774 })
775
776 test.run(t)
777 }()
778 }
779
780 func TestCAAndInsecureDisallowed(t *testing.T) {
781 test := configCommandTest{
782 args: []string{"set-cluster", "another-cluster", "--" + clientcmd.FlagCAFile + "=cafile", "--" + clientcmd.FlagInsecure + "=true"},
783 startingConfig: newRedFederalCowHammerConfig(),
784 expectedConfig: newRedFederalCowHammerConfig(),
785 }
786
787 func() {
788 defer func() {
789
790 cmdutil.DefaultBehaviorOnFatal()
791 }()
792
793
794 cmdutil.BehaviorOnFatal(func(e string, code int) {
795 if code != 1 {
796 t.Errorf("The exit code is %d, expected 1", code)
797 }
798
799 expectedOutputs := []string{"certificate", "insecure"}
800 test.checkOutput(e, expectedOutputs, t)
801 })
802
803 test.run(t)
804 }()
805 }
806
807 func TestMergeExistingAuth(t *testing.T) {
808 expectedConfig := newRedFederalCowHammerConfig()
809 authInfo := expectedConfig.AuthInfos["red-user"]
810 authInfo.ClientKey = "/key"
811 expectedConfig.AuthInfos["red-user"] = authInfo
812 test := configCommandTest{
813 args: []string{"set-credentials", "red-user", "--" + clientcmd.FlagKeyFile + "=/key"},
814 startingConfig: newRedFederalCowHammerConfig(),
815 expectedConfig: expectedConfig,
816 }
817
818 test.run(t)
819 }
820
821 func TestNewEmptyCluster(t *testing.T) {
822 expectedConfig := *clientcmdapi.NewConfig()
823 expectedConfig.Clusters["new-cluster"] = clientcmdapi.NewCluster()
824 test := configCommandTest{
825 args: []string{"set-cluster", "new-cluster"},
826 startingConfig: *clientcmdapi.NewConfig(),
827 expectedConfig: expectedConfig,
828 }
829
830 test.run(t)
831 }
832
833 func TestAdditionalCluster(t *testing.T) {
834 expectedConfig := newRedFederalCowHammerConfig()
835 cluster := clientcmdapi.NewCluster()
836 cluster.CertificateAuthority = "/ca-location"
837 cluster.InsecureSkipTLSVerify = false
838 cluster.Server = "serverlocation"
839 expectedConfig.Clusters["different-cluster"] = cluster
840 test := configCommandTest{
841 args: []string{"set-cluster", "different-cluster", "--" + clientcmd.FlagAPIServer + "=serverlocation", "--" + clientcmd.FlagInsecure + "=false", "--" + clientcmd.FlagCAFile + "=/ca-location"},
842 startingConfig: newRedFederalCowHammerConfig(),
843 expectedConfig: expectedConfig,
844 }
845
846 test.run(t)
847 }
848
849 func TestOverwriteExistingCluster(t *testing.T) {
850 expectedConfig := newRedFederalCowHammerConfig()
851 cluster := clientcmdapi.NewCluster()
852 cluster.Server = "serverlocation"
853 expectedConfig.Clusters["cow-cluster"] = cluster
854
855 test := configCommandTest{
856 args: []string{"set-cluster", "cow-cluster", "--" + clientcmd.FlagAPIServer + "=serverlocation"},
857 startingConfig: newRedFederalCowHammerConfig(),
858 expectedConfig: expectedConfig,
859 }
860
861 test.run(t)
862 }
863
864 func TestNewEmptyContext(t *testing.T) {
865 expectedConfig := *clientcmdapi.NewConfig()
866 expectedConfig.Contexts["new-context"] = clientcmdapi.NewContext()
867 test := configCommandTest{
868 args: []string{"set-context", "new-context"},
869 startingConfig: *clientcmdapi.NewConfig(),
870 expectedConfig: expectedConfig,
871 }
872
873 test.run(t)
874 }
875
876 func TestAdditionalContext(t *testing.T) {
877 expectedConfig := newRedFederalCowHammerConfig()
878 context := clientcmdapi.NewContext()
879 context.Cluster = "some-cluster"
880 context.AuthInfo = "some-user"
881 context.Namespace = "different-namespace"
882 expectedConfig.Contexts["different-context"] = context
883 test := configCommandTest{
884 args: []string{"set-context", "different-context", "--" + clientcmd.FlagClusterName + "=some-cluster", "--" + clientcmd.FlagAuthInfoName + "=some-user", "--" + clientcmd.FlagNamespace + "=different-namespace"},
885 startingConfig: newRedFederalCowHammerConfig(),
886 expectedConfig: expectedConfig,
887 }
888
889 test.run(t)
890 }
891
892 func TestMergeExistingContext(t *testing.T) {
893 expectedConfig := newRedFederalCowHammerConfig()
894 context := expectedConfig.Contexts["federal-context"]
895 context.Namespace = "hammer"
896 expectedConfig.Contexts["federal-context"] = context
897
898 test := configCommandTest{
899 args: []string{"set-context", "federal-context", "--" + clientcmd.FlagNamespace + "=hammer"},
900 startingConfig: newRedFederalCowHammerConfig(),
901 expectedConfig: expectedConfig,
902 }
903
904 test.run(t)
905 }
906
907 func TestToBool(t *testing.T) {
908 type test struct {
909 in string
910 out bool
911 err string
912 }
913
914 tests := []test{
915 {"", false, ""},
916 {"true", true, ""},
917 {"on", false, `strconv.ParseBool: parsing "on": invalid syntax`},
918 }
919
920 for _, curr := range tests {
921 b, err := toBool(curr.in)
922 if (len(curr.err) != 0) && err == nil {
923 t.Errorf("Expected error: %v, but got nil", curr.err)
924 }
925 if (len(curr.err) == 0) && err != nil {
926 t.Errorf("Unexpected error: %v", err)
927 }
928 if (err != nil) && (err.Error() != curr.err) {
929 t.Errorf("Expected %v, got %v", curr.err, err)
930
931 }
932 if b != curr.out {
933 t.Errorf("Expected %v, got %v", curr.out, b)
934 }
935 }
936
937 }
938
939 func testConfigCommand(args []string, startingConfig clientcmdapi.Config, t *testing.T) (string, clientcmdapi.Config) {
940 fakeKubeFile, _ := os.CreateTemp(os.TempDir(), "")
941 defer utiltesting.CloseAndRemove(t, fakeKubeFile)
942 err := clientcmd.WriteToFile(startingConfig, fakeKubeFile.Name())
943 if err != nil {
944 t.Fatalf("unexpected error: %v", err)
945 }
946
947 argsToUse := make([]string, 0, 2+len(args))
948 argsToUse = append(argsToUse, "--kubeconfig="+fakeKubeFile.Name())
949 argsToUse = append(argsToUse, args...)
950
951 streams, _, buf, _ := genericiooptions.NewTestIOStreams()
952 cmd := NewCmdConfig(clientcmd.NewDefaultPathOptions(), streams)
953
954 cmd.PersistentFlags().String("context", "", "The name of the kubeconfig context to use")
955 cmd.SetArgs(argsToUse)
956 cmd.Execute()
957
958 config := clientcmd.GetConfigFromFileOrDie(fakeKubeFile.Name())
959 return buf.String(), *config
960 }
961
962 type configCommandTest struct {
963 args []string
964 startingConfig clientcmdapi.Config
965 expectedConfig clientcmdapi.Config
966 expectedOutputs []string
967 }
968
969 func (test configCommandTest) checkOutput(out string, expectedOutputs []string, t *testing.T) {
970 for _, expectedOutput := range expectedOutputs {
971 if !strings.Contains(out, expectedOutput) {
972 t.Errorf("expected '%s' in output, got '%s'", expectedOutput, out)
973 }
974 }
975 }
976
977 func (test configCommandTest) run(t *testing.T) string {
978 out, actualConfig := testConfigCommand(test.args, test.startingConfig, t)
979
980 testSetNilMapsToEmpties(reflect.ValueOf(&test.expectedConfig))
981 testSetNilMapsToEmpties(reflect.ValueOf(&actualConfig))
982 testClearLocationOfOrigin(&actualConfig)
983
984 if !apiequality.Semantic.DeepEqual(test.expectedConfig, actualConfig) {
985 t.Errorf("diff: %v", cmp.Diff(test.expectedConfig, actualConfig))
986 t.Errorf("expected: %#v\n actual: %#v", test.expectedConfig, actualConfig)
987 }
988
989 test.checkOutput(out, test.expectedOutputs, t)
990
991 return out
992 }
993 func testClearLocationOfOrigin(config *clientcmdapi.Config) {
994 for key, obj := range config.AuthInfos {
995 obj.LocationOfOrigin = ""
996 config.AuthInfos[key] = obj
997 }
998 for key, obj := range config.Clusters {
999 obj.LocationOfOrigin = ""
1000 config.Clusters[key] = obj
1001 }
1002 for key, obj := range config.Contexts {
1003 obj.LocationOfOrigin = ""
1004 config.Contexts[key] = obj
1005 }
1006 }
1007 func testSetNilMapsToEmpties(curr reflect.Value) {
1008 actualCurrValue := curr
1009 if curr.Kind() == reflect.Pointer {
1010 actualCurrValue = curr.Elem()
1011 }
1012
1013 switch actualCurrValue.Kind() {
1014 case reflect.Map:
1015 for _, mapKey := range actualCurrValue.MapKeys() {
1016 currMapValue := actualCurrValue.MapIndex(mapKey)
1017 testSetNilMapsToEmpties(currMapValue)
1018 }
1019
1020 case reflect.Struct:
1021 for fieldIndex := 0; fieldIndex < actualCurrValue.NumField(); fieldIndex++ {
1022 currFieldValue := actualCurrValue.Field(fieldIndex)
1023
1024 if currFieldValue.Kind() == reflect.Map && currFieldValue.IsNil() {
1025 newValue := reflect.MakeMap(currFieldValue.Type())
1026 currFieldValue.Set(newValue)
1027 } else {
1028 testSetNilMapsToEmpties(currFieldValue.Addr())
1029 }
1030 }
1031
1032 }
1033
1034 }
1035
View as plain text