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.

224 lines
4.9 KiB

8 years ago
8 years ago
10 years ago
8 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. package blockchain
  2. import (
  3. "fmt"
  4. "testing"
  5. "time"
  6. "github.com/stretchr/testify/assert"
  7. "github.com/stretchr/testify/require"
  8. cmn "github.com/tendermint/tendermint/libs/common"
  9. "github.com/tendermint/tendermint/libs/log"
  10. "github.com/tendermint/tendermint/p2p"
  11. "github.com/tendermint/tendermint/types"
  12. )
  13. func init() {
  14. peerTimeout = 2 * time.Second
  15. }
  16. type testPeer struct {
  17. id p2p.ID
  18. height int64
  19. inputChan chan inputData //make sure each peer's data is sequential
  20. }
  21. type inputData struct {
  22. t *testing.T
  23. pool *BlockPool
  24. request BlockRequest
  25. }
  26. func (p testPeer) runInputRoutine() {
  27. go func() {
  28. for input := range p.inputChan {
  29. p.simulateInput(input)
  30. }
  31. }()
  32. }
  33. // Request desired, pretend like we got the block immediately.
  34. func (p testPeer) simulateInput(input inputData) {
  35. block := &types.Block{Header: types.Header{Height: input.request.Height}}
  36. input.pool.AddBlock(input.request.PeerID, block, 123)
  37. // TODO: uncommenting this creates a race which is detected by: https://github.com/golang/go/blob/2bd767b1022dd3254bcec469f0ee164024726486/src/testing/testing.go#L854-L856
  38. // see: https://github.com/tendermint/tendermint/issues/3390#issue-418379890
  39. // input.t.Logf("Added block from peer %v (height: %v)", input.request.PeerID, input.request.Height)
  40. }
  41. type testPeers map[p2p.ID]testPeer
  42. func (ps testPeers) start() {
  43. for _, v := range ps {
  44. v.runInputRoutine()
  45. }
  46. }
  47. func (ps testPeers) stop() {
  48. for _, v := range ps {
  49. close(v.inputChan)
  50. }
  51. }
  52. func makePeers(numPeers int, minHeight, maxHeight int64) testPeers {
  53. peers := make(testPeers, numPeers)
  54. for i := 0; i < numPeers; i++ {
  55. peerID := p2p.ID(cmn.RandStr(12))
  56. height := minHeight + cmn.RandInt63n(maxHeight-minHeight)
  57. peers[peerID] = testPeer{peerID, height, make(chan inputData, 10)}
  58. }
  59. return peers
  60. }
  61. func TestBlockPoolBasic(t *testing.T) {
  62. start := int64(42)
  63. peers := makePeers(10, start+1, 1000)
  64. errorsCh := make(chan peerError, 1000)
  65. requestsCh := make(chan BlockRequest, 1000)
  66. pool := NewBlockPool(start, requestsCh, errorsCh)
  67. pool.SetLogger(log.TestingLogger())
  68. err := pool.Start()
  69. if err != nil {
  70. t.Error(err)
  71. }
  72. defer pool.Stop()
  73. peers.start()
  74. defer peers.stop()
  75. // Introduce each peer.
  76. go func() {
  77. for _, peer := range peers {
  78. pool.SetPeerHeight(peer.id, peer.height)
  79. }
  80. }()
  81. // Start a goroutine to pull blocks
  82. go func() {
  83. for {
  84. if !pool.IsRunning() {
  85. return
  86. }
  87. first, second := pool.PeekTwoBlocks()
  88. if first != nil && second != nil {
  89. pool.PopRequest()
  90. } else {
  91. time.Sleep(1 * time.Second)
  92. }
  93. }
  94. }()
  95. // Pull from channels
  96. for {
  97. select {
  98. case err := <-errorsCh:
  99. t.Error(err)
  100. case request := <-requestsCh:
  101. t.Logf("Pulled new BlockRequest %v", request)
  102. if request.Height == 300 {
  103. return // Done!
  104. }
  105. peers[request.PeerID].inputChan <- inputData{t, pool, request}
  106. }
  107. }
  108. }
  109. func TestBlockPoolTimeout(t *testing.T) {
  110. start := int64(42)
  111. peers := makePeers(10, start+1, 1000)
  112. errorsCh := make(chan peerError, 1000)
  113. requestsCh := make(chan BlockRequest, 1000)
  114. pool := NewBlockPool(start, requestsCh, errorsCh)
  115. pool.SetLogger(log.TestingLogger())
  116. err := pool.Start()
  117. if err != nil {
  118. t.Error(err)
  119. }
  120. defer pool.Stop()
  121. for _, peer := range peers {
  122. t.Logf("Peer %v", peer.id)
  123. }
  124. // Introduce each peer.
  125. go func() {
  126. for _, peer := range peers {
  127. pool.SetPeerHeight(peer.id, peer.height)
  128. }
  129. }()
  130. // Start a goroutine to pull blocks
  131. go func() {
  132. for {
  133. if !pool.IsRunning() {
  134. return
  135. }
  136. first, second := pool.PeekTwoBlocks()
  137. if first != nil && second != nil {
  138. pool.PopRequest()
  139. } else {
  140. time.Sleep(1 * time.Second)
  141. }
  142. }
  143. }()
  144. // Pull from channels
  145. counter := 0
  146. timedOut := map[p2p.ID]struct{}{}
  147. for {
  148. select {
  149. case err := <-errorsCh:
  150. t.Log(err)
  151. // consider error to be always timeout here
  152. if _, ok := timedOut[err.peerID]; !ok {
  153. counter++
  154. if counter == len(peers) {
  155. return // Done!
  156. }
  157. }
  158. case request := <-requestsCh:
  159. t.Logf("Pulled new BlockRequest %+v", request)
  160. }
  161. }
  162. }
  163. func TestBlockPoolRemovePeer(t *testing.T) {
  164. peers := make(testPeers, 10)
  165. for i := 0; i < 10; i++ {
  166. peerID := p2p.ID(fmt.Sprintf("%d", i+1))
  167. height := int64(i + 1)
  168. peers[peerID] = testPeer{peerID, height, make(chan inputData)}
  169. }
  170. requestsCh := make(chan BlockRequest)
  171. errorsCh := make(chan peerError)
  172. pool := NewBlockPool(1, requestsCh, errorsCh)
  173. pool.SetLogger(log.TestingLogger())
  174. err := pool.Start()
  175. require.NoError(t, err)
  176. defer pool.Stop()
  177. // add peers
  178. for peerID, peer := range peers {
  179. pool.SetPeerHeight(peerID, peer.height)
  180. }
  181. assert.EqualValues(t, 10, pool.MaxPeerHeight())
  182. // remove not-existing peer
  183. assert.NotPanics(t, func() { pool.RemovePeer(p2p.ID("Superman")) })
  184. // remove peer with biggest height
  185. pool.RemovePeer(p2p.ID("10"))
  186. assert.EqualValues(t, 9, pool.MaxPeerHeight())
  187. // remove all peers
  188. for peerID := range peers {
  189. pool.RemovePeer(peerID)
  190. }
  191. assert.EqualValues(t, 0, pool.MaxPeerHeight())
  192. }