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.

221 lines
5.1 KiB

  1. package p2p
  2. import (
  3. "context"
  4. "errors"
  5. "testing"
  6. "time"
  7. "github.com/fortytw2/leaktest"
  8. "github.com/stretchr/testify/require"
  9. )
  10. type channelInternal struct {
  11. In chan Envelope
  12. Out chan Envelope
  13. Error chan PeerError
  14. }
  15. func testChannel(size int) (*channelInternal, *Channel) {
  16. in := &channelInternal{
  17. In: make(chan Envelope, size),
  18. Out: make(chan Envelope, size),
  19. Error: make(chan PeerError, size),
  20. }
  21. ch := &Channel{
  22. inCh: in.In,
  23. outCh: in.Out,
  24. errCh: in.Error,
  25. }
  26. return in, ch
  27. }
  28. func TestChannel(t *testing.T) {
  29. t.Cleanup(leaktest.Check(t))
  30. bctx, bcancel := context.WithCancel(context.Background())
  31. defer bcancel()
  32. testCases := []struct {
  33. Name string
  34. Case func(context.Context, *testing.T)
  35. }{
  36. {
  37. Name: "Send",
  38. Case: func(ctx context.Context, t *testing.T) {
  39. ins, ch := testChannel(1)
  40. require.NoError(t, ch.Send(ctx, Envelope{From: "kip", To: "merlin"}))
  41. res, ok := <-ins.Out
  42. require.True(t, ok)
  43. require.EqualValues(t, "kip", res.From)
  44. require.EqualValues(t, "merlin", res.To)
  45. },
  46. },
  47. {
  48. Name: "SendError",
  49. Case: func(ctx context.Context, t *testing.T) {
  50. ins, ch := testChannel(1)
  51. require.NoError(t, ch.SendError(ctx, PeerError{NodeID: "kip", Err: errors.New("merlin")}))
  52. res, ok := <-ins.Error
  53. require.True(t, ok)
  54. require.EqualValues(t, "kip", res.NodeID)
  55. require.EqualValues(t, "merlin", res.Err.Error())
  56. },
  57. },
  58. {
  59. Name: "SendWithCanceledContext",
  60. Case: func(ctx context.Context, t *testing.T) {
  61. _, ch := testChannel(0)
  62. cctx, ccancel := context.WithCancel(ctx)
  63. ccancel()
  64. require.Error(t, ch.Send(cctx, Envelope{From: "kip", To: "merlin"}))
  65. },
  66. },
  67. {
  68. Name: "SendErrorWithCanceledContext",
  69. Case: func(ctx context.Context, t *testing.T) {
  70. _, ch := testChannel(0)
  71. cctx, ccancel := context.WithCancel(ctx)
  72. ccancel()
  73. require.Error(t, ch.SendError(cctx, PeerError{NodeID: "kip", Err: errors.New("merlin")}))
  74. },
  75. },
  76. {
  77. Name: "ReceiveEmptyIteratorBlocks",
  78. Case: func(ctx context.Context, t *testing.T) {
  79. _, ch := testChannel(1)
  80. iter := ch.Receive(ctx)
  81. require.NotNil(t, iter)
  82. out := make(chan bool)
  83. go func() {
  84. defer close(out)
  85. select {
  86. case <-ctx.Done():
  87. case out <- iter.Next(ctx):
  88. }
  89. }()
  90. select {
  91. case <-time.After(10 * time.Millisecond):
  92. case <-out:
  93. require.Fail(t, "iterator should not advance")
  94. }
  95. require.Nil(t, iter.Envelope())
  96. },
  97. },
  98. {
  99. Name: "ReceiveWithData",
  100. Case: func(ctx context.Context, t *testing.T) {
  101. ins, ch := testChannel(1)
  102. ins.In <- Envelope{From: "kip", To: "merlin"}
  103. iter := ch.Receive(ctx)
  104. require.NotNil(t, iter)
  105. require.True(t, iter.Next(ctx))
  106. res := iter.Envelope()
  107. require.EqualValues(t, "kip", res.From)
  108. require.EqualValues(t, "merlin", res.To)
  109. },
  110. },
  111. {
  112. Name: "ReceiveWithCanceledContext",
  113. Case: func(ctx context.Context, t *testing.T) {
  114. _, ch := testChannel(0)
  115. cctx, ccancel := context.WithCancel(ctx)
  116. ccancel()
  117. iter := ch.Receive(cctx)
  118. require.NotNil(t, iter)
  119. require.False(t, iter.Next(cctx))
  120. require.Nil(t, iter.Envelope())
  121. },
  122. },
  123. {
  124. Name: "IteratorWithCanceledContext",
  125. Case: func(ctx context.Context, t *testing.T) {
  126. _, ch := testChannel(0)
  127. iter := ch.Receive(ctx)
  128. require.NotNil(t, iter)
  129. cctx, ccancel := context.WithCancel(ctx)
  130. ccancel()
  131. require.False(t, iter.Next(cctx))
  132. require.Nil(t, iter.Envelope())
  133. },
  134. },
  135. {
  136. Name: "IteratorCanceledAfterFirstUseBecomesNil",
  137. Case: func(ctx context.Context, t *testing.T) {
  138. ins, ch := testChannel(1)
  139. ins.In <- Envelope{From: "kip", To: "merlin"}
  140. iter := ch.Receive(ctx)
  141. require.NotNil(t, iter)
  142. require.True(t, iter.Next(ctx))
  143. res := iter.Envelope()
  144. require.EqualValues(t, "kip", res.From)
  145. require.EqualValues(t, "merlin", res.To)
  146. cctx, ccancel := context.WithCancel(ctx)
  147. ccancel()
  148. require.False(t, iter.Next(cctx))
  149. require.Nil(t, iter.Envelope())
  150. },
  151. },
  152. {
  153. Name: "IteratorMultipleNextCalls",
  154. Case: func(ctx context.Context, t *testing.T) {
  155. ins, ch := testChannel(1)
  156. ins.In <- Envelope{From: "kip", To: "merlin"}
  157. iter := ch.Receive(ctx)
  158. require.NotNil(t, iter)
  159. require.True(t, iter.Next(ctx))
  160. res := iter.Envelope()
  161. require.EqualValues(t, "kip", res.From)
  162. require.EqualValues(t, "merlin", res.To)
  163. res1 := iter.Envelope()
  164. require.Equal(t, res, res1)
  165. },
  166. },
  167. {
  168. Name: "IteratorProducesNilObjectBeforeNext",
  169. Case: func(ctx context.Context, t *testing.T) {
  170. ins, ch := testChannel(1)
  171. iter := ch.Receive(ctx)
  172. require.NotNil(t, iter)
  173. require.Nil(t, iter.Envelope())
  174. ins.In <- Envelope{From: "kip", To: "merlin"}
  175. require.NotNil(t, iter)
  176. require.True(t, iter.Next(ctx))
  177. res := iter.Envelope()
  178. require.NotNil(t, res)
  179. require.EqualValues(t, "kip", res.From)
  180. require.EqualValues(t, "merlin", res.To)
  181. },
  182. },
  183. }
  184. for _, tc := range testCases {
  185. t.Run(tc.Name, func(t *testing.T) {
  186. t.Cleanup(leaktest.Check(t))
  187. ctx, cancel := context.WithCancel(bctx)
  188. defer cancel()
  189. tc.Case(ctx, t)
  190. })
  191. }
  192. }