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.

527 lines
14 KiB

  1. package conn
  2. import (
  3. "bytes"
  4. "net"
  5. "testing"
  6. "time"
  7. "github.com/fortytw2/leaktest"
  8. "github.com/stretchr/testify/assert"
  9. "github.com/stretchr/testify/require"
  10. amino "github.com/tendermint/go-amino"
  11. "github.com/tendermint/tendermint/libs/log"
  12. )
  13. const maxPingPongPacketSize = 1024 // bytes
  14. func createTestMConnection(conn net.Conn) *MConnection {
  15. onReceive := func(chID byte, msgBytes []byte) {
  16. }
  17. onError := func(r interface{}) {
  18. }
  19. c := createMConnectionWithCallbacks(conn, onReceive, onError)
  20. c.SetLogger(log.TestingLogger())
  21. return c
  22. }
  23. func createMConnectionWithCallbacks(conn net.Conn, onReceive func(chID byte, msgBytes []byte), onError func(r interface{})) *MConnection {
  24. cfg := DefaultMConnConfig()
  25. cfg.PingInterval = 90 * time.Millisecond
  26. cfg.PongTimeout = 45 * time.Millisecond
  27. chDescs := []*ChannelDescriptor{&ChannelDescriptor{ID: 0x01, Priority: 1, SendQueueCapacity: 1}}
  28. c := NewMConnectionWithConfig(conn, chDescs, onReceive, onError, cfg)
  29. c.SetLogger(log.TestingLogger())
  30. return c
  31. }
  32. func TestMConnectionSendFlushStop(t *testing.T) {
  33. server, client := NetPipe()
  34. defer server.Close() // nolint: errcheck
  35. defer client.Close() // nolint: errcheck
  36. clientConn := createTestMConnection(client)
  37. err := clientConn.Start()
  38. require.Nil(t, err)
  39. defer clientConn.Stop()
  40. msg := []byte("abc")
  41. assert.True(t, clientConn.Send(0x01, msg))
  42. aminoMsgLength := 14
  43. // start the reader in a new routine, so we can flush
  44. errCh := make(chan error)
  45. go func() {
  46. msgB := make([]byte, aminoMsgLength)
  47. _, err := server.Read(msgB)
  48. if err != nil {
  49. t.Fatal(err)
  50. }
  51. errCh <- err
  52. }()
  53. // stop the conn - it should flush all conns
  54. clientConn.FlushStop()
  55. timer := time.NewTimer(3 * time.Second)
  56. select {
  57. case <-errCh:
  58. case <-timer.C:
  59. t.Error("timed out waiting for msgs to be read")
  60. }
  61. }
  62. func TestMConnectionSend(t *testing.T) {
  63. server, client := NetPipe()
  64. defer server.Close() // nolint: errcheck
  65. defer client.Close() // nolint: errcheck
  66. mconn := createTestMConnection(client)
  67. err := mconn.Start()
  68. require.Nil(t, err)
  69. defer mconn.Stop()
  70. msg := []byte("Ant-Man")
  71. assert.True(t, mconn.Send(0x01, msg))
  72. // Note: subsequent Send/TrySend calls could pass because we are reading from
  73. // the send queue in a separate goroutine.
  74. _, err = server.Read(make([]byte, len(msg)))
  75. if err != nil {
  76. t.Error(err)
  77. }
  78. assert.True(t, mconn.CanSend(0x01))
  79. msg = []byte("Spider-Man")
  80. assert.True(t, mconn.TrySend(0x01, msg))
  81. _, err = server.Read(make([]byte, len(msg)))
  82. if err != nil {
  83. t.Error(err)
  84. }
  85. assert.False(t, mconn.CanSend(0x05), "CanSend should return false because channel is unknown")
  86. assert.False(t, mconn.Send(0x05, []byte("Absorbing Man")), "Send should return false because channel is unknown")
  87. }
  88. func TestMConnectionReceive(t *testing.T) {
  89. server, client := NetPipe()
  90. defer server.Close() // nolint: errcheck
  91. defer client.Close() // nolint: errcheck
  92. receivedCh := make(chan []byte)
  93. errorsCh := make(chan interface{})
  94. onReceive := func(chID byte, msgBytes []byte) {
  95. receivedCh <- msgBytes
  96. }
  97. onError := func(r interface{}) {
  98. errorsCh <- r
  99. }
  100. mconn1 := createMConnectionWithCallbacks(client, onReceive, onError)
  101. err := mconn1.Start()
  102. require.Nil(t, err)
  103. defer mconn1.Stop()
  104. mconn2 := createTestMConnection(server)
  105. err = mconn2.Start()
  106. require.Nil(t, err)
  107. defer mconn2.Stop()
  108. msg := []byte("Cyclops")
  109. assert.True(t, mconn2.Send(0x01, msg))
  110. select {
  111. case receivedBytes := <-receivedCh:
  112. assert.Equal(t, []byte(msg), receivedBytes)
  113. case err := <-errorsCh:
  114. t.Fatalf("Expected %s, got %+v", msg, err)
  115. case <-time.After(500 * time.Millisecond):
  116. t.Fatalf("Did not receive %s message in 500ms", msg)
  117. }
  118. }
  119. func TestMConnectionStatus(t *testing.T) {
  120. server, client := NetPipe()
  121. defer server.Close() // nolint: errcheck
  122. defer client.Close() // nolint: errcheck
  123. mconn := createTestMConnection(client)
  124. err := mconn.Start()
  125. require.Nil(t, err)
  126. defer mconn.Stop()
  127. status := mconn.Status()
  128. assert.NotNil(t, status)
  129. assert.Zero(t, status.Channels[0].SendQueueSize)
  130. }
  131. func TestMConnectionPongTimeoutResultsInError(t *testing.T) {
  132. server, client := net.Pipe()
  133. defer server.Close()
  134. defer client.Close()
  135. receivedCh := make(chan []byte)
  136. errorsCh := make(chan interface{})
  137. onReceive := func(chID byte, msgBytes []byte) {
  138. receivedCh <- msgBytes
  139. }
  140. onError := func(r interface{}) {
  141. errorsCh <- r
  142. }
  143. mconn := createMConnectionWithCallbacks(client, onReceive, onError)
  144. err := mconn.Start()
  145. require.Nil(t, err)
  146. defer mconn.Stop()
  147. serverGotPing := make(chan struct{})
  148. go func() {
  149. // read ping
  150. var pkt PacketPing
  151. _, err = cdc.UnmarshalBinaryLengthPrefixedReader(server, &pkt, maxPingPongPacketSize)
  152. assert.Nil(t, err)
  153. serverGotPing <- struct{}{}
  154. }()
  155. <-serverGotPing
  156. pongTimerExpired := mconn.config.PongTimeout + 20*time.Millisecond
  157. select {
  158. case msgBytes := <-receivedCh:
  159. t.Fatalf("Expected error, but got %v", msgBytes)
  160. case err := <-errorsCh:
  161. assert.NotNil(t, err)
  162. case <-time.After(pongTimerExpired):
  163. t.Fatalf("Expected to receive error after %v", pongTimerExpired)
  164. }
  165. }
  166. func TestMConnectionMultiplePongsInTheBeginning(t *testing.T) {
  167. server, client := net.Pipe()
  168. defer server.Close()
  169. defer client.Close()
  170. receivedCh := make(chan []byte)
  171. errorsCh := make(chan interface{})
  172. onReceive := func(chID byte, msgBytes []byte) {
  173. receivedCh <- msgBytes
  174. }
  175. onError := func(r interface{}) {
  176. errorsCh <- r
  177. }
  178. mconn := createMConnectionWithCallbacks(client, onReceive, onError)
  179. err := mconn.Start()
  180. require.Nil(t, err)
  181. defer mconn.Stop()
  182. // sending 3 pongs in a row (abuse)
  183. _, err = server.Write(cdc.MustMarshalBinaryLengthPrefixed(PacketPong{}))
  184. require.Nil(t, err)
  185. _, err = server.Write(cdc.MustMarshalBinaryLengthPrefixed(PacketPong{}))
  186. require.Nil(t, err)
  187. _, err = server.Write(cdc.MustMarshalBinaryLengthPrefixed(PacketPong{}))
  188. require.Nil(t, err)
  189. serverGotPing := make(chan struct{})
  190. go func() {
  191. // read ping (one byte)
  192. var packet, err = Packet(nil), error(nil)
  193. _, err = cdc.UnmarshalBinaryLengthPrefixedReader(server, &packet, maxPingPongPacketSize)
  194. require.Nil(t, err)
  195. serverGotPing <- struct{}{}
  196. // respond with pong
  197. _, err = server.Write(cdc.MustMarshalBinaryLengthPrefixed(PacketPong{}))
  198. require.Nil(t, err)
  199. }()
  200. <-serverGotPing
  201. pongTimerExpired := mconn.config.PongTimeout + 20*time.Millisecond
  202. select {
  203. case msgBytes := <-receivedCh:
  204. t.Fatalf("Expected no data, but got %v", msgBytes)
  205. case err := <-errorsCh:
  206. t.Fatalf("Expected no error, but got %v", err)
  207. case <-time.After(pongTimerExpired):
  208. assert.True(t, mconn.IsRunning())
  209. }
  210. }
  211. func TestMConnectionMultiplePings(t *testing.T) {
  212. server, client := net.Pipe()
  213. defer server.Close()
  214. defer client.Close()
  215. receivedCh := make(chan []byte)
  216. errorsCh := make(chan interface{})
  217. onReceive := func(chID byte, msgBytes []byte) {
  218. receivedCh <- msgBytes
  219. }
  220. onError := func(r interface{}) {
  221. errorsCh <- r
  222. }
  223. mconn := createMConnectionWithCallbacks(client, onReceive, onError)
  224. err := mconn.Start()
  225. require.Nil(t, err)
  226. defer mconn.Stop()
  227. // sending 3 pings in a row (abuse)
  228. // see https://github.com/tendermint/tendermint/issues/1190
  229. _, err = server.Write(cdc.MustMarshalBinaryLengthPrefixed(PacketPing{}))
  230. require.Nil(t, err)
  231. var pkt PacketPong
  232. _, err = cdc.UnmarshalBinaryLengthPrefixedReader(server, &pkt, maxPingPongPacketSize)
  233. require.Nil(t, err)
  234. _, err = server.Write(cdc.MustMarshalBinaryLengthPrefixed(PacketPing{}))
  235. require.Nil(t, err)
  236. _, err = cdc.UnmarshalBinaryLengthPrefixedReader(server, &pkt, maxPingPongPacketSize)
  237. require.Nil(t, err)
  238. _, err = server.Write(cdc.MustMarshalBinaryLengthPrefixed(PacketPing{}))
  239. require.Nil(t, err)
  240. _, err = cdc.UnmarshalBinaryLengthPrefixedReader(server, &pkt, maxPingPongPacketSize)
  241. require.Nil(t, err)
  242. assert.True(t, mconn.IsRunning())
  243. }
  244. func TestMConnectionPingPongs(t *testing.T) {
  245. // check that we are not leaking any go-routines
  246. defer leaktest.CheckTimeout(t, 10*time.Second)()
  247. server, client := net.Pipe()
  248. defer server.Close()
  249. defer client.Close()
  250. receivedCh := make(chan []byte)
  251. errorsCh := make(chan interface{})
  252. onReceive := func(chID byte, msgBytes []byte) {
  253. receivedCh <- msgBytes
  254. }
  255. onError := func(r interface{}) {
  256. errorsCh <- r
  257. }
  258. mconn := createMConnectionWithCallbacks(client, onReceive, onError)
  259. err := mconn.Start()
  260. require.Nil(t, err)
  261. defer mconn.Stop()
  262. serverGotPing := make(chan struct{})
  263. go func() {
  264. // read ping
  265. var pkt PacketPing
  266. _, err = cdc.UnmarshalBinaryLengthPrefixedReader(server, &pkt, maxPingPongPacketSize)
  267. require.Nil(t, err)
  268. serverGotPing <- struct{}{}
  269. // respond with pong
  270. _, err = server.Write(cdc.MustMarshalBinaryLengthPrefixed(PacketPong{}))
  271. require.Nil(t, err)
  272. time.Sleep(mconn.config.PingInterval)
  273. // read ping
  274. _, err = cdc.UnmarshalBinaryLengthPrefixedReader(server, &pkt, maxPingPongPacketSize)
  275. require.Nil(t, err)
  276. // respond with pong
  277. _, err = server.Write(cdc.MustMarshalBinaryLengthPrefixed(PacketPong{}))
  278. require.Nil(t, err)
  279. }()
  280. <-serverGotPing
  281. pongTimerExpired := (mconn.config.PongTimeout + 20*time.Millisecond) * 2
  282. select {
  283. case msgBytes := <-receivedCh:
  284. t.Fatalf("Expected no data, but got %v", msgBytes)
  285. case err := <-errorsCh:
  286. t.Fatalf("Expected no error, but got %v", err)
  287. case <-time.After(2 * pongTimerExpired):
  288. assert.True(t, mconn.IsRunning())
  289. }
  290. }
  291. func TestMConnectionStopsAndReturnsError(t *testing.T) {
  292. server, client := NetPipe()
  293. defer server.Close() // nolint: errcheck
  294. defer client.Close() // nolint: errcheck
  295. receivedCh := make(chan []byte)
  296. errorsCh := make(chan interface{})
  297. onReceive := func(chID byte, msgBytes []byte) {
  298. receivedCh <- msgBytes
  299. }
  300. onError := func(r interface{}) {
  301. errorsCh <- r
  302. }
  303. mconn := createMConnectionWithCallbacks(client, onReceive, onError)
  304. err := mconn.Start()
  305. require.Nil(t, err)
  306. defer mconn.Stop()
  307. if err := client.Close(); err != nil {
  308. t.Error(err)
  309. }
  310. select {
  311. case receivedBytes := <-receivedCh:
  312. t.Fatalf("Expected error, got %v", receivedBytes)
  313. case err := <-errorsCh:
  314. assert.NotNil(t, err)
  315. assert.False(t, mconn.IsRunning())
  316. case <-time.After(500 * time.Millisecond):
  317. t.Fatal("Did not receive error in 500ms")
  318. }
  319. }
  320. func newClientAndServerConnsForReadErrors(t *testing.T, chOnErr chan struct{}) (*MConnection, *MConnection) {
  321. server, client := NetPipe()
  322. onReceive := func(chID byte, msgBytes []byte) {}
  323. onError := func(r interface{}) {}
  324. // create client conn with two channels
  325. chDescs := []*ChannelDescriptor{
  326. {ID: 0x01, Priority: 1, SendQueueCapacity: 1},
  327. {ID: 0x02, Priority: 1, SendQueueCapacity: 1},
  328. }
  329. mconnClient := NewMConnection(client, chDescs, onReceive, onError)
  330. mconnClient.SetLogger(log.TestingLogger().With("module", "client"))
  331. err := mconnClient.Start()
  332. require.Nil(t, err)
  333. // create server conn with 1 channel
  334. // it fires on chOnErr when there's an error
  335. serverLogger := log.TestingLogger().With("module", "server")
  336. onError = func(r interface{}) {
  337. chOnErr <- struct{}{}
  338. }
  339. mconnServer := createMConnectionWithCallbacks(server, onReceive, onError)
  340. mconnServer.SetLogger(serverLogger)
  341. err = mconnServer.Start()
  342. require.Nil(t, err)
  343. return mconnClient, mconnServer
  344. }
  345. func expectSend(ch chan struct{}) bool {
  346. after := time.After(time.Second * 5)
  347. select {
  348. case <-ch:
  349. return true
  350. case <-after:
  351. return false
  352. }
  353. }
  354. func TestMConnectionReadErrorBadEncoding(t *testing.T) {
  355. chOnErr := make(chan struct{})
  356. mconnClient, mconnServer := newClientAndServerConnsForReadErrors(t, chOnErr)
  357. defer mconnClient.Stop()
  358. defer mconnServer.Stop()
  359. client := mconnClient.conn
  360. // send badly encoded msgPacket
  361. bz := cdc.MustMarshalBinaryLengthPrefixed(PacketMsg{})
  362. bz[4] += 0x01 // Invalid prefix bytes.
  363. // Write it.
  364. _, err := client.Write(bz)
  365. assert.Nil(t, err)
  366. assert.True(t, expectSend(chOnErr), "badly encoded msgPacket")
  367. }
  368. func TestMConnectionReadErrorUnknownChannel(t *testing.T) {
  369. chOnErr := make(chan struct{})
  370. mconnClient, mconnServer := newClientAndServerConnsForReadErrors(t, chOnErr)
  371. defer mconnClient.Stop()
  372. defer mconnServer.Stop()
  373. msg := []byte("Ant-Man")
  374. // fail to send msg on channel unknown by client
  375. assert.False(t, mconnClient.Send(0x03, msg))
  376. // send msg on channel unknown by the server.
  377. // should cause an error
  378. assert.True(t, mconnClient.Send(0x02, msg))
  379. assert.True(t, expectSend(chOnErr), "unknown channel")
  380. }
  381. func TestMConnectionReadErrorLongMessage(t *testing.T) {
  382. chOnErr := make(chan struct{})
  383. chOnRcv := make(chan struct{})
  384. mconnClient, mconnServer := newClientAndServerConnsForReadErrors(t, chOnErr)
  385. defer mconnClient.Stop()
  386. defer mconnServer.Stop()
  387. mconnServer.onReceive = func(chID byte, msgBytes []byte) {
  388. chOnRcv <- struct{}{}
  389. }
  390. client := mconnClient.conn
  391. // send msg thats just right
  392. var err error
  393. var buf = new(bytes.Buffer)
  394. var packet = PacketMsg{
  395. ChannelID: 0x01,
  396. EOF: 1,
  397. Bytes: make([]byte, mconnClient.config.MaxPacketMsgPayloadSize),
  398. }
  399. _, err = cdc.MarshalBinaryLengthPrefixedWriter(buf, packet)
  400. assert.Nil(t, err)
  401. _, err = client.Write(buf.Bytes())
  402. assert.Nil(t, err)
  403. assert.True(t, expectSend(chOnRcv), "msg just right")
  404. // send msg thats too long
  405. buf = new(bytes.Buffer)
  406. packet = PacketMsg{
  407. ChannelID: 0x01,
  408. EOF: 1,
  409. Bytes: make([]byte, mconnClient.config.MaxPacketMsgPayloadSize+100),
  410. }
  411. _, err = cdc.MarshalBinaryLengthPrefixedWriter(buf, packet)
  412. assert.Nil(t, err)
  413. _, err = client.Write(buf.Bytes())
  414. assert.NotNil(t, err)
  415. assert.True(t, expectSend(chOnErr), "msg too long")
  416. }
  417. func TestMConnectionReadErrorUnknownMsgType(t *testing.T) {
  418. chOnErr := make(chan struct{})
  419. mconnClient, mconnServer := newClientAndServerConnsForReadErrors(t, chOnErr)
  420. defer mconnClient.Stop()
  421. defer mconnServer.Stop()
  422. // send msg with unknown msg type
  423. err := error(nil)
  424. err = amino.EncodeUvarint(mconnClient.conn, 4)
  425. assert.Nil(t, err)
  426. _, err = mconnClient.conn.Write([]byte{0xFF, 0xFF, 0xFF, 0xFF})
  427. assert.Nil(t, err)
  428. assert.True(t, expectSend(chOnErr), "unknown msg type")
  429. }
  430. func TestMConnectionTrySend(t *testing.T) {
  431. server, client := NetPipe()
  432. defer server.Close()
  433. defer client.Close()
  434. mconn := createTestMConnection(client)
  435. err := mconn.Start()
  436. require.Nil(t, err)
  437. defer mconn.Stop()
  438. msg := []byte("Semicolon-Woman")
  439. resultCh := make(chan string, 2)
  440. assert.True(t, mconn.TrySend(0x01, msg))
  441. server.Read(make([]byte, len(msg)))
  442. assert.True(t, mconn.CanSend(0x01))
  443. assert.True(t, mconn.TrySend(0x01, msg))
  444. assert.False(t, mconn.CanSend(0x01))
  445. go func() {
  446. mconn.TrySend(0x01, msg)
  447. resultCh <- "TrySend"
  448. }()
  449. assert.False(t, mconn.CanSend(0x01))
  450. assert.False(t, mconn.TrySend(0x01, msg))
  451. assert.Equal(t, "TrySend", <-resultCh)
  452. }