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