github.com/koko1123/flow-go-1@v0.29.6/network/test/echoengine_test.go (about) 1 package test 2 3 import ( 4 "context" 5 "fmt" 6 "os" 7 "strings" 8 "sync" 9 "testing" 10 "time" 11 12 "github.com/koko1123/flow-go-1/network/p2p" 13 14 "github.com/ipfs/go-log" 15 "github.com/rs/zerolog" 16 "github.com/stretchr/testify/assert" 17 "github.com/stretchr/testify/require" 18 "github.com/stretchr/testify/suite" 19 20 "github.com/koko1123/flow-go-1/model/flow" 21 "github.com/koko1123/flow-go-1/model/libp2p/message" 22 "github.com/koko1123/flow-go-1/module/irrecoverable" 23 "github.com/koko1123/flow-go-1/network" 24 "github.com/koko1123/flow-go-1/network/channels" 25 "github.com/koko1123/flow-go-1/network/internal/testutils" 26 "github.com/koko1123/flow-go-1/network/mocknetwork" 27 "github.com/koko1123/flow-go-1/utils/unittest" 28 ) 29 30 // EchoEngineTestSuite tests the correctness of the entire pipeline of network -> middleware -> libp2p 31 // protocol stack. It creates two instances of a stubengine, connects them through network, and sends a 32 // single message from one engine to the other one through different scenarios. 33 type EchoEngineTestSuite struct { 34 suite.Suite 35 testutils.ConduitWrapper // used as a wrapper around conduit methods 36 nets []network.Network // used to keep track of the networks 37 mws []network.Middleware // used to keep track of the middlewares 38 ids flow.IdentityList // used to keep track of the identifiers associated with networks 39 cancel context.CancelFunc 40 } 41 42 // Some tests are skipped in short mode to speedup the build. 43 44 // TestStubEngineTestSuite runs all the test methods in this test suit 45 func TestStubEngineTestSuite(t *testing.T) { 46 suite.Run(t, new(EchoEngineTestSuite)) 47 } 48 49 func (suite *EchoEngineTestSuite) SetupTest() { 50 const count = 2 51 logger := zerolog.New(os.Stderr).Level(zerolog.ErrorLevel) 52 log.SetAllLoggers(log.LevelError) 53 54 ctx, cancel := context.WithCancel(context.Background()) 55 suite.cancel = cancel 56 57 signalerCtx := irrecoverable.NewMockSignalerContext(suite.T(), ctx) 58 59 // both nodes should be of the same role to get connected on epidemic dissemination 60 var nodes []p2p.LibP2PNode 61 suite.ids, nodes, suite.mws, suite.nets, _ = testutils.GenerateIDsMiddlewaresNetworks( 62 suite.T(), 63 count, 64 logger, 65 unittest.NetworkCodec(), 66 mocknetwork.NewViolationsConsumer(suite.T()), 67 ) 68 69 testutils.StartNodesAndNetworks(signalerCtx, suite.T(), nodes, suite.nets, 100*time.Millisecond) 70 } 71 72 // TearDownTest closes the networks within a specified timeout 73 func (suite *EchoEngineTestSuite) TearDownTest() { 74 suite.cancel() 75 testutils.StopComponents(suite.T(), suite.nets, 3*time.Second) 76 testutils.StopComponents(suite.T(), suite.mws, 3*time.Second) 77 } 78 79 // TestUnknownChannel evaluates that registering an engine with an unknown channel returns an error. 80 // All channels should be registered as topics in engine.topicMap. 81 func (suite *EchoEngineTestSuite) TestUnknownChannel() { 82 e := NewEchoEngine(suite.T(), suite.nets[0], 1, channels.TestNetworkChannel, false, suite.Unicast) 83 _, err := suite.nets[0].Register("unknown-channel-id", e) 84 require.Error(suite.T(), err) 85 } 86 87 // TestClusterChannel evaluates that registering a cluster channel is done without any error. 88 func (suite *EchoEngineTestSuite) TestClusterChannel() { 89 e := NewEchoEngine(suite.T(), suite.nets[0], 1, channels.TestNetworkChannel, false, suite.Unicast) 90 // creates a cluster channel 91 clusterChannel := channels.SyncCluster(flow.Testnet) 92 // registers engine with cluster channel 93 _, err := suite.nets[0].Register(clusterChannel, e) 94 // registering cluster channel should not cause an error 95 require.NoError(suite.T(), err) 96 } 97 98 // TestDuplicateChannel evaluates that registering an engine with duplicate channel returns an error. 99 func (suite *EchoEngineTestSuite) TestDuplicateChannel() { 100 // creates an echo engine, which registers it on test network channel 101 e := NewEchoEngine(suite.T(), suite.nets[0], 1, channels.TestNetworkChannel, false, suite.Unicast) 102 103 // attempts to register the same engine again on test network channel which 104 // should cause an error 105 _, err := suite.nets[0].Register(channels.TestNetworkChannel, e) 106 require.Error(suite.T(), err) 107 } 108 109 // TestEchoMultiMsgAsync_Publish tests sending multiple messages from sender to receiver 110 // using the Publish method of their Conduit. 111 // It also evaluates the correct reception of an echo message back for each send. 112 // Sender and receiver are not synchronized 113 func (suite *EchoEngineTestSuite) TestEchoMultiMsgAsync_Publish() { 114 // set to true for an echo expectation 115 suite.multiMessageAsync(true, 10, suite.Publish) 116 } 117 118 // TestEchoMultiMsgAsync_Unicast tests sending multiple messages from sender to receiver 119 // using the Unicast method of their Conduit. 120 // It also evaluates the correct reception of an echo message back for each send. 121 // Sender and receiver are not synchronized 122 func (suite *EchoEngineTestSuite) TestEchoMultiMsgAsync_Unicast() { 123 // set to true for an echo expectation 124 suite.multiMessageAsync(true, 10, suite.Unicast) 125 } 126 127 // TestEchoMultiMsgAsync_Multicast tests sending multiple messages from sender to receiver 128 // using the Multicast method of their Conduit. 129 // It also evaluates the correct reception of an echo message back for each send. 130 // Sender and receiver are not synchronized 131 func (suite *EchoEngineTestSuite) TestEchoMultiMsgAsync_Multicast() { 132 // set to true for an echo expectation 133 suite.multiMessageAsync(true, 10, suite.Multicast) 134 } 135 136 // TestDuplicateMessageSequential_Publish evaluates the correctness of network layer on deduplicating 137 // the received messages over Publish method of nodes' Conduits. 138 // Messages are delivered to the receiver in a sequential manner. 139 func (suite *EchoEngineTestSuite) TestDuplicateMessageSequential_Publish() { 140 unittest.SkipUnless(suite.T(), unittest.TEST_LONG_RUNNING, "covered by TestDuplicateMessageParallel_Publish") 141 suite.duplicateMessageSequential(suite.Publish) 142 } 143 144 // TestDuplicateMessageSequential_Unicast evaluates the correctness of network layer on deduplicating 145 // the received messages over Unicast method of nodes' Conduits. 146 // Messages are delivered to the receiver in a sequential manner. 147 func (suite *EchoEngineTestSuite) TestDuplicateMessageSequential_Unicast() { 148 unittest.SkipUnless(suite.T(), unittest.TEST_LONG_RUNNING, "covered by TestDuplicateMessageParallel_Unicast") 149 suite.duplicateMessageSequential(suite.Unicast) 150 } 151 152 // TestDuplicateMessageSequential_Multicast evaluates the correctness of network layer on deduplicating 153 // the received messages over Multicast method of nodes' Conduits. 154 // Messages are delivered to the receiver in a sequential manner. 155 func (suite *EchoEngineTestSuite) TestDuplicateMessageSequential_Multicast() { 156 unittest.SkipUnless(suite.T(), unittest.TEST_LONG_RUNNING, "covered by TestDuplicateMessageParallel_Multicast") 157 suite.duplicateMessageSequential(suite.Multicast) 158 } 159 160 // TestDuplicateMessageParallel_Publish evaluates the correctness of network layer 161 // on deduplicating the received messages via Publish method of nodes' Conduits. 162 // Messages are delivered to the receiver in parallel via the Publish method of Conduits. 163 func (suite *EchoEngineTestSuite) TestDuplicateMessageParallel_Publish() { 164 suite.duplicateMessageParallel(suite.Publish) 165 } 166 167 // TestDuplicateMessageParallel_Unicast evaluates the correctness of network layer 168 // on deduplicating the received messages via Unicast method of nodes' Conduits. 169 // Messages are delivered to the receiver in parallel via the Unicast method of Conduits. 170 func (suite *EchoEngineTestSuite) TestDuplicateMessageParallel_Unicast() { 171 suite.duplicateMessageParallel(suite.Unicast) 172 } 173 174 // TestDuplicateMessageParallel_Multicast evaluates the correctness of network layer 175 // on deduplicating the received messages via Multicast method of nodes' Conduits. 176 // Messages are delivered to the receiver in parallel via the Multicast method of Conduits. 177 func (suite *EchoEngineTestSuite) TestDuplicateMessageParallel_Multicast() { 178 suite.duplicateMessageParallel(suite.Multicast) 179 } 180 181 // TestDuplicateMessageDifferentChan_Publish evaluates the correctness of network layer 182 // on deduplicating the received messages against different engine ids. In specific, the 183 // desire behavior is that the deduplication should happen based on both eventID and channel. 184 // Messages are sent via the Publish methods of the Conduits. 185 func (suite *EchoEngineTestSuite) TestDuplicateMessageDifferentChan_Publish() { 186 suite.duplicateMessageDifferentChan(suite.Publish) 187 } 188 189 // TestDuplicateMessageDifferentChan_Unicast evaluates the correctness of network layer 190 // on deduplicating the received messages against different engine ids. In specific, the 191 // desire behavior is that the deduplication should happen based on both eventID and channel. 192 // Messages are sent via the Unicast methods of the Conduits. 193 func (suite *EchoEngineTestSuite) TestDuplicateMessageDifferentChan_Unicast() { 194 suite.duplicateMessageDifferentChan(suite.Unicast) 195 } 196 197 // TestDuplicateMessageDifferentChan_Multicast evaluates the correctness of network layer 198 // on deduplicating the received messages against different engine ids. In specific, the 199 // desire behavior is that the deduplication should happen based on both eventID and channel. 200 // Messages are sent via the Multicast methods of the Conduits. 201 func (suite *EchoEngineTestSuite) TestDuplicateMessageDifferentChan_Multicast() { 202 suite.duplicateMessageDifferentChan(suite.Multicast) 203 } 204 205 // duplicateMessageSequential is a helper function that sends duplicate messages sequentially 206 // from a receiver to the sender via the injected send wrapper function of conduit. 207 func (suite *EchoEngineTestSuite) duplicateMessageSequential(send testutils.ConduitSendWrapperFunc) { 208 sndID := 0 209 rcvID := 1 210 // registers engines in the network 211 // sender's engine 212 sender := NewEchoEngine(suite.Suite.T(), suite.nets[sndID], 10, channels.TestNetworkChannel, false, send) 213 214 // receiver's engine 215 receiver := NewEchoEngine(suite.Suite.T(), suite.nets[rcvID], 10, channels.TestNetworkChannel, false, send) 216 217 // allow nodes to heartbeat and discover each other if using PubSub 218 testutils.OptionalSleep(send) 219 220 // Sends a message from sender to receiver 221 event := &message.TestMessage{ 222 Text: "hello", 223 } 224 225 // sends the same message 10 times 226 for i := 0; i < 10; i++ { 227 require.NoError(suite.Suite.T(), send(event, sender.con, suite.ids[rcvID].NodeID)) 228 } 229 230 time.Sleep(1 * time.Second) 231 232 // receiver should only see the message once, and the rest should be dropped due to 233 // duplication 234 receiver.RLock() 235 require.Equal(suite.Suite.T(), 1, receiver.seen[event.Text]) 236 require.Len(suite.Suite.T(), receiver.seen, 1) 237 receiver.RUnlock() 238 } 239 240 // duplicateMessageParallel is a helper function that sends duplicate messages concurrent;u 241 // from a receiver to the sender via the injected send wrapper function of conduit. 242 func (suite *EchoEngineTestSuite) duplicateMessageParallel(send testutils.ConduitSendWrapperFunc) { 243 sndID := 0 244 rcvID := 1 245 // registers engines in the network 246 // sender's engine 247 sender := NewEchoEngine(suite.Suite.T(), suite.nets[sndID], 10, channels.TestNetworkChannel, false, send) 248 249 // receiver's engine 250 receiver := NewEchoEngine(suite.Suite.T(), suite.nets[rcvID], 10, channels.TestNetworkChannel, false, send) 251 252 // allow nodes to heartbeat and discover each other 253 testutils.OptionalSleep(send) 254 255 // Sends a message from sender to receiver 256 event := &message.TestMessage{ 257 Text: "hello", 258 } 259 260 // sends the same message 10 times 261 wg := sync.WaitGroup{} 262 for i := 0; i < 10; i++ { 263 wg.Add(1) 264 go func() { 265 require.NoError(suite.Suite.T(), send(event, sender.con, suite.ids[rcvID].NodeID)) 266 wg.Done() 267 }() 268 } 269 unittest.RequireReturnsBefore(suite.T(), wg.Wait, 1*time.Second, "could not send message on time") 270 time.Sleep(1 * time.Second) 271 272 // receiver should only see the message once, and the rest should be dropped due to 273 // duplication 274 receiver.RLock() 275 require.Equal(suite.Suite.T(), 1, receiver.seen[event.Text]) 276 require.Len(suite.Suite.T(), receiver.seen, 1) 277 receiver.RUnlock() 278 } 279 280 // duplicateMessageDifferentChan is a helper function that sends the same message from two distinct 281 // sender engines to the two distinct receiver engines via the send wrapper function of Conduits. 282 func (suite *EchoEngineTestSuite) duplicateMessageDifferentChan(send testutils.ConduitSendWrapperFunc) { 283 const ( 284 sndNode = iota 285 rcvNode 286 ) 287 const ( 288 channel1 = channels.TestNetworkChannel 289 channel2 = channels.TestMetricsChannel 290 ) 291 // registers engines in the network 292 // first type 293 // sender'suite engine 294 sender1 := NewEchoEngine(suite.Suite.T(), suite.nets[sndNode], 10, channel1, false, send) 295 296 // receiver's engine 297 receiver1 := NewEchoEngine(suite.Suite.T(), suite.nets[rcvNode], 10, channel1, false, send) 298 299 // second type 300 // registers engines in the network 301 // sender'suite engine 302 sender2 := NewEchoEngine(suite.Suite.T(), suite.nets[sndNode], 10, channel2, false, send) 303 304 // receiver's engine 305 receiver2 := NewEchoEngine(suite.Suite.T(), suite.nets[rcvNode], 10, channel2, false, send) 306 307 // allow nodes to heartbeat and discover each other 308 testutils.OptionalSleep(send) 309 310 // Sends a message from sender to receiver 311 event := &message.TestMessage{ 312 Text: "hello", 313 } 314 315 // sends the same message 10 times on both channels 316 wg := sync.WaitGroup{} 317 for i := 0; i < 10; i++ { 318 wg.Add(1) 319 go func() { 320 defer wg.Done() 321 // sender1 to receiver1 on channel1 322 require.NoError(suite.Suite.T(), send(event, sender1.con, suite.ids[rcvNode].NodeID)) 323 324 // sender2 to receiver2 on channel2 325 require.NoError(suite.Suite.T(), send(event, sender2.con, suite.ids[rcvNode].NodeID)) 326 }() 327 } 328 unittest.RequireReturnsBefore(suite.T(), wg.Wait, 1*time.Second, "could not handle sending unicasts on time") 329 time.Sleep(1 * time.Second) 330 331 // each receiver should only see the message once, and the rest should be dropped due to 332 // duplication 333 receiver1.RLock() 334 receiver2.RLock() 335 require.Equal(suite.Suite.T(), 1, receiver1.seen[event.Text]) 336 require.Equal(suite.Suite.T(), 1, receiver2.seen[event.Text]) 337 338 require.Len(suite.Suite.T(), receiver1.seen, 1) 339 require.Len(suite.Suite.T(), receiver2.seen, 1) 340 receiver1.RUnlock() 341 receiver2.RUnlock() 342 } 343 344 // singleMessage sends a single message from one network instance to the other one 345 // it evaluates the correctness of implementation against correct delivery of the message. 346 // in case echo is true, it also evaluates correct reception of the echo message from the receiver side 347 func (suite *EchoEngineTestSuite) singleMessage(echo bool, send testutils.ConduitSendWrapperFunc) { 348 sndID := 0 349 rcvID := 1 350 351 // registers engines in the network 352 // sender's engine 353 sender := NewEchoEngine(suite.Suite.T(), suite.nets[sndID], 10, channels.TestNetworkChannel, echo, send) 354 355 // receiver's engine 356 receiver := NewEchoEngine(suite.Suite.T(), suite.nets[rcvID], 10, channels.TestNetworkChannel, echo, send) 357 358 // allow nodes to heartbeat and discover each other 359 testutils.OptionalSleep(send) 360 361 // Sends a message from sender to receiver 362 event := &message.TestMessage{ 363 Text: "hello", 364 } 365 require.NoError(suite.Suite.T(), send(event, sender.con, suite.ids[rcvID].NodeID)) 366 367 // evaluates reception of echo request 368 select { 369 case <-receiver.received: 370 // evaluates reception of message at the other side 371 // does not evaluate the content 372 receiver.RLock() 373 require.NotNil(suite.Suite.T(), receiver.originID) 374 require.NotNil(suite.Suite.T(), receiver.event) 375 assert.Equal(suite.Suite.T(), suite.ids[sndID].NodeID, receiver.originID) 376 receiver.RUnlock() 377 378 assertMessageReceived(suite.T(), receiver, event, channels.TestNetworkChannel) 379 380 case <-time.After(10 * time.Second): 381 assert.Fail(suite.Suite.T(), "sender failed to send a message to receiver") 382 } 383 384 // evaluates echo back 385 if echo { 386 // evaluates reception of echo response 387 select { 388 case <-sender.received: 389 // evaluates reception of message at the other side 390 // does not evaluate the content 391 sender.RLock() 392 require.NotNil(suite.Suite.T(), sender.originID) 393 require.NotNil(suite.Suite.T(), sender.event) 394 assert.Equal(suite.Suite.T(), suite.ids[rcvID].NodeID, sender.originID) 395 sender.RUnlock() 396 397 echoEvent := &message.TestMessage{ 398 Text: fmt.Sprintf("%s: %s", receiver.echomsg, event.Text), 399 } 400 assertMessageReceived(suite.T(), sender, echoEvent, channels.TestNetworkChannel) 401 402 case <-time.After(10 * time.Second): 403 assert.Fail(suite.Suite.T(), "receiver failed to send an echo message back to sender") 404 } 405 } 406 } 407 408 // multiMessageSync sends a multiple messages from one network instance to the other one 409 // it evaluates the correctness of implementation against correct delivery of the messages. 410 // sender and receiver are sync over reception, i.e., sender sends one message at a time and 411 // waits for its reception 412 // count defines number of messages 413 func (suite *EchoEngineTestSuite) multiMessageSync(echo bool, count int, send testutils.ConduitSendWrapperFunc) { 414 sndID := 0 415 rcvID := 1 416 // registers engines in the network 417 // sender's engine 418 sender := NewEchoEngine(suite.Suite.T(), suite.nets[sndID], 10, channels.TestNetworkChannel, echo, send) 419 420 // receiver's engine 421 receiver := NewEchoEngine(suite.Suite.T(), suite.nets[rcvID], 10, channels.TestNetworkChannel, echo, send) 422 423 // allow nodes to heartbeat and discover each other 424 testutils.OptionalSleep(send) 425 426 for i := 0; i < count; i++ { 427 // Send the message to receiver 428 event := &message.TestMessage{ 429 Text: fmt.Sprintf("hello%d", i), 430 } 431 // sends a message from sender to receiver using send wrapper function 432 require.NoError(suite.Suite.T(), send(event, sender.con, suite.ids[rcvID].NodeID)) 433 434 select { 435 case <-receiver.received: 436 // evaluates reception of message at the other side 437 // does not evaluate the content 438 receiver.RLock() 439 require.NotNil(suite.Suite.T(), receiver.originID) 440 require.NotNil(suite.Suite.T(), receiver.event) 441 assert.Equal(suite.Suite.T(), suite.ids[sndID].NodeID, receiver.originID) 442 receiver.RUnlock() 443 444 assertMessageReceived(suite.T(), receiver, event, channels.TestNetworkChannel) 445 446 case <-time.After(2 * time.Second): 447 assert.Fail(suite.Suite.T(), "sender failed to send a message to receiver") 448 } 449 450 // evaluates echo back 451 if echo { 452 // evaluates reception of echo response 453 select { 454 case <-sender.received: 455 // evaluates reception of message at the other side 456 // does not evaluate the content 457 sender.RLock() 458 require.NotNil(suite.Suite.T(), sender.originID) 459 require.NotNil(suite.Suite.T(), sender.event) 460 assert.Equal(suite.Suite.T(), suite.ids[rcvID].NodeID, sender.originID) 461 462 receiver.RLock() 463 echoEvent := &message.TestMessage{ 464 Text: fmt.Sprintf("%s: %s", receiver.echomsg, event.Text), 465 } 466 assertMessageReceived(suite.T(), sender, echoEvent, channels.TestNetworkChannel) 467 receiver.RUnlock() 468 sender.RUnlock() 469 470 case <-time.After(10 * time.Second): 471 assert.Fail(suite.Suite.T(), "receiver failed to send an echo message back to sender") 472 } 473 } 474 475 } 476 477 } 478 479 // multiMessageAsync sends a multiple messages from one network instance to the other one 480 // it evaluates the correctness of implementation against correct delivery of the messages. 481 // sender and receiver are async, i.e., sender sends all its message at blast 482 // count defines number of messages 483 func (suite *EchoEngineTestSuite) multiMessageAsync(echo bool, count int, send testutils.ConduitSendWrapperFunc) { 484 sndID := 0 485 rcvID := 1 486 487 // registers engines in the network 488 // sender's engine 489 sender := NewEchoEngine(suite.Suite.T(), suite.nets[sndID], 10, channels.TestNetworkChannel, echo, send) 490 491 // receiver's engine 492 receiver := NewEchoEngine(suite.Suite.T(), suite.nets[rcvID], 10, channels.TestNetworkChannel, echo, send) 493 494 // allow nodes to heartbeat and discover each other 495 testutils.OptionalSleep(send) 496 497 // keeps track of async received messages at receiver side 498 received := make(map[string]struct{}) 499 500 // keeps track of async received echo messages at sender side 501 // echorcv := make(map[string]struct{}) 502 503 for i := 0; i < count; i++ { 504 // Send the message to node 2 using the conduit of node 1 505 event := &message.TestMessage{ 506 Text: fmt.Sprintf("hello%d", i), 507 } 508 require.NoError(suite.Suite.T(), send(event, sender.con, suite.ids[1].NodeID)) 509 } 510 511 for i := 0; i < count; i++ { 512 select { 513 case <-receiver.received: 514 // evaluates reception of message at the other side 515 // does not evaluate the content 516 receiver.RLock() 517 require.NotNil(suite.Suite.T(), receiver.originID) 518 require.NotNil(suite.Suite.T(), receiver.event) 519 assert.Equal(suite.Suite.T(), suite.ids[0].NodeID, receiver.originID) 520 receiver.RUnlock() 521 522 // wrap blocking channel reads with a timeout 523 unittest.AssertReturnsBefore(suite.T(), func() { 524 // evaluates proper reception of event 525 // casts the received event at the receiver side 526 rcvEvent, ok := (<-receiver.event).(*message.TestMessage) 527 // evaluates correctness of casting 528 require.True(suite.T(), ok) 529 530 // evaluates content of received message 531 // the content should not yet received and be unique 532 _, rcv := received[rcvEvent.Text] 533 assert.False(suite.T(), rcv) 534 // marking event as received 535 received[rcvEvent.Text] = struct{}{} 536 537 // evaluates channel that message was received on 538 assert.Equal(suite.T(), channels.TestNetworkChannel, <-receiver.channel) 539 }, 100*time.Millisecond) 540 541 case <-time.After(2 * time.Second): 542 assert.Fail(suite.Suite.T(), "sender failed to send a message to receiver") 543 } 544 } 545 546 for i := 0; i < count; i++ { 547 // evaluates echo back 548 if echo { 549 // evaluates reception of echo response 550 select { 551 case <-sender.received: 552 // evaluates reception of message at the other side 553 // does not evaluate the content 554 sender.RLock() 555 require.NotNil(suite.Suite.T(), sender.originID) 556 require.NotNil(suite.Suite.T(), sender.event) 557 assert.Equal(suite.Suite.T(), suite.ids[rcvID].NodeID, sender.originID) 558 sender.RUnlock() 559 560 // wrap blocking channel reads with a timeout 561 unittest.AssertReturnsBefore(suite.T(), func() { 562 // evaluates proper reception of event 563 // casts the received event at the receiver side 564 rcvEvent, ok := (<-sender.event).(*message.TestMessage) 565 // evaluates correctness of casting 566 require.True(suite.T(), ok) 567 // evaluates content of received echo message 568 // the content should not yet received and be unique 569 _, rcv := received[rcvEvent.Text] 570 assert.False(suite.T(), rcv) 571 // echo messages should start with prefix msg of receiver that echos back 572 assert.True(suite.T(), strings.HasPrefix(rcvEvent.Text, receiver.echomsg)) 573 // marking echo event as received 574 received[rcvEvent.Text] = struct{}{} 575 576 // evaluates channel that message was received on 577 assert.Equal(suite.T(), channels.TestNetworkChannel, <-sender.channel) 578 }, 100*time.Millisecond) 579 580 case <-time.After(10 * time.Second): 581 assert.Fail(suite.Suite.T(), "receiver failed to send an echo message back to sender") 582 } 583 } 584 } 585 } 586 587 // assertMessageReceived asserts that the given message was received on the given channel 588 // for the given engine 589 func assertMessageReceived(t *testing.T, e *EchoEngine, m *message.TestMessage, c channels.Channel) { 590 // wrap blocking channel reads with a timeout 591 unittest.AssertReturnsBefore(t, func() { 592 // evaluates proper reception of event 593 // casts the received event at the receiver side 594 rcvEvent, ok := (<-e.event).(*message.TestMessage) 595 // evaluates correctness of casting 596 require.True(t, ok) 597 // evaluates content of received message 598 assert.Equal(t, m, rcvEvent) 599 600 // evaluates channel that message was received on 601 assert.Equal(t, c, <-e.channel) 602 }, 100*time.Millisecond) 603 }