google.golang.org/grpc@v1.72.2/internal/transport/keepalive_test.go (about)

     1  /*
     2   *
     3   * Copyright 2019 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  // This file contains tests related to the following proposals:
    20  // https://github.com/grpc/proposal/blob/master/A8-client-side-keepalive.md
    21  // https://github.com/grpc/proposal/blob/master/A9-server-side-conn-mgt.md
    22  // https://github.com/grpc/proposal/blob/master/A18-tcp-user-timeout.md
    23  package transport
    24  
    25  import (
    26  	"context"
    27  	"crypto/tls"
    28  	"crypto/x509"
    29  	"fmt"
    30  	"io"
    31  	"net"
    32  	"os"
    33  	"strings"
    34  	"testing"
    35  	"time"
    36  
    37  	"golang.org/x/net/http2"
    38  	"google.golang.org/grpc/credentials"
    39  	"google.golang.org/grpc/internal/channelz"
    40  	"google.golang.org/grpc/internal/grpctest"
    41  	"google.golang.org/grpc/internal/syscall"
    42  	"google.golang.org/grpc/keepalive"
    43  	"google.golang.org/grpc/testdata"
    44  )
    45  
    46  const defaultTestTimeout = 10 * time.Second
    47  const defaultTestShortTimeout = 10 * time.Millisecond
    48  
    49  // TestMaxConnectionIdle tests that a server will send GoAway to an idle
    50  // client. An idle client is one who doesn't make any RPC calls for a duration
    51  // of MaxConnectionIdle time.
    52  func (s) TestMaxConnectionIdle(t *testing.T) {
    53  	serverConfig := &ServerConfig{
    54  		KeepaliveParams: keepalive.ServerParameters{
    55  			MaxConnectionIdle: 30 * time.Millisecond,
    56  		},
    57  	}
    58  	server, client, cancel := setUpWithOptions(t, 0, serverConfig, suspended, ConnectOptions{})
    59  	defer func() {
    60  		client.Close(fmt.Errorf("closed manually by test"))
    61  		server.stop()
    62  		cancel()
    63  	}()
    64  
    65  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
    66  	defer cancel()
    67  	stream, err := client.NewStream(ctx, &CallHdr{})
    68  	if err != nil {
    69  		t.Fatalf("client.NewStream() failed: %v", err)
    70  	}
    71  	stream.Close(io.EOF)
    72  
    73  	// Verify the server sends a GoAway to client after MaxConnectionIdle timeout
    74  	// kicks in.
    75  	select {
    76  	case <-ctx.Done():
    77  		t.Fatalf("context expired before receiving GoAway from the server.")
    78  	case <-client.GoAway():
    79  		reason, debugMsg := client.GetGoAwayReason()
    80  		if reason != GoAwayNoReason {
    81  			t.Fatalf("GoAwayReason is %v, want %v", reason, GoAwayNoReason)
    82  		}
    83  		if !strings.Contains(debugMsg, "max_idle") {
    84  			t.Fatalf("GoAwayDebugMessage is %v, want %v", debugMsg, "max_idle")
    85  		}
    86  	}
    87  }
    88  
    89  // TestMaxConnectionIdleBusyClient tests that a server will not send GoAway to
    90  // a busy client.
    91  func (s) TestMaxConnectionIdleBusyClient(t *testing.T) {
    92  	serverConfig := &ServerConfig{
    93  		KeepaliveParams: keepalive.ServerParameters{
    94  			MaxConnectionIdle: 100 * time.Millisecond,
    95  		},
    96  	}
    97  	server, client, cancel := setUpWithOptions(t, 0, serverConfig, suspended, ConnectOptions{})
    98  	defer func() {
    99  		client.Close(fmt.Errorf("closed manually by test"))
   100  		server.stop()
   101  		cancel()
   102  	}()
   103  
   104  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   105  	defer cancel()
   106  	_, err := client.NewStream(ctx, &CallHdr{})
   107  	if err != nil {
   108  		t.Fatalf("client.NewStream() failed: %v", err)
   109  	}
   110  
   111  	// Verify the server does not send a GoAway to client even after MaxConnectionIdle
   112  	// timeout kicks in.
   113  	ctx, cancel = context.WithTimeout(context.Background(), time.Second)
   114  	defer cancel()
   115  	select {
   116  	case <-client.GoAway():
   117  		t.Fatalf("A busy client received a GoAway.")
   118  	case <-ctx.Done():
   119  	}
   120  }
   121  
   122  // TestMaxConnectionAge tests that a server will send GoAway after a duration
   123  // of MaxConnectionAge.
   124  func (s) TestMaxConnectionAge(t *testing.T) {
   125  	maxConnAge := 100 * time.Millisecond
   126  	serverConfig := &ServerConfig{
   127  		KeepaliveParams: keepalive.ServerParameters{
   128  			MaxConnectionAge:      maxConnAge,
   129  			MaxConnectionAgeGrace: 10 * time.Millisecond,
   130  		},
   131  	}
   132  	server, client, cancel := setUpWithOptions(t, 0, serverConfig, suspended, ConnectOptions{})
   133  	defer func() {
   134  		client.Close(fmt.Errorf("closed manually by test"))
   135  		server.stop()
   136  		cancel()
   137  	}()
   138  
   139  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   140  	defer cancel()
   141  	if _, err := client.NewStream(ctx, &CallHdr{}); err != nil {
   142  		t.Fatalf("client.NewStream() failed: %v", err)
   143  	}
   144  
   145  	// Verify the server sends a GoAway to client even after client remains idle
   146  	// for more than MaxConnectionIdle time.
   147  	select {
   148  	case <-client.GoAway():
   149  		reason, debugMsg := client.GetGoAwayReason()
   150  		if reason != GoAwayNoReason {
   151  			t.Fatalf("GoAwayReason is %v, want %v", reason, GoAwayNoReason)
   152  		}
   153  		if !strings.Contains(debugMsg, "max_age") {
   154  			t.Fatalf("GoAwayDebugMessage is %v, want %v", debugMsg, "max_age")
   155  		}
   156  	case <-ctx.Done():
   157  		t.Fatalf("timed out before getting a GoAway from the server.")
   158  	}
   159  }
   160  
   161  const (
   162  	defaultWriteBufSize = 32 * 1024
   163  	defaultReadBufSize  = 32 * 1024
   164  )
   165  
   166  // TestKeepaliveServerClosesUnresponsiveClient tests that a server closes
   167  // the connection with a client that doesn't respond to keepalive pings.
   168  //
   169  // This test creates a regular net.Conn connection to the server and sends the
   170  // clientPreface and the initial Settings frame, and then remains unresponsive.
   171  func (s) TestKeepaliveServerClosesUnresponsiveClient(t *testing.T) {
   172  	serverConfig := &ServerConfig{
   173  		KeepaliveParams: keepalive.ServerParameters{
   174  			Time:    100 * time.Millisecond,
   175  			Timeout: 10 * time.Millisecond,
   176  		},
   177  	}
   178  	server, client, cancel := setUpWithOptions(t, 0, serverConfig, suspended, ConnectOptions{})
   179  	defer func() {
   180  		client.Close(fmt.Errorf("closed manually by test"))
   181  		server.stop()
   182  		cancel()
   183  	}()
   184  
   185  	addr := server.addr()
   186  	conn, err := net.Dial("tcp", addr)
   187  	if err != nil {
   188  		t.Fatalf("net.Dial(tcp, %v) failed: %v", addr, err)
   189  	}
   190  	defer conn.Close()
   191  
   192  	if n, err := conn.Write(clientPreface); err != nil || n != len(clientPreface) {
   193  		t.Fatalf("conn.Write(clientPreface) failed: n=%v, err=%v", n, err)
   194  	}
   195  	framer := newFramer(conn, defaultWriteBufSize, defaultReadBufSize, false, 0)
   196  	if err := framer.fr.WriteSettings(http2.Setting{}); err != nil {
   197  		t.Fatal("framer.WriteSettings(http2.Setting{}) failed:", err)
   198  	}
   199  	framer.writer.Flush()
   200  
   201  	// We read from the net.Conn till we get an error, which is expected when
   202  	// the server closes the connection as part of the keepalive logic.
   203  	errCh := make(chan error, 1)
   204  	go func() {
   205  		b := make([]byte, 24)
   206  		for {
   207  			if _, err = conn.Read(b); err != nil {
   208  				errCh <- err
   209  				return
   210  			}
   211  		}
   212  	}()
   213  
   214  	// Server waits for KeepaliveParams.Time seconds before sending out a ping,
   215  	// and then waits for KeepaliveParams.Timeout for a ping ack.
   216  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   217  	defer cancel()
   218  	select {
   219  	case err := <-errCh:
   220  		if err != io.EOF {
   221  			t.Fatalf("client.Read(_) = _,%v, want io.EOF", err)
   222  
   223  		}
   224  	case <-ctx.Done():
   225  		t.Fatalf("Test timed out before server closed the connection.")
   226  	}
   227  }
   228  
   229  // TestKeepaliveServerWithResponsiveClient tests that a server doesn't close
   230  // the connection with a client that responds to keepalive pings.
   231  func (s) TestKeepaliveServerWithResponsiveClient(t *testing.T) {
   232  	serverConfig := &ServerConfig{
   233  		KeepaliveParams: keepalive.ServerParameters{
   234  			Time:    100 * time.Millisecond,
   235  			Timeout: 100 * time.Millisecond,
   236  		},
   237  	}
   238  	server, client, cancel := setUpWithOptions(t, 0, serverConfig, suspended, ConnectOptions{})
   239  	defer func() {
   240  		client.Close(fmt.Errorf("closed manually by test"))
   241  		server.stop()
   242  		cancel()
   243  	}()
   244  
   245  	// Give keepalive logic some time by sleeping.
   246  	time.Sleep(500 * time.Millisecond)
   247  
   248  	if err := checkForHealthyStream(client); err != nil {
   249  		t.Fatalf("Stream creation failed: %v", err)
   250  	}
   251  }
   252  
   253  func channelzSubChannel(t *testing.T) *channelz.SubChannel {
   254  	ch := channelz.RegisterChannel(nil, "test chan")
   255  	sc := channelz.RegisterSubChannel(ch, "test subchan")
   256  	t.Cleanup(func() {
   257  		channelz.RemoveEntry(sc.ID)
   258  		channelz.RemoveEntry(ch.ID)
   259  	})
   260  	return sc
   261  }
   262  
   263  // TestKeepaliveClientClosesUnresponsiveServer creates a server which does not
   264  // respond to keepalive pings, and makes sure that the client closes the
   265  // transport once the keepalive logic kicks in. Here, we set the
   266  // `PermitWithoutStream` parameter to true which ensures that the keepalive
   267  // logic is running even without any active streams.
   268  func (s) TestKeepaliveClientClosesUnresponsiveServer(t *testing.T) {
   269  	connCh := make(chan net.Conn, 1)
   270  	copts := ConnectOptions{
   271  		ChannelzParent: channelzSubChannel(t),
   272  		KeepaliveParams: keepalive.ClientParameters{
   273  			Time:                10 * time.Millisecond,
   274  			Timeout:             10 * time.Millisecond,
   275  			PermitWithoutStream: true,
   276  		},
   277  	}
   278  	client, cancel := setUpWithNoPingServer(t, copts, connCh)
   279  	defer cancel()
   280  	defer client.Close(fmt.Errorf("closed manually by test"))
   281  
   282  	conn, ok := <-connCh
   283  	if !ok {
   284  		t.Fatalf("Server didn't return connection object")
   285  	}
   286  	defer conn.Close()
   287  
   288  	if err := pollForStreamCreationError(client); err != nil {
   289  		t.Fatal(err)
   290  	}
   291  }
   292  
   293  // TestKeepaliveClientOpenWithUnresponsiveServer creates a server which does
   294  // not respond to keepalive pings, and makes sure that the client does not
   295  // close the transport. Here, we do not set the `PermitWithoutStream` parameter
   296  // to true which ensures that the keepalive logic is turned off without any
   297  // active streams, and therefore the transport stays open.
   298  func (s) TestKeepaliveClientOpenWithUnresponsiveServer(t *testing.T) {
   299  	connCh := make(chan net.Conn, 1)
   300  	copts := ConnectOptions{
   301  		ChannelzParent: channelzSubChannel(t),
   302  		KeepaliveParams: keepalive.ClientParameters{
   303  			Time:    10 * time.Millisecond,
   304  			Timeout: 10 * time.Millisecond,
   305  		},
   306  	}
   307  	client, cancel := setUpWithNoPingServer(t, copts, connCh)
   308  	defer cancel()
   309  	defer client.Close(fmt.Errorf("closed manually by test"))
   310  
   311  	conn, ok := <-connCh
   312  	if !ok {
   313  		t.Fatalf("Server didn't return connection object")
   314  	}
   315  	defer conn.Close()
   316  
   317  	// Give keepalive some time.
   318  	time.Sleep(500 * time.Millisecond)
   319  
   320  	if err := checkForHealthyStream(client); err != nil {
   321  		t.Fatalf("Stream creation failed: %v", err)
   322  	}
   323  }
   324  
   325  // TestKeepaliveClientClosesWithActiveStreams creates a server which does not
   326  // respond to keepalive pings, and makes sure that the client closes the
   327  // transport even when there is an active stream.
   328  func (s) TestKeepaliveClientClosesWithActiveStreams(t *testing.T) {
   329  	connCh := make(chan net.Conn, 1)
   330  	copts := ConnectOptions{
   331  		ChannelzParent: channelzSubChannel(t),
   332  		KeepaliveParams: keepalive.ClientParameters{
   333  			Time:    500 * time.Millisecond,
   334  			Timeout: 500 * time.Millisecond,
   335  		},
   336  	}
   337  	// TODO(i/6099): Setup a server which can ping and no-ping based on a flag to
   338  	// reduce the flakiness in this test.
   339  	client, cancel := setUpWithNoPingServer(t, copts, connCh)
   340  	defer cancel()
   341  	defer client.Close(fmt.Errorf("closed manually by test"))
   342  
   343  	conn, ok := <-connCh
   344  	if !ok {
   345  		t.Fatalf("Server didn't return connection object")
   346  	}
   347  	defer conn.Close()
   348  
   349  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   350  	defer cancel()
   351  	// Create a stream, but send no data on it.
   352  	if _, err := client.NewStream(ctx, &CallHdr{}); err != nil {
   353  		t.Fatalf("Stream creation failed: %v", err)
   354  	}
   355  
   356  	if err := pollForStreamCreationError(client); err != nil {
   357  		t.Fatal(err)
   358  	}
   359  }
   360  
   361  // TestKeepaliveClientStaysHealthyWithResponsiveServer creates a server which
   362  // responds to keepalive pings, and makes sure than a client transport stays
   363  // healthy without any active streams.
   364  func (s) TestKeepaliveClientStaysHealthyWithResponsiveServer(t *testing.T) {
   365  	server, client, cancel := setUpWithOptions(t, 0,
   366  		&ServerConfig{
   367  			KeepalivePolicy: keepalive.EnforcementPolicy{
   368  				MinTime:             50 * time.Millisecond,
   369  				PermitWithoutStream: true,
   370  			},
   371  		},
   372  		normal,
   373  		ConnectOptions{
   374  			KeepaliveParams: keepalive.ClientParameters{
   375  				Time:                55 * time.Millisecond,
   376  				Timeout:             time.Second,
   377  				PermitWithoutStream: true,
   378  			}})
   379  	defer func() {
   380  		client.Close(fmt.Errorf("closed manually by test"))
   381  		server.stop()
   382  		cancel()
   383  	}()
   384  
   385  	// Give keepalive some time.
   386  	time.Sleep(500 * time.Millisecond)
   387  
   388  	if err := checkForHealthyStream(client); err != nil {
   389  		t.Fatalf("Stream creation failed: %v", err)
   390  	}
   391  }
   392  
   393  // TestKeepaliveClientFrequency creates a server which expects at most 1 client
   394  // ping for every 100 ms, while the client is configured to send a ping
   395  // every 50 ms. So, this configuration should end up with the client
   396  // transport being closed. But we had a bug wherein the client was sending one
   397  // ping every [Time+Timeout] instead of every [Time] period, and this test
   398  // explicitly makes sure the fix works and the client sends a ping every [Time]
   399  // period.
   400  func (s) TestKeepaliveClientFrequency(t *testing.T) {
   401  	grpctest.TLogger.ExpectError("Client received GoAway with error code ENHANCE_YOUR_CALM and debug data equal to ASCII \"too_many_pings\"")
   402  
   403  	serverConfig := &ServerConfig{
   404  		KeepalivePolicy: keepalive.EnforcementPolicy{
   405  			MinTime:             100 * time.Millisecond,
   406  			PermitWithoutStream: true,
   407  		},
   408  	}
   409  	clientOptions := ConnectOptions{
   410  		KeepaliveParams: keepalive.ClientParameters{
   411  			Time:                50 * time.Millisecond,
   412  			Timeout:             time.Second,
   413  			PermitWithoutStream: true,
   414  		},
   415  	}
   416  	server, client, cancel := setUpWithOptions(t, 0, serverConfig, normal, clientOptions)
   417  	defer func() {
   418  		client.Close(fmt.Errorf("closed manually by test"))
   419  		server.stop()
   420  		cancel()
   421  	}()
   422  
   423  	if err := waitForGoAwayTooManyPings(client); err != nil {
   424  		t.Fatal(err)
   425  	}
   426  }
   427  
   428  // TestKeepaliveServerEnforcementWithAbusiveClientNoRPC verifies that the
   429  // server closes a client transport when it sends too many keepalive pings
   430  // (when there are no active streams), based on the configured
   431  // EnforcementPolicy.
   432  func (s) TestKeepaliveServerEnforcementWithAbusiveClientNoRPC(t *testing.T) {
   433  	grpctest.TLogger.ExpectError("Client received GoAway with error code ENHANCE_YOUR_CALM and debug data equal to ASCII \"too_many_pings\"")
   434  
   435  	serverConfig := &ServerConfig{
   436  		KeepalivePolicy: keepalive.EnforcementPolicy{
   437  			MinTime: time.Second,
   438  		},
   439  	}
   440  	clientOptions := ConnectOptions{
   441  		KeepaliveParams: keepalive.ClientParameters{
   442  			Time:                20 * time.Millisecond,
   443  			Timeout:             100 * time.Millisecond,
   444  			PermitWithoutStream: true,
   445  		},
   446  	}
   447  	server, client, cancel := setUpWithOptions(t, 0, serverConfig, normal, clientOptions)
   448  	defer func() {
   449  		client.Close(fmt.Errorf("closed manually by test"))
   450  		server.stop()
   451  		cancel()
   452  	}()
   453  
   454  	if err := waitForGoAwayTooManyPings(client); err != nil {
   455  		t.Fatal(err)
   456  	}
   457  }
   458  
   459  // TestKeepaliveServerEnforcementWithAbusiveClientWithRPC verifies that the
   460  // server closes a client transport when it sends too many keepalive pings
   461  // (even when there is an active stream), based on the configured
   462  // EnforcementPolicy.
   463  func (s) TestKeepaliveServerEnforcementWithAbusiveClientWithRPC(t *testing.T) {
   464  	grpctest.TLogger.ExpectError("Client received GoAway with error code ENHANCE_YOUR_CALM and debug data equal to ASCII \"too_many_pings\"")
   465  
   466  	serverConfig := &ServerConfig{
   467  		KeepalivePolicy: keepalive.EnforcementPolicy{
   468  			MinTime: time.Second,
   469  		},
   470  	}
   471  	clientOptions := ConnectOptions{
   472  		KeepaliveParams: keepalive.ClientParameters{
   473  			Time:    50 * time.Millisecond,
   474  			Timeout: 100 * time.Millisecond,
   475  		},
   476  	}
   477  	server, client, cancel := setUpWithOptions(t, 0, serverConfig, suspended, clientOptions)
   478  	defer func() {
   479  		client.Close(fmt.Errorf("closed manually by test"))
   480  		server.stop()
   481  		cancel()
   482  	}()
   483  
   484  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   485  	defer cancel()
   486  	if _, err := client.NewStream(ctx, &CallHdr{}); err != nil {
   487  		t.Fatalf("Stream creation failed: %v", err)
   488  	}
   489  
   490  	if err := waitForGoAwayTooManyPings(client); err != nil {
   491  		t.Fatal(err)
   492  	}
   493  }
   494  
   495  // TestKeepaliveServerEnforcementWithObeyingClientNoRPC verifies that the
   496  // server does not close a client transport (with no active streams) which
   497  // sends keepalive pings in accordance to the configured keepalive
   498  // EnforcementPolicy.
   499  func (s) TestKeepaliveServerEnforcementWithObeyingClientNoRPC(t *testing.T) {
   500  	serverConfig := &ServerConfig{
   501  		KeepalivePolicy: keepalive.EnforcementPolicy{
   502  			MinTime:             40 * time.Millisecond,
   503  			PermitWithoutStream: true,
   504  		},
   505  	}
   506  	clientOptions := ConnectOptions{
   507  		KeepaliveParams: keepalive.ClientParameters{
   508  			Time:                50 * time.Millisecond,
   509  			Timeout:             time.Second,
   510  			PermitWithoutStream: true,
   511  		},
   512  	}
   513  	server, client, cancel := setUpWithOptions(t, 0, serverConfig, normal, clientOptions)
   514  	defer func() {
   515  		client.Close(fmt.Errorf("closed manually by test"))
   516  		server.stop()
   517  		cancel()
   518  	}()
   519  
   520  	// Sleep for client to send ~10 keepalive pings.
   521  	time.Sleep(500 * time.Millisecond)
   522  
   523  	// Verify that the server does not close the client transport.
   524  	if err := checkForHealthyStream(client); err != nil {
   525  		t.Fatalf("Stream creation failed: %v", err)
   526  	}
   527  }
   528  
   529  // TestKeepaliveServerEnforcementWithObeyingClientWithRPC verifies that the
   530  // server does not close a client transport (with active streams) which
   531  // sends keepalive pings in accordance to the configured keepalive
   532  // EnforcementPolicy.
   533  func (s) TestKeepaliveServerEnforcementWithObeyingClientWithRPC(t *testing.T) {
   534  	serverConfig := &ServerConfig{
   535  		KeepalivePolicy: keepalive.EnforcementPolicy{
   536  			MinTime: 40 * time.Millisecond,
   537  		},
   538  	}
   539  	clientOptions := ConnectOptions{
   540  		KeepaliveParams: keepalive.ClientParameters{
   541  			Time: 50 * time.Millisecond,
   542  		},
   543  	}
   544  	server, client, cancel := setUpWithOptions(t, 0, serverConfig, suspended, clientOptions)
   545  	defer func() {
   546  		client.Close(fmt.Errorf("closed manually by test"))
   547  		server.stop()
   548  		cancel()
   549  	}()
   550  
   551  	if err := checkForHealthyStream(client); err != nil {
   552  		t.Fatalf("Stream creation failed: %v", err)
   553  	}
   554  
   555  	// Give keepalive enough time.
   556  	time.Sleep(500 * time.Millisecond)
   557  
   558  	if err := checkForHealthyStream(client); err != nil {
   559  		t.Fatalf("Stream creation failed: %v", err)
   560  	}
   561  }
   562  
   563  // TestKeepaliveServerEnforcementWithDormantKeepaliveOnClient verifies that the
   564  // server does not closes a client transport, which has been configured to send
   565  // more pings than allowed by the server's EnforcementPolicy. This client
   566  // transport does not have any active streams and `PermitWithoutStream` is set
   567  // to false. This should ensure that the keepalive functionality on the client
   568  // side enters a dormant state.
   569  func (s) TestKeepaliveServerEnforcementWithDormantKeepaliveOnClient(t *testing.T) {
   570  	serverConfig := &ServerConfig{
   571  		KeepalivePolicy: keepalive.EnforcementPolicy{
   572  			MinTime: 100 * time.Millisecond,
   573  		},
   574  	}
   575  	clientOptions := ConnectOptions{
   576  		KeepaliveParams: keepalive.ClientParameters{
   577  			Time:    10 * time.Millisecond,
   578  			Timeout: 10 * time.Millisecond,
   579  		},
   580  	}
   581  	server, client, cancel := setUpWithOptions(t, 0, serverConfig, normal, clientOptions)
   582  	defer func() {
   583  		client.Close(fmt.Errorf("closed manually by test"))
   584  		server.stop()
   585  		cancel()
   586  	}()
   587  
   588  	// No active streams on the client. Give keepalive enough time.
   589  	time.Sleep(500 * time.Millisecond)
   590  
   591  	if err := checkForHealthyStream(client); err != nil {
   592  		t.Fatalf("Stream creation failed: %v", err)
   593  	}
   594  }
   595  
   596  // TestTCPUserTimeout tests that the TCP_USER_TIMEOUT socket option is set to
   597  // the keepalive timeout, as detailed in proposal A18.
   598  func (s) TestTCPUserTimeout(t *testing.T) {
   599  	tests := []struct {
   600  		tls               bool
   601  		time              time.Duration
   602  		timeout           time.Duration
   603  		clientWantTimeout time.Duration
   604  		serverWantTimeout time.Duration
   605  	}{
   606  		{
   607  			false,
   608  			10 * time.Second,
   609  			10 * time.Second,
   610  			10 * 1000 * time.Millisecond,
   611  			10 * 1000 * time.Millisecond,
   612  		},
   613  		{
   614  			false,
   615  			0,
   616  			0,
   617  			0,
   618  			20 * 1000 * time.Millisecond,
   619  		},
   620  		{
   621  			false,
   622  			infinity,
   623  			infinity,
   624  			0,
   625  			0,
   626  		},
   627  		{
   628  			true,
   629  			10 * time.Second,
   630  			10 * time.Second,
   631  			10 * 1000 * time.Millisecond,
   632  			10 * 1000 * time.Millisecond,
   633  		},
   634  		{
   635  			true,
   636  			0,
   637  			0,
   638  			0,
   639  			20 * 1000 * time.Millisecond,
   640  		},
   641  		{
   642  			true,
   643  			infinity,
   644  			infinity,
   645  			0,
   646  			0,
   647  		},
   648  	}
   649  	for _, tt := range tests {
   650  		sopts := &ServerConfig{
   651  			KeepaliveParams: keepalive.ServerParameters{
   652  				Time:    tt.time,
   653  				Timeout: tt.timeout,
   654  			},
   655  		}
   656  
   657  		copts := ConnectOptions{
   658  			KeepaliveParams: keepalive.ClientParameters{
   659  				Time:    tt.time,
   660  				Timeout: tt.timeout,
   661  			},
   662  		}
   663  
   664  		if tt.tls {
   665  			copts.TransportCredentials = makeTLSCreds(t, "x509/client1_cert.pem", "x509/client1_key.pem", "x509/server_ca_cert.pem")
   666  			sopts.Credentials = makeTLSCreds(t, "x509/server1_cert.pem", "x509/server1_key.pem", "x509/client_ca_cert.pem")
   667  
   668  		}
   669  
   670  		server, client, cancel := setUpWithOptions(
   671  			t,
   672  			0,
   673  			sopts,
   674  			normal,
   675  			copts,
   676  		)
   677  		defer func() {
   678  			client.Close(fmt.Errorf("closed manually by test"))
   679  			server.stop()
   680  			cancel()
   681  		}()
   682  
   683  		var sc *http2Server
   684  		var srawConn net.Conn
   685  		// Wait until the server transport is setup.
   686  		for {
   687  			server.mu.Lock()
   688  			if len(server.conns) == 0 {
   689  				server.mu.Unlock()
   690  				time.Sleep(time.Millisecond)
   691  				continue
   692  			}
   693  			for k := range server.conns {
   694  				var ok bool
   695  				sc, ok = k.(*http2Server)
   696  				if !ok {
   697  					t.Fatalf("Failed to convert %v to *http2Server", k)
   698  				}
   699  				srawConn = server.conns[k]
   700  			}
   701  			server.mu.Unlock()
   702  			break
   703  		}
   704  
   705  		ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   706  		defer cancel()
   707  		stream, err := client.NewStream(ctx, &CallHdr{})
   708  		if err != nil {
   709  			t.Fatalf("client.NewStream() failed: %v", err)
   710  		}
   711  		stream.Close(io.EOF)
   712  
   713  		// check client TCP user timeout only when non TLS
   714  		// TODO : find a way to get the underlying conn for client when TLS
   715  		if !tt.tls {
   716  			cltOpt, err := syscall.GetTCPUserTimeout(client.conn)
   717  			if err != nil {
   718  				t.Fatalf("syscall.GetTCPUserTimeout() failed: %v", err)
   719  			}
   720  			if cltOpt < 0 {
   721  				t.Skipf("skipping test on unsupported environment")
   722  			}
   723  			if gotTimeout := time.Duration(cltOpt) * time.Millisecond; gotTimeout != tt.clientWantTimeout {
   724  				t.Fatalf("syscall.GetTCPUserTimeout() = %d, want %d", gotTimeout, tt.clientWantTimeout)
   725  			}
   726  		}
   727  		scConn := sc.conn
   728  		if tt.tls {
   729  			if _, ok := sc.conn.(*net.TCPConn); ok {
   730  				t.Fatalf("sc.conn is should have wrapped conn with TLS")
   731  			}
   732  			scConn = srawConn
   733  		}
   734  		// verify the type of scConn (on which TCP user timeout will be got)
   735  		if _, ok := scConn.(*net.TCPConn); !ok {
   736  			t.Fatalf("server underlying conn is of type %T, want net.TCPConn", scConn)
   737  		}
   738  		srvOpt, err := syscall.GetTCPUserTimeout(scConn)
   739  		if err != nil {
   740  			t.Fatalf("syscall.GetTCPUserTimeout() failed: %v", err)
   741  		}
   742  		if gotTimeout := time.Duration(srvOpt) * time.Millisecond; gotTimeout != tt.serverWantTimeout {
   743  			t.Fatalf("syscall.GetTCPUserTimeout() = %d, want %d", gotTimeout, tt.serverWantTimeout)
   744  		}
   745  
   746  	}
   747  }
   748  
   749  func makeTLSCreds(t *testing.T, certPath, keyPath, rootsPath string) credentials.TransportCredentials {
   750  	cert, err := tls.LoadX509KeyPair(testdata.Path(certPath), testdata.Path(keyPath))
   751  	if err != nil {
   752  		t.Fatalf("tls.LoadX509KeyPair(%q, %q) failed: %v", certPath, keyPath, err)
   753  	}
   754  	b, err := os.ReadFile(testdata.Path(rootsPath))
   755  	if err != nil {
   756  		t.Fatalf("os.ReadFile(%q) failed: %v", rootsPath, err)
   757  	}
   758  	roots := x509.NewCertPool()
   759  	if !roots.AppendCertsFromPEM(b) {
   760  		t.Fatal("failed to append certificates")
   761  	}
   762  	return credentials.NewTLS(&tls.Config{
   763  		Certificates:       []tls.Certificate{cert},
   764  		RootCAs:            roots,
   765  		InsecureSkipVerify: true,
   766  	})
   767  }
   768  
   769  // checkForHealthyStream attempts to create a stream and return error if any.
   770  // The stream created is closed right after to avoid any leakages.
   771  func checkForHealthyStream(client *http2Client) error {
   772  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   773  	defer cancel()
   774  	stream, err := client.NewStream(ctx, &CallHdr{})
   775  	stream.Close(err)
   776  	return err
   777  }
   778  
   779  func pollForStreamCreationError(client *http2Client) error {
   780  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   781  	defer cancel()
   782  	for {
   783  		if _, err := client.NewStream(ctx, &CallHdr{}); err != nil {
   784  			break
   785  		}
   786  		time.Sleep(50 * time.Millisecond)
   787  	}
   788  	if ctx.Err() != nil {
   789  		return fmt.Errorf("test timed out before stream creation returned an error")
   790  	}
   791  	return nil
   792  }
   793  
   794  // waitForGoAwayTooManyPings waits for client to receive a GoAwayTooManyPings
   795  // from server. It also asserts that stream creation fails after receiving a
   796  // GoAway.
   797  func waitForGoAwayTooManyPings(client *http2Client) error {
   798  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   799  	defer cancel()
   800  	select {
   801  	case <-client.GoAway():
   802  		if reason, _ := client.GetGoAwayReason(); reason != GoAwayTooManyPings {
   803  			return fmt.Errorf("goAwayReason is %v, want %v", reason, GoAwayTooManyPings)
   804  		}
   805  	case <-ctx.Done():
   806  		return fmt.Errorf("test timed out before getting GoAway with reason:GoAwayTooManyPings from server")
   807  	}
   808  
   809  	if _, err := client.NewStream(ctx, &CallHdr{}); err == nil {
   810  		return fmt.Errorf("stream creation succeeded after receiving a GoAway from the server")
   811  	}
   812  	return nil
   813  }