k8s.io/client-go@v0.31.1/tools/auth/exec/types_test.go (about) 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 exec 18 19 import ( 20 "fmt" 21 "reflect" 22 "testing" 23 24 "k8s.io/apimachinery/pkg/runtime" 25 "k8s.io/apimachinery/pkg/util/sets" 26 clientauthenticationv1 "k8s.io/client-go/pkg/apis/clientauthentication/v1" 27 clientauthenticationv1beta1 "k8s.io/client-go/pkg/apis/clientauthentication/v1beta1" 28 clientcmdv1 "k8s.io/client-go/tools/clientcmd/api/v1" 29 ) 30 31 func TestClientAuthenticationClusterTypesAreSynced(t *testing.T) { 32 t.Parallel() 33 34 for _, cluster := range []interface{}{ 35 clientauthenticationv1beta1.Cluster{}, 36 clientauthenticationv1.Cluster{}, 37 } { 38 cluster := cluster 39 t.Run(fmt.Sprintf("%T", cluster), func(t *testing.T) { 40 t.Parallel() 41 testClientAuthenticationClusterTypesAreSynced(t, cluster) 42 }) 43 } 44 } 45 46 // testClusterTypesAreSynced ensures that the provided cluster type stays in sync 47 // with clientcmdv1.Cluster. 48 // 49 // We want clientauthentication*.Cluster types to offer the same knobs as clientcmdv1.Cluster to 50 // allow someone to connect to the kubernetes API. This test should fail if a new field is added to 51 // one of the structs without updating the other. 52 func testClientAuthenticationClusterTypesAreSynced(t *testing.T, cluster interface{}) { 53 execType := reflect.TypeOf(cluster) 54 clientcmdType := reflect.TypeOf(clientcmdv1.Cluster{}) 55 56 t.Run("exec cluster fields match clientcmd cluster fields", func(t *testing.T) { 57 t.Parallel() 58 59 // These are fields that are specific to Cluster and shouldn't be in clientcmdv1.Cluster. 60 execSkippedFieldNames := sets.NewString( 61 // Cluster uses Config to provide its cluster-specific configuration object. 62 "Config", 63 ) 64 65 for i := 0; i < execType.NumField(); i++ { 66 execField := execType.Field(i) 67 if execSkippedFieldNames.Has(execField.Name) { 68 continue 69 } 70 71 t.Run(execField.Name, func(t *testing.T) { 72 t.Parallel() 73 clientcmdField, ok := clientcmdType.FieldByName(execField.Name) 74 if !ok { 75 t.Errorf("unknown field (please add field to clientcmdv1.Cluster): '%s'", execField.Name) 76 } else if execField.Type != clientcmdField.Type { 77 t.Errorf( 78 "type mismatch (please update Cluster.%s field type to match clientcmdv1.Cluster.%s field type): %q != %q", 79 execField.Name, 80 clientcmdField.Name, 81 execField.Type, 82 clientcmdField.Type, 83 ) 84 } else if execField.Tag != clientcmdField.Tag { 85 t.Errorf( 86 "tag mismatch (please update Cluster.%s tag to match clientcmdv1.Cluster.%s tag): %q != %q", 87 execField.Name, 88 clientcmdField.Name, 89 execField.Tag, 90 clientcmdField.Tag, 91 ) 92 } 93 }) 94 } 95 }) 96 97 t.Run("clientcmd cluster fields match exec cluster fields", func(t *testing.T) { 98 t.Parallel() 99 100 // These are the fields that we don't want to shadow from clientcmdv1.Cluster. 101 clientcmdSkippedFieldNames := sets.NewString( 102 // CA data will be passed via CertificateAuthorityData, so we don't need this field. 103 "CertificateAuthority", 104 // Cluster uses Config to provide its cluster-specific configuration object. 105 "Extensions", 106 ) 107 108 for i := 0; i < clientcmdType.NumField(); i++ { 109 clientcmdField := clientcmdType.Field(i) 110 if clientcmdSkippedFieldNames.Has(clientcmdField.Name) { 111 continue 112 } 113 114 t.Run(clientcmdField.Name, func(t *testing.T) { 115 t.Parallel() 116 execField, ok := execType.FieldByName(clientcmdField.Name) 117 if !ok { 118 t.Errorf("unknown field (please add field to Cluster): '%s'", clientcmdField.Name) 119 } else if clientcmdField.Type != execField.Type { 120 t.Errorf( 121 "type mismatch (please update clientcmdv1.Cluster.%s field type to match Cluster.%s field type): %q != %q", 122 clientcmdField.Name, 123 execField.Name, 124 clientcmdField.Type, 125 execField.Type, 126 ) 127 } else if clientcmdField.Tag != execField.Tag { 128 t.Errorf( 129 "tag mismatch (please update clientcmdv1.Cluster.%s tag to match Cluster.%s tag): %q != %q", 130 clientcmdField.Name, 131 execField.Name, 132 clientcmdField.Tag, 133 execField.Tag, 134 ) 135 } 136 }) 137 } 138 }) 139 } 140 141 // TestAllClusterTypesAreSynced is a TODO so that we remember to write a test similar to 142 // TestClientAuthenticationClusterTypesAreSynced for any future ExecCredential version. It should start failing 143 // when someone adds support for any other ExecCredential type to this package. 144 func TestAllClusterTypesAreSynced(t *testing.T) { 145 versionsThatDontNeedTests := sets.NewString( 146 // The internal Cluster type should only be used...internally...and therefore doesn't 147 // necessarily need to be synced with clientcmdv1. 148 runtime.APIVersionInternal, 149 // We have a test for v1beta1 above. 150 clientauthenticationv1beta1.SchemeGroupVersion.Version, 151 // We have a test for v1 above. 152 clientauthenticationv1.SchemeGroupVersion.Version, 153 ) 154 for gvk := range scheme.AllKnownTypes() { 155 if gvk.Group == clientauthenticationv1beta1.SchemeGroupVersion.Group && 156 gvk.Kind == "ExecCredential" { 157 if !versionsThatDontNeedTests.Has(gvk.Version) { 158 t.Errorf( 159 "TODO: add test similar to TestV1beta1ClusterTypesAreSynced for client.authentication.k8s.io/%s", 160 gvk.Version, 161 ) 162 } 163 } 164 } 165 }