google.golang.org/grpc@v1.72.2/clientconn_test.go (about) 1 /* 2 * 3 * Copyright 2014 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 package grpc 20 21 import ( 22 "context" 23 "errors" 24 "fmt" 25 "math" 26 "net" 27 "strings" 28 "sync" 29 "sync/atomic" 30 "testing" 31 "time" 32 33 "golang.org/x/net/http2" 34 "google.golang.org/grpc/backoff" 35 "google.golang.org/grpc/balancer" 36 "google.golang.org/grpc/connectivity" 37 "google.golang.org/grpc/credentials" 38 "google.golang.org/grpc/credentials/insecure" 39 internalbackoff "google.golang.org/grpc/internal/backoff" 40 "google.golang.org/grpc/internal/envconfig" 41 "google.golang.org/grpc/internal/grpcsync" 42 "google.golang.org/grpc/internal/grpctest" 43 "google.golang.org/grpc/internal/transport" 44 "google.golang.org/grpc/keepalive" 45 "google.golang.org/grpc/resolver" 46 "google.golang.org/grpc/resolver/manual" 47 "google.golang.org/grpc/serviceconfig" 48 "google.golang.org/grpc/testdata" 49 ) 50 51 const ( 52 defaultTestTimeout = 10 * time.Second 53 defaultTestShortTimeout = 10 * time.Millisecond 54 stateRecordingBalancerName = "state_recording_balancer" 55 grpclbServiceConfig = `{"loadBalancingConfig": [{"grpclb": {}}]}` 56 rrServiceConfig = `{"loadBalancingPolicy": [{"round_robin": {}}]}` 57 ) 58 59 var testBalancerBuilder = newStateRecordingBalancerBuilder() 60 61 func init() { 62 balancer.Register(testBalancerBuilder) 63 } 64 65 func parseCfg(r *manual.Resolver, s string) *serviceconfig.ParseResult { 66 scpr := r.CC().ParseServiceConfig(s) 67 if scpr.Err != nil { 68 panic(fmt.Sprintf("Error parsing config %q: %v", s, scpr.Err)) 69 } 70 return scpr 71 } 72 73 func (s) TestDialWithTimeout(t *testing.T) { 74 lis, err := net.Listen("tcp", "localhost:0") 75 if err != nil { 76 t.Fatalf("Error while listening. Err: %v", err) 77 } 78 defer lis.Close() 79 lisAddr := resolver.Address{Addr: lis.Addr().String()} 80 lisDone := make(chan struct{}) 81 dialDone := make(chan struct{}) 82 // 1st listener accepts the connection and then does nothing 83 go func() { 84 defer close(lisDone) 85 conn, err := lis.Accept() 86 if err != nil { 87 t.Errorf("Error while accepting. Err: %v", err) 88 return 89 } 90 framer := http2.NewFramer(conn, conn) 91 if err := framer.WriteSettings(http2.Setting{}); err != nil { 92 t.Errorf("Error while writing settings. Err: %v", err) 93 return 94 } 95 <-dialDone // Close conn only after dial returns. 96 }() 97 98 r := manual.NewBuilderWithScheme("whatever") 99 r.InitialState(resolver.State{Addresses: []resolver.Address{lisAddr}}) 100 client, err := Dial(r.Scheme()+":///test.server", WithTransportCredentials(insecure.NewCredentials()), WithResolvers(r), WithTimeout(5*time.Second)) 101 close(dialDone) 102 if err != nil { 103 t.Fatalf("Dial failed. Err: %v", err) 104 } 105 defer client.Close() 106 timeout := time.After(1 * time.Second) 107 select { 108 case <-timeout: 109 t.Fatal("timed out waiting for server to finish") 110 case <-lisDone: 111 } 112 } 113 114 func (s) TestNewClientWithMultipleBackendsNotSendingServerPreface(t *testing.T) { 115 lis1, err := net.Listen("tcp", "localhost:0") 116 if err != nil { 117 t.Fatalf("Error while listening. Err: %v", err) 118 } 119 defer lis1.Close() 120 lis1Addr := resolver.Address{Addr: lis1.Addr().String()} 121 lis1Done := make(chan struct{}) 122 // 1st listener accepts the connection and immediately closes it. 123 go func() { 124 defer close(lis1Done) 125 conn, err := lis1.Accept() 126 if err != nil { 127 t.Errorf("Error while accepting. Err: %v", err) 128 return 129 } 130 conn.Close() 131 }() 132 133 lis2, err := net.Listen("tcp", "localhost:0") 134 if err != nil { 135 t.Fatalf("Error while listening. Err: %v", err) 136 } 137 defer lis2.Close() 138 lis2Done := make(chan struct{}) 139 lis2Addr := resolver.Address{Addr: lis2.Addr().String()} 140 // 2nd listener should get a connection attempt since the first one failed. 141 go func() { 142 defer close(lis2Done) 143 _, err := lis2.Accept() // Closing the client will clean up this conn. 144 if err != nil { 145 t.Errorf("Error while accepting. Err: %v", err) 146 return 147 } 148 }() 149 150 r := manual.NewBuilderWithScheme("whatever") 151 r.InitialState(resolver.State{Addresses: []resolver.Address{lis1Addr, lis2Addr}}) 152 client, err := NewClient(r.Scheme()+":///test.server", WithTransportCredentials(insecure.NewCredentials()), WithResolvers(r)) 153 if err != nil { 154 t.Fatalf("grpc.NewClient() failed: %v", err) 155 } 156 client.Connect() 157 defer client.Close() 158 timeout := time.After(5 * time.Second) 159 select { 160 case <-timeout: 161 t.Fatal("timed out waiting for server 1 to finish") 162 case <-lis1Done: 163 } 164 select { 165 case <-timeout: 166 t.Fatal("timed out waiting for server 2 to finish") 167 case <-lis2Done: 168 } 169 } 170 171 func (s) TestDialWaitsForServerSettings(t *testing.T) { 172 lis, err := net.Listen("tcp", "localhost:0") 173 if err != nil { 174 t.Fatalf("Error while listening. Err: %v", err) 175 } 176 defer lis.Close() 177 done := make(chan struct{}) 178 sent := make(chan struct{}) 179 dialDone := make(chan struct{}) 180 go func() { // Launch the server. 181 defer func() { 182 close(done) 183 }() 184 conn, err := lis.Accept() 185 if err != nil { 186 t.Errorf("Error while accepting. Err: %v", err) 187 return 188 } 189 defer conn.Close() 190 // Sleep for a little bit to make sure that Dial on client 191 // side blocks until settings are received. 192 time.Sleep(100 * time.Millisecond) 193 framer := http2.NewFramer(conn, conn) 194 close(sent) 195 if err := framer.WriteSettings(http2.Setting{}); err != nil { 196 t.Errorf("Error while writing settings. Err: %v", err) 197 return 198 } 199 <-dialDone // Close conn only after dial returns. 200 }() 201 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 202 defer cancel() 203 client, err := DialContext(ctx, lis.Addr().String(), WithTransportCredentials(insecure.NewCredentials()), WithBlock()) 204 close(dialDone) 205 if err != nil { 206 t.Fatalf("Error while dialing. Err: %v", err) 207 } 208 defer client.Close() 209 select { 210 case <-sent: 211 default: 212 t.Fatalf("Dial returned before server settings were sent") 213 } 214 <-done 215 } 216 217 func (s) TestDialWaitsForServerSettingsAndFails(t *testing.T) { 218 lis, err := net.Listen("tcp", "localhost:0") 219 if err != nil { 220 t.Fatalf("Error while listening. Err: %v", err) 221 } 222 done := make(chan struct{}) 223 numConns := 0 224 go func() { // Launch the server. 225 defer func() { 226 close(done) 227 }() 228 for { 229 conn, err := lis.Accept() 230 if err != nil { 231 break 232 } 233 numConns++ 234 defer conn.Close() 235 } 236 }() 237 ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) 238 defer cancel() 239 client, err := DialContext(ctx, 240 lis.Addr().String(), 241 WithTransportCredentials(insecure.NewCredentials()), 242 WithReturnConnectionError(), 243 WithConnectParams(ConnectParams{ 244 Backoff: backoff.Config{}, 245 MinConnectTimeout: 250 * time.Millisecond, 246 })) 247 lis.Close() 248 if err == nil { 249 client.Close() 250 t.Fatalf("Unexpected success (err=nil) while dialing") 251 } 252 expectedMsg := "server preface" 253 if !strings.Contains(err.Error(), context.DeadlineExceeded.Error()) || !strings.Contains(err.Error(), expectedMsg) { 254 t.Fatalf("DialContext(_) = %v; want a message that includes both %q and %q", err, context.DeadlineExceeded.Error(), expectedMsg) 255 } 256 <-done 257 if numConns < 2 { 258 t.Fatalf("dial attempts: %v; want > 1", numConns) 259 } 260 } 261 262 // 1. Client connects to a server that doesn't send preface. 263 // 2. After minConnectTimeout(500 ms here), client disconnects and retries. 264 // 3. The new server sends its preface. 265 // 4. Client doesn't kill the connection this time. 266 func (s) TestCloseConnectionWhenServerPrefaceNotReceived(t *testing.T) { 267 lis, err := net.Listen("tcp", "localhost:0") 268 if err != nil { 269 t.Fatalf("Error while listening. Err: %v", err) 270 } 271 var ( 272 conn2 net.Conn 273 over uint32 274 ) 275 defer func() { 276 lis.Close() 277 // conn2 shouldn't be closed until the client has 278 // observed a successful test. 279 if conn2 != nil { 280 conn2.Close() 281 } 282 }() 283 done := make(chan struct{}) 284 accepted := make(chan struct{}) 285 go func() { // Launch the server. 286 defer close(done) 287 conn1, err := lis.Accept() 288 if err != nil { 289 t.Errorf("Error while accepting. Err: %v", err) 290 return 291 } 292 defer conn1.Close() 293 // Don't send server settings and the client should close the connection and try again. 294 conn2, err = lis.Accept() // Accept a reconnection request from client. 295 if err != nil { 296 t.Errorf("Error while accepting. Err: %v", err) 297 return 298 } 299 close(accepted) 300 framer := http2.NewFramer(conn2, conn2) 301 if err = framer.WriteSettings(http2.Setting{}); err != nil { 302 t.Errorf("Error while writing settings. Err: %v", err) 303 return 304 } 305 b := make([]byte, 8) 306 for { 307 _, err = conn2.Read(b) 308 if err == nil { 309 continue 310 } 311 if atomic.LoadUint32(&over) == 1 { 312 // The connection stayed alive for the timer. 313 // Success. 314 return 315 } 316 t.Errorf("Unexpected error while reading. Err: %v, want timeout error", err) 317 break 318 } 319 }() 320 client, err := NewClient(lis.Addr().String(), WithTransportCredentials(insecure.NewCredentials()), withMinConnectDeadline(func() time.Duration { return time.Millisecond * 500 })) 321 if err != nil { 322 t.Fatalf("grpc.NewClient(%q) = %v", lis.Addr().String(), err) 323 } 324 325 go stayConnected(client) 326 327 // wait for connection to be accepted on the server. 328 timer := time.NewTimer(time.Second * 10) 329 select { 330 case <-accepted: 331 case <-timer.C: 332 t.Fatalf("Client didn't make another connection request in time.") 333 } 334 // Make sure the connection stays alive for some time. 335 time.Sleep(time.Second) 336 atomic.StoreUint32(&over, 1) 337 client.Close() 338 <-done 339 } 340 341 func (s) TestBackoffWhenNoServerPrefaceReceived(t *testing.T) { 342 lis, err := net.Listen("tcp", "localhost:0") 343 if err != nil { 344 t.Fatalf("Unexpected error from net.Listen(%q, %q): %v", "tcp", "localhost:0", err) 345 } 346 defer lis.Close() 347 done := make(chan struct{}) 348 go func() { // Launch the server. 349 defer close(done) 350 conn, err := lis.Accept() // Accept the connection only to close it immediately. 351 if err != nil { 352 t.Errorf("Error while accepting. Err: %v", err) 353 return 354 } 355 prevAt := time.Now() 356 conn.Close() 357 var prevDuration time.Duration 358 // Make sure the retry attempts are backed off properly. 359 for i := 0; i < 3; i++ { 360 conn, err := lis.Accept() 361 if err != nil { 362 t.Errorf("Error while accepting. Err: %v", err) 363 return 364 } 365 meow := time.Now() 366 conn.Close() 367 dr := meow.Sub(prevAt) 368 if dr <= prevDuration { 369 t.Errorf("Client backoff did not increase with retries. Previous duration: %v, current duration: %v", prevDuration, dr) 370 return 371 } 372 prevDuration = dr 373 prevAt = meow 374 } 375 }() 376 bc := backoff.Config{ 377 BaseDelay: 200 * time.Millisecond, 378 Multiplier: 2.0, 379 Jitter: 0, 380 MaxDelay: 120 * time.Second, 381 } 382 cp := ConnectParams{ 383 Backoff: bc, 384 MinConnectTimeout: 1 * time.Second, 385 } 386 cc, err := NewClient(lis.Addr().String(), WithTransportCredentials(insecure.NewCredentials()), WithConnectParams(cp)) 387 if err != nil { 388 t.Fatalf("grpc.NewClient(%q) = %v", lis.Addr().String(), err) 389 } 390 defer cc.Close() 391 go stayConnected(cc) 392 <-done 393 } 394 395 func (s) TestWithTimeout(t *testing.T) { 396 conn, err := Dial("passthrough:///Non-Existent.Server:80", 397 WithTimeout(time.Millisecond), 398 WithBlock(), 399 WithTransportCredentials(insecure.NewCredentials())) 400 if err == nil { 401 conn.Close() 402 } 403 if err != context.DeadlineExceeded { 404 t.Fatalf("Dial(_, _) = %v, %v, want %v", conn, err, context.DeadlineExceeded) 405 } 406 } 407 408 func (s) TestWithTransportCredentialsTLS(t *testing.T) { 409 ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond) 410 defer cancel() 411 creds, err := credentials.NewClientTLSFromFile(testdata.Path("x509/server_ca_cert.pem"), "x.test.example.com") 412 if err != nil { 413 t.Fatalf("Failed to create credentials %v", err) 414 } 415 conn, err := DialContext(ctx, "passthrough:///Non-Existent.Server:80", WithTransportCredentials(creds), WithBlock()) 416 if err == nil { 417 conn.Close() 418 } 419 if err != context.DeadlineExceeded { 420 t.Fatalf("Dial(_, _) = %v, %v, want %v", conn, err, context.DeadlineExceeded) 421 } 422 } 423 424 // When creating a transport configured with n addresses, only calculate the 425 // backoff once per "round" of attempts instead of once per address (n times 426 // per "round" of attempts) for old pickfirst and once per address for new pickfirst. 427 func (s) TestNewClient_BackoffCountPerRetryGroup(t *testing.T) { 428 var attempts uint32 429 wantBackoffs := uint32(1) 430 if envconfig.NewPickFirstEnabled { 431 wantBackoffs = 2 432 } 433 getMinConnectTimeout := func() time.Duration { 434 if atomic.AddUint32(&attempts, 1) <= wantBackoffs { 435 // Once all addresses are exhausted, hang around and wait for the 436 // client.Close to happen rather than re-starting a new round of 437 // attempts. 438 return time.Hour 439 } 440 t.Errorf("only %d attempt backoff calculation, but got more", wantBackoffs) 441 return 0 442 } 443 444 lis1, err := net.Listen("tcp", "localhost:0") 445 if err != nil { 446 t.Fatalf("Error while listening. Err: %v", err) 447 } 448 defer lis1.Close() 449 450 lis2, err := net.Listen("tcp", "localhost:0") 451 if err != nil { 452 t.Fatalf("Error while listening. Err: %v", err) 453 } 454 defer lis2.Close() 455 456 server1Done := make(chan struct{}) 457 server2Done := make(chan struct{}) 458 459 // Launch server 1. 460 go func() { 461 conn, err := lis1.Accept() 462 if err != nil { 463 t.Error(err) 464 return 465 } 466 467 conn.Close() 468 close(server1Done) 469 }() 470 // Launch server 2. 471 go func() { 472 conn, err := lis2.Accept() 473 if err != nil { 474 t.Error(err) 475 return 476 } 477 conn.Close() 478 close(server2Done) 479 }() 480 481 rb := manual.NewBuilderWithScheme("whatever") 482 rb.InitialState(resolver.State{Addresses: []resolver.Address{ 483 {Addr: lis1.Addr().String()}, 484 {Addr: lis2.Addr().String()}, 485 }}) 486 client, err := NewClient("whatever:///this-gets-overwritten", 487 WithTransportCredentials(insecure.NewCredentials()), 488 WithResolvers(rb), 489 withMinConnectDeadline(getMinConnectTimeout)) 490 if err != nil { 491 t.Fatal(err) 492 } 493 defer client.Close() 494 client.Connect() 495 timeout := time.After(15 * time.Second) 496 497 select { 498 case <-timeout: 499 t.Fatal("timed out waiting for test to finish") 500 case <-server1Done: 501 } 502 503 select { 504 case <-timeout: 505 t.Fatal("timed out waiting for test to finish") 506 case <-server2Done: 507 } 508 509 if got, want := atomic.LoadUint32(&attempts), wantBackoffs; got != want { 510 t.Errorf("attempts = %d, want %d", got, want) 511 } 512 } 513 514 func (s) TestDialContextCancel(t *testing.T) { 515 ctx, cancel := context.WithCancel(context.Background()) 516 cancel() 517 if _, err := DialContext(ctx, "Non-Existent.Server:80", WithBlock(), WithTransportCredentials(insecure.NewCredentials())); err != context.Canceled { 518 t.Fatalf("DialContext(%v, _) = _, %v, want _, %v", ctx, err, context.Canceled) 519 } 520 } 521 522 type failFastError struct{} 523 524 func (failFastError) Error() string { return "failfast" } 525 func (failFastError) Temporary() bool { return false } 526 527 func (s) TestDialContextFailFast(t *testing.T) { 528 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 529 defer cancel() 530 failErr := failFastError{} 531 dialer := func(string, time.Duration) (net.Conn, error) { 532 return nil, failErr 533 } 534 535 _, err := DialContext(ctx, "Non-Existent.Server:80", WithBlock(), WithTransportCredentials(insecure.NewCredentials()), WithDialer(dialer), FailOnNonTempDialError(true)) 536 if terr, ok := err.(transport.ConnectionError); !ok || terr.Origin() != failErr { 537 t.Fatalf("DialContext() = _, %v, want _, %v", err, failErr) 538 } 539 } 540 541 // securePerRPCCredentials always requires transport security. 542 type securePerRPCCredentials struct { 543 credentials.PerRPCCredentials 544 } 545 546 func (c securePerRPCCredentials) RequireTransportSecurity() bool { 547 return true 548 } 549 550 type fakeBundleCreds struct { 551 credentials.Bundle 552 transportCreds credentials.TransportCredentials 553 } 554 555 func (b *fakeBundleCreds) TransportCredentials() credentials.TransportCredentials { 556 return b.transportCreds 557 } 558 559 func (s) TestCredentialsMisuse(t *testing.T) { 560 // Use of no transport creds and no creds bundle must fail. 561 if _, err := NewClient("passthrough:///Non-Existent.Server:80"); err != errNoTransportSecurity { 562 t.Fatalf("grpc.NewClient() failed with error: %v, want: %v", err, errNoTransportSecurity) 563 } 564 565 // Use of both transport creds and creds bundle must fail. 566 creds, err := credentials.NewClientTLSFromFile(testdata.Path("x509/server_ca_cert.pem"), "x.test.example.com") 567 if err != nil { 568 t.Fatalf("Failed to create authenticator %v", err) 569 } 570 dopts := []DialOption{ 571 WithTransportCredentials(creds), 572 WithCredentialsBundle(&fakeBundleCreds{transportCreds: creds}), 573 } 574 if _, err := NewClient("passthrough:///Non-Existent.Server:80", dopts...); err != errTransportCredsAndBundle { 575 t.Fatalf("grpc.NewClient() failed with error: %v, want: %v", err, errTransportCredsAndBundle) 576 } 577 578 // Use of perRPC creds requiring transport security over an insecure 579 // transport must fail. 580 if _, err := NewClient("passthrough:///Non-Existent.Server:80", WithPerRPCCredentials(securePerRPCCredentials{}), WithTransportCredentials(insecure.NewCredentials())); err != errTransportCredentialsMissing { 581 t.Fatalf("grpc.NewClient() failed with error: %v, want: %v", err, errTransportCredentialsMissing) 582 } 583 584 // Use of a creds bundle with nil transport credentials must fail. 585 if _, err := NewClient("passthrough:///Non-Existent.Server:80", WithCredentialsBundle(&fakeBundleCreds{})); err != errNoTransportCredsInBundle { 586 t.Fatalf("grpc.NewClient() failed with error: %v, want: %v", err, errTransportCredsAndBundle) 587 } 588 } 589 590 func (s) TestWithBackoffConfigDefault(t *testing.T) { 591 testBackoffConfigSet(t, internalbackoff.DefaultExponential) 592 } 593 594 func (s) TestWithBackoffConfig(t *testing.T) { 595 b := BackoffConfig{MaxDelay: DefaultBackoffConfig.MaxDelay / 2} 596 bc := backoff.DefaultConfig 597 bc.MaxDelay = b.MaxDelay 598 wantBackoff := internalbackoff.Exponential{Config: bc} 599 testBackoffConfigSet(t, wantBackoff, WithBackoffConfig(b)) 600 } 601 602 func (s) TestWithBackoffMaxDelay(t *testing.T) { 603 md := DefaultBackoffConfig.MaxDelay / 2 604 bc := backoff.DefaultConfig 605 bc.MaxDelay = md 606 wantBackoff := internalbackoff.Exponential{Config: bc} 607 testBackoffConfigSet(t, wantBackoff, WithBackoffMaxDelay(md)) 608 } 609 610 func (s) TestWithConnectParams(t *testing.T) { 611 bd := 2 * time.Second 612 mltpr := 2.0 613 jitter := 0.0 614 bc := backoff.Config{BaseDelay: bd, Multiplier: mltpr, Jitter: jitter} 615 616 crt := ConnectParams{Backoff: bc} 617 // MaxDelay is not set in the ConnectParams. So it should not be set on 618 // internalbackoff.Exponential as well. 619 wantBackoff := internalbackoff.Exponential{Config: bc} 620 testBackoffConfigSet(t, wantBackoff, WithConnectParams(crt)) 621 } 622 623 func testBackoffConfigSet(t *testing.T, wantBackoff internalbackoff.Exponential, opts ...DialOption) { 624 opts = append(opts, WithTransportCredentials(insecure.NewCredentials())) 625 conn, err := NewClient("passthrough:///foo:80", opts...) 626 if err != nil { 627 t.Fatalf("grpc.NewClient() failed: %v", err) 628 } 629 defer conn.Close() 630 631 if conn.dopts.bs == nil { 632 t.Fatalf("backoff config not set") 633 } 634 635 gotBackoff, ok := conn.dopts.bs.(internalbackoff.Exponential) 636 if !ok { 637 t.Fatalf("unexpected type of backoff config: %#v", conn.dopts.bs) 638 } 639 640 if gotBackoff != wantBackoff { 641 t.Fatalf("unexpected backoff config on connection: %v, want %v", gotBackoff, wantBackoff) 642 } 643 } 644 645 func (s) TestConnectParamsWithMinConnectTimeout(t *testing.T) { 646 // Default value specified for minConnectTimeout in the spec is 20 seconds. 647 mct := 1 * time.Minute 648 conn, err := NewClient("passthrough:///foo:80", WithTransportCredentials(insecure.NewCredentials()), WithConnectParams(ConnectParams{MinConnectTimeout: mct})) 649 if err != nil { 650 t.Fatalf("grpc.NewClient() failed: %v", err) 651 } 652 defer conn.Close() 653 654 if got := conn.dopts.minConnectTimeout(); got != mct { 655 t.Errorf("unexpected minConnectTimeout on the connection: %v, want %v", got, mct) 656 } 657 } 658 659 func (s) TestResolverServiceConfigBeforeAddressNotPanic(t *testing.T) { 660 r := manual.NewBuilderWithScheme("whatever") 661 662 cc, err := NewClient(r.Scheme()+":///test.server", WithTransportCredentials(insecure.NewCredentials()), WithResolvers(r)) 663 if err != nil { 664 t.Fatalf("grpc.NewClient() failed: %v", err) 665 } 666 defer cc.Close() 667 cc.Connect() 668 // SwitchBalancer before NewAddress. There was no balancer created, this 669 // makes sure we don't call close on nil balancerWrapper. 670 r.UpdateState(resolver.State{ServiceConfig: r.CC().ParseServiceConfig(grpclbServiceConfig)}) // This should not panic. 671 672 time.Sleep(time.Second) // Sleep to make sure the service config is handled by ClientConn. 673 } 674 675 func (s) TestResolverServiceConfigWhileClosingNotPanic(t *testing.T) { 676 for i := 0; i < 10; i++ { // Run this multiple times to make sure it doesn't panic. 677 r := manual.NewBuilderWithScheme(fmt.Sprintf("whatever-%d", i)) 678 cc, err := NewClient(r.Scheme()+":///test.server", WithTransportCredentials(insecure.NewCredentials()), WithResolvers(r)) 679 if err != nil { 680 t.Fatalf("grpc.NewClient() failed: %v", err) 681 } 682 cc.Connect() 683 // Send a new service config while closing the ClientConn. 684 go cc.Close() 685 go r.UpdateState(resolver.State{ServiceConfig: r.CC().ParseServiceConfig(rrServiceConfig)}) // This should not panic. 686 } 687 } 688 689 func (s) TestResolverEmptyUpdateNotPanic(t *testing.T) { 690 r := manual.NewBuilderWithScheme("whatever") 691 692 cc, err := NewClient(r.Scheme()+":///test.server", WithTransportCredentials(insecure.NewCredentials()), WithResolvers(r)) 693 if err != nil { 694 t.Fatalf("grpc.NewClient() failed: %v", err) 695 } 696 defer cc.Close() 697 cc.Connect() 698 // This make sure we don't create addrConn with empty address list. 699 r.UpdateState(resolver.State{}) // This should not panic. 700 701 time.Sleep(time.Second) // Sleep to make sure the service config is handled by ClientConn. 702 } 703 704 func (s) TestClientUpdatesParamsAfterGoAway(t *testing.T) { 705 grpctest.TLogger.ExpectError("Client received GoAway with error code ENHANCE_YOUR_CALM and debug data equal to ASCII \"too_many_pings\"") 706 707 lis, err := net.Listen("tcp", "localhost:0") 708 if err != nil { 709 t.Fatalf("Failed to listen. Err: %v", err) 710 } 711 defer lis.Close() 712 connected := grpcsync.NewEvent() 713 defer connected.Fire() 714 go func() { 715 conn, err := lis.Accept() 716 if err != nil { 717 t.Errorf("error accepting connection: %v", err) 718 return 719 } 720 defer conn.Close() 721 f := http2.NewFramer(conn, conn) 722 // Start a goroutine to read from the conn to prevent the client from 723 // blocking after it writes its preface. 724 go func() { 725 for { 726 if _, err := f.ReadFrame(); err != nil { 727 return 728 } 729 } 730 }() 731 if err := f.WriteSettings(http2.Setting{}); err != nil { 732 t.Errorf("error writing settings: %v", err) 733 return 734 } 735 <-connected.Done() 736 if err := f.WriteGoAway(0, http2.ErrCodeEnhanceYourCalm, []byte("too_many_pings")); err != nil { 737 t.Errorf("error writing GOAWAY: %v", err) 738 return 739 } 740 }() 741 addr := lis.Addr().String() 742 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) 743 defer cancel() 744 cc, err := DialContext(ctx, addr, WithBlock(), WithTransportCredentials(insecure.NewCredentials()), WithKeepaliveParams(keepalive.ClientParameters{ 745 Time: 10 * time.Second, 746 Timeout: 100 * time.Millisecond, 747 PermitWithoutStream: true, 748 })) 749 if err != nil { 750 t.Fatalf("DialContext(%s) failed: %v, want: nil", addr, err) 751 } 752 defer cc.Close() 753 connected.Fire() 754 for { 755 time.Sleep(10 * time.Millisecond) 756 cc.mu.RLock() 757 v := cc.keepaliveParams.Time 758 cc.mu.RUnlock() 759 if v == 20*time.Second { 760 // Success 761 return 762 } 763 if ctx.Err() != nil { 764 // Timeout 765 t.Fatalf("cc.dopts.copts.Keepalive.Time = %v , want 20s", v) 766 } 767 } 768 } 769 770 func (s) TestDisableServiceConfigOption(t *testing.T) { 771 r := manual.NewBuilderWithScheme("whatever") 772 addr := r.Scheme() + ":///non.existent" 773 cc, err := NewClient(addr, WithTransportCredentials(insecure.NewCredentials()), WithResolvers(r), WithDisableServiceConfig()) 774 if err != nil { 775 t.Fatalf("grpc.NewClient(%s) failed: %v, want: nil", addr, err) 776 } 777 defer cc.Close() 778 cc.Connect() 779 r.UpdateState(resolver.State{ServiceConfig: r.CC().ParseServiceConfig(`{ 780 "methodConfig": [ 781 { 782 "name": [ 783 { 784 "service": "foo", 785 "method": "Bar" 786 } 787 ], 788 "waitForReady": true 789 } 790 ] 791 }`)}) 792 time.Sleep(1 * time.Second) 793 m := cc.GetMethodConfig("/foo/Bar") 794 if m.WaitForReady != nil { 795 t.Fatalf("want: method (\"/foo/bar/\") config to be empty, got: %+v", m) 796 } 797 } 798 799 func (s) TestMethodConfigDefaultService(t *testing.T) { 800 addr := "passthrough:///non.existent" 801 cc, err := NewClient(addr, WithTransportCredentials(insecure.NewCredentials()), WithDefaultServiceConfig(`{ 802 "methodConfig": [{ 803 "name": [ 804 { 805 "service": "" 806 } 807 ], 808 "waitForReady": true 809 }] 810 }`)) 811 if err != nil { 812 t.Fatalf("grpc.NewClient(%s) failed: %v, want: nil", addr, err) 813 } 814 cc.Connect() 815 defer cc.Close() 816 817 m := cc.GetMethodConfig("/foo/Bar") 818 if m.WaitForReady == nil { 819 t.Fatalf("want: method (%q) config to fallback to the default service", "/foo/Bar") 820 } 821 } 822 823 func (s) TestClientConnCanonicalTarget(t *testing.T) { 824 tests := []struct { 825 name string 826 addr string 827 canonicalTargetWant string 828 }{ 829 { 830 name: "normal-case", 831 addr: "dns://a.server.com/google.com", 832 canonicalTargetWant: "dns://a.server.com/google.com", 833 }, 834 { 835 name: "canonical-target-not-specified", 836 addr: "no.scheme", 837 canonicalTargetWant: "dns:///no.scheme", 838 }, 839 { 840 name: "canonical-target-nonexistent", 841 addr: "nonexist:///non.existent", 842 canonicalTargetWant: "dns:///nonexist:///non.existent", 843 }, 844 { 845 name: "canonical-target-add-colon-slash", 846 addr: "dns:hostname:port", 847 canonicalTargetWant: "dns:///hostname:port", 848 }, 849 } 850 for _, test := range tests { 851 t.Run(test.name, func(t *testing.T) { 852 cc, err := NewClient(test.addr, WithTransportCredentials(insecure.NewCredentials())) 853 if err != nil { 854 t.Fatalf("grpc.NewClient(%s) failed: %v, want: nil", test.addr, err) 855 } 856 defer cc.Close() 857 if cc.Target() != test.addr { 858 t.Fatalf("Target() = %s, want %s", cc.Target(), test.addr) 859 } 860 if cc.CanonicalTarget() != test.canonicalTargetWant { 861 t.Fatalf("CanonicalTarget() = %s, want %s", cc.CanonicalTarget(), test.canonicalTargetWant) 862 } 863 }) 864 } 865 } 866 867 type backoffForever struct{} 868 869 func (b backoffForever) Backoff(int) time.Duration { return time.Duration(math.MaxInt64) } 870 871 func (s) TestResetConnectBackoff(t *testing.T) { 872 dials := make(chan struct{}) 873 defer func() { // If we fail, let the http2client break out of dialing. 874 select { 875 case <-dials: 876 default: 877 } 878 }() 879 dialer := func(string, time.Duration) (net.Conn, error) { 880 dials <- struct{}{} 881 return nil, errors.New("failed to fake dial") 882 } 883 cc, err := NewClient("passthrough:///", WithTransportCredentials(insecure.NewCredentials()), WithDialer(dialer), withBackoff(backoffForever{})) 884 if err != nil { 885 t.Fatalf("grpc.NewClient() failed with error: %v, want: nil", err) 886 } 887 defer cc.Close() 888 go stayConnected(cc) 889 select { 890 case <-dials: 891 case <-time.NewTimer(10 * time.Second).C: 892 t.Fatal("Failed to call dial within 10s") 893 } 894 895 select { 896 case <-dials: 897 t.Fatal("Dial called unexpectedly before resetting backoff") 898 case <-time.NewTimer(100 * time.Millisecond).C: 899 } 900 901 cc.ResetConnectBackoff() 902 903 select { 904 case <-dials: 905 case <-time.NewTimer(10 * time.Second).C: 906 t.Fatal("Failed to call dial within 10s after resetting backoff") 907 } 908 } 909 910 func (s) TestBackoffCancel(t *testing.T) { 911 dialStrCh := make(chan string) 912 cc, err := NewClient("passthrough:///", WithTransportCredentials(insecure.NewCredentials()), WithDialer(func(t string, _ time.Duration) (net.Conn, error) { 913 dialStrCh <- t 914 return nil, fmt.Errorf("test dialer, always error") 915 })) 916 if err != nil { 917 t.Fatalf("grpc.NewClient() failed: %v", err) 918 } 919 cc.Connect() 920 defer cc.Close() 921 922 select { 923 case <-time.After(defaultTestTimeout): 924 t.Fatal("Timeout when waiting for custom dialer to be invoked during Connect()") 925 case <-dialStrCh: 926 } 927 } 928 929 // TestUpdateAddresses_NoopIfCalledWithSameAddresses tests that UpdateAddresses 930 // should be noop if UpdateAddresses is called with the same list of addresses, 931 // even when the SubConn is in Connecting and doesn't have a current address. 932 func (s) TestUpdateAddresses_NoopIfCalledWithSameAddresses(t *testing.T) { 933 lis1, err := net.Listen("tcp", "localhost:0") 934 if err != nil { 935 t.Fatalf("Error while listening. Err: %v", err) 936 } 937 defer lis1.Close() 938 939 lis2, err := net.Listen("tcp", "localhost:0") 940 if err != nil { 941 t.Fatalf("Error while listening. Err: %v", err) 942 } 943 defer lis2.Close() 944 945 lis3, err := net.Listen("tcp", "localhost:0") 946 if err != nil { 947 t.Fatalf("Error while listening. Err: %v", err) 948 } 949 defer lis3.Close() 950 951 closeServer2 := make(chan struct{}) 952 exitCh := make(chan struct{}) 953 server1ContactedFirstTime := make(chan struct{}) 954 server1ContactedSecondTime := make(chan struct{}) 955 server2ContactedFirstTime := make(chan struct{}) 956 server2ContactedSecondTime := make(chan struct{}) 957 server3Contacted := make(chan struct{}) 958 959 defer close(exitCh) 960 961 // Launch server 1. 962 go func() { 963 // First, let's allow the initial connection to go READY. We need to do 964 // this because tryUpdateAddrs only works after there's some non-nil 965 // address on the ac, and curAddress is only set after READY. 966 conn1, err := lis1.Accept() 967 if err != nil { 968 t.Error(err) 969 return 970 } 971 go keepReading(conn1) 972 973 framer := http2.NewFramer(conn1, conn1) 974 if err := framer.WriteSettings(http2.Setting{}); err != nil { 975 t.Errorf("Error while writing settings frame. %v", err) 976 return 977 } 978 979 // nextStateNotifier() is updated after balancerBuilder.Build(), which 980 // is called by ClientConn.Connect in stayConnected. It's safe to do it 981 // here because lis1.Accept blocks until ClientConn.Connect is called 982 // and the balancer is built to process the addresses. 983 stateNotifications := testBalancerBuilder.nextStateNotifier() 984 // Wait for the transport to become ready. 985 for { 986 select { 987 case st := <-stateNotifications: 988 if st == connectivity.Ready { 989 goto ready 990 } 991 case <-exitCh: 992 return 993 } 994 } 995 996 ready: 997 // Once it's ready, curAddress has been set. So let's close this 998 // connection prompting the first reconnect cycle. 999 conn1.Close() 1000 1001 // Accept and immediately close, causing it to go to server2. 1002 conn2, err := lis1.Accept() 1003 if err != nil { 1004 t.Error(err) 1005 return 1006 } 1007 close(server1ContactedFirstTime) 1008 conn2.Close() 1009 1010 // Hopefully it picks this server after tryUpdateAddrs. 1011 lis1.Accept() 1012 close(server1ContactedSecondTime) 1013 }() 1014 // Launch server 2. 1015 go func() { 1016 // Accept and then hang waiting for the test call tryUpdateAddrs and 1017 // then signal to this server to close. After this server closes, it 1018 // should start from the top instead of trying server2 or continuing 1019 // to server3. 1020 conn, err := lis2.Accept() 1021 if err != nil { 1022 t.Error(err) 1023 return 1024 } 1025 1026 close(server2ContactedFirstTime) 1027 <-closeServer2 1028 conn.Close() 1029 1030 // After tryUpdateAddrs, it should NOT try server2. 1031 lis2.Accept() 1032 close(server2ContactedSecondTime) 1033 }() 1034 // Launch server 3. 1035 go func() { 1036 // After tryUpdateAddrs, it should NOT try server3. (or any other time) 1037 lis3.Accept() 1038 close(server3Contacted) 1039 }() 1040 1041 addrsList := []resolver.Address{ 1042 {Addr: lis1.Addr().String()}, 1043 {Addr: lis2.Addr().String()}, 1044 {Addr: lis3.Addr().String()}, 1045 } 1046 rb := manual.NewBuilderWithScheme("whatever") 1047 rb.InitialState(resolver.State{Addresses: addrsList}) 1048 1049 client, err := NewClient("whatever:///this-gets-overwritten", 1050 WithTransportCredentials(insecure.NewCredentials()), 1051 WithResolvers(rb), 1052 WithConnectParams(ConnectParams{ 1053 Backoff: backoff.Config{}, 1054 MinConnectTimeout: time.Hour, 1055 }), 1056 WithDefaultServiceConfig(fmt.Sprintf(`{"loadBalancingConfig": [{"%s":{}}]}`, stateRecordingBalancerName))) 1057 if err != nil { 1058 t.Fatal(err) 1059 } 1060 defer client.Close() 1061 go stayConnected(client) 1062 1063 timeout := time.After(5 * time.Second) 1064 1065 // Wait for server1 to be contacted (which will immediately fail), then 1066 // server2 (which will hang waiting for our signal). 1067 select { 1068 case <-server1ContactedFirstTime: 1069 case <-timeout: 1070 t.Fatal("timed out waiting for server1 to be contacted") 1071 } 1072 select { 1073 case <-server2ContactedFirstTime: 1074 case <-timeout: 1075 t.Fatal("timed out waiting for server2 to be contacted") 1076 } 1077 1078 // Grab the addrConn and call tryUpdateAddrs. 1079 client.mu.Lock() 1080 for clientAC := range client.conns { 1081 // Call UpdateAddresses with the same list of addresses, it should be a noop 1082 // (even when the SubConn is Connecting, and doesn't have a curAddr). 1083 clientAC.acbw.UpdateAddresses(clientAC.addrs) 1084 } 1085 client.mu.Unlock() 1086 1087 // We've called tryUpdateAddrs - now let's make server2 close the 1088 // connection and check that it continues to server3. 1089 close(closeServer2) 1090 1091 select { 1092 case <-server1ContactedSecondTime: 1093 t.Fatal("server1 was contacted a second time, but it should have continued to server 3") 1094 case <-server2ContactedSecondTime: 1095 t.Fatal("server2 was contacted a second time, but it should have continued to server 3") 1096 case <-server3Contacted: 1097 case <-timeout: 1098 t.Fatal("timed out waiting for any server to be contacted after tryUpdateAddrs") 1099 } 1100 } 1101 1102 func (s) TestDefaultServiceConfig(t *testing.T) { 1103 const defaultSC = ` 1104 { 1105 "methodConfig": [ 1106 { 1107 "name": [ 1108 { 1109 "service": "foo", 1110 "method": "bar" 1111 } 1112 ], 1113 "waitForReady": true 1114 } 1115 ] 1116 }` 1117 tests := []struct { 1118 name string 1119 testF func(t *testing.T, r *manual.Resolver, addr, sc string) 1120 sc string 1121 }{ 1122 { 1123 name: "invalid-service-config", 1124 testF: testInvalidDefaultServiceConfig, 1125 sc: "", 1126 }, 1127 { 1128 name: "resolver-service-config-disabled", 1129 testF: testDefaultServiceConfigWhenResolverServiceConfigDisabled, 1130 sc: defaultSC, 1131 }, 1132 { 1133 name: "resolver-does-not-return-service-config", 1134 testF: testDefaultServiceConfigWhenResolverDoesNotReturnServiceConfig, 1135 sc: defaultSC, 1136 }, 1137 { 1138 name: "resolver-returns-invalid-service-config", 1139 testF: testDefaultServiceConfigWhenResolverReturnInvalidServiceConfig, 1140 sc: defaultSC, 1141 }, 1142 } 1143 1144 for _, test := range tests { 1145 t.Run(test.name, func(t *testing.T) { 1146 r := manual.NewBuilderWithScheme(test.name) 1147 addr := r.Scheme() + ":///non.existent" 1148 test.testF(t, r, addr, test.sc) 1149 }) 1150 } 1151 } 1152 1153 func verifyWaitForReadyEqualsTrue(cc *ClientConn) bool { 1154 var i int 1155 for i = 0; i < 10; i++ { 1156 mc := cc.GetMethodConfig("/foo/bar") 1157 if mc.WaitForReady != nil && *mc.WaitForReady == true { 1158 break 1159 } 1160 time.Sleep(100 * time.Millisecond) 1161 } 1162 return i != 10 1163 } 1164 1165 func testInvalidDefaultServiceConfig(t *testing.T, r *manual.Resolver, addr, sc string) { 1166 _, err := NewClient(addr, WithTransportCredentials(insecure.NewCredentials()), WithResolvers(r), WithDefaultServiceConfig(sc)) 1167 if !strings.Contains(err.Error(), invalidDefaultServiceConfigErrPrefix) { 1168 t.Fatalf("grpc.NewClient() got err: %v, want err contains: %v", err, invalidDefaultServiceConfigErrPrefix) 1169 } 1170 } 1171 1172 func testDefaultServiceConfigWhenResolverServiceConfigDisabled(t *testing.T, r *manual.Resolver, addr string, js string) { 1173 cc, err := NewClient(addr, WithTransportCredentials(insecure.NewCredentials()), WithDisableServiceConfig(), WithResolvers(r), WithDefaultServiceConfig(js)) 1174 if err != nil { 1175 t.Fatalf("grpc.NewClient(%s) failed: %v, want: nil", addr, err) 1176 } 1177 cc.Connect() 1178 defer cc.Close() 1179 // Resolver service config gets ignored since resolver service config is disabled. 1180 r.UpdateState(resolver.State{ 1181 Addresses: []resolver.Address{{Addr: addr}}, 1182 ServiceConfig: parseCfg(r, "{}"), 1183 }) 1184 if !verifyWaitForReadyEqualsTrue(cc) { 1185 t.Fatal("default service config failed to be applied after 1s") 1186 } 1187 } 1188 1189 func testDefaultServiceConfigWhenResolverDoesNotReturnServiceConfig(t *testing.T, r *manual.Resolver, addr string, js string) { 1190 cc, err := NewClient(addr, WithTransportCredentials(insecure.NewCredentials()), WithResolvers(r), WithDefaultServiceConfig(js)) 1191 if err != nil { 1192 t.Fatalf("grpc.NewClient(%s) failed: %v, want: nil", addr, err) 1193 } 1194 cc.Connect() 1195 defer cc.Close() 1196 r.UpdateState(resolver.State{ 1197 Addresses: []resolver.Address{{Addr: addr}}, 1198 }) 1199 if !verifyWaitForReadyEqualsTrue(cc) { 1200 t.Fatal("default service config failed to be applied after 1s") 1201 } 1202 } 1203 1204 func testDefaultServiceConfigWhenResolverReturnInvalidServiceConfig(t *testing.T, r *manual.Resolver, addr string, js string) { 1205 cc, err := NewClient(addr, WithTransportCredentials(insecure.NewCredentials()), WithResolvers(r), WithDefaultServiceConfig(js)) 1206 if err != nil { 1207 t.Fatalf("grpc.NewClient(%s) failed: %v, want: nil", addr, err) 1208 } 1209 cc.Connect() 1210 defer cc.Close() 1211 r.UpdateState(resolver.State{ 1212 Addresses: []resolver.Address{{Addr: addr}}, 1213 }) 1214 if !verifyWaitForReadyEqualsTrue(cc) { 1215 t.Fatal("default service config failed to be applied after 1s") 1216 } 1217 } 1218 1219 type stateRecordingBalancer struct { 1220 balancer.Balancer 1221 } 1222 1223 func (b *stateRecordingBalancer) UpdateSubConnState(sc balancer.SubConn, s balancer.SubConnState) { 1224 panic(fmt.Sprintf("UpdateSubConnState(%v, %+v) called unexpectedly", sc, s)) 1225 } 1226 1227 func (b *stateRecordingBalancer) Close() { 1228 b.Balancer.Close() 1229 } 1230 1231 type stateRecordingBalancerBuilder struct { 1232 mu sync.Mutex 1233 notifier chan connectivity.State // The notifier used in the last Balancer. 1234 } 1235 1236 func newStateRecordingBalancerBuilder() *stateRecordingBalancerBuilder { 1237 return &stateRecordingBalancerBuilder{} 1238 } 1239 1240 func (b *stateRecordingBalancerBuilder) Name() string { 1241 return stateRecordingBalancerName 1242 } 1243 1244 func (b *stateRecordingBalancerBuilder) Build(cc balancer.ClientConn, opts balancer.BuildOptions) balancer.Balancer { 1245 stateNotifications := make(chan connectivity.State, 10) 1246 b.mu.Lock() 1247 b.notifier = stateNotifications 1248 b.mu.Unlock() 1249 return &stateRecordingBalancer{ 1250 Balancer: balancer.Get("pick_first").Build(&stateRecordingCCWrapper{cc, stateNotifications}, opts), 1251 } 1252 } 1253 1254 func (b *stateRecordingBalancerBuilder) nextStateNotifier() <-chan connectivity.State { 1255 b.mu.Lock() 1256 defer b.mu.Unlock() 1257 ret := b.notifier 1258 b.notifier = nil 1259 return ret 1260 } 1261 1262 type stateRecordingCCWrapper struct { 1263 balancer.ClientConn 1264 notifier chan<- connectivity.State 1265 } 1266 1267 func (ccw *stateRecordingCCWrapper) NewSubConn(addrs []resolver.Address, opts balancer.NewSubConnOptions) (balancer.SubConn, error) { 1268 oldListener := opts.StateListener 1269 opts.StateListener = func(s balancer.SubConnState) { 1270 ccw.notifier <- s.ConnectivityState 1271 oldListener(s) 1272 } 1273 return ccw.ClientConn.NewSubConn(addrs, opts) 1274 } 1275 1276 // Keep reading until something causes the connection to die (EOF, server 1277 // closed, etc). Useful as a tool for mindlessly keeping the connection 1278 // healthy, since the client will error if things like client prefaces are not 1279 // accepted in a timely fashion. 1280 func keepReading(conn net.Conn) { 1281 buf := make([]byte, 1024) 1282 for _, err := conn.Read(buf); err == nil; _, err = conn.Read(buf) { 1283 } 1284 } 1285 1286 // stayConnected makes cc stay connected by repeatedly calling cc.Connect() 1287 // until the state becomes Shutdown or until 10 seconds elapses. 1288 func stayConnected(cc *ClientConn) { 1289 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 1290 defer cancel() 1291 1292 for { 1293 state := cc.GetState() 1294 switch state { 1295 case connectivity.Idle: 1296 cc.Connect() 1297 case connectivity.Shutdown: 1298 return 1299 } 1300 if !cc.WaitForStateChange(ctx, state) { 1301 return 1302 } 1303 } 1304 } 1305 1306 func (s) TestURLAuthorityEscape(t *testing.T) { 1307 tests := []struct { 1308 name string 1309 authority string 1310 want string 1311 }{ 1312 { 1313 name: "ipv6_authority", 1314 authority: "[::1]", 1315 want: "[::1]", 1316 }, 1317 { 1318 name: "with_user_and_host", 1319 authority: "userinfo@host:10001", 1320 want: "userinfo@host:10001", 1321 }, 1322 { 1323 name: "with_multiple_slashes", 1324 authority: "projects/123/network/abc/service", 1325 want: "projects%2F123%2Fnetwork%2Fabc%2Fservice", 1326 }, 1327 { 1328 name: "all_possible_allowed_chars", 1329 authority: "abc123-._~!$&'()*+,;=@:[]", 1330 want: "abc123-._~!$&'()*+,;=@:[]", 1331 }, 1332 } 1333 1334 for _, test := range tests { 1335 t.Run(test.name, func(t *testing.T) { 1336 if got, want := encodeAuthority(test.authority), test.want; got != want { 1337 t.Errorf("encodeAuthority(%s) = %s, want %s", test.authority, got, test.want) 1338 } 1339 }) 1340 } 1341 }