github.com/evdatsion/aphelion-dpos-bft@v0.32.1/rpc/lib/client/integration_test.go (about) 1 // +build release 2 3 // The code in here is comprehensive as an integration 4 // test and is long, hence is only run before releases. 5 6 package rpcclient 7 8 import ( 9 "bytes" 10 "errors" 11 "net" 12 "regexp" 13 "testing" 14 "time" 15 16 "github.com/stretchr/testify/require" 17 "github.com/evdatsion/aphelion-dpos-bft/libs/log" 18 ) 19 20 func TestWSClientReconnectWithJitter(t *testing.T) { 21 n := 8 22 maxReconnectAttempts := 3 23 // Max wait time is ceil(1+0.999) + ceil(2+0.999) + ceil(4+0.999) + ceil(...) = 2 + 3 + 5 = 10s + ... 24 maxSleepTime := time.Second * time.Duration(((1<<uint(maxReconnectAttempts))-1)+maxReconnectAttempts) 25 26 var errNotConnected = errors.New("not connected") 27 clientMap := make(map[int]*WSClient) 28 buf := new(bytes.Buffer) 29 logger := log.NewTMLogger(buf) 30 for i := 0; i < n; i++ { 31 c := NewWSClient("tcp://foo", "/websocket") 32 c.Dialer = func(string, string) (net.Conn, error) { 33 return nil, errNotConnected 34 } 35 c.SetLogger(logger) 36 c.maxReconnectAttempts = maxReconnectAttempts 37 // Not invoking defer c.Stop() because 38 // after all the reconnect attempts have been 39 // exhausted, c.Stop is implicitly invoked. 40 clientMap[i] = c 41 // Trigger the reconnect routine that performs exponential backoff. 42 go c.reconnect() 43 } 44 45 stopCount := 0 46 time.Sleep(maxSleepTime) 47 for key, c := range clientMap { 48 if !c.IsActive() { 49 delete(clientMap, key) 50 stopCount += 1 51 } 52 } 53 require.Equal(t, stopCount, n, "expecting all clients to have been stopped") 54 55 // Next we have to examine the logs to ensure that no single time was repeated 56 backoffDurRegexp := regexp.MustCompile(`backoff_duration=(.+)`) 57 matches := backoffDurRegexp.FindAll(buf.Bytes(), -1) 58 seenMap := make(map[string]int) 59 for i, match := range matches { 60 if origIndex, seen := seenMap[string(match)]; seen { 61 t.Errorf("Match #%d (%q) was seen originally at log entry #%d", i, match, origIndex) 62 } else { 63 seenMap[string(match)] = i 64 } 65 } 66 }