ably-rest 1.1.7 → 1.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/lib/submodules/ably-ruby/CHANGELOG.md +59 -0
  3. data/lib/submodules/ably-ruby/COPYRIGHT +1 -1
  4. data/lib/submodules/ably-ruby/SPEC.md +0 -7
  5. data/lib/submodules/ably-ruby/ably.gemspec +1 -1
  6. data/lib/submodules/ably-ruby/lib/ably/models/connection_details.rb +8 -2
  7. data/lib/submodules/ably-ruby/lib/ably/models/delta_extras.rb +29 -0
  8. data/lib/submodules/ably-ruby/lib/ably/models/error_info.rb +6 -2
  9. data/lib/submodules/ably-ruby/lib/ably/models/message.rb +11 -0
  10. data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +5 -8
  11. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_state_machine.rb +5 -1
  12. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/publisher.rb +3 -2
  13. data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +2 -0
  14. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_manager.rb +13 -4
  15. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_state_machine.rb +4 -0
  16. data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +0 -3
  17. data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +4 -3
  18. data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +16 -4
  19. data/lib/submodules/ably-ruby/lib/ably/version.rb +1 -1
  20. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +212 -7
  21. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +56 -1
  22. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +249 -0
  23. data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +18 -1
  24. data/lib/submodules/ably-ruby/spec/acceptance/rest/channel_spec.rb +73 -11
  25. data/lib/submodules/ably-ruby/spec/acceptance/rest/channels_spec.rb +1 -1
  26. data/lib/submodules/ably-ruby/spec/support/test_app.rb +1 -1
  27. data/lib/submodules/ably-ruby/spec/unit/models/delta_extras_spec.rb +14 -0
  28. data/lib/submodules/ably-ruby/spec/unit/models/error_info_spec.rb +17 -1
  29. data/lib/submodules/ably-ruby/spec/unit/models/message_spec.rb +24 -0
  30. data/lib/submodules/ably-ruby/spec/unit/models/protocol_message_spec.rb +24 -20
  31. data/lib/submodules/ably-ruby/spec/unit/realtime/channel_spec.rb +2 -1
  32. data/lib/submodules/ably-ruby/spec/unit/realtime/channels_spec.rb +3 -3
  33. data/lib/submodules/ably-ruby/spec/unit/rest/channel_spec.rb +40 -7
  34. data/lib/submodules/ably-ruby/spec/unit/rest/client_spec.rb +27 -0
  35. metadata +4 -2
@@ -750,6 +750,107 @@ describe Ably::Realtime::Channel, :event_machine do
750
750
  end
751
751
  end
752
752
 
753
+ describe '#(RTL17)' do
754
+ context 'when channel is initialized' do
755
+ it 'sends messages only on attach' do
756
+ expect(channel).to be_initialized
757
+ channel.publish('event', payload)
758
+
759
+ channel.subscribe do |message|
760
+ stop_reactor if message.data == payload && channel.attached?
761
+ end
762
+
763
+ channel.attach
764
+ end
765
+ end
766
+
767
+ context 'when channel is attaching' do
768
+ it 'sends messages only on attach' do
769
+ channel.publish('event', payload)
770
+
771
+ sent_message = nil
772
+ channel.subscribe do |message|
773
+ return if message.data != payload
774
+ sent_message = message
775
+
776
+ stop_reactor if channel.attached?
777
+ end
778
+
779
+ channel.on(:attaching) do
780
+ expect(channel).to be_attaching
781
+ expect(sent_message).to be_nil
782
+ end
783
+
784
+ channel.attach
785
+ end
786
+ end
787
+
788
+ context 'when channel is detaching' do
789
+ it 'stops sending message' do
790
+ sent_message = nil
791
+ event_published = false
792
+ channel.subscribe do |message|
793
+ sent_message = message if message.data == payload
794
+ end
795
+
796
+ channel.on(:detaching) do
797
+ channel.publish('event', payload)
798
+ event_published = true
799
+ end
800
+
801
+ channel.on(:detaching) do
802
+ EventMachine.next_tick do
803
+ expect(sent_message).to be_nil
804
+ stop_reactor if event_published
805
+ end
806
+ end
807
+
808
+ channel.attach do
809
+ channel.detach
810
+ end
811
+ end
812
+ end
813
+
814
+ context 'when channel is detached' do
815
+ it 'stops sending message' do
816
+ sent_message = nil
817
+ event_published = false
818
+ channel.subscribe do |message|
819
+ sent_message = message if message.data == payload
820
+ end
821
+
822
+ channel.on(:detaching) do
823
+ channel.publish('event', payload)
824
+ event_published = true
825
+ end
826
+
827
+ channel.on(:detached) do
828
+ expect(sent_message).to be_nil
829
+ stop_reactor if event_published
830
+ end
831
+
832
+ channel.attach do
833
+ channel.detach
834
+ end
835
+ end
836
+ end
837
+
838
+ context 'when channel is failed' do
839
+ it 'errors when trying to send a message' do
840
+ channel.once(:failed) do
841
+ channel.publish('event', payload).errback do |error|
842
+ expect(error).to be_a(Ably::Exceptions::ChannelInactive)
843
+ stop_reactor
844
+ end
845
+ end
846
+
847
+ channel.attach do
848
+ channel.transition_state_machine(:failed)
849
+ end
850
+ end
851
+ end
852
+ end
853
+
753
854
  context 'when channel is not attached in state Initializing (#RTL6c1)' do
754
855
  it 'publishes messages immediately and does not implicitly attach (#RTL6c1)' do
755
856
  sub_channel.attach do
@@ -1181,7 +1282,7 @@ describe Ably::Realtime::Channel, :event_machine do
1181
1282
  end
1182
1283
 
1183
1284
  context 'with more than allowed messages in a single publish' do
1184
- let(:channel_name) { random_str }
1285
+ 65536
1185
1286
 
1186
1287
  it 'rejects the publish' do
1187
1288
  messages = (Ably::Realtime::Connection::MAX_PROTOCOL_MESSAGE_BATCH_SIZE + 1).times.map do
@@ -1405,15 +1506,98 @@ describe Ably::Realtime::Channel, :event_machine do
1405
1506
  end
1406
1507
 
1407
1508
  context 'message size exceeded (#TO3l8)' do
1408
- let(:message) { 'x' * 700000 }
1409
-
1410
1509
  let(:client) { auto_close Ably::Realtime::Client.new(client_options) }
1411
1510
  let(:channel) { client.channels.get(channel_name) }
1412
1511
 
1413
- it 'should not allow to send a message' do
1414
- channel.publish('event', message).errback do |error|
1415
- expect(error).to be_instance_of(Ably::Exceptions::MaxMessageSizeExceeded)
1416
- stop_reactor
1512
+ context 'and max_message_size is default (65536 bytes)' do
1513
+ let(:channel_name) { random_str }
1514
+ let(:max_message_size) { 65536 }
1515
+
1516
+ it 'should allow to send a message (32 bytes)' do
1517
+ client.connection.once(:connected) do
1518
+ channel.subscribe('event') do |msg|
1519
+ expect(msg.data).to eq('x' * 32)
1520
+ stop_reactor
1521
+ end
1522
+ channel.publish('event', 'x' * 32)
1523
+ end
1524
+ end
1525
+
1526
+ it 'should not allow to send a message (700000 bytes)' do
1527
+ client.connection.once(:connected) do
1528
+ connection_details = Ably::Models::ConnectionDetails.new(
1529
+ client.connection.details.attributes.attributes.merge('maxMessageSize' => max_message_size)
1530
+ )
1531
+ client.connection.set_connection_details(connection_details)
1532
+ expect(client.connection.details.max_message_size).to eq(65536)
1533
+ channel.publish('event', 'x' * 700000).errback do |error|
1534
+ expect(error).to be_instance_of(Ably::Exceptions::MaxMessageSizeExceeded)
1535
+ stop_reactor
1536
+ end
1537
+ end
1538
+ end
1539
+ end
1540
+
1541
+ context 'and max_message_size is customized (11 bytes)' do
1542
+ let(:max_message_size) { 11 }
1543
+
1544
+ context 'and the message size is 30 bytes' do
1545
+ let(:channel_name) { random_str }
1546
+
1547
+ it 'should not allow to send a message' do
1548
+ client.connection.once(:connected) do
1549
+ connection_details = Ably::Models::ConnectionDetails.new(
1550
+ client.connection.details.attributes.attributes.merge('maxMessageSize' => max_message_size)
1551
+ )
1552
+ client.connection.set_connection_details(connection_details)
1553
+ expect(client.connection.details.max_message_size).to eq(11)
1554
+ channel.publish('event', 'x' * 30).errback do |error|
1555
+ expect(error).to be_instance_of(Ably::Exceptions::MaxMessageSizeExceeded)
1556
+ stop_reactor
1557
+ end
1558
+ end
1559
+ end
1560
+ end
1561
+ end
1562
+
1563
+ context 'and max_message_size is nil' do
1564
+ let(:max_message_size) { nil }
1565
+
1566
+ context 'and the message size is 30 bytes' do
1567
+ let(:channel_name) { random_str }
1568
+
1569
+ it 'should allow to send a message' do
1570
+ client.connection.once(:connected) do
1571
+ connection_details = Ably::Models::ConnectionDetails.new(
1572
+ client.connection.details.attributes.attributes.merge('maxMessageSize' => max_message_size)
1573
+ )
1574
+ client.connection.set_connection_details(connection_details)
1575
+ expect(client.connection.details.max_message_size).to eq(65536)
1576
+ channel.subscribe('event') do |msg|
1577
+ expect(msg.data).to eq('x' * 30)
1578
+ stop_reactor
1579
+ end
1580
+ channel.publish('event', 'x' * 30)
1581
+ end
1582
+ end
1583
+ end
1584
+
1585
+ context 'and the message size is 65537 bytes' do
1586
+ let(:channel_name) { random_str }
1587
+
1588
+ it 'should not allow to send a message' do
1589
+ client.connection.once(:connected) do
1590
+ connection_details = Ably::Models::ConnectionDetails.new(
1591
+ client.connection.details.attributes.attributes.merge('maxMessageSize' => max_message_size)
1592
+ )
1593
+ client.connection.set_connection_details(connection_details)
1594
+ expect(client.connection.details.max_message_size).to eq(65536)
1595
+ channel.publish('event', 'x' * 65537).errback do |error|
1596
+ expect(error).to be_instance_of(Ably::Exceptions::MaxMessageSizeExceeded)
1597
+ stop_reactor
1598
+ end
1599
+ end
1600
+ end
1417
1601
  end
1418
1602
  end
1419
1603
  end
@@ -2224,6 +2408,27 @@ describe Ably::Realtime::Channel, :event_machine do
2224
2408
  channel.transition_state_machine! :suspended
2225
2409
  end
2226
2410
  end
2411
+
2412
+ context 'when connection is no longer connected' do
2413
+ it 'will not attempt to reattach (#RTL13c)' do
2414
+ channel.attach do
2415
+ connection.once(:closing) do
2416
+ channel.once(:attaching) do |state_change|
2417
+ raise 'Channel should not attempt to reattach'
2418
+ end
2419
+
2420
+ channel.transition_state_machine! :suspended
2421
+ end
2422
+
2423
+ connection.once(:closed) do
2424
+ expect(channel).to be_suspended
2425
+ stop_reactor
2426
+ end
2427
+
2428
+ connection.close
2429
+ end
2430
+ end
2431
+ end
2227
2432
  end
2228
2433
 
2229
2434
  context 'and channel is attaching' do
@@ -570,7 +570,7 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
570
570
  end
571
571
 
572
572
  context 'when DISCONNECTED ProtocolMessage received from the server' do
573
- it 'reconnects automatically and immediately' do
573
+ it 'reconnects automatically and immediately (#RTN15a)' do
574
574
  fail_if_suspended_or_failed
575
575
 
576
576
  connection.once(:connected) do
@@ -590,6 +590,61 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
590
590
  end
591
591
  end
592
592
 
593
+ context 'when protocolMessage contains token error' do
594
+ context "library does not have a means to renew the token (#RTN15h1)" do
595
+ let(:auth_url) { 'https://echo.ably.io/createJWT' }
596
+ let(:token) { Faraday.get("#{auth_url}?keyName=#{key_name}&keySecret=#{key_secret}").body }
597
+ let(:client_options) { default_options.merge(token: token, log_level: :none) }
598
+
599
+ let(:error_message) { 'error_message' }
600
+
601
+ it 'moves connection state to failed' do
602
+ connection.on(:failed) do |connection_state_change|
603
+ expect(connection.error_reason.message).to eq(error_message)
604
+ stop_reactor
605
+ end
606
+
607
+ connection.on(:connected) do
608
+ protocol_message = Ably::Models::ProtocolMessage.new(action: Ably::Models::ProtocolMessage::ACTION.Disconnected.to_i, error: { code: 40140, message: error_message })
609
+ connection.__incoming_protocol_msgbus__.publish :protocol_message, protocol_message
610
+ end
611
+
612
+ connection.connect
613
+ end
614
+ end
615
+
616
+ context "library have a means to renew the token (#RTN15h2)" do
617
+ let(:client_options) { default_options.merge(log_level: :none) }
618
+ let(:error_message) { 'error_message' }
619
+
620
+ def send_disconnect_message
621
+ protocol_message = Ably::Models::ProtocolMessage.new(action: Ably::Models::ProtocolMessage::ACTION.Disconnected.to_i, error: { code: 40140, message: error_message })
622
+ connection.__incoming_protocol_msgbus__.publish :protocol_message, protocol_message
623
+ end
624
+
625
+ it 'attempts to reconnect' do
626
+ connection.on(:failed) do |connection_state_change|
627
+ raise "Connection shouldn't be failed"
628
+ end
629
+
630
+ connection.on(:connected) do
631
+ connection.once(:connecting) do
632
+ connection.once(:disconnected) do
633
+ expect(connection.error_reason.message).to eq(error_message)
634
+ stop_reactor
635
+ end
636
+
637
+ send_disconnect_message
638
+ end
639
+
640
+ send_disconnect_message
641
+ end
642
+
643
+ connection.connect
644
+ end
645
+ end
646
+ end
647
+
593
648
  context 'connection state freshness is monitored' do
594
649
  it 'resumes connections when disconnected within the connection_state_ttl period (#RTN15g)' do
595
650
  connection.once(:connected) do
@@ -482,6 +482,118 @@ describe Ably::Realtime::Connection, :event_machine do
482
482
  end
483
483
  end
484
484
 
485
+ context 'when explicitly reconnecting disconnected/suspended connection in retry (#RTN11c)' do
486
+ let(:close_connection_proc) do
487
+ lambda do
488
+ EventMachine.add_timer(0.001) do
489
+ if connection.transport.nil?
490
+ close_connection_proc.call
491
+ else
492
+ connection.transport.close_connection_after_writing
493
+ end
494
+ end
495
+ end
496
+ end
497
+
498
+ context 'when suspended' do
499
+ let(:suspended_retry_timeout) { 60 }
500
+ let(:client_options) do
501
+ default_options.merge(
502
+ disconnected_retry_timeout: 0.02,
503
+ suspended_retry_timeout: suspended_retry_timeout,
504
+ connection_state_ttl: 0
505
+ )
506
+ end
507
+
508
+ it 'reconnects immediately' do
509
+ connection.once(:connecting) { close_connection_proc.call }
510
+
511
+ connection.on(:suspended) do |connection_state_change|
512
+ if connection_state_change.retry_in.zero?
513
+ # Exhausting immediate retries
514
+ connection.once(:connecting) { close_connection_proc.call }
515
+ else
516
+ suspended_at = Time.now.to_f
517
+ connection.on(:connected) do
518
+ expect(connection_state_change.retry_in).to eq(suspended_retry_timeout)
519
+ expect(connection.state).to eq(:connected)
520
+ expect(Time.now.to_f).to be_within(4).of(suspended_at)
521
+ stop_reactor
522
+ end
523
+ end
524
+
525
+ connection.connect
526
+ end
527
+
528
+ connection.connect
529
+ end
530
+ end
531
+
532
+ context 'when disconnected' do
533
+ let(:retry_timeout) { 60 }
534
+ let(:client_options) do
535
+ default_options.merge(
536
+ disconnected_retry_timeout: retry_timeout,
537
+ suspended_retry_timeout: retry_timeout,
538
+ connection_state_ttl: 0
539
+ )
540
+ end
541
+
542
+ it 'reconnects immediately' do
543
+ connection.once(:connected) do
544
+ connection.on(:disconnected) do |connection_state_change|
545
+ disconnected_at = Time.now.to_f
546
+ connection.on(:connected) do
547
+ if connection_state_change.retry_in.zero?
548
+ # Exhausting immediate retries
549
+ close_connection_proc.call
550
+ else
551
+ expect(connection_state_change.retry_in).to eq(retry_timeout)
552
+ expect(connection.state).to eq(:connected)
553
+ expect(Time.now.to_f).to be_within(4).of(disconnected_at)
554
+ stop_reactor
555
+ end
556
+ end
557
+ connection.connect
558
+ end
559
+
560
+ close_connection_proc.call
561
+ end
562
+
563
+ connection.connect
564
+ end
565
+ end
566
+ end
567
+
568
+ context 'when reconnecting a failed connection' do
569
+ let(:channel) { client.channel(random_str) }
570
+ let(:client_options) { default_options.merge(log_level: :none) }
571
+
572
+ it 'transitions all channels state to initialized and cleares error_reason' do
573
+ connection.on(:failed) do |connection_state_change|
574
+ expect(connection.error_reason).to be_a(Ably::Exceptions::BaseAblyException)
575
+ expect(channel.error_reason).to be_a(Ably::Exceptions::BaseAblyException)
576
+ expect(channel).to be_failed
577
+
578
+ connection.on(:connected) do
579
+ expect(connection.error_reason).to eq(nil)
580
+ expect(channel).to be_initialized
581
+ expect(channel.error_reason).to eq(nil)
582
+ stop_reactor
583
+ end
584
+
585
+ connection.connect
586
+ end
587
+
588
+ connection.connect do
589
+ channel.attach do
590
+ error = Ably::Exceptions::ConnectionFailed.new('forced failure', 500, 50000)
591
+ client.connection.manager.error_received_from_server error
592
+ end
593
+ end
594
+ end
595
+ end
596
+
485
597
  context 'with invalid auth details' do
486
598
  let(:client_options) { default_options.merge(key: 'this.is:invalid', log_level: :none) }
487
599
 
@@ -693,6 +805,18 @@ describe Ably::Realtime::Connection, :event_machine do
693
805
  end
694
806
 
695
807
  context '#close' do
808
+ let(:close_connection_proc) do
809
+ lambda do
810
+ EventMachine.add_timer(0.001) do
811
+ if connection.transport.nil?
812
+ close_connection_proc.call
813
+ else
814
+ connection.transport.close_connection_after_writing
815
+ end
816
+ end
817
+ end
818
+ end
819
+
696
820
  it 'returns a SafeDeferrable that catches exceptions in callbacks and logs them' do
697
821
  connection.connect do
698
822
  expect(connection.close).to be_a(Ably::Util::SafeDeferrable)
@@ -754,6 +878,56 @@ describe Ably::Realtime::Connection, :event_machine do
754
878
  end
755
879
  end
756
880
 
881
+ context ':connecting RTN12f' do
882
+ context ":connected does not arrive when trying to close" do
883
+ it 'moves to closed' do
884
+ connection.on(:closed) do |state_change|
885
+ state_changes = connection.state_history.map { |t| t[:state].to_sym }
886
+
887
+ expect(state_changes).to eq([:connecting, :closing, :closed])
888
+ stop_reactor
889
+ end
890
+
891
+ connection.on(:connecting) do
892
+ connection.close
893
+ connection.__outgoing_protocol_msgbus__.unsubscribe
894
+ end
895
+
896
+ connection.connect
897
+ end
898
+ end
899
+
900
+ context ":connected arrive when trying to close" do
901
+ let(:protocol_message_attributes) do
902
+ {
903
+ action: Ably::Models::ProtocolMessage::ACTION.Connected.to_i,
904
+ connection_serial: 55,
905
+ connection_details: {
906
+ max_idle_interval: 2 * 1000
907
+ }
908
+ }
909
+ end
910
+
911
+ it 'moves to connected and then to closed' do
912
+ connection.on(:closed) do |state_change|
913
+ state_changes = connection.state_history.map { |t| t[:state].to_sym }
914
+
915
+ expect(state_changes).to eq([:connecting, :connected, :closing, :closed])
916
+ stop_reactor
917
+ end
918
+
919
+ connection.on(:connecting) do
920
+ connection.__outgoing_protocol_msgbus__.unsubscribe
921
+
922
+ connection.__incoming_protocol_msgbus__.publish :protocol_message, Ably::Models::ProtocolMessage.new(protocol_message_attributes)
923
+ connection.close
924
+ end
925
+
926
+ connection.connect
927
+ end
928
+ end
929
+ end
930
+
757
931
  context ':connected' do
758
932
  it 'changes the connection state to :closing and waits for the server to confirm connection is :closed with a ProtocolMessage' do
759
933
  connection.on(:connected) do
@@ -800,6 +974,81 @@ describe Ably::Realtime::Connection, :event_machine do
800
974
  end
801
975
  end
802
976
  end
977
+
978
+ context ':suspended RTN12d' do
979
+ let(:suspended_retry_timeout) { 60 }
980
+ let(:client_options) do
981
+ default_options.merge(
982
+ disconnected_retry_timeout: 0.02,
983
+ suspended_retry_timeout: suspended_retry_timeout,
984
+ connection_state_ttl: 0
985
+ )
986
+ end
987
+
988
+ it 'immediatly closes connection' do
989
+ connection.on(:connecting) { close_connection_proc.call }
990
+ connection.on(:suspended) do |connection_state_change|
991
+ if connection_state_change.retry_in.zero?
992
+ # Exhausting immediate retries
993
+ connection.once(:connecting) { close_connection_proc.call }
994
+ else
995
+ suspended_at = Time.now.to_f
996
+ connection.on(:closed) do
997
+ expect(connection_state_change.retry_in).to eq(suspended_retry_timeout)
998
+ expect(connection.state).to eq(:closed)
999
+ expect(Time.now.to_f).to be_within(4).of(suspended_at)
1000
+ stop_reactor
1001
+ end
1002
+
1003
+ connection.close
1004
+ end
1005
+
1006
+ connection.connect
1007
+ end
1008
+
1009
+ connection.connect
1010
+ end
1011
+ end
1012
+
1013
+ context ':disconnected RTN12d' do
1014
+ let(:retry_timeout) { 60 }
1015
+ let(:client_options) do
1016
+ default_options.merge(
1017
+ disconnected_retry_timeout: retry_timeout,
1018
+ suspended_retry_timeout: retry_timeout,
1019
+ connection_state_ttl: 0
1020
+ )
1021
+ end
1022
+
1023
+ it 'immediatly closes connection' do
1024
+ connection.once(:connected) do
1025
+ connection.on(:disconnected) do |connection_state_change|
1026
+ disconnected_at = Time.now.to_f
1027
+ connection.on(:connected) do
1028
+ if connection_state_change.retry_in.zero?
1029
+ # Exhausting immediate retries
1030
+ close_connection_proc.call
1031
+ else
1032
+ connection.once(:closed) do
1033
+ expect(connection_state_change.retry_in).to eq(retry_timeout)
1034
+ expect(connection.state).to eq(:closed)
1035
+ expect(Time.now.to_f).to be_within(4).of(disconnected_at)
1036
+ stop_reactor
1037
+ end
1038
+
1039
+ connection.close
1040
+ end
1041
+ end
1042
+
1043
+ connection.connect
1044
+ end
1045
+
1046
+ close_connection_proc.call
1047
+ end
1048
+
1049
+ connection.connect
1050
+ end
1051
+ end
803
1052
  end
804
1053
  end
805
1054
 
@@ -2634,7 +2634,24 @@ describe Ably::Realtime::Presence, :event_machine do
2634
2634
  end
2635
2635
  end
2636
2636
 
2637
- context 'channel state side effects' do
2637
+ context 'channel state side effects (RTP5)' do
2638
+ context 'channel transitions to the ATTACHED state (RTP5b)' do
2639
+ it 'all queued presence messages are sent' do
2640
+ channel_client_one.on(:attached) do
2641
+ client_one.connection.__outgoing_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
2642
+ if protocol_message.action == :presence
2643
+ expect(protocol_message.action).to eq(:presence)
2644
+ stop_reactor
2645
+ end
2646
+ end
2647
+ end
2648
+
2649
+ presence_client_one.enter do
2650
+ channel_client_one.attach
2651
+ end
2652
+ end
2653
+ end
2654
+
2638
2655
  context 'channel transitions to the FAILED state' do
2639
2656
  let(:anonymous_client) { auto_close Ably::Realtime::Client.new(client_options.merge(log_level: :fatal)) }
2640
2657
  let(:client_one) { auto_close Ably::Realtime::Client.new(client_options.merge(client_id: client_one_id, log_level: :fatal)) }