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