k8s.io/client-go@v0.22.2/transport/transport_test.go (about)

     1  /*
     2  Copyright 2015 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 transport
    18  
    19  import (
    20  	"context"
    21  	"crypto/tls"
    22  	"errors"
    23  	"fmt"
    24  	"net/http"
    25  	"testing"
    26  )
    27  
    28  const (
    29  	rootCACert = `-----BEGIN CERTIFICATE-----
    30  MIIC4DCCAcqgAwIBAgIBATALBgkqhkiG9w0BAQswIzEhMB8GA1UEAwwYMTAuMTMu
    31  MTI5LjEwNkAxNDIxMzU5MDU4MB4XDTE1MDExNTIxNTczN1oXDTE2MDExNTIxNTcz
    32  OFowIzEhMB8GA1UEAwwYMTAuMTMuMTI5LjEwNkAxNDIxMzU5MDU4MIIBIjANBgkq
    33  hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAunDRXGwsiYWGFDlWH6kjGun+PshDGeZX
    34  xtx9lUnL8pIRWH3wX6f13PO9sktaOWW0T0mlo6k2bMlSLlSZgG9H6og0W6gLS3vq
    35  s4VavZ6DbXIwemZG2vbRwsvR+t4G6Nbwelm6F8RFnA1Fwt428pavmNQ/wgYzo+T1
    36  1eS+HiN4ACnSoDSx3QRWcgBkB1g6VReofVjx63i0J+w8Q/41L9GUuLqquFxu6ZnH
    37  60vTB55lHgFiDLjA1FkEz2dGvGh/wtnFlRvjaPC54JH2K1mPYAUXTreoeJtLJKX0
    38  ycoiyB24+zGCniUmgIsmQWRPaOPircexCp1BOeze82BT1LCZNTVaxQIDAQABoyMw
    39  ITAOBgNVHQ8BAf8EBAMCAKQwDwYDVR0TAQH/BAUwAwEB/zALBgkqhkiG9w0BAQsD
    40  ggEBADMxsUuAFlsYDpF4fRCzXXwrhbtj4oQwcHpbu+rnOPHCZupiafzZpDu+rw4x
    41  YGPnCb594bRTQn4pAu3Ac18NbLD5pV3uioAkv8oPkgr8aUhXqiv7KdDiaWm6sbAL
    42  EHiXVBBAFvQws10HMqMoKtO8f1XDNAUkWduakR/U6yMgvOPwS7xl0eUTqyRB6zGb
    43  K55q2dejiFWaFqB/y78txzvz6UlOZKE44g2JAVoJVM6kGaxh33q8/FmrL4kuN3ut
    44  W+MmJCVDvd4eEqPwbp7146ZWTqpIJ8lvA6wuChtqV8lhAPka2hD/LMqY8iXNmfXD
    45  uml0obOEy+ON91k+SWTJ3ggmF/U=
    46  -----END CERTIFICATE-----`
    47  
    48  	certData = `-----BEGIN CERTIFICATE-----
    49  MIIC6jCCAdSgAwIBAgIBCzALBgkqhkiG9w0BAQswIzEhMB8GA1UEAwwYMTAuMTMu
    50  MTI5LjEwNkAxNDIxMzU5MDU4MB4XDTE1MDExNTIyMDEzMVoXDTE2MDExNTIyMDEz
    51  MlowGzEZMBcGA1UEAxMQb3BlbnNoaWZ0LWNsaWVudDCCASIwDQYJKoZIhvcNAQEB
    52  BQADggEPADCCAQoCggEBAKtdhz0+uCLXw5cSYns9rU/XifFSpb/x24WDdrm72S/v
    53  b9BPYsAStiP148buylr1SOuNi8sTAZmlVDDIpIVwMLff+o2rKYDicn9fjbrTxTOj
    54  lI4pHJBH+JU3AJ0tbajupioh70jwFS0oYpwtneg2zcnE2Z4l6mhrj2okrc5Q1/X2
    55  I2HChtIU4JYTisObtin10QKJX01CLfYXJLa8upWzKZ4/GOcHG+eAV3jXWoXidtjb
    56  1Usw70amoTZ6mIVCkiu1QwCoa8+ycojGfZhvqMsAp1536ZcCul+Na+AbCv4zKS7F
    57  kQQaImVrXdUiFansIoofGlw/JNuoKK6ssVpS5Ic3pgcCAwEAAaM1MDMwDgYDVR0P
    58  AQH/BAQDAgCgMBMGA1UdJQQMMAoGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwCwYJ
    59  KoZIhvcNAQELA4IBAQCKLREH7bXtXtZ+8vI6cjD7W3QikiArGqbl36bAhhWsJLp/
    60  p/ndKz39iFNaiZ3GlwIURWOOKx3y3GA0x9m8FR+Llthf0EQ8sUjnwaknWs0Y6DQ3
    61  jjPFZOpV3KPCFrdMJ3++E3MgwFC/Ih/N2ebFX9EcV9Vcc6oVWMdwT0fsrhu683rq
    62  6GSR/3iVX1G/pmOiuaR0fNUaCyCfYrnI4zHBDgSfnlm3vIvN2lrsR/DQBakNL8DJ
    63  HBgKxMGeUPoneBv+c8DMXIL0EhaFXRlBv9QW45/GiAIOuyFJ0i6hCtGZpJjq4OpQ
    64  BRjCI+izPzFTjsxD4aORE+WOkyWFCGPWKfNejfw0
    65  -----END CERTIFICATE-----`
    66  
    67  	keyData = `-----BEGIN RSA PRIVATE KEY-----
    68  MIIEowIBAAKCAQEAq12HPT64ItfDlxJiez2tT9eJ8VKlv/HbhYN2ubvZL+9v0E9i
    69  wBK2I/Xjxu7KWvVI642LyxMBmaVUMMikhXAwt9/6jaspgOJyf1+NutPFM6OUjikc
    70  kEf4lTcAnS1tqO6mKiHvSPAVLShinC2d6DbNycTZniXqaGuPaiStzlDX9fYjYcKG
    71  0hTglhOKw5u2KfXRAolfTUIt9hcktry6lbMpnj8Y5wcb54BXeNdaheJ22NvVSzDv
    72  RqahNnqYhUKSK7VDAKhrz7JyiMZ9mG+oywCnXnfplwK6X41r4BsK/jMpLsWRBBoi
    73  ZWtd1SIVqewiih8aXD8k26gorqyxWlLkhzemBwIDAQABAoIBAD2XYRs3JrGHQUpU
    74  FkdbVKZkvrSY0vAZOqBTLuH0zUv4UATb8487anGkWBjRDLQCgxH+jucPTrztekQK
    75  aW94clo0S3aNtV4YhbSYIHWs1a0It0UdK6ID7CmdWkAj6s0T8W8lQT7C46mWYVLm
    76  5mFnCTHi6aB42jZrqmEpC7sivWwuU0xqj3Ml8kkxQCGmyc9JjmCB4OrFFC8NNt6M
    77  ObvQkUI6Z3nO4phTbpxkE1/9dT0MmPIF7GhHVzJMS+EyyRYUDllZ0wvVSOM3qZT0
    78  JMUaBerkNwm9foKJ1+dv2nMKZZbJajv7suUDCfU44mVeaEO+4kmTKSGCGjjTBGkr
    79  7L1ySDECgYEA5ElIMhpdBzIivCuBIH8LlUeuzd93pqssO1G2Xg0jHtfM4tz7fyeI
    80  cr90dc8gpli24dkSxzLeg3Tn3wIj/Bu64m2TpZPZEIlukYvgdgArmRIPQVxerYey
    81  OkrfTNkxU1HXsYjLCdGcGXs5lmb+K/kuTcFxaMOs7jZi7La+jEONwf8CgYEAwCs/
    82  rUOOA0klDsWWisbivOiNPII79c9McZCNBqncCBfMUoiGe8uWDEO4TFHN60vFuVk9
    83  8PkwpCfvaBUX+ajvbafIfHxsnfk1M04WLGCeqQ/ym5Q4sQoQOcC1b1y9qc/xEWfg
    84  nIUuia0ukYRpl7qQa3tNg+BNFyjypW8zukUAC/kCgYB1/Kojuxx5q5/oQVPrx73k
    85  2bevD+B3c+DYh9MJqSCNwFtUpYIWpggPxoQan4LwdsmO0PKzocb/ilyNFj4i/vII
    86  NToqSc/WjDFpaDIKyuu9oWfhECye45NqLWhb/6VOuu4QA/Nsj7luMhIBehnEAHW+
    87  GkzTKM8oD1PxpEG3nPKXYQKBgQC6AuMPRt3XBl1NkCrpSBy/uObFlFaP2Enpf39S
    88  3OZ0Gv0XQrnSaL1kP8TMcz68rMrGX8DaWYsgytstR4W+jyy7WvZwsUu+GjTJ5aMG
    89  77uEcEBpIi9CBzivfn7hPccE8ZgqPf+n4i6q66yxBJflW5xhvafJqDtW2LcPNbW/
    90  bvzdmQKBgExALRUXpq+5dbmkdXBHtvXdRDZ6rVmrnjy4nI5bPw+1GqQqk6uAR6B/
    91  F6NmLCQOO4PDG/cuatNHIr2FrwTmGdEL6ObLUGWn9Oer9gJhHVqqsY5I4sEPo4XX
    92  stR0Yiw0buV6DL/moUO0HIM9Bjh96HJp+LxiIS6UCdIhMPp5HoQa
    93  -----END RSA PRIVATE KEY-----`
    94  )
    95  
    96  func TestNew(t *testing.T) {
    97  	testCases := map[string]struct {
    98  		Config       *Config
    99  		Err          bool
   100  		TLS          bool
   101  		TLSCert      bool
   102  		TLSErr       bool
   103  		Default      bool
   104  		Insecure     bool
   105  		DefaultRoots bool
   106  	}{
   107  		"default transport": {
   108  			Default: true,
   109  			Config:  &Config{},
   110  		},
   111  
   112  		"insecure": {
   113  			TLS:          true,
   114  			Insecure:     true,
   115  			DefaultRoots: true,
   116  			Config: &Config{TLS: TLSConfig{
   117  				Insecure: true,
   118  			}},
   119  		},
   120  
   121  		"server name": {
   122  			TLS:          true,
   123  			DefaultRoots: true,
   124  			Config: &Config{TLS: TLSConfig{
   125  				ServerName: "foo",
   126  			}},
   127  		},
   128  
   129  		"ca transport": {
   130  			TLS: true,
   131  			Config: &Config{
   132  				TLS: TLSConfig{
   133  					CAData: []byte(rootCACert),
   134  				},
   135  			},
   136  		},
   137  		"bad ca file transport": {
   138  			Err: true,
   139  			Config: &Config{
   140  				TLS: TLSConfig{
   141  					CAFile: "invalid file",
   142  				},
   143  			},
   144  		},
   145  		"bad ca data transport": {
   146  			Err: true,
   147  			Config: &Config{
   148  				TLS: TLSConfig{
   149  					CAData: []byte(rootCACert + "this is not valid"),
   150  				},
   151  			},
   152  		},
   153  		"ca data overriding bad ca file transport": {
   154  			TLS: true,
   155  			Config: &Config{
   156  				TLS: TLSConfig{
   157  					CAData: []byte(rootCACert),
   158  					CAFile: "invalid file",
   159  				},
   160  			},
   161  		},
   162  
   163  		"cert transport": {
   164  			TLS:     true,
   165  			TLSCert: true,
   166  			Config: &Config{
   167  				TLS: TLSConfig{
   168  					CAData:   []byte(rootCACert),
   169  					CertData: []byte(certData),
   170  					KeyData:  []byte(keyData),
   171  				},
   172  			},
   173  		},
   174  		"bad cert data transport": {
   175  			Err: true,
   176  			Config: &Config{
   177  				TLS: TLSConfig{
   178  					CAData:   []byte(rootCACert),
   179  					CertData: []byte(certData),
   180  					KeyData:  []byte("bad key data"),
   181  				},
   182  			},
   183  		},
   184  		"bad file cert transport": {
   185  			Err: true,
   186  			Config: &Config{
   187  				TLS: TLSConfig{
   188  					CAData:   []byte(rootCACert),
   189  					CertData: []byte(certData),
   190  					KeyFile:  "invalid file",
   191  				},
   192  			},
   193  		},
   194  		"key data overriding bad file cert transport": {
   195  			TLS:     true,
   196  			TLSCert: true,
   197  			Config: &Config{
   198  				TLS: TLSConfig{
   199  					CAData:   []byte(rootCACert),
   200  					CertData: []byte(certData),
   201  					KeyData:  []byte(keyData),
   202  					KeyFile:  "invalid file",
   203  				},
   204  			},
   205  		},
   206  		"callback cert and key": {
   207  			TLS:     true,
   208  			TLSCert: true,
   209  			Config: &Config{
   210  				TLS: TLSConfig{
   211  					CAData: []byte(rootCACert),
   212  					GetCert: func() (*tls.Certificate, error) {
   213  						crt, err := tls.X509KeyPair([]byte(certData), []byte(keyData))
   214  						return &crt, err
   215  					},
   216  				},
   217  			},
   218  		},
   219  		"cert callback error": {
   220  			TLS:     true,
   221  			TLSCert: true,
   222  			TLSErr:  true,
   223  			Config: &Config{
   224  				TLS: TLSConfig{
   225  					CAData: []byte(rootCACert),
   226  					GetCert: func() (*tls.Certificate, error) {
   227  						return nil, errors.New("GetCert failure")
   228  					},
   229  				},
   230  			},
   231  		},
   232  		"cert data overrides empty callback result": {
   233  			TLS:     true,
   234  			TLSCert: true,
   235  			Config: &Config{
   236  				TLS: TLSConfig{
   237  					CAData: []byte(rootCACert),
   238  					GetCert: func() (*tls.Certificate, error) {
   239  						return nil, nil
   240  					},
   241  					CertData: []byte(certData),
   242  					KeyData:  []byte(keyData),
   243  				},
   244  			},
   245  		},
   246  		"callback returns nothing": {
   247  			TLS:     true,
   248  			TLSCert: true,
   249  			Config: &Config{
   250  				TLS: TLSConfig{
   251  					CAData: []byte(rootCACert),
   252  					GetCert: func() (*tls.Certificate, error) {
   253  						return nil, nil
   254  					},
   255  				},
   256  			},
   257  		},
   258  	}
   259  	for k, testCase := range testCases {
   260  		t.Run(k, func(t *testing.T) {
   261  			rt, err := New(testCase.Config)
   262  			switch {
   263  			case testCase.Err && err == nil:
   264  				t.Fatal("unexpected non-error")
   265  			case !testCase.Err && err != nil:
   266  				t.Fatalf("unexpected error: %v", err)
   267  			}
   268  			if testCase.Err {
   269  				return
   270  			}
   271  
   272  			switch {
   273  			case testCase.Default && rt != http.DefaultTransport:
   274  				t.Fatalf("got %#v, expected the default transport", rt)
   275  			case !testCase.Default && rt == http.DefaultTransport:
   276  				t.Fatalf("got %#v, expected non-default transport", rt)
   277  			}
   278  
   279  			// We only know how to check TLSConfig on http.Transports
   280  			transport := rt.(*http.Transport)
   281  			switch {
   282  			case testCase.TLS && transport.TLSClientConfig == nil:
   283  				t.Fatalf("got %#v, expected TLSClientConfig", transport)
   284  			case !testCase.TLS && transport.TLSClientConfig != nil:
   285  				t.Fatalf("got %#v, expected no TLSClientConfig", transport)
   286  			}
   287  			if !testCase.TLS {
   288  				return
   289  			}
   290  
   291  			switch {
   292  			case testCase.DefaultRoots && transport.TLSClientConfig.RootCAs != nil:
   293  				t.Fatalf("got %#v, expected nil root CAs", transport.TLSClientConfig.RootCAs)
   294  			case !testCase.DefaultRoots && transport.TLSClientConfig.RootCAs == nil:
   295  				t.Fatalf("got %#v, expected non-nil root CAs", transport.TLSClientConfig.RootCAs)
   296  			}
   297  
   298  			switch {
   299  			case testCase.Insecure != transport.TLSClientConfig.InsecureSkipVerify:
   300  				t.Fatalf("got %#v, expected %#v", transport.TLSClientConfig.InsecureSkipVerify, testCase.Insecure)
   301  			}
   302  
   303  			switch {
   304  			case testCase.TLSCert && transport.TLSClientConfig.GetClientCertificate == nil:
   305  				t.Fatalf("got %#v, expected TLSClientConfig.GetClientCertificate", transport.TLSClientConfig)
   306  			case !testCase.TLSCert && transport.TLSClientConfig.GetClientCertificate != nil:
   307  				t.Fatalf("got %#v, expected no TLSClientConfig.GetClientCertificate", transport.TLSClientConfig)
   308  			}
   309  			if !testCase.TLSCert {
   310  				return
   311  			}
   312  
   313  			_, err = transport.TLSClientConfig.GetClientCertificate(nil)
   314  			switch {
   315  			case testCase.TLSErr && err == nil:
   316  				t.Error("got nil error from GetClientCertificate, expected non-nil")
   317  			case !testCase.TLSErr && err != nil:
   318  				t.Errorf("got error from GetClientCertificate: %q, expected nil", err)
   319  			}
   320  		})
   321  	}
   322  }
   323  
   324  type fakeRoundTripper struct {
   325  	Req  *http.Request
   326  	Resp *http.Response
   327  	Err  error
   328  }
   329  
   330  func (rt *fakeRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
   331  	rt.Req = req
   332  	return rt.Resp, rt.Err
   333  }
   334  
   335  type chainRoundTripper struct {
   336  	rt    http.RoundTripper
   337  	value string
   338  }
   339  
   340  func testChain(value string) WrapperFunc {
   341  	return func(rt http.RoundTripper) http.RoundTripper {
   342  		return &chainRoundTripper{rt: rt, value: value}
   343  	}
   344  }
   345  
   346  func (rt *chainRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
   347  	resp, err := rt.rt.RoundTrip(req)
   348  	if resp != nil {
   349  		if resp.Header == nil {
   350  			resp.Header = make(http.Header)
   351  		}
   352  		resp.Header.Set("Value", resp.Header.Get("Value")+rt.value)
   353  	}
   354  	return resp, err
   355  }
   356  
   357  func TestWrappers(t *testing.T) {
   358  	resp1 := &http.Response{}
   359  	wrapperResp1 := func(rt http.RoundTripper) http.RoundTripper {
   360  		return &fakeRoundTripper{Resp: resp1}
   361  	}
   362  	resp2 := &http.Response{}
   363  	wrapperResp2 := func(rt http.RoundTripper) http.RoundTripper {
   364  		return &fakeRoundTripper{Resp: resp2}
   365  	}
   366  
   367  	tests := []struct {
   368  		name    string
   369  		fns     []WrapperFunc
   370  		wantNil bool
   371  		want    func(*http.Response) bool
   372  	}{
   373  		{fns: []WrapperFunc{}, wantNil: true},
   374  		{fns: []WrapperFunc{nil, nil}, wantNil: true},
   375  		{fns: []WrapperFunc{nil}, wantNil: false},
   376  
   377  		{fns: []WrapperFunc{nil, wrapperResp1}, want: func(resp *http.Response) bool { return resp == resp1 }},
   378  		{fns: []WrapperFunc{wrapperResp1, nil}, want: func(resp *http.Response) bool { return resp == resp1 }},
   379  		{fns: []WrapperFunc{nil, wrapperResp1, nil}, want: func(resp *http.Response) bool { return resp == resp1 }},
   380  		{fns: []WrapperFunc{nil, wrapperResp1, wrapperResp2}, want: func(resp *http.Response) bool { return resp == resp2 }},
   381  		{fns: []WrapperFunc{wrapperResp1, wrapperResp2}, want: func(resp *http.Response) bool { return resp == resp2 }},
   382  		{fns: []WrapperFunc{wrapperResp2, wrapperResp1}, want: func(resp *http.Response) bool { return resp == resp1 }},
   383  
   384  		{fns: []WrapperFunc{testChain("1")}, want: func(resp *http.Response) bool { return resp.Header.Get("Value") == "1" }},
   385  		{fns: []WrapperFunc{testChain("1"), testChain("2")}, want: func(resp *http.Response) bool { return resp.Header.Get("Value") == "12" }},
   386  		{fns: []WrapperFunc{testChain("2"), testChain("1")}, want: func(resp *http.Response) bool { return resp.Header.Get("Value") == "21" }},
   387  		{fns: []WrapperFunc{testChain("1"), testChain("2"), testChain("3")}, want: func(resp *http.Response) bool { return resp.Header.Get("Value") == "123" }},
   388  	}
   389  	for _, tt := range tests {
   390  		t.Run(tt.name, func(t *testing.T) {
   391  			got := Wrappers(tt.fns...)
   392  			if got == nil != tt.wantNil {
   393  				t.Errorf("Wrappers() = %v", got)
   394  				return
   395  			}
   396  			if got == nil {
   397  				return
   398  			}
   399  
   400  			rt := &fakeRoundTripper{Resp: &http.Response{}}
   401  			nested := got(rt)
   402  			req := &http.Request{}
   403  			resp, _ := nested.RoundTrip(req)
   404  			if tt.want != nil && !tt.want(resp) {
   405  				t.Errorf("unexpected response: %#v", resp)
   406  			}
   407  		})
   408  	}
   409  }
   410  
   411  func Test_contextCanceller_RoundTrip(t *testing.T) {
   412  	tests := []struct {
   413  		name string
   414  		open bool
   415  		want bool
   416  	}{
   417  		{name: "open context should call nested round tripper", open: true, want: true},
   418  		{name: "closed context should return a known error", open: false, want: false},
   419  	}
   420  	for _, tt := range tests {
   421  		t.Run(tt.name, func(t *testing.T) {
   422  			req := &http.Request{}
   423  			rt := &fakeRoundTripper{Resp: &http.Response{}}
   424  			ctx := context.Background()
   425  			if !tt.open {
   426  				c, fn := context.WithCancel(ctx)
   427  				fn()
   428  				ctx = c
   429  			}
   430  			errTesting := fmt.Errorf("testing")
   431  			b := &contextCanceller{
   432  				rt:  rt,
   433  				ctx: ctx,
   434  				err: errTesting,
   435  			}
   436  			got, err := b.RoundTrip(req)
   437  			if tt.want {
   438  				if err != nil {
   439  					t.Errorf("unexpected error: %v", err)
   440  				}
   441  				if got != rt.Resp {
   442  					t.Errorf("wanted response")
   443  				}
   444  				if req != rt.Req {
   445  					t.Errorf("expect nested call")
   446  				}
   447  			} else {
   448  				if err != errTesting {
   449  					t.Errorf("unexpected error: %v", err)
   450  				}
   451  				if got != nil {
   452  					t.Errorf("wanted no response")
   453  				}
   454  				if rt.Req != nil {
   455  					t.Errorf("want no nested call")
   456  				}
   457  			}
   458  		})
   459  	}
   460  }