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