github.com/anycable/anycable-go@v1.5.1/node/node_test.go (about) 1 package node 2 3 import ( 4 "encoding/json" 5 "errors" 6 "testing" 7 8 "github.com/anycable/anycable-go/common" 9 "github.com/anycable/anycable-go/encoders" 10 "github.com/anycable/anycable-go/mocks" 11 "github.com/stretchr/testify/assert" 12 "github.com/stretchr/testify/mock" 13 "github.com/stretchr/testify/require" 14 ) 15 16 func TestAuthenticate(t *testing.T) { 17 node := NewMockNode() 18 go node.hub.Run() 19 defer node.hub.Shutdown() 20 21 t.Run("Successful authentication", func(t *testing.T) { 22 session := NewMockSessionWithEnv("1", node, "/cable", &map[string]string{"id": "test_id"}) 23 _, err := node.Authenticate(session) 24 defer node.hub.RemoveSession(session) 25 26 assert.Nil(t, err, "Error must be nil") 27 assert.Equal(t, true, session.Connected, "Session must be marked as connected") 28 assert.Equalf(t, "test_id", session.GetIdentifiers(), "Identifiers must be equal to %s", "test_id") 29 30 msg, err := session.conn.Read() 31 assert.Nil(t, err) 32 33 assert.Equalf(t, []byte("welcome"), msg, "Sent message is invalid: %s", msg) 34 35 assert.Equal(t, 1, node.hub.Size()) 36 }) 37 38 t.Run("Failed authentication", func(t *testing.T) { 39 session := NewMockSessionWithEnv("1", node, "/failure", &map[string]string{"id": "test_id"}) 40 41 _, err := node.Authenticate(session) 42 43 assert.Nil(t, err, "Error must be nil") 44 45 msg, err := session.conn.Read() 46 assert.Nil(t, err) 47 48 assert.Equalf(t, []byte("unauthorized"), msg, "Sent message is invalid: %s", msg) 49 assert.Equal(t, 0, node.hub.Size()) 50 }) 51 52 t.Run("Error during authentication", func(t *testing.T) { 53 session := NewMockSessionWithEnv("1", node, "/error", &map[string]string{"id": "test_id"}) 54 55 _, err := node.Authenticate(session) 56 57 assert.NotNil(t, err, "Error must not be nil") 58 assert.Equal(t, 0, node.hub.Size()) 59 }) 60 61 t.Run("With connection state", func(t *testing.T) { 62 session := NewMockSessionWithEnv("1", node, "/cable", &map[string]string{"x-session-test": "my_session", "id": "session_id"}) 63 defer node.hub.RemoveSession(session) 64 65 _, err := node.Authenticate(session) 66 67 assert.Nil(t, err, "Error must be nil") 68 assert.Equal(t, true, session.Connected, "Session must be marked as connected") 69 70 assert.Len(t, *session.env.ConnectionState, 1) 71 assert.Equal(t, "my_session", (*session.env.ConnectionState)["_s_"]) 72 73 assert.Equal(t, 1, node.hub.Size()) 74 }) 75 } 76 77 func TestSubscribe(t *testing.T) { 78 node := NewMockNode() 79 session := NewMockSession("14", node) 80 81 node.hub.AddSession(session) 82 defer node.hub.RemoveSession(session) 83 84 go node.hub.Run() 85 defer node.hub.Shutdown() 86 87 t.Run("Successful subscription", func(t *testing.T) { 88 _, err := node.Subscribe(session, &common.Message{Identifier: "test_channel"}) 89 assert.Nil(t, err, "Error must be nil") 90 91 // Adds subscription to session 92 assert.Truef(t, session.subscriptions.HasChannel("test_channel"), "Session subscription must be set") 93 94 msg, err := session.conn.Read() 95 assert.Nil(t, err) 96 97 assert.Equalf(t, []byte("14"), msg, "Sent message is invalid: %s", msg) 98 }) 99 100 t.Run("Subscription with a stream", func(t *testing.T) { 101 _, err := node.Subscribe(session, &common.Message{Identifier: "with_stream"}) 102 assert.Nil(t, err, "Error must be nil") 103 104 // Adds subscription and stream to session 105 assert.Truef(t, session.subscriptions.HasChannel("with_stream"), "Session subsription must be set") 106 assert.Equal(t, []string{"stream"}, session.subscriptions.StreamsFor("with_stream")) 107 108 msg, err := session.conn.Read() 109 assert.Nil(t, err) 110 111 assert.Equalf(t, "14", string(msg), "Sent message is invalid: %s", msg) 112 113 // Make sure session is subscribed 114 node.hub.BroadcastMessage(&common.StreamMessage{Stream: "stream", Data: "41"}) 115 116 msg, err = session.conn.Read() 117 assert.Nil(t, err) 118 119 assert.Equalf(t, "{\"identifier\":\"with_stream\",\"message\":41}", string(msg), "Broadcasted message is invalid: %s", msg) 120 }) 121 122 t.Run("Error during subscription", func(t *testing.T) { 123 _, err := node.Subscribe(session, &common.Message{Identifier: "error"}) 124 assert.Error(t, err) 125 }) 126 127 t.Run("Rejected subscription", func(t *testing.T) { 128 session := NewMockSession("15", node) 129 130 node.hub.AddSession(session) 131 defer node.hub.RemoveSession(session) 132 133 res, err := node.Subscribe(session, &common.Message{Identifier: "failure"}) 134 135 assert.Equal(t, common.FAILURE, res.Status) 136 assert.Equal(t, 0, len(session.subscriptions.Channels())) 137 assert.NoError(t, err) 138 }) 139 } 140 141 func TestUnsubscribe(t *testing.T) { 142 node := NewMockNode() 143 session := NewMockSession("14", node) 144 145 node.hub.AddSession(session) 146 defer node.hub.RemoveSession(session) 147 148 go node.hub.Run() 149 defer node.hub.Shutdown() 150 151 t.Run("Successful unsubscribe", func(t *testing.T) { 152 session.subscriptions.AddChannel("test_channel") 153 node.hub.SubscribeSession(session, "streamo", "test_channel") 154 155 node.hub.Broadcast("streamo", `"before"`) 156 msg, err := session.conn.Read() 157 require.NoError(t, err) 158 159 assert.Equalf(t, `{"identifier":"test_channel","message":"before"}`, string(msg), "Broadcasted message is invalid: %s", msg) 160 161 _, err = node.Unsubscribe(session, &common.Message{Identifier: "test_channel"}) 162 assert.Nil(t, err, "Error must be nil") 163 164 // Removes subscription from session 165 assert.Falsef(t, session.subscriptions.HasChannel("test_channel"), "Shouldn't contain test_channel") 166 167 node.hub.BroadcastMessage(&common.StreamMessage{Stream: "streamo", Data: "41"}) 168 169 msg, err = session.conn.Read() 170 assert.Nil(t, msg) 171 assert.Error(t, err, "Session hasn't received any messages") 172 }) 173 174 t.Run("Error during unsubscription", func(t *testing.T) { 175 session.subscriptions.AddChannel("failure") 176 177 _, err := node.Unsubscribe(session, &common.Message{Identifier: "failure"}) 178 assert.Error(t, err) 179 }) 180 } 181 182 func TestPerform(t *testing.T) { 183 node := NewMockNode() 184 session := NewMockSession("14", node) 185 186 node.hub.AddSession(session) 187 defer node.hub.RemoveSession(session) 188 189 session.subscriptions.AddChannel("test_channel") 190 191 go node.hub.Run() 192 defer node.hub.Shutdown() 193 194 t.Run("Successful perform", func(t *testing.T) { 195 _, err := node.Perform(session, &common.Message{Identifier: "test_channel", Data: "action"}) 196 assert.Nil(t, err) 197 198 msg, err := session.conn.Read() 199 assert.Nil(t, err) 200 201 assert.Equalf(t, []byte("action"), msg, "Sent message is invalid: %s", msg) 202 }) 203 204 t.Run("With connection state", func(t *testing.T) { 205 _, err := node.Perform(session, &common.Message{Identifier: "test_channel", Data: "session"}) 206 assert.Nil(t, err) 207 208 _, err = session.conn.Read() 209 assert.Nil(t, err) 210 211 assert.Len(t, *session.env.ConnectionState, 1) 212 assert.Equal(t, "performed", (*session.env.ConnectionState)["_s_"]) 213 }) 214 215 t.Run("Error during perform", func(t *testing.T) { 216 session.subscriptions.AddChannel("failure") 217 218 _, err := node.Perform(session, &common.Message{Identifier: "failure", Data: "test"}) 219 assert.NotNil(t, err, "Error must not be nil") 220 }) 221 222 t.Run("With stopped streams", func(t *testing.T) { 223 session.subscriptions.AddChannelStream("test_channel", "stop_stream") 224 node.hub.SubscribeSession(session, "stop_stream", "test_channel") 225 226 node.hub.BroadcastMessage(&common.StreamMessage{Stream: "stop_stream", Data: "40"}) 227 228 msg, _ := session.conn.Read() 229 assert.NotNil(t, msg) 230 231 _, err := node.Perform(session, &common.Message{Identifier: "test_channel", Data: "stop_stream"}) 232 assert.Nil(t, err) 233 234 assert.Empty(t, session.subscriptions.StreamsFor("test_channel")) 235 236 _, err = node.Perform(session, &common.Message{Identifier: "test_channel", Data: "stop_stream"}) 237 assert.Nil(t, err) 238 239 node.hub.BroadcastMessage(&common.StreamMessage{Stream: "stop_stream", Data: "41"}) 240 241 msg, err = session.conn.Read() 242 assert.Nil(t, msg) 243 assert.Error(t, err, "Session hasn't received any messages") 244 }) 245 246 t.Run("With channel state", func(t *testing.T) { 247 assert.Len(t, *session.env.ChannelStates, 0) 248 249 _, err := node.Perform(session, &common.Message{Identifier: "test_channel", Data: "channel_state"}) 250 assert.Nil(t, err) 251 252 _, err = session.conn.Read() 253 assert.Nil(t, err) 254 255 assert.Len(t, *session.env.ChannelStates, 1) 256 assert.Len(t, (*session.env.ChannelStates)["test_channel"], 1) 257 assert.Equal(t, "performed", (*session.env.ChannelStates)["test_channel"]["_c_"]) 258 }) 259 } 260 261 func TestWhisper(t *testing.T) { 262 node := NewMockNode() 263 session := NewMockSession("14", node) 264 session2 := NewMockSession("15", node) 265 266 // Subscribe using different identifiers to make sure whisper is working 267 // per stream name, not per identifier 268 defer subscribeSessionToStream(session, node, "test_channel", "test_whisper")() 269 defer subscribeSessionToStream(session2, node, "test_channel_2", "test_whisper")() 270 271 go node.hub.Run() 272 defer node.hub.Shutdown() 273 274 t.Run("When whispering stream is configured for sending subscription", func(t *testing.T) { 275 session.env.MergeChannelState("test_channel", &map[string]string{common.WHISPER_STREAM_STATE: "test_whisper"}) 276 277 err := node.Whisper(session, &common.Message{Identifier: "test_channel", Data: "tshh... it's a secret"}) 278 assert.Nil(t, err) 279 280 expected := `{"identifier":"test_channel_2","message":"tshh... it's a secret"}` 281 282 msg, err := session2.conn.Read() 283 assert.NoError(t, err) 284 assert.Equal(t, expected, string(msg)) 285 286 // Sender do not receive the message 287 msg, err = session.conn.Read() 288 assert.Nil(t, msg) 289 assert.Error(t, err, "Session hasn't received any messages") 290 }) 291 292 t.Run("When whispering stream is not configured", func(t *testing.T) { 293 session.env.RemoveChannelState("test_channel") 294 295 err := node.Whisper(session, &common.Message{Identifier: "test_channel", Data: "tshh... it's a secret"}) 296 assert.Nil(t, err) 297 298 msg, err := session2.conn.Read() 299 assert.Error(t, err) 300 assert.Nil(t, msg) 301 302 // Sender do not receive the message 303 msg, err = session.conn.Read() 304 assert.Nil(t, msg) 305 assert.Error(t, err, "Session hasn't received any messages") 306 }) 307 } 308 309 func TestStreamSubscriptionRaceConditions(t *testing.T) { 310 node := NewMockNode() 311 session := NewMockSession("14", node) 312 313 node.hub.AddSession(session) 314 session.subscriptions.AddChannel("test_channel") 315 316 // We need a real hub here to catch a race condition 317 go node.hub.Run() 318 defer node.hub.Shutdown() 319 320 t.Run("stop and start streams race conditions", func(t *testing.T) { 321 _, err := node.Perform(session, &common.Message{Identifier: "test_channel", Data: "stop_and_start_streams"}) 322 assert.Nil(t, err) 323 324 // Make sure session is subscribed to the stream 325 node.hub.Broadcast("all", "2022") 326 327 msg, err := session.conn.Read() 328 require.NoError(t, err) 329 330 assert.Equalf(t, "{\"identifier\":\"test_channel\",\"message\":2022}", string(msg), "Broadcasted message is invalid: %s", msg) 331 }) 332 } 333 334 func TestDisconnect(t *testing.T) { 335 node := NewMockNode() 336 go node.hub.Run() 337 defer node.hub.Shutdown() 338 339 t.Run("Disconnectable session", func(t *testing.T) { 340 session := NewMockSessionWithEnv("1", node, "/cable", &map[string]string{"id": "test_id"}) 341 // Authenticate via controller marks session as disconnectable automatically 342 _, err := node.Authenticate(session) 343 require.NoError(t, err) 344 345 assert.True(t, session.IsDisconnectable()) 346 347 assert.Nil(t, node.Disconnect(session)) 348 349 assert.Equal(t, 1, node.disconnector.Size(), "Expected disconnect to have 1 task in a queue") 350 351 task := <-node.disconnector.(*DisconnectQueue).disconnect 352 assert.Equal(t, session, task, "Expected to disconnect session") 353 }) 354 355 t.Run("Non-disconnectable session", func(t *testing.T) { 356 session := NewMockSessionWithEnv("1", node, "/cable", &map[string]string{"id": "test_id"}) 357 // Authenticate via controller marks session as disconnectable automatically 358 _, err := node.Authenticate(session) 359 require.NoError(t, err) 360 361 session.disconnectInterest = false 362 363 assert.Nil(t, node.Disconnect(session)) 364 365 assert.Equal(t, 0, node.disconnector.Size(), "Expected disconnect to have 0 tasks in a queue") 366 }) 367 } 368 369 func TestHistory(t *testing.T) { 370 node := NewMockNode() 371 372 broker := &mocks.Broker{} 373 node.SetBroker(broker) 374 375 broker. 376 On("CommitSession", mock.Anything, mock.Anything). 377 Return(nil) 378 379 go node.hub.Run() 380 defer node.hub.Shutdown() 381 382 session := NewMockSession("14", node) 383 384 session.subscriptions.AddChannel("test_channel") 385 session.subscriptions.AddChannelStream("test_channel", "streamo") 386 session.subscriptions.AddChannelStream("test_channel", "emptissimo") 387 388 stream := []common.StreamMessage{ 389 { 390 Stream: "streamo", 391 Data: "ciao", 392 Offset: 22, 393 Epoch: "test", 394 }, 395 { 396 Stream: "streamo", 397 Data: "buona sera", 398 Offset: 23, 399 Epoch: "test", 400 }, 401 } 402 403 var ts int64 404 405 t.Run("Successful history with only Since", func(t *testing.T) { 406 ts = 100200 407 408 broker. 409 On("HistorySince", "streamo", ts). 410 Return(stream, nil) 411 broker. 412 On("HistorySince", "emptissimo", ts). 413 Return(nil, nil) 414 415 err := node.History( 416 session, 417 &common.Message{ 418 Identifier: "test_channel", 419 History: common.HistoryRequest{ 420 Since: ts, 421 }, 422 }, 423 ) 424 require.NoError(t, err) 425 426 history := []string{ 427 "{\"identifier\":\"test_channel\",\"message\":\"ciao\",\"stream_id\":\"streamo\",\"epoch\":\"test\",\"offset\":22}", 428 "{\"identifier\":\"test_channel\",\"message\":\"buona sera\",\"stream_id\":\"streamo\",\"epoch\":\"test\",\"offset\":23}", 429 } 430 431 for _, msg := range history { 432 received, herr := session.conn.Read() 433 require.NoError(t, herr) 434 435 require.Equalf( 436 t, 437 msg, 438 string(received), 439 "Sent message is invalid: %s", received, 440 ) 441 } 442 443 ack, err := session.conn.Read() 444 require.NoError(t, err) 445 446 assert.Equal(t, `{"type":"confirm_history","identifier":"test_channel"}`, string(ack)) 447 448 _, err = session.conn.Read() 449 require.Error(t, err) 450 }) 451 452 t.Run("Successful history with Since and Offset", func(t *testing.T) { 453 ts = 100300 454 455 broker. 456 On("HistoryFrom", "streamo", "test", uint64(20)). 457 Return(stream, nil) 458 broker. 459 On("HistorySince", "emptissimo", ts). 460 Return([]common.StreamMessage{{ 461 Stream: "emptissimo", 462 Data: "zer0", 463 Offset: 2, 464 Epoch: "test_zero", 465 }}, nil) 466 467 err := node.History( 468 session, 469 &common.Message{ 470 Identifier: "test_channel", 471 History: common.HistoryRequest{ 472 Since: ts, 473 Streams: map[string]common.HistoryPosition{ 474 "streamo": {Epoch: "test", Offset: 20}, 475 }, 476 }, 477 }, 478 ) 479 require.NoError(t, err) 480 481 history := []string{ 482 "{\"identifier\":\"test_channel\",\"message\":\"ciao\",\"stream_id\":\"streamo\",\"epoch\":\"test\",\"offset\":22}", 483 "{\"identifier\":\"test_channel\",\"message\":\"buona sera\",\"stream_id\":\"streamo\",\"epoch\":\"test\",\"offset\":23}", 484 "{\"identifier\":\"test_channel\",\"message\":\"zer0\",\"stream_id\":\"emptissimo\",\"epoch\":\"test_zero\",\"offset\":2}", 485 } 486 487 // The order of streams is non-deterministic, so 488 // we're collecting messages first and checking for inclusion later 489 received := []string{} 490 491 for range history { 492 data, herr := session.conn.Read() 493 require.NoError(t, herr) 494 495 received = append(received, string(data)) 496 } 497 498 for _, msg := range history { 499 require.Contains( 500 t, 501 received, 502 msg, 503 ) 504 } 505 506 ack, err := session.conn.Read() 507 require.NoError(t, err) 508 509 assert.Equal(t, `{"type":"confirm_history","identifier":"test_channel"}`, string(ack)) 510 511 _, err = session.conn.Read() 512 require.Error(t, err) 513 }) 514 515 t.Run("Fetching history with Subscribe", func(t *testing.T) { 516 ts = 100400 517 518 broker. 519 On("HistoryFrom", "streamo", "test", uint64(21)). 520 Return(stream, nil) 521 broker. 522 On("HistorySince", "s1", ts). 523 Return([]common.StreamMessage{{ 524 Stream: "s1", 525 Data: "{\"foo\":\"bar\"}", 526 Offset: 10, 527 Epoch: "test", 528 }}, nil) 529 broker. 530 On("Subscribe", "stream"). 531 Return("s1") 532 533 _, err := node.Subscribe( 534 session, 535 &common.Message{ 536 Identifier: "with_stream", 537 History: common.HistoryRequest{ 538 Since: ts, 539 Streams: map[string]common.HistoryPosition{ 540 "streamo": {Epoch: "test", Offset: 21}, 541 }, 542 }, 543 }, 544 ) 545 require.NoError(t, err) 546 547 msg, err := session.conn.Read() 548 require.NoError(t, err) 549 550 require.Equalf(t, "14", string(msg), "Sent message is invalid: %s", msg) 551 552 history := []string{ 553 "{\"identifier\":\"with_stream\",\"message\":{\"foo\":\"bar\"},\"stream_id\":\"s1\",\"epoch\":\"test\",\"offset\":10}", 554 } 555 556 for _, msg := range history { 557 received, herr := session.conn.Read() 558 require.NoError(t, herr) 559 560 require.Equalf( 561 t, 562 msg, 563 string(received), 564 "Sent message is invalid: %s", received, 565 ) 566 } 567 568 ack, err := session.conn.Read() 569 require.NoError(t, err) 570 571 assert.Equal(t, `{"type":"confirm_history","identifier":"with_stream"}`, string(ack)) 572 573 _, err = session.conn.Read() 574 require.Error(t, err) 575 }) 576 577 t.Run("Error retrieving history", func(t *testing.T) { 578 ts = 200100 579 580 broker. 581 On("HistorySince", "streamo", ts). 582 Return(nil, errors.New("Couldn't restore history")) 583 broker. 584 On("HistorySince", "emptissimo", ts). 585 Return(stream, nil) 586 587 err := node.History( 588 session, 589 &common.Message{ 590 Identifier: "test_channel", 591 History: common.HistoryRequest{ 592 Since: ts, 593 }, 594 }, 595 ) 596 597 assert.Error(t, err, "Couldn't restore history") 598 599 ack, err := session.conn.Read() 600 require.NoError(t, err) 601 602 assert.Equal(t, `{"type":"reject_history","identifier":"test_channel"}`, string(ack)) 603 }) 604 } 605 606 func TestRestoreSession(t *testing.T) { 607 node := NewMockNode() 608 609 broker := &mocks.Broker{} 610 node.SetBroker(broker) 611 612 go node.hub.Run() 613 defer node.hub.Shutdown() 614 615 prev_session := NewMockSession("114", node, WithResumable(true)) 616 prev_session.subscriptions.AddChannel("fruits_channel") 617 prev_session.subscriptions.AddChannelStream("fruits_channel", "arancia") 618 prev_session.subscriptions.AddChannelStream("fruits_channel", "limoni") 619 prev_session.env.MergeConnectionState(&(map[string]string{"tenant_id": "71"})) 620 prev_session.env.MergeChannelState("fruits_channel", &(map[string]string{"gardini": "ischia"})) 621 622 cached, err := prev_session.ToCacheEntry() 623 require.NoError(t, err) 624 625 broker. 626 On("RestoreSession", "114"). 627 Return(cached, nil) 628 broker. 629 On("CommitSession", mock.Anything, mock.Anything). 630 Return(nil) 631 broker. 632 On("Subscribe", mock.Anything). 633 Return(func(name string) string { return name }) 634 635 session := NewMockSession("214", node, WithResumable(true), WithPrevSID("114")) 636 637 t.Run("Successful restore via header", func(t *testing.T) { 638 res, err := node.Authenticate(session) 639 require.NoError(t, err) 640 assert.Equal(t, common.SUCCESS, res.Status) 641 642 assert.Contains(t, session.subscriptions.StreamsFor("fruits_channel"), "arancia") 643 assert.Contains(t, session.subscriptions.StreamsFor("fruits_channel"), "limoni") 644 645 assert.Equal(t, "71", session.env.GetConnectionStateField("tenant_id")) 646 assert.Equal(t, "ischia", session.env.GetChannelStateField("fruits_channel", "gardini")) 647 648 welcome, err := session.conn.Read() 649 require.NoError(t, err) 650 651 require.Equalf( 652 t, 653 `{"type":"welcome","sid":"214","restored":true,"restored_ids":["fruits_channel"]}`, 654 string(welcome), 655 "Sent message is invalid: %s", welcome, 656 ) 657 658 node.hub.Broadcast("arancia", "delissimo") 659 660 msg, err := session.conn.Read() 661 require.NoError(t, err) 662 663 require.Equalf( 664 t, 665 `{"identifier":"fruits_channel","message":"delissimo"}`, 666 string(msg), 667 "Sent message is invalid: %s", msg, 668 ) 669 670 node.hub.Broadcast("limoni", "acido") 671 672 msg, err = session.conn.Read() 673 require.NoError(t, err) 674 675 require.Equalf( 676 t, 677 `{"identifier":"fruits_channel","message":"acido"}`, 678 string(msg), 679 "Sent message is invalid: %s", msg, 680 ) 681 }) 682 683 t.Run("Failed to restore", func(t *testing.T) { 684 broker. 685 On("RestoreSession", "114"). 686 Return(nil, nil) 687 688 session = NewMockSession("154", node) 689 690 res, err := node.Authenticate(session) 691 require.NoError(t, err) 692 assert.Equal(t, common.SUCCESS, res.Status) 693 694 welcome, err := session.conn.Read() 695 require.NoError(t, err) 696 697 require.Equalf( 698 t, 699 "welcome", 700 string(welcome), 701 "Sent message is invalid: %s", welcome, 702 ) 703 }) 704 } 705 706 func TestBroadcasting(t *testing.T) { 707 node := NewMockNode() 708 709 go node.hub.Run() 710 defer node.hub.Shutdown() 711 712 session := NewMockSession("14", node) 713 session2 := NewMockSession("15", node) 714 715 node.hub.AddSession(session) 716 node.hub.SubscribeSession(session, "test", "test_channel") 717 node.hub.SubscribeSession(session, "staind_2023", "music_channel") 718 719 node.hub.AddSession(session2) 720 node.hub.SubscribeSession(session2, "test", "test_channel") 721 node.hub.SubscribeSession(session2, "staind_2023", "music_channel") 722 723 node.broker.Subscribe("test") 724 node.broker.Subscribe("staind_2023") 725 726 t.Run("HandlePubSub", func(t *testing.T) { 727 node.HandlePubSub([]byte(`{"stream":"test","data":"\"abc123\""}`)) 728 729 expected := `{"identifier":"test_channel","message":"abc123"}` 730 731 msg, err := session.conn.Read() 732 assert.Nil(t, err) 733 assert.Equalf(t, expected, string(msg), "Expected to receive %s but got %s", expected, string(msg)) 734 735 msg2, err := session2.conn.Read() 736 assert.Nil(t, err) 737 assert.Equalf(t, expected, string(msg2), "Expected to receive %s but got %s", expected, string(msg2)) 738 }) 739 740 t.Run("HandlePubSub_Batch", func(t *testing.T) { 741 node.HandlePubSub([]byte(`[{"stream":"test","data":"\"follow me\""},{"stream":"untest","data":"\"missing\""},{"stream":"staind_2023","data":"{\"num\":7,\"title\":\"The Fray\"}"}]`)) 742 743 first := `{"identifier":"test_channel","message":"follow me"}` 744 second := `{"identifier":"music_channel","message":{"num":7,"title":"The Fray"}}` 745 746 msgs, err := readMessages(session.conn, 2) 747 assert.Nil(t, err) 748 assert.Contains(t, msgs, first) 749 assert.Contains(t, msgs, second) 750 751 msgs2, err := readMessages(session2.conn, 2) 752 assert.Nil(t, err) 753 assert.Contains(t, msgs2, first) 754 assert.Contains(t, msgs2, second) 755 }) 756 757 t.Run("HandleBroadcast", func(t *testing.T) { 758 node.HandleBroadcast([]byte(`{"stream":"staind_2023","data":"{\"num\":5,\"title\":\"Out of time\"}"}`)) 759 760 expected := `{"identifier":"music_channel","message":{"num":5,"title":"Out of time"}}` 761 762 msg, err := session.conn.Read() 763 assert.Nil(t, err) 764 assert.Equalf(t, expected, string(msg), "Expected to receive %s but got %s", expected, string(msg)) 765 766 msg2, err := session2.conn.Read() 767 assert.Nil(t, err) 768 assert.Equalf(t, expected, string(msg2), "Expected to receive %s but got %s", expected, string(msg2)) 769 }) 770 771 t.Run("HandleBroadcast_Batch", func(t *testing.T) { 772 node.HandleBroadcast([]byte(`[{"stream":"staind_2023","data":"{\"num\":9,\"title\":\"Hate me too\"}"},{"stream":"untest","data":"\"missing\""},{"stream":"staind_2023","data":"{\"num\":10,\"title\":\"Confessions of Fallen\"}"}]`)) 773 774 first := `{"identifier":"music_channel","message":{"num":9,"title":"Hate me too"}}` 775 second := `{"identifier":"music_channel","message":{"num":10,"title":"Confessions of Fallen"}}` 776 777 msgs, err := readMessages(session.conn, 2) 778 assert.Nil(t, err) 779 assert.Contains(t, msgs, first) 780 assert.Contains(t, msgs, second) 781 782 msgs2, err := readMessages(session2.conn, 2) 783 assert.Nil(t, err) 784 assert.Contains(t, msgs2, first) 785 assert.Contains(t, msgs2, second) 786 }) 787 } 788 789 func TestHandlePubSubWithCommand(t *testing.T) { 790 node := NewMockNode() 791 792 go node.hub.Run() 793 defer node.hub.Shutdown() 794 795 session := NewMockSession("14", node) 796 node.hub.AddSession(session) 797 798 node.HandlePubSub([]byte("{\"command\":\"disconnect\",\"payload\":{\"identifier\":\"14\",\"reconnect\":false}}")) 799 800 expected := string(toJSON(common.NewDisconnectMessage("remote", false))) 801 802 msg, err := session.conn.Read() 803 assert.Nil(t, err) 804 assert.Equalf(t, expected, string(msg), "Expected to receive %s but got %s", expected, string(msg)) 805 assert.True(t, session.closed) 806 } 807 808 func TestLookupSession(t *testing.T) { 809 node := NewMockNode() 810 811 go node.hub.Run() 812 defer node.hub.Shutdown() 813 814 assert.Nil(t, node.LookupSession("{\"foo\":\"bar\"}")) 815 816 session := NewMockSession("14", node) 817 session.SetIdentifiers("{\"foo\":\"bar\"}") 818 node.hub.AddSession(session) 819 820 assert.Equal(t, session, node.LookupSession("{\"foo\":\"bar\"}")) 821 } 822 823 func toJSON(msg encoders.EncodedMessage) []byte { 824 b, err := json.Marshal(&msg) 825 if err != nil { 826 panic("Failed to build JSON 😲") 827 } 828 829 return b 830 } 831 832 func subscribeSessionToStream(s *Session, n *Node, identifier string, stream string) func() { 833 n.hub.AddSession(s) 834 835 s.subscriptions.AddChannel(identifier) 836 s.subscriptions.AddChannelStream(identifier, stream) 837 n.hub.SubscribeSession(s, stream, identifier) 838 n.broker.Subscribe(stream) 839 840 return func() { 841 n.hub.RemoveSession(s) 842 } 843 } 844 845 func readMessages(conn Connection, count int) ([]string, error) { 846 var messages []string 847 848 for i := 0; i < count; i++ { 849 msg, err := conn.Read() 850 if err != nil { 851 return nil, err 852 } 853 854 messages = append(messages, string(msg)) 855 } 856 857 return messages, nil 858 }