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.

171 lines
4.9 KiB

  1. package p2ptest
  2. import (
  3. "context"
  4. "errors"
  5. "testing"
  6. "time"
  7. "github.com/gogo/protobuf/proto"
  8. "github.com/stretchr/testify/assert"
  9. "github.com/stretchr/testify/require"
  10. "github.com/tendermint/tendermint/internal/p2p"
  11. "github.com/tendermint/tendermint/types"
  12. )
  13. // RequireEmpty requires that the given channel is empty.
  14. func RequireEmpty(ctx context.Context, t *testing.T, channels ...*p2p.Channel) {
  15. t.Helper()
  16. ctx, cancel := context.WithTimeout(ctx, 10*time.Millisecond)
  17. defer cancel()
  18. iter := p2p.MergedChannelIterator(ctx, channels...)
  19. count := 0
  20. for iter.Next(ctx) {
  21. count++
  22. require.Nil(t, iter.Envelope())
  23. }
  24. require.Zero(t, count)
  25. require.Error(t, ctx.Err())
  26. }
  27. // RequireReceive requires that the given envelope is received on the channel.
  28. func RequireReceive(ctx context.Context, t *testing.T, channel *p2p.Channel, expect p2p.Envelope) {
  29. t.Helper()
  30. ctx, cancel := context.WithTimeout(ctx, time.Second)
  31. defer cancel()
  32. iter := channel.Receive(ctx)
  33. count := 0
  34. for iter.Next(ctx) {
  35. count++
  36. envelope := iter.Envelope()
  37. require.Equal(t, expect.From, envelope.From)
  38. require.Equal(t, expect.Message, envelope.Message)
  39. }
  40. if !assert.True(t, count >= 1) {
  41. require.NoError(t, ctx.Err(), "timed out waiting for message %v", expect)
  42. }
  43. }
  44. // RequireReceiveUnordered requires that the given envelopes are all received on
  45. // the channel, ignoring order.
  46. func RequireReceiveUnordered(ctx context.Context, t *testing.T, channel *p2p.Channel, expect []*p2p.Envelope) {
  47. ctx, cancel := context.WithTimeout(ctx, time.Second)
  48. defer cancel()
  49. actual := []*p2p.Envelope{}
  50. iter := channel.Receive(ctx)
  51. for iter.Next(ctx) {
  52. actual = append(actual, iter.Envelope())
  53. if len(actual) == len(expect) {
  54. require.ElementsMatch(t, expect, actual, "len=%d", len(actual))
  55. return
  56. }
  57. }
  58. if errors.Is(ctx.Err(), context.DeadlineExceeded) {
  59. require.ElementsMatch(t, expect, actual)
  60. }
  61. }
  62. // RequireSend requires that the given envelope is sent on the channel.
  63. func RequireSend(ctx context.Context, t *testing.T, channel *p2p.Channel, envelope p2p.Envelope) {
  64. tctx, cancel := context.WithTimeout(ctx, time.Second)
  65. defer cancel()
  66. err := channel.Send(tctx, envelope)
  67. switch {
  68. case errors.Is(err, context.DeadlineExceeded):
  69. require.Fail(t, "timed out sending message to %q", envelope.To)
  70. default:
  71. require.NoError(t, err, "unexpected error")
  72. }
  73. }
  74. // RequireSendReceive requires that a given Protobuf message is sent to the
  75. // given peer, and then that the given response is received back.
  76. func RequireSendReceive(
  77. ctx context.Context,
  78. t *testing.T,
  79. channel *p2p.Channel,
  80. peerID types.NodeID,
  81. send proto.Message,
  82. receive proto.Message,
  83. ) {
  84. RequireSend(ctx, t, channel, p2p.Envelope{To: peerID, Message: send})
  85. RequireReceive(ctx, t, channel, p2p.Envelope{From: peerID, Message: send})
  86. }
  87. // RequireNoUpdates requires that a PeerUpdates subscription is empty.
  88. func RequireNoUpdates(ctx context.Context, t *testing.T, peerUpdates *p2p.PeerUpdates) {
  89. t.Helper()
  90. select {
  91. case update := <-peerUpdates.Updates():
  92. if ctx.Err() == nil {
  93. require.Fail(t, "unexpected peer updates", "got %v", update)
  94. }
  95. case <-ctx.Done():
  96. default:
  97. }
  98. }
  99. // RequireError requires that the given peer error is submitted for a peer.
  100. func RequireError(ctx context.Context, t *testing.T, channel *p2p.Channel, peerError p2p.PeerError) {
  101. tctx, tcancel := context.WithTimeout(ctx, time.Second)
  102. defer tcancel()
  103. err := channel.SendError(tctx, peerError)
  104. switch {
  105. case errors.Is(err, context.DeadlineExceeded):
  106. require.Fail(t, "timed out reporting error", "%v on %v", peerError, channel.ID)
  107. default:
  108. require.NoError(t, err, "unexpected error")
  109. }
  110. }
  111. // RequireUpdate requires that a PeerUpdates subscription yields the given update.
  112. func RequireUpdate(t *testing.T, peerUpdates *p2p.PeerUpdates, expect p2p.PeerUpdate) {
  113. timer := time.NewTimer(time.Second) // not time.After due to goroutine leaks
  114. defer timer.Stop()
  115. select {
  116. case update := <-peerUpdates.Updates():
  117. require.Equal(t, expect.NodeID, update.NodeID, "node id did not match")
  118. require.Equal(t, expect.Status, update.Status, "statuses did not match")
  119. case <-timer.C:
  120. require.Fail(t, "timed out waiting for peer update", "expected %v", expect)
  121. }
  122. }
  123. // RequireUpdates requires that a PeerUpdates subscription yields the given updates
  124. // in the given order.
  125. func RequireUpdates(t *testing.T, peerUpdates *p2p.PeerUpdates, expect []p2p.PeerUpdate) {
  126. timer := time.NewTimer(time.Second) // not time.After due to goroutine leaks
  127. defer timer.Stop()
  128. actual := []p2p.PeerUpdate{}
  129. for {
  130. select {
  131. case update := <-peerUpdates.Updates():
  132. actual = append(actual, update)
  133. if len(actual) == len(expect) {
  134. for idx := range expect {
  135. require.Equal(t, expect[idx].NodeID, actual[idx].NodeID)
  136. require.Equal(t, expect[idx].Status, actual[idx].Status)
  137. }
  138. return
  139. }
  140. case <-timer.C:
  141. require.Equal(t, expect, actual, "did not receive expected peer updates")
  142. return
  143. }
  144. }
  145. }