ably 1.2.5 → 1.2.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/check.yml +1 -1
  3. data/CHANGELOG.md +17 -0
  4. data/README.md +24 -7
  5. data/SPEC.md +1722 -853
  6. data/ably.gemspec +1 -1
  7. data/lib/ably/auth.rb +19 -11
  8. data/lib/ably/models/protocol_message.rb +5 -26
  9. data/lib/ably/modules/safe_deferrable.rb +2 -2
  10. data/lib/ably/modules/state_emitter.rb +1 -1
  11. data/lib/ably/realtime/auth.rb +4 -0
  12. data/lib/ably/realtime/channel/channel_manager.rb +51 -48
  13. data/lib/ably/realtime/channel/channel_properties.rb +9 -0
  14. data/lib/ably/realtime/channel/channel_state_machine.rb +2 -0
  15. data/lib/ably/realtime/channel.rb +4 -3
  16. data/lib/ably/realtime/channels.rb +20 -0
  17. data/lib/ably/realtime/client/incoming_message_dispatcher.rb +14 -13
  18. data/lib/ably/realtime/client.rb +14 -6
  19. data/lib/ably/realtime/connection/connection_manager.rb +21 -22
  20. data/lib/ably/realtime/connection.rb +77 -109
  21. data/lib/ably/realtime/presence/members_map.rb +41 -92
  22. data/lib/ably/realtime/presence/presence_manager.rb +12 -17
  23. data/lib/ably/realtime/presence.rb +15 -6
  24. data/lib/ably/realtime/push.rb +0 -27
  25. data/lib/ably/realtime/recovery_key_context.rb +36 -0
  26. data/lib/ably/rest/client.rb +4 -6
  27. data/lib/ably/rest/push/admin.rb +1 -1
  28. data/lib/ably/rest/push.rb +0 -19
  29. data/lib/ably/util/ably_extensions.rb +29 -0
  30. data/lib/ably/util/crypto.rb +2 -2
  31. data/lib/ably/util/safe_deferrable.rb +1 -1
  32. data/lib/ably/version.rb +5 -7
  33. data/spec/acceptance/realtime/channel_history_spec.rb +8 -12
  34. data/spec/acceptance/realtime/channel_spec.rb +474 -300
  35. data/spec/acceptance/realtime/client_spec.rb +1 -1
  36. data/spec/acceptance/realtime/connection_failures_spec.rb +8 -25
  37. data/spec/acceptance/realtime/connection_spec.rb +28 -120
  38. data/spec/acceptance/realtime/message_spec.rb +23 -52
  39. data/spec/acceptance/realtime/presence_spec.rb +123 -92
  40. data/spec/acceptance/rest/channel_spec.rb +2 -2
  41. data/spec/acceptance/rest/client_spec.rb +9 -2
  42. data/spec/acceptance/rest/message_spec.rb +8 -11
  43. data/spec/acceptance/rest/push_admin_spec.rb +20 -15
  44. data/spec/shared/client_initializer_behaviour.rb +1 -1
  45. data/spec/support/markdown_spec_formatter.rb +1 -1
  46. data/spec/unit/models/protocol_message_spec.rb +0 -78
  47. data/spec/unit/models/token_details_spec.rb +4 -2
  48. data/spec/unit/realtime/channels_spec.rb +1 -1
  49. data/spec/unit/realtime/connection_spec.rb +0 -30
  50. data/spec/unit/realtime/recovery_key_context_spec.rb +36 -0
  51. data/spec/unit/util/crypto_spec.rb +15 -15
  52. metadata +9 -9
  53. data/spec/acceptance/realtime/push_spec.rb +0 -27
  54. data/spec/acceptance/rest/push_spec.rb +0 -25
@@ -342,8 +342,10 @@ describe Ably::Realtime::Channel, :event_machine do
342
342
  channel.attach
343
343
  end
344
344
 
345
- channel.attach do
346
- channel.detach
345
+ client.connection.once :connected do
346
+ channel.attach do
347
+ channel.detach
348
+ end
347
349
  end
348
350
  end
349
351
  end
@@ -430,9 +432,35 @@ describe Ably::Realtime::Channel, :event_machine do
430
432
  end
431
433
 
432
434
  context 'with connection state' do
435
+
436
+ sent_attach_messages = []
437
+ received_attached_messages = []
438
+ before(:each) do
439
+ sent_attach_messages = []
440
+ received_attached_messages = []
441
+ client.connection.__outgoing_protocol_msgbus__.subscribe do |message|
442
+ if message.action == :attach
443
+ sent_attach_messages << message
444
+ end
445
+ end
446
+ client.connection.__incoming_protocol_msgbus__.subscribe do |message|
447
+ if message.action == :attached
448
+ received_attached_messages << message
449
+ end
450
+ end
451
+ end
452
+
453
+ # Should send/receive attach/attached message only once
454
+ # No duplicates should be sent or received
455
+ let(:check_for_attach_messages) do
456
+ expect(sent_attach_messages.size).to eq(1)
457
+ expect(received_attached_messages.size).to eq(1)
458
+ end
459
+
433
460
  it 'is initialized (#RTL4i)' do
434
461
  expect(connection).to be_initialized
435
462
  channel.attach do
463
+ check_for_attach_messages
436
464
  stop_reactor
437
465
  end
438
466
  end
@@ -440,6 +468,7 @@ describe Ably::Realtime::Channel, :event_machine do
440
468
  it 'is connecting (#RTL4i)' do
441
469
  connection.once(:connecting) do
442
470
  channel.attach do
471
+ check_for_attach_messages
443
472
  stop_reactor
444
473
  end
445
474
  end
@@ -449,6 +478,7 @@ describe Ably::Realtime::Channel, :event_machine do
449
478
  connection.once(:connected) do
450
479
  connection.once(:disconnected) do
451
480
  channel.attach do
481
+ check_for_attach_messages
452
482
  stop_reactor
453
483
  end
454
484
  end
@@ -467,7 +497,9 @@ describe Ably::Realtime::Channel, :event_machine do
467
497
  stop_reactor
468
498
  end
469
499
 
470
- channel.attach
500
+ client.connection.once :connected do
501
+ channel.attach
502
+ end
471
503
  end
472
504
  end
473
505
 
@@ -488,7 +520,9 @@ describe Ably::Realtime::Channel, :event_machine do
488
520
  channel.detach
489
521
  end
490
522
 
491
- channel.attach
523
+ client.connection.once :connected do
524
+ channel.attach
525
+ end
492
526
  end
493
527
  end
494
528
  end
@@ -497,23 +531,29 @@ describe Ably::Realtime::Channel, :event_machine do
497
531
  describe '#detach' do
498
532
  context 'when state is :attached' do
499
533
  it 'it detaches from a channel (#RTL5d)' do
500
- channel.attach do
534
+ channel.once :attached do
501
535
  channel.detach
502
536
  channel.on(:detached) do
503
537
  expect(channel.state).to eq(:detached)
504
538
  stop_reactor
505
539
  end
506
540
  end
541
+ connection.once :connected do
542
+ channel.attach
543
+ end
507
544
  end
508
545
 
509
546
  it 'detaches from a channel and calls the provided block (#RTL5d, #RTL5e)' do
510
- channel.attach do
547
+ channel.once :attached do
511
548
  expect(channel.state).to eq(:attached)
512
549
  channel.detach do
513
550
  expect(channel.state).to eq(:detached)
514
551
  stop_reactor
515
552
  end
516
553
  end
554
+ connection.once :connected do
555
+ channel.attach
556
+ end
517
557
  end
518
558
 
519
559
  it 'emits :detaching then :detached events' do
@@ -523,26 +563,34 @@ describe Ably::Realtime::Channel, :event_machine do
523
563
  end
524
564
  end
525
565
 
526
- channel.attach do
527
- channel.detach
566
+ connection.once :connected do
567
+ channel.attach do
568
+ channel.detach
569
+ end
528
570
  end
529
571
  end
530
572
 
531
573
  it 'returns a SafeDeferrable that catches exceptions in callbacks and logs them' do
532
- channel.attach do
574
+ channel.once :attached do
533
575
  expect(channel.detach).to be_a(Ably::Util::SafeDeferrable)
534
576
  stop_reactor
535
577
  end
578
+ connection.once :connected do
579
+ channel.attach
580
+ end
536
581
  end
537
582
 
538
583
  it 'calls the Deferrable callback on success' do
539
- channel.attach do
584
+ channel.once :attached do
540
585
  channel.detach.callback do
541
586
  expect(channel).to be_a(Ably::Realtime::Channel)
542
587
  expect(channel.state).to eq(:detached)
543
588
  stop_reactor
544
589
  end
545
590
  end
591
+ connection.once :connected do
592
+ channel.attach
593
+ end
546
594
  end
547
595
 
548
596
  context 'and DETACHED message is not received within realtime request timeout' do
@@ -551,7 +599,6 @@ describe Ably::Realtime::Channel, :event_machine do
551
599
 
552
600
  it 'fails the deferrable and returns to the previous state (#RTL5f, #RTL5e)' do
553
601
  channel.attach do
554
- # don't process any incoming ProtocolMessages so the channel never becomes detached
555
602
  connection.__incoming_protocol_msgbus__.unsubscribe
556
603
  detached_requested_at = Time.now.to_i
557
604
  channel.detach do
@@ -566,6 +613,7 @@ describe Ably::Realtime::Channel, :event_machine do
566
613
  end
567
614
  end
568
615
 
616
+
569
617
  context 'when state is :failed' do
570
618
  let(:client_options) { default_options.merge(log_level: :fatal) }
571
619
 
@@ -609,15 +657,17 @@ describe Ably::Realtime::Channel, :event_machine do
609
657
  channel.detach
610
658
  end
611
659
 
612
- channel.attach do
613
- channel.detach
660
+ connection.once :connected do
661
+ channel.attach do
662
+ channel.detach
663
+ end
614
664
  end
615
665
  end
616
666
  end
617
667
 
618
668
  context 'when state is :suspended' do
619
669
  it 'moves the channel state immediately to DETACHED state (#RTL5j)' do
620
- channel.attach do
670
+ channel.once :attached do
621
671
  channel.once(:suspended) do
622
672
  channel.on do |channel_state_change|
623
673
  expect(channel_state_change.current).to eq(:detached)
@@ -632,6 +682,9 @@ describe Ably::Realtime::Channel, :event_machine do
632
682
  end
633
683
  channel.transition_state_machine :suspended
634
684
  end
685
+ connection.once :connected do
686
+ channel.attach
687
+ end
635
688
  end
636
689
  end
637
690
 
@@ -655,7 +708,7 @@ describe Ably::Realtime::Channel, :event_machine do
655
708
 
656
709
  context 'when state is :detached' do
657
710
  it 'does nothing as the channel is detached (#RTL5a)' do
658
- channel.attach do
711
+ channel.once :attached do
659
712
  channel.detach do
660
713
  expect(channel).to be_detached
661
714
  channel.on do
@@ -666,6 +719,9 @@ describe Ably::Realtime::Channel, :event_machine do
666
719
  end
667
720
  end
668
721
  end
722
+ connection.once :connected do
723
+ channel.attach
724
+ end
669
725
  end
670
726
  end
671
727
 
@@ -735,8 +791,10 @@ describe Ably::Realtime::Channel, :event_machine do
735
791
  context 'initialized' do
736
792
  it 'does the detach operation once the connection state is connected (#RTL5h)' do
737
793
  expect(connection).to be_initialized
794
+ channel.on :attaching do
795
+ channel.detach
796
+ end
738
797
  channel.attach
739
- channel.detach
740
798
  connection.once(:connected) do
741
799
  channel.once(:attached) do
742
800
  channel.once(:detached) do
@@ -750,8 +808,10 @@ describe Ably::Realtime::Channel, :event_machine do
750
808
  context 'connecting' do
751
809
  it 'does the detach operation once the connection state is connected (#RTL5h)' do
752
810
  connection.once(:connecting) do
811
+ channel.on :attaching do
812
+ channel.detach
813
+ end
753
814
  channel.attach
754
- channel.detach
755
815
  connection.once(:connected) do
756
816
  channel.once(:attached) do
757
817
  channel.once(:detached) do
@@ -877,84 +937,92 @@ describe Ably::Realtime::Channel, :event_machine do
877
937
  describe '#(RTL17)' do
878
938
  context 'when channel is initialized' do
879
939
  it 'sends messages only on attach' do
880
- expect(channel).to be_initialized
881
- channel.publish('event', payload)
940
+ connection.once :connected do
941
+ expect(channel).to be_initialized
942
+ channel.publish('event', payload)
882
943
 
883
- channel.subscribe do |message|
884
- stop_reactor if message.data == payload && channel.attached?
885
- end
944
+ channel.subscribe do |message|
945
+ stop_reactor if message.data == payload && channel.attached?
946
+ end
886
947
 
887
- channel.attach
948
+ channel.attach
949
+ end
888
950
  end
889
951
  end
890
952
 
891
953
  context 'when channel is attaching' do
892
954
  it 'sends messages only on attach' do
893
- channel.publish('event', payload)
955
+ connection.once :connected do
956
+ channel.publish('event', payload)
894
957
 
895
- sent_message = nil
896
- channel.subscribe do |message|
897
- return if message.data != payload
898
- sent_message = message
958
+ sent_message = nil
959
+ channel.subscribe do |message|
960
+ return if message.data != payload
961
+ sent_message = message
899
962
 
900
- stop_reactor if channel.attached?
901
- end
963
+ stop_reactor if channel.attached?
964
+ end
902
965
 
903
- channel.on(:attaching) do
904
- expect(channel).to be_attaching
905
- expect(sent_message).to be_nil
906
- end
966
+ channel.on(:attaching) do
967
+ expect(channel).to be_attaching
968
+ expect(sent_message).to be_nil
969
+ end
907
970
 
908
- channel.attach
971
+ channel.attach
972
+ end
909
973
  end
910
974
  end
911
975
 
912
976
  context 'when channel is detaching' do
913
977
  it 'stops sending message' do
914
- sent_message = nil
915
- event_published = false
916
- channel.subscribe do |message|
917
- sent_message = message if message.data == payload
918
- end
978
+ connection.once :connected do
979
+ sent_message = nil
980
+ event_published = false
981
+ channel.subscribe do |message|
982
+ sent_message = message if message.data == payload
983
+ end
919
984
 
920
- channel.on(:detaching) do
921
- channel.publish('event', payload)
922
- event_published = true
923
- end
985
+ channel.on(:detaching) do
986
+ channel.publish('event', payload)
987
+ event_published = true
988
+ end
924
989
 
925
- channel.on(:detaching) do
926
- EventMachine.next_tick do
927
- expect(sent_message).to be_nil
928
- stop_reactor if event_published
990
+ channel.on(:detaching) do
991
+ EventMachine.next_tick do
992
+ expect(sent_message).to be_nil
993
+ stop_reactor if event_published
994
+ end
929
995
  end
930
- end
931
996
 
932
- channel.attach do
933
- channel.detach
997
+ channel.attach do
998
+ channel.detach
999
+ end
934
1000
  end
935
1001
  end
936
1002
  end
937
1003
 
938
1004
  context 'when channel is detached' do
939
1005
  it 'stops sending message' do
940
- sent_message = nil
941
- event_published = false
942
- channel.subscribe do |message|
943
- sent_message = message if message.data == payload
944
- end
1006
+ connection.once :connected do
1007
+ sent_message = nil
1008
+ event_published = false
1009
+ channel.subscribe do |message|
1010
+ sent_message = message if message.data == payload
1011
+ end
945
1012
 
946
- channel.on(:detaching) do
947
- channel.publish('event', payload)
948
- event_published = true
949
- end
1013
+ channel.on(:detaching) do
1014
+ channel.publish('event', payload)
1015
+ event_published = true
1016
+ end
950
1017
 
951
- channel.on(:detached) do
952
- expect(sent_message).to be_nil
953
- stop_reactor if event_published
954
- end
1018
+ channel.on(:detached) do
1019
+ expect(sent_message).to be_nil
1020
+ stop_reactor if event_published
1021
+ end
955
1022
 
956
- channel.attach do
957
- channel.detach
1023
+ channel.attach do
1024
+ channel.detach
1025
+ end
958
1026
  end
959
1027
  end
960
1028
  end
@@ -968,8 +1036,10 @@ describe Ably::Realtime::Channel, :event_machine do
968
1036
  end
969
1037
  end
970
1038
 
971
- channel.attach do
972
- channel.transition_state_machine(:failed)
1039
+ connection.once :connected do
1040
+ channel.attach do
1041
+ channel.transition_state_machine(:failed)
1042
+ end
973
1043
  end
974
1044
  end
975
1045
  end
@@ -1019,7 +1089,7 @@ describe Ably::Realtime::Channel, :event_machine do
1019
1089
 
1020
1090
  context 'when channel is Detaching (#RTL6c1)' do
1021
1091
  it 'publishes messages immediately (#RTL6c1)' do
1022
- sub_channel.attach do
1092
+ sub_channel.once :attached do
1023
1093
  channel.attach do
1024
1094
  channel.once(:detaching) do
1025
1095
  outgoing_message_count = 0
@@ -1041,32 +1111,37 @@ describe Ably::Realtime::Channel, :event_machine do
1041
1111
  channel.detach
1042
1112
  end
1043
1113
  end
1114
+ connection.once :connected do
1115
+ sub_channel.attach
1116
+ end
1044
1117
  end
1045
1118
  end
1046
1119
 
1047
1120
  context 'when channel is Detached (#RTL6c1)' do
1048
1121
  it 'publishes messages immediately (#RTL6c1)' do
1049
- sub_channel.attach do
1050
- channel.attach
1051
- channel.once(:attached) do
1052
- channel.once(:detached) do
1053
- outgoing_message_count = 0
1054
- client.connection.__outgoing_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
1055
- if protocol_message.action == :message
1056
- raise "Expected channel state to be attaching when publishing messages, not #{channel.state}" unless channel.detached?
1057
- outgoing_message_count += protocol_message.messages.count
1122
+ connection.once :connected do
1123
+ sub_channel.attach do
1124
+ channel.attach
1125
+ channel.once(:attached) do
1126
+ channel.once(:detached) do
1127
+ outgoing_message_count = 0
1128
+ client.connection.__outgoing_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
1129
+ if protocol_message.action == :message
1130
+ raise "Expected channel state to be attaching when publishing messages, not #{channel.state}" unless channel.detached?
1131
+ outgoing_message_count += protocol_message.messages.count
1132
+ end
1058
1133
  end
1059
- end
1060
- sub_channel.subscribe do |message|
1061
- messages << message if message.name == 'event'
1062
- if messages.count == 3
1063
- expect(outgoing_message_count).to eql(3)
1064
- stop_reactor
1134
+ sub_channel.subscribe do |message|
1135
+ messages << message if message.name == 'event'
1136
+ if messages.count == 3
1137
+ expect(outgoing_message_count).to eql(3)
1138
+ stop_reactor
1139
+ end
1065
1140
  end
1141
+ 3.times { channel.publish('event', random_str) }
1066
1142
  end
1067
- 3.times { channel.publish('event', random_str) }
1143
+ channel.detach
1068
1144
  end
1069
- channel.detach
1070
1145
  end
1071
1146
  end
1072
1147
  end
@@ -1429,12 +1504,14 @@ describe Ably::Realtime::Channel, :event_machine do
1429
1504
 
1430
1505
  context 'with a valid client_id in the message' do
1431
1506
  it 'succeeds' do
1432
- channel.publish([name: 'event', client_id: 'validClient']).tap do |deferrable|
1433
- deferrable.errback { raise 'Should have succeeded' }
1434
- end
1435
- channel.subscribe('event') do |message|
1436
- expect(message.client_id).to eql('validClient')
1437
- EM.add_timer(0.5) { stop_reactor }
1507
+ connection.once :connected do
1508
+ channel.publish([name: 'event', client_id: 'validClient']).tap do |deferrable|
1509
+ deferrable.errback { raise 'Should have succeeded' }
1510
+ end
1511
+ channel.subscribe('event') do |message|
1512
+ expect(message.client_id).to eql('validClient')
1513
+ EM.add_timer(0.5) { stop_reactor }
1514
+ end
1438
1515
  end
1439
1516
  end
1440
1517
  end
@@ -1455,12 +1532,14 @@ describe Ably::Realtime::Channel, :event_machine do
1455
1532
 
1456
1533
  context 'with an empty client_id in the message' do
1457
1534
  it 'succeeds and publishes without a client_id' do
1458
- channel.publish([name: 'event', client_id: nil]).tap do |deferrable|
1459
- deferrable.errback { raise 'Should have succeeded' }
1460
- end
1461
- channel.subscribe('event') do |message|
1462
- expect(message.client_id).to be_nil
1463
- EM.add_timer(0.5) { stop_reactor }
1535
+ connection.once :connected do
1536
+ channel.publish([name: 'event', client_id: nil]).tap do |deferrable|
1537
+ deferrable.errback { raise 'Should have succeeded' }
1538
+ end
1539
+ channel.subscribe('event') do |message|
1540
+ expect(message.client_id).to be_nil
1541
+ EM.add_timer(0.5) { stop_reactor }
1542
+ end
1464
1543
  end
1465
1544
  end
1466
1545
  end
@@ -1475,20 +1554,25 @@ describe Ably::Realtime::Channel, :event_machine do
1475
1554
  context 'before the client is CONNECTED and the client\'s identity has been obtained' do
1476
1555
  context 'with a valid client_id in the message' do
1477
1556
  it 'succeeds' do
1478
- channel.publish([name: 'event', client_id: 'valid']).tap do |deferrable|
1479
- deferrable.errback { raise 'Should have succeeded' }
1480
- end
1481
- channel.subscribe('event') do |message|
1482
- expect(message.client_id).to eql('valid')
1483
- EM.add_timer(0.5) { stop_reactor }
1557
+ connection.once :connected do
1558
+ channel.publish([name: 'event', client_id: 'valid']).tap do |deferrable|
1559
+ deferrable.errback { raise 'Should have succeeded' }
1560
+ end
1561
+ channel.subscribe('event') do |message|
1562
+ expect(message.client_id).to eql('valid')
1563
+ EM.add_timer(0.5) { stop_reactor }
1564
+ end
1484
1565
  end
1485
1566
  end
1486
1567
  end
1487
1568
 
1488
1569
  context 'with an invalid client_id in the message' do
1489
1570
  let(:client_options) { default_options.merge(key: nil, token: token, log_level: :error) }
1490
- it 'succeeds in the client library but then fails when delivered to Ably' do
1571
+ it 'succeeds in the client library ( while connecting ) but then fails when delivered to Ably' do
1491
1572
  channel.publish([name: 'event', client_id: 'invalid']).tap do |deferrable|
1573
+ deferrable.errback do |err|
1574
+ expect(err).to be_truthy
1575
+ end
1492
1576
  EM.add_timer(0.5) { stop_reactor }
1493
1577
  end
1494
1578
  channel.subscribe('event') do |message|
@@ -1499,12 +1583,14 @@ describe Ably::Realtime::Channel, :event_machine do
1499
1583
 
1500
1584
  context 'with an empty client_id in the message' do
1501
1585
  it 'succeeds and publishes with an implicit client_id' do
1502
- channel.publish([name: 'event', client_id: nil]).tap do |deferrable|
1503
- deferrable.errback { raise 'Should have succeeded' }
1504
- end
1505
- channel.subscribe('event') do |message|
1506
- expect(message.client_id).to eql('valid')
1507
- EM.add_timer(0.5) { stop_reactor }
1586
+ connection.once :connected do
1587
+ channel.publish([name: 'event', client_id: nil]).tap do |deferrable|
1588
+ deferrable.errback { raise 'Should have succeeded' }
1589
+ end
1590
+ channel.subscribe('event') do |message|
1591
+ expect(message.client_id).to eql('valid')
1592
+ EM.add_timer(0.5) { stop_reactor }
1593
+ end
1508
1594
  end
1509
1595
  end
1510
1596
  end
@@ -1558,12 +1644,14 @@ describe Ably::Realtime::Channel, :event_machine do
1558
1644
 
1559
1645
  context 'with a valid client_id' do
1560
1646
  it 'succeeds' do
1561
- channel.publish([name: 'event', client_id: 'valid']).tap do |deferrable|
1562
- deferrable.errback { raise 'Should have succeeded' }
1563
- end
1564
- channel.subscribe('event') do |message|
1565
- expect(message.client_id).to eql('valid')
1566
- EM.add_timer(0.5) { stop_reactor }
1647
+ connection.once :connected do
1648
+ channel.publish([name: 'event', client_id: 'valid']).tap do |deferrable|
1649
+ deferrable.errback { raise 'Should have succeeded' }
1650
+ end
1651
+ channel.subscribe('event') do |message|
1652
+ expect(message.client_id).to eql('valid')
1653
+ EM.add_timer(0.5) { stop_reactor }
1654
+ end
1567
1655
  end
1568
1656
  end
1569
1657
  end
@@ -1584,12 +1672,14 @@ describe Ably::Realtime::Channel, :event_machine do
1584
1672
 
1585
1673
  context 'with an empty client_id in the message' do
1586
1674
  it 'succeeds and publishes with an implicit client_id' do
1587
- channel.publish([name: 'event', client_id: nil]).tap do |deferrable|
1588
- deferrable.errback { raise 'Should have succeeded' }
1589
- end
1590
- channel.subscribe('event') do |message|
1591
- expect(message.client_id).to eql('valid')
1592
- EM.add_timer(0.5) { stop_reactor }
1675
+ connection.once :connected do
1676
+ channel.publish([name: 'event', client_id: nil]).tap do |deferrable|
1677
+ deferrable.errback { raise 'Should have succeeded' }
1678
+ end
1679
+ channel.subscribe('event') do |message|
1680
+ expect(message.client_id).to eql('valid')
1681
+ EM.add_timer(0.5) { stop_reactor }
1682
+ end
1593
1683
  end
1594
1684
  end
1595
1685
  end
@@ -1617,12 +1707,14 @@ describe Ably::Realtime::Channel, :event_machine do
1617
1707
 
1618
1708
  context 'with an empty client_id in the message' do
1619
1709
  it 'succeeds and publishes with an implicit client_id' do
1620
- channel.publish([name: 'event', client_id: nil]).tap do |deferrable|
1621
- deferrable.errback { raise 'Should have succeeded' }
1622
- end
1623
- channel.subscribe('event') do |message|
1624
- expect(message.client_id).to be_nil
1625
- EM.add_timer(0.5) { stop_reactor }
1710
+ connection.once :connected do
1711
+ channel.publish([name: 'event', client_id: nil]).tap do |deferrable|
1712
+ deferrable.errback { raise 'Should have succeeded' }
1713
+ end
1714
+ channel.subscribe('event') do |message|
1715
+ expect(message.client_id).to be_nil
1716
+ EM.add_timer(0.5) { stop_reactor }
1717
+ end
1626
1718
  end
1627
1719
  end
1628
1720
  end
@@ -1766,18 +1858,20 @@ describe Ably::Realtime::Channel, :event_machine do
1766
1858
  let(:exception) { StandardError.new("Intentional error") }
1767
1859
 
1768
1860
  it 'logs the error and continues' do
1769
- emitted_exception = false
1770
- expect(client.logger).to receive(:error) do |*args, &block|
1771
- expect(args.concat([block ? block.call : nil]).join(',')).to match(/#{exception.message}/)
1772
- end
1773
- channel.subscribe('click') do |message|
1774
- emitted_exception = true
1775
- raise exception
1776
- end
1777
- channel.publish('click', 'data') do
1778
- EventMachine.add_timer(1) do
1779
- expect(emitted_exception).to eql(true)
1780
- stop_reactor
1861
+ connection.once :connected do
1862
+ emitted_exception = false
1863
+ expect(client.logger).to receive(:error) do |*args, &block|
1864
+ expect(args.concat([block ? block.call : nil]).join(',')).to match(/#{exception.message}/)
1865
+ end
1866
+ channel.subscribe('click') do |message|
1867
+ emitted_exception = true
1868
+ raise exception
1869
+ end
1870
+ channel.publish('click', 'data') do
1871
+ EventMachine.add_timer(1) do
1872
+ expect(emitted_exception).to eql(true)
1873
+ stop_reactor
1874
+ end
1781
1875
  end
1782
1876
  end
1783
1877
  end
@@ -1785,19 +1879,21 @@ describe Ably::Realtime::Channel, :event_machine do
1785
1879
 
1786
1880
  context 'many times with different event names' do
1787
1881
  it 'filters events accordingly to each callback' do
1788
- click_callback = lambda { |message| messages << message }
1882
+ connection.once :connected do
1883
+ click_callback = lambda { |message| messages << message }
1789
1884
 
1790
- channel.subscribe('click', &click_callback)
1791
- channel.subscribe('move', &click_callback)
1792
- channel.subscribe('press', &click_callback)
1885
+ channel.subscribe('click', &click_callback)
1886
+ channel.subscribe('move', &click_callback)
1887
+ channel.subscribe('press', &click_callback)
1793
1888
 
1794
- channel.attach do
1795
- channel.publish('click', 'data')
1796
- channel.publish('move', 'data')
1797
- channel.publish('press', 'data') do
1798
- EventMachine.add_timer(2) do
1799
- expect(messages.count).to eql(3)
1800
- stop_reactor
1889
+ channel.attach do
1890
+ channel.publish('click', 'data')
1891
+ channel.publish('move', 'data')
1892
+ channel.publish('press', 'data') do
1893
+ EventMachine.add_timer(2) do
1894
+ expect(messages.count).to eql(3)
1895
+ stop_reactor
1896
+ end
1801
1897
  end
1802
1898
  end
1803
1899
  end
@@ -1808,12 +1904,14 @@ describe Ably::Realtime::Channel, :event_machine do
1808
1904
  describe '#unsubscribe' do
1809
1905
  context 'with an event argument' do
1810
1906
  it 'unsubscribes for a single event' do
1811
- channel.subscribe('click') { raise 'Should not have been called' }
1812
- channel.unsubscribe('click')
1907
+ connection.once :connected do
1908
+ channel.subscribe('click') { raise 'Should not have been called' }
1909
+ channel.unsubscribe('click')
1813
1910
 
1814
- channel.publish('click', 'data') do
1815
- EventMachine.add_timer(1) do
1816
- stop_reactor
1911
+ channel.publish('click', 'data') do
1912
+ EventMachine.add_timer(1) do
1913
+ stop_reactor
1914
+ end
1817
1915
  end
1818
1916
  end
1819
1917
  end
@@ -1821,12 +1919,14 @@ describe Ably::Realtime::Channel, :event_machine do
1821
1919
 
1822
1920
  context 'with no event argument' do
1823
1921
  it 'unsubscribes for a single event' do
1824
- channel.subscribe { raise 'Should not have been called' }
1825
- channel.unsubscribe
1922
+ connection.once :connected do
1923
+ channel.subscribe { raise 'Should not have been called' }
1924
+ channel.unsubscribe
1826
1925
 
1827
- channel.publish('click', 'data') do
1828
- EventMachine.add_timer(1) do
1829
- stop_reactor
1926
+ channel.publish('click', 'data') do
1927
+ EventMachine.add_timer(1) do
1928
+ stop_reactor
1929
+ end
1830
1930
  end
1831
1931
  end
1832
1932
  end
@@ -1861,33 +1961,37 @@ describe Ably::Realtime::Channel, :event_machine do
1861
1961
 
1862
1962
  context 'an :attached channel' do
1863
1963
  it 'transitions state to :failed (#RTL3a)' do
1864
- channel.attach do
1865
- channel.on(:failed) do |connection_state_change|
1866
- error = connection_state_change.reason
1867
- expect(error).to be_a(Ably::Exceptions::ConnectionFailed)
1868
- expect(error.code).to eql(50000)
1869
- stop_reactor
1964
+ connection.once :connected do
1965
+ channel.attach do
1966
+ channel.on(:failed) do |connection_state_change|
1967
+ error = connection_state_change.reason
1968
+ expect(error).to be_a(Ably::Exceptions::ConnectionFailed)
1969
+ expect(error.code).to eql(50000)
1970
+ stop_reactor
1971
+ end
1972
+ fake_error connection_error
1870
1973
  end
1871
- fake_error connection_error
1872
1974
  end
1873
1975
  end
1874
1976
 
1875
1977
  it 'updates the channel error_reason (#RTL3a)' do
1876
- channel.attach do
1877
- channel.on(:failed) do |connection_state_change|
1878
- error = connection_state_change.reason
1879
- expect(error).to be_a(Ably::Exceptions::ConnectionFailed)
1880
- expect(error.code).to eql(50000)
1881
- stop_reactor
1978
+ connection.once :connected do
1979
+ channel.attach do
1980
+ channel.on(:failed) do |connection_state_change|
1981
+ error = connection_state_change.reason
1982
+ expect(error).to be_a(Ably::Exceptions::ConnectionFailed)
1983
+ expect(error.code).to eql(50000)
1984
+ stop_reactor
1985
+ end
1986
+ fake_error connection_error
1882
1987
  end
1883
- fake_error connection_error
1884
1988
  end
1885
1989
  end
1886
1990
  end
1887
1991
 
1888
1992
  context 'a :detached channel' do
1889
1993
  it 'remains in the :detached state (#RTL3a)' do
1890
- channel.attach do
1994
+ channel.once :attached do
1891
1995
  channel.on(:failed) { raise 'Failed state should not have been reached' }
1892
1996
 
1893
1997
  channel.detach do
@@ -1899,6 +2003,10 @@ describe Ably::Realtime::Channel, :event_machine do
1899
2003
  fake_error connection_error
1900
2004
  end
1901
2005
  end
2006
+
2007
+ connection.once :connected do
2008
+ channel.attach
2009
+ end
1902
2010
  end
1903
2011
  end
1904
2012
 
@@ -1906,20 +2014,22 @@ describe Ably::Realtime::Channel, :event_machine do
1906
2014
  let(:original_error) { RuntimeError.new }
1907
2015
 
1908
2016
  it 'remains in the :failed state and ignores the failure error (#RTL3a)' do
1909
- channel.attach do
1910
- channel.on(:failed) do
1911
- channel.on(:failed) { raise 'Failed state should not have been reached' }
2017
+ connection.once :connected do
2018
+ channel.attach do
2019
+ channel.on(:failed) do
2020
+ channel.on(:failed) { raise 'Failed state should not have been reached' }
1912
2021
 
1913
- EventMachine.add_timer(1) do
1914
- expect(channel).to be_failed
1915
- expect(channel.error_reason).to eql(original_error)
1916
- stop_reactor
2022
+ EventMachine.add_timer(1) do
2023
+ expect(channel).to be_failed
2024
+ expect(channel.error_reason).to eql(original_error)
2025
+ stop_reactor
2026
+ end
2027
+
2028
+ fake_error connection_error
1917
2029
  end
1918
2030
 
1919
- fake_error connection_error
2031
+ channel.transition_state_machine :failed, reason: original_error
1920
2032
  end
1921
-
1922
- channel.transition_state_machine :failed, reason: original_error
1923
2033
  end
1924
2034
  end
1925
2035
  end
@@ -1942,11 +2052,13 @@ describe Ably::Realtime::Channel, :event_machine do
1942
2052
  context ':closed' do
1943
2053
  context 'an :attached channel' do
1944
2054
  it 'transitions state to :detached (#RTL3b)' do
1945
- channel.attach do
1946
- channel.on(:detached) do
1947
- stop_reactor
2055
+ connection.once :connected do
2056
+ channel.attach do
2057
+ channel.on(:detached) do
2058
+ stop_reactor
2059
+ end
2060
+ client.connection.close
1948
2061
  end
1949
- client.connection.close
1950
2062
  end
1951
2063
  end
1952
2064
  end
@@ -1962,13 +2074,15 @@ describe Ably::Realtime::Channel, :event_machine do
1962
2074
  closed_message = Ably::Models::ProtocolMessage.new(action: 8) # CLOSED
1963
2075
  client.connection.__incoming_protocol_msgbus__.publish :protocol_message, closed_message
1964
2076
  end
1965
- channel.attach
2077
+ connection.once :connected do
2078
+ channel.attach
2079
+ end
1966
2080
  end
1967
2081
  end
1968
2082
 
1969
2083
  context 'a :detached channel' do
1970
2084
  it 'remains in the :detached state (#RTL3b)' do
1971
- channel.attach do
2085
+ channel.once :attached do
1972
2086
  channel.detach do
1973
2087
  channel.on(:detached) { raise 'Detached state should not have been reached' }
1974
2088
 
@@ -1980,6 +2094,9 @@ describe Ably::Realtime::Channel, :event_machine do
1980
2094
  client.connection.close
1981
2095
  end
1982
2096
  end
2097
+ connection.once :connected do
2098
+ channel.attach
2099
+ end
1983
2100
  end
1984
2101
  end
1985
2102
 
@@ -1988,20 +2105,22 @@ describe Ably::Realtime::Channel, :event_machine do
1988
2105
  let(:original_error) { Ably::Models::ErrorInfo.new(message: 'Error') }
1989
2106
 
1990
2107
  it 'remains in the :failed state and retains the error_reason (#RTL3b)' do
1991
- channel.attach do
1992
- channel.once(:failed) do
1993
- channel.on(:detached) { raise 'Detached state should not have been reached' }
2108
+ connection.on :connected do
2109
+ channel.attach do
2110
+ channel.once(:failed) do
2111
+ channel.on(:detached) { raise 'Detached state should not have been reached' }
1994
2112
 
1995
- EventMachine.add_timer(1) do
1996
- expect(channel).to be_failed
1997
- expect(channel.error_reason).to eql(original_error)
1998
- stop_reactor
2113
+ EventMachine.add_timer(1) do
2114
+ expect(channel).to be_failed
2115
+ expect(channel.error_reason).to eql(original_error)
2116
+ stop_reactor
2117
+ end
2118
+
2119
+ client.connection.close
1999
2120
  end
2000
2121
 
2001
- client.connection.close
2122
+ channel.transition_state_machine :failed, reason: original_error
2002
2123
  end
2003
-
2004
- channel.transition_state_machine :failed, reason: original_error
2005
2124
  end
2006
2125
  end
2007
2126
  end
@@ -2046,23 +2165,26 @@ describe Ably::Realtime::Channel, :event_machine do
2046
2165
  client.connection.transition_state_machine :suspended
2047
2166
  end
2048
2167
  end
2049
- channel.attach
2168
+ channel.attach
2050
2169
  end
2051
2170
  end
2052
2171
 
2053
2172
  context 'an :attached channel' do
2054
2173
  it 'transitions state to :suspended (#RTL3c)' do
2055
- channel.attach do
2174
+ channel.once :attached do
2056
2175
  channel.on(:suspended) do
2057
2176
  stop_reactor
2058
2177
  end
2059
2178
  client.connection.transition_state_machine :suspended
2060
2179
  end
2180
+ connection.once :connected do
2181
+ channel.attach
2182
+ end
2061
2183
  end
2062
2184
 
2063
2185
  describe 'reattaching (#RTN15c3)' do
2064
2186
  it 'transitions state automatically to :attaching once the connection is re-established ' do
2065
- channel.attach do
2187
+ channel.once :attached do
2066
2188
  channel.on(:suspended) do
2067
2189
  client.connection.connect
2068
2190
  channel.once(:attached) do
@@ -2071,10 +2193,13 @@ describe Ably::Realtime::Channel, :event_machine do
2071
2193
  end
2072
2194
  client.connection.transition_state_machine :suspended
2073
2195
  end
2196
+ connection.once :connected do
2197
+ channel.attach
2198
+ end
2074
2199
  end
2075
2200
 
2076
2201
  it 'sends ATTACH_RESUME flag when reattaching (RTL4j)' do
2077
- channel.attach do
2202
+ channel.once :attached do
2078
2203
  channel.on(:suspended) do
2079
2204
  client.connection.__outgoing_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
2080
2205
  next if protocol_message.action != :attach
@@ -2087,13 +2212,16 @@ describe Ably::Realtime::Channel, :event_machine do
2087
2212
  end
2088
2213
  client.connection.transition_state_machine :suspended
2089
2214
  end
2215
+ connection.once :connected do
2216
+ channel.attach
2217
+ end
2090
2218
  end
2091
2219
  end
2092
2220
  end
2093
2221
 
2094
2222
  context 'a :detached channel' do
2095
2223
  it 'remains in the :detached state (#RTL3c)' do
2096
- channel.attach do
2224
+ channel.once :attached do
2097
2225
  channel.detach do
2098
2226
  channel.on(:detached) { raise 'Detached state should not have been reached' }
2099
2227
 
@@ -2105,6 +2233,9 @@ describe Ably::Realtime::Channel, :event_machine do
2105
2233
  client.connection.transition_state_machine :suspended
2106
2234
  end
2107
2235
  end
2236
+ connection.once :connected do
2237
+ channel.attach
2238
+ end
2108
2239
  end
2109
2240
  end
2110
2241
 
@@ -2113,20 +2244,22 @@ describe Ably::Realtime::Channel, :event_machine do
2113
2244
  let(:client_options) { default_options.merge(log_level: :fatal) }
2114
2245
 
2115
2246
  it 'remains in the :failed state and retains the error_reason (#RTL3c)' do
2116
- channel.attach do
2117
- channel.once(:failed) do
2118
- channel.on(:detached) { raise 'Detached state should not have been reached' }
2247
+ connection.once :connected do
2248
+ channel.attach do
2249
+ channel.once(:failed) do
2250
+ channel.on(:detached) { raise 'Detached state should not have been reached' }
2119
2251
 
2120
- EventMachine.add_timer(1) do
2121
- expect(channel).to be_failed
2122
- expect(channel.error_reason).to eql(original_error)
2123
- stop_reactor
2252
+ EventMachine.add_timer(1) do
2253
+ expect(channel).to be_failed
2254
+ expect(channel.error_reason).to eql(original_error)
2255
+ stop_reactor
2256
+ end
2257
+
2258
+ client.connection.transition_state_machine :suspended
2124
2259
  end
2125
2260
 
2126
- client.connection.transition_state_machine :suspended
2261
+ channel.transition_state_machine :failed, reason: original_error
2127
2262
  end
2128
-
2129
- channel.transition_state_machine :failed, reason: original_error
2130
2263
  end
2131
2264
  end
2132
2265
  end
@@ -2151,14 +2284,16 @@ describe Ably::Realtime::Channel, :event_machine do
2151
2284
  context ':connected' do
2152
2285
  context 'a :suspended channel' do
2153
2286
  it 'is automatically reattached (#RTL3d)' do
2154
- channel.attach do
2155
- channel.once(:suspended) do
2156
- client.connection.connect
2157
- channel.once(:attached) do
2158
- stop_reactor
2287
+ connection.once :connected do
2288
+ channel.attach do
2289
+ channel.once(:suspended) do
2290
+ client.connection.connect
2291
+ channel.once(:attached) do
2292
+ stop_reactor
2293
+ end
2159
2294
  end
2295
+ client.connection.transition_state_machine :suspended
2160
2296
  end
2161
- client.connection.transition_state_machine :suspended
2162
2297
  end
2163
2298
  end
2164
2299
 
@@ -2168,29 +2303,32 @@ describe Ably::Realtime::Channel, :event_machine do
2168
2303
  end
2169
2304
 
2170
2305
  it 'returns to a suspended state (#RTL3d)' do
2171
- channel.attach do
2172
- channel.once(:attached) do
2173
- fail "Channel should not have become attached"
2174
- end
2306
+ connection.once :connected do
2307
+ channel.attach do
2308
+ channel.once(:attached) do
2309
+ fail "Channel should not have become attached"
2310
+ end
2175
2311
 
2176
- channel.once(:suspended) do
2177
- client.connection.connect
2178
- channel.once(:attaching) do
2179
- # don't process any incoming ProtocolMessages so the connection never opens
2180
- client.connection.__incoming_protocol_msgbus__.unsubscribe
2181
- channel.once(:suspended) do |state_change|
2182
- expect(state_change.reason.code).to eql(90007)
2183
- stop_reactor
2312
+ channel.once(:suspended) do
2313
+ client.connection.connect
2314
+ channel.once(:attaching) do
2315
+ # don't process any incoming ProtocolMessages so the connection never opens
2316
+ client.connection.__incoming_protocol_msgbus__.unsubscribe
2317
+ channel.once(:suspended) do |state_change|
2318
+ expect(state_change.reason.code).to eql(90007)
2319
+ stop_reactor
2320
+ end
2184
2321
  end
2185
2322
  end
2323
+ client.connection.transition_state_machine :suspended
2186
2324
  end
2187
- client.connection.transition_state_machine :suspended
2188
2325
  end
2189
2326
  end
2190
2327
  end
2191
2328
  end
2192
2329
  end
2193
2330
 
2331
+
2194
2332
  context ':disconnected' do
2195
2333
  context 'with an initialized channel' do
2196
2334
  it 'has no effect on the channel states (#RTL3e)' do
@@ -2222,25 +2360,31 @@ describe Ably::Realtime::Channel, :event_machine do
2222
2360
 
2223
2361
  context 'with an attached channel' do
2224
2362
  it 'has no effect on the channel states (#RTL3e)' do
2225
- channel.attach do
2363
+ channel.once :attached do
2226
2364
  connection.once(:disconnected) do
2227
2365
  expect(channel).to be_attached
2228
2366
  stop_reactor
2229
2367
  end
2230
2368
  disconnect_transport
2231
2369
  end
2370
+
2371
+ connection.once :connected do
2372
+ channel.attach
2373
+ end
2232
2374
  end
2233
2375
  end
2234
2376
 
2235
2377
  context 'with a detached channel' do
2236
2378
  it 'has no effect on the channel states (#RTL3e)' do
2237
- channel.attach do
2238
- channel.detach do
2239
- connection.once(:disconnected) do
2240
- expect(channel).to be_detached
2241
- stop_reactor
2379
+ connection.once :connected do
2380
+ channel.attach do
2381
+ channel.detach do
2382
+ connection.once(:disconnected) do
2383
+ expect(channel).to be_detached
2384
+ stop_reactor
2385
+ end
2386
+ disconnect_transport
2242
2387
  end
2243
- disconnect_transport
2244
2388
  end
2245
2389
  end
2246
2390
  end
@@ -2288,12 +2432,12 @@ describe Ably::Realtime::Channel, :event_machine do
2288
2432
 
2289
2433
  shared_examples 'an update that sends ATTACH message' do |state, flags|
2290
2434
  it 'sends an ATTACH message on options change' do
2291
- attach_sent = nil
2435
+ attach_sent_with_flags_set_via_channel_options = nil
2292
2436
 
2293
2437
  client.connection.__outgoing_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
2294
2438
  if protocol_message.action == :attach && protocol_message.flags.nonzero?
2295
- attach_sent = true
2296
2439
  expect(protocol_message.flags).to eq(flags)
2440
+ attach_sent_with_flags_set_via_channel_options = true
2297
2441
  end
2298
2442
  end
2299
2443
 
@@ -2302,10 +2446,7 @@ describe Ably::Realtime::Channel, :event_machine do
2302
2446
  end
2303
2447
 
2304
2448
  channel.on(:attached) do
2305
- client.connection.__incoming_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
2306
- next if protocol_message.action != :attached
2307
-
2308
- expect(attach_sent).to eq(true)
2449
+ wait_until(lambda { attach_sent_with_flags_set_via_channel_options }) do
2309
2450
  stop_reactor
2310
2451
  end
2311
2452
  end
@@ -2318,7 +2459,7 @@ describe Ably::Realtime::Channel, :event_machine do
2318
2459
  it_behaves_like 'an update that sends ATTACH message', :attaching, build_flags(%i[subscribe])
2319
2460
  end
2320
2461
 
2321
- context 'when channel is attaching' do
2462
+ context 'when channel is attached' do
2322
2463
  it_behaves_like 'an update that sends ATTACH message', :attached, build_flags(%i[resume subscribe])
2323
2464
  end
2324
2465
 
@@ -2389,8 +2530,10 @@ describe Ably::Realtime::Channel, :event_machine do
2389
2530
  expect(channel_state_change.reason).to be_nil
2390
2531
  stop_reactor
2391
2532
  end
2392
- channel.attach do
2393
- channel.detach
2533
+ connection.once :connected do
2534
+ channel.attach do
2535
+ channel.detach
2536
+ end
2394
2537
  end
2395
2538
  end
2396
2539
 
@@ -2426,7 +2569,7 @@ describe Ably::Realtime::Channel, :event_machine do
2426
2569
  connection_id = client.connection.id
2427
2570
  expect(channel_state_change.resumed).to be_falsey
2428
2571
 
2429
- recover_client = auto_close Ably::Realtime::Client.new(client_options.merge(recover: client.connection.recovery_key))
2572
+ recover_client = auto_close Ably::Realtime::Client.new(client_options.merge(recover: client.connection.create_recovery_key))
2430
2573
  recover_client.connection.once(:connected) do
2431
2574
  expect(recover_client.connection.id).to eql(connection_id)
2432
2575
  recover_channel = recover_client.channels.get(channel_name)
@@ -2441,7 +2584,7 @@ describe Ably::Realtime::Channel, :event_machine do
2441
2584
 
2442
2585
  it 'is false when a connection fails to recover and the channel is attached' do
2443
2586
  client.connection.once(:connected) do
2444
- recovery_key = client.connection.recovery_key
2587
+ recovery_key = client.connection.create_recovery_key
2445
2588
  client.connection.once(:closed) do
2446
2589
  recover_client = auto_close Ably::Realtime::Client.new(client_options.merge(recover: recovery_key, log_level: :error))
2447
2590
  recover_client.connection.once(:connected) do
@@ -2458,11 +2601,11 @@ describe Ably::Realtime::Channel, :event_machine do
2458
2601
  end
2459
2602
  end
2460
2603
 
2461
- context 'when a resume fails' do
2604
+ context 'when a connection resume fails' do
2462
2605
  let(:client_options) { default_options.merge(log_level: :error) }
2463
2606
 
2464
- it 'is false when a resume fails to recover and the channel is automatically re-attached' do
2465
- channel.attach do
2607
+ it 'is false when channel_serial goes nil (RTP5a1) and the channel is automatically re-attached' do
2608
+ channel.once :attached do
2466
2609
  connection_id = client.connection.id
2467
2610
  channel.once(:attached) do |channel_state_change|
2468
2611
  expect(client.connection.id).to_not eql(connection_id)
@@ -2470,7 +2613,29 @@ describe Ably::Realtime::Channel, :event_machine do
2470
2613
  stop_reactor
2471
2614
  end
2472
2615
  client.connection.transport.close_connection_after_writing
2473
- client.connection.configure_new '0123456789abcdef', 'wVIsgTHAB1UvXh7z-1991d8586', -1 # force the resume connection key to be invalid
2616
+ channel.properties.channel_serial = nil
2617
+ client.connection.configure_new '0123456789abcdef', 'wVIsgTHAB1UvXh7z-1991d8586' # force the resume connection key to be invalid
2618
+ end
2619
+
2620
+ connection.once :connected do
2621
+ channel.attach
2622
+ end
2623
+ end
2624
+
2625
+ it 'is true when channel_serial is intact and the channel is automatically re-attached' do
2626
+ channel.once :attached do
2627
+ connection_id = client.connection.id
2628
+ channel.once(:attached) do |channel_state_change|
2629
+ expect(client.connection.id).to_not eql(connection_id)
2630
+ expect(channel_state_change.resumed).to be_truthy
2631
+ stop_reactor
2632
+ end
2633
+ client.connection.transport.close_connection_after_writing
2634
+ client.connection.configure_new '0123456789abcdef', 'wVIsgTHAB1UvXh7z-1991d8586' # force the resume connection key to be invalid
2635
+ end
2636
+
2637
+ connection.once :connected do
2638
+ channel.attach
2474
2639
  end
2475
2640
  end
2476
2641
  end
@@ -2601,7 +2766,9 @@ describe Ably::Realtime::Channel, :event_machine do
2601
2766
  client.connection.__incoming_protocol_msgbus__.publish :protocol_message, detach_message
2602
2767
  end
2603
2768
 
2604
- channel.attach
2769
+ connection.once :connected do
2770
+ channel.attach
2771
+ end
2605
2772
  end
2606
2773
  end
2607
2774
 
@@ -2632,26 +2799,30 @@ describe Ably::Realtime::Channel, :event_machine do
2632
2799
  client.connection.__incoming_protocol_msgbus__.publish :protocol_message, detach_message
2633
2800
  end
2634
2801
 
2635
- channel.attach
2802
+ connection.once :connected do
2803
+ channel.attach
2804
+ end
2636
2805
  end
2637
2806
 
2638
2807
  context 'when connection is no longer connected' do
2639
2808
  it 'will not attempt to reattach (#RTL13c)' do
2640
- channel.attach do
2641
- connection.once(:closing) do
2642
- channel.once(:attaching) do |state_change|
2643
- raise 'Channel should not attempt to reattach'
2809
+ connection.once :connected do
2810
+ channel.attach do
2811
+ connection.once(:closing) do
2812
+ channel.once(:attaching) do |state_change|
2813
+ raise 'Channel should not attempt to reattach'
2814
+ end
2815
+
2816
+ channel.transition_state_machine! :suspended
2644
2817
  end
2645
2818
 
2646
- channel.transition_state_machine! :suspended
2647
- end
2819
+ connection.once(:closed) do
2820
+ expect(channel).to be_suspended
2821
+ stop_reactor
2822
+ end
2648
2823
 
2649
- connection.once(:closed) do
2650
- expect(channel).to be_suspended
2651
- stop_reactor
2824
+ connection.close
2652
2825
  end
2653
-
2654
- connection.close
2655
2826
  end
2656
2827
  end
2657
2828
  end
@@ -2672,35 +2843,36 @@ describe Ably::Realtime::Channel, :event_machine do
2672
2843
  end
2673
2844
  end
2674
2845
  prevent_protocol_messages_proc.call
2675
- end
2676
2846
 
2677
- channel.once(:attaching) do
2678
- attaching_at = Time.now
2679
- # First attaching fails during server-initiated ATTACHED received
2680
- channel.once(:suspended) do |state_change|
2681
- expect(Time.now.to_i - attaching_at.to_i).to be_within(1).of(1)
2682
-
2683
- suspended_at = Time.now
2684
- # Automatic attach happens at channel_retry_timeout
2685
- channel.once(:attaching) do
2686
- expect(Time.now.to_i - attaching_at.to_i).to be_within(1).of(2)
2687
- channel.once(:suspended) do
2688
- channel.once(:attaching) do
2689
- channel.once(:attached) do
2690
- stop_reactor
2847
+ channel.once(:attaching) do
2848
+ attaching_at = Time.now
2849
+ # First attaching fails during server-initiated ATTACHED received
2850
+ channel.once(:suspended) do |state_change|
2851
+ expect(Time.now.to_i - attaching_at.to_i).to be_within(1).of(1)
2852
+
2853
+ suspended_at = Time.now
2854
+ # Automatic attach happens at channel_retry_timeout
2855
+ channel.once(:attaching) do
2856
+ expect(Time.now.to_i - attaching_at.to_i).to be_within(1).of(2)
2857
+ channel.once(:suspended) do
2858
+ channel.once(:attaching) do
2859
+ channel.once(:attached) do
2860
+ stop_reactor
2861
+ end
2862
+ # Simulate ATTACHED from Ably
2863
+ attached_message = Ably::Models::ProtocolMessage.new(action: 11, channel: channel_name) # ATTACHED
2864
+ client.connection.__incoming_protocol_msgbus__.publish :protocol_message, attached_message
2691
2865
  end
2692
- # Simulate ATTACHED from Ably
2693
- attached_message = Ably::Models::ProtocolMessage.new(action: 11, channel: channel_name) # ATTACHED
2694
- client.connection.__incoming_protocol_msgbus__.publish :protocol_message, attached_message
2695
2866
  end
2696
2867
  end
2697
2868
  end
2869
+
2870
+ detach_message = Ably::Models::ProtocolMessage.new(action: detached_action, channel: channel_name)
2871
+ client.connection.__incoming_protocol_msgbus__.publish :protocol_message, detach_message
2698
2872
  end
2699
2873
 
2700
- detach_message = Ably::Models::ProtocolMessage.new(action: detached_action, channel: channel_name)
2701
- client.connection.__incoming_protocol_msgbus__.publish :protocol_message, detach_message
2874
+ channel.attach
2702
2875
  end
2703
- channel.attach
2704
2876
  end
2705
2877
  end
2706
2878
  end
@@ -2709,14 +2881,16 @@ describe Ably::Realtime::Channel, :event_machine do
2709
2881
  let(:client_options) { default_options.merge(log_level: :fatal) }
2710
2882
 
2711
2883
  it 'should transition to the failed state and the error_reason should be set (#RTL14)' do
2712
- channel.attach do
2713
- channel.once(:failed) do |state_change|
2714
- expect(state_change.reason.code).to eql(50505)
2715
- expect(channel.error_reason.code).to eql(50505)
2716
- stop_reactor
2884
+ connection.once :connected do
2885
+ channel.attach do
2886
+ channel.once(:failed) do |state_change|
2887
+ expect(state_change.reason.code).to eql(50505)
2888
+ expect(channel.error_reason.code).to eql(50505)
2889
+ stop_reactor
2890
+ end
2891
+ error_message = Ably::Models::ProtocolMessage.new(action: 9, channel: channel_name, error: { code: 50505 }) # ProtocolMessage ERROR type
2892
+ client.connection.__incoming_protocol_msgbus__.publish :protocol_message, error_message
2717
2893
  end
2718
- error_message = Ably::Models::ProtocolMessage.new(action: 9, channel: channel_name, error: { code: 50505 }) # ProtocolMessage ERROR type
2719
- client.connection.__incoming_protocol_msgbus__.publish :protocol_message, error_message
2720
2894
  end
2721
2895
  end
2722
2896
  end