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 }