Files
tendermint/rpc/jsonrpc/client/integration_test.go
M. J. Fromberger ce61abc038 rpc: remove the placeholder RunState type. (#7749)
* rpc/client: remove the placeholder RunState type.

I added the RunState type in #6971 to disconnect clients from the service
plumbing, which they do not need. Now that we have more complete context
plumbing, the lifecycle of a client no longer depends on this type: It serves
as a carrier for a logger, and a Boolean flag for "running" status, neither of
which is used outside of tests.

Logging in particular is defaulted to a no-op logger in all production use.
Arguably we could just remove the logging calls, since they are never invoked
except in tests. To defer the question of whether we should do that or make the
logging go somewhere more productive, I've preserved the existing use here.

Remove use of the IsRunning method that was provided by the RunState, and use
the Start method and context to govern client lifecycle.

Remove the one test that exercised "unstarted" clients. I would like to remove
that method entirely, but that will require updating the constructors for all
the client types to plumb a context and possibly other options. I have deferred
that for now.
2022-02-02 12:02:04 -08:00

62 lines
1.6 KiB
Go

//go:build release
// +build release
// The code in here is comprehensive as an integration
// test and is long, hence is only run before releases.
package client
import (
"bytes"
"context"
"errors"
"net"
"regexp"
"testing"
"time"
"github.com/stretchr/testify/require"
)
func TestWSClientReconnectWithJitter(t *testing.T) {
const numClients = 8
const maxReconnectAttempts = 3
const maxSleepTime = time.Duration(((1<<maxReconnectAttempts)-1)+maxReconnectAttempts) * time.Second
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
failDialer := func(net, addr string) (net.Conn, error) {
return nil, errors.New("not connected")
}
clientMap := make(map[int]*WSClient)
buf := new(bytes.Buffer)
for i := 0; i < numClients; i++ {
c, err := NewWS("tcp://foo", "/websocket")
require.NoError(t, err)
c.Dialer = failDialer
c.maxReconnectAttempts = maxReconnectAttempts
c.Start(ctx)
// Not invoking defer c.Stop() because
// after all the reconnect attempts have been
// exhausted, c.Stop is implicitly invoked.
clientMap[i] = c
// Trigger the reconnect routine that performs exponential backoff.
go c.reconnect(ctx)
}
// Next we have to examine the logs to ensure that no single time was repeated
backoffDurRegexp := regexp.MustCompile(`backoff_duration=(.+)`)
matches := backoffDurRegexp.FindAll(buf.Bytes(), -1)
seenMap := make(map[string]int)
for i, match := range matches {
if origIndex, seen := seenMap[string(match)]; seen {
t.Errorf("match #%d (%q) was seen originally at log entry #%d", i, match, origIndex)
} else {
seenMap[string(match)] = i
}
}
}