func TestPeerSelectionConnClosed(t *testing.T) { ctx, cancel := NewContext(time.Second) defer cancel() WithVerifiedServer(t, nil, func(server *Channel, hostPort string) { client := testutils.NewServer(t, nil) defer client.Close() // Ping will create an outbound connection from client -> server. require.NoError(t, testutils.Ping(client, server), "Ping failed") waitTillInboundEmpty(t, server, client.PeerInfo().HostPort, func() { peer, ok := client.RootPeers().Get(server.PeerInfo().HostPort) require.True(t, ok, "Client has no peer for %v", server.PeerInfo()) conn, err := peer.GetConnection(ctx) require.NoError(t, err, "Failed to get a connection") conn.Close() }) // Make sure the closed connection is not used. for i := 0; i < 10; i++ { require.NoError(t, testutils.Ping(client, server), "Ping failed") } }) }
// TestCloseSendError tests that system errors are not attempted to be sent when // a connection is closed, and ensures there's no race conditions such as the error // frame being added to the channel just as it is closed. func TestCloseSendError(t *testing.T) { var ( closed atomic.Uint32 counter atomic.Uint32 ) opts := testutils.NewOpts().DisableLogVerification() serverCh := testutils.NewServer(t, opts) testutils.RegisterEcho(serverCh, func() { if counter.Inc() > 10 { // Close the server in a goroutine to possibly trigger more race conditions. go func() { closed.Inc() serverCh.Close() }() } }) clientCh := testutils.NewClient(t, opts) // Create a connection that will be shared. require.NoError(t, testutils.Ping(clientCh, serverCh), "Ping from client to server failed") var wg sync.WaitGroup for i := 0; i < 100; i++ { wg.Add(1) go func() { time.Sleep(time.Duration(rand.Intn(1000)) * time.Microsecond) err := testutils.CallEcho(clientCh, serverCh.PeerInfo().HostPort, serverCh.ServiceName(), nil) if err != nil && closed.Load() == 0 { t.Errorf("Call failed: %v", err) } wg.Done() }() } // Wait for all the goroutines to end wg.Wait() clientCh.Close() goroutines.VerifyNoLeaks(t, nil) }
// TestCloseSendError tests that system errors are not attempted to be sent when // a connection is closed, and ensures there's no race conditions such as the error // frame being added to the channel just as it is closed. // TODO(prashant): This test is waiting for timeout, but socket close shouldn't wait for timeout. func TestCloseSendError(t *testing.T) { closed := uint32(0) counter := uint32(0) serverCh := testutils.NewServer(t, nil) testutils.RegisterEcho(serverCh, func() { if atomic.AddUint32(&counter, 1) > 10 { // Close the server in a goroutine to possibly trigger more race conditions. go func() { atomic.AddUint32(&closed, 1) serverCh.Close() }() } }) clientCh := testutils.NewClient(t, nil) // Create a connection that will be shared. require.NoError(t, testutils.Ping(clientCh, serverCh), "Ping from client to server failed") var wg sync.WaitGroup for i := 0; i < 100; i++ { wg.Add(1) go func() { time.Sleep(time.Duration(rand.Intn(1000)) * time.Microsecond) err := testutils.CallEcho(clientCh, serverCh, nil) if err != nil && atomic.LoadUint32(&closed) == 0 { t.Errorf("Call failed: %v", err) } wg.Done() }() } // Wait for all the goroutines to end wg.Wait() clientCh.Close() goroutines.VerifyNoLeaks(t, nil) }