You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

66 lines
1.9 KiB

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