...

Source file src/k8s.io/client-go/tools/auth/exec/types_test.go

Documentation: k8s.io/client-go/tools/auth/exec

     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  }
   166  

View as plain text