ably 1.1.6 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/check.yml +15 -1
  3. data/CHANGELOG.md +131 -0
  4. data/COPYRIGHT +1 -1
  5. data/README.md +14 -2
  6. data/SPEC.md +0 -7
  7. data/UPDATING.md +30 -0
  8. data/ably.gemspec +12 -7
  9. data/lib/ably/agent.rb +3 -0
  10. data/lib/ably/auth.rb +3 -3
  11. data/lib/ably/exceptions.rb +6 -0
  12. data/lib/ably/models/channel_options.rb +97 -0
  13. data/lib/ably/models/connection_details.rb +8 -0
  14. data/lib/ably/models/delta_extras.rb +29 -0
  15. data/lib/ably/models/error_info.rb +6 -2
  16. data/lib/ably/models/idiomatic_ruby_wrapper.rb +4 -0
  17. data/lib/ably/models/message.rb +28 -3
  18. data/lib/ably/models/presence_message.rb +14 -0
  19. data/lib/ably/models/protocol_message.rb +29 -12
  20. data/lib/ably/models/token_details.rb +7 -2
  21. data/lib/ably/modules/channels_collection.rb +22 -2
  22. data/lib/ably/modules/conversions.rb +34 -0
  23. data/lib/ably/realtime/channel/channel_manager.rb +18 -6
  24. data/lib/ably/realtime/channel/channel_state_machine.rb +10 -1
  25. data/lib/ably/realtime/channel/publisher.rb +6 -0
  26. data/lib/ably/realtime/channel.rb +54 -22
  27. data/lib/ably/realtime/channels.rb +1 -1
  28. data/lib/ably/realtime/client/incoming_message_dispatcher.rb +14 -6
  29. data/lib/ably/realtime/connection/connection_manager.rb +13 -4
  30. data/lib/ably/realtime/connection/connection_state_machine.rb +4 -0
  31. data/lib/ably/realtime/connection.rb +2 -2
  32. data/lib/ably/rest/channel.rb +31 -31
  33. data/lib/ably/rest/client.rb +27 -12
  34. data/lib/ably/util/crypto.rb +1 -1
  35. data/lib/ably/version.rb +2 -14
  36. data/lib/ably.rb +1 -0
  37. data/spec/acceptance/realtime/auth_spec.rb +1 -1
  38. data/spec/acceptance/realtime/channel_history_spec.rb +25 -0
  39. data/spec/acceptance/realtime/channel_spec.rb +466 -21
  40. data/spec/acceptance/realtime/channels_spec.rb +59 -7
  41. data/spec/acceptance/realtime/connection_failures_spec.rb +59 -2
  42. data/spec/acceptance/realtime/connection_spec.rb +256 -28
  43. data/spec/acceptance/realtime/message_spec.rb +77 -0
  44. data/spec/acceptance/realtime/presence_history_spec.rb +3 -1
  45. data/spec/acceptance/realtime/presence_spec.rb +31 -159
  46. data/spec/acceptance/rest/auth_spec.rb +18 -0
  47. data/spec/acceptance/rest/channel_spec.rb +84 -9
  48. data/spec/acceptance/rest/channels_spec.rb +23 -6
  49. data/spec/acceptance/rest/client_spec.rb +25 -21
  50. data/spec/acceptance/rest/message_spec.rb +61 -3
  51. data/spec/lib/unit/models/channel_options_spec.rb +52 -0
  52. data/spec/shared/model_behaviour.rb +1 -1
  53. data/spec/spec_helper.rb +11 -2
  54. data/spec/support/test_app.rb +1 -1
  55. data/spec/unit/models/delta_extras_spec.rb +14 -0
  56. data/spec/unit/models/error_info_spec.rb +17 -1
  57. data/spec/unit/models/message_spec.rb +97 -0
  58. data/spec/unit/models/presence_message_spec.rb +49 -0
  59. data/spec/unit/models/protocol_message_spec.rb +125 -27
  60. data/spec/unit/models/token_details_spec.rb +14 -0
  61. data/spec/unit/realtime/channel_spec.rb +3 -2
  62. data/spec/unit/realtime/channels_spec.rb +53 -15
  63. data/spec/unit/realtime/incoming_message_dispatcher_spec.rb +38 -0
  64. data/spec/unit/rest/channel_spec.rb +44 -1
  65. data/spec/unit/rest/channels_spec.rb +81 -14
  66. data/spec/unit/rest/client_spec.rb +47 -0
  67. metadata +60 -24
@@ -117,6 +117,94 @@ describe Ably::Realtime::Channel, :event_machine do
117
117
  end
118
118
  end
119
119
 
120
+ context 'context when channel options contain modes' do
121
+ before do
122
+ channel.options = { modes: %i[publish] }
123
+ end
124
+
125
+ it 'sends an ATTACH with options as flags (#RTL4l)' do
126
+ connection.once(:connected) do
127
+ client.connection.__outgoing_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
128
+ next if protocol_message.action != :attach
129
+
130
+ expect(protocol_message.has_attach_publish_flag?).to eq(true)
131
+ stop_reactor
132
+ end
133
+
134
+ channel.attach
135
+ end
136
+ end
137
+
138
+ context 'when channel is reattaching' do
139
+ it 'sends ATTACH_RESUME flag along with other modes (RTL4j)' do
140
+ channel.attach do
141
+ channel.on(:suspended) do
142
+ client.connection.__outgoing_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
143
+ next if protocol_message.action != :attach
144
+
145
+ expect(protocol_message.has_attach_resume_flag?).to eq(true)
146
+ expect(protocol_message.has_attach_publish_flag?).to eq(true)
147
+ stop_reactor
148
+ end
149
+
150
+ client.connection.connect
151
+ end
152
+ client.connection.transition_state_machine :suspended
153
+ end
154
+ end
155
+ end
156
+ end
157
+
158
+ context 'context when channel options contain params' do
159
+ let(:params) do
160
+ { foo: 'foo', bar: 'bar'}
161
+ end
162
+
163
+ before do
164
+ channel.options = { params: params }
165
+ end
166
+
167
+ it 'sends an ATTACH with params (#RTL4k)' do
168
+ connection.once(:connected) do
169
+ client.connection.__outgoing_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
170
+ next if protocol_message.action != :attach
171
+
172
+ expect(protocol_message.params).to eq(params)
173
+ stop_reactor
174
+ end
175
+
176
+ channel.attach
177
+ end
178
+ end
179
+ end
180
+
181
+ context 'when received attached' do
182
+ it 'decodes flags and sets it as modes on channel options (#RTL4m)'do
183
+ channel.on(:attached) do
184
+ expect(channel.options.modes.map(&:to_sym)).to eq(%i[subscribe])
185
+ stop_reactor
186
+ end
187
+
188
+ channel.transition_state_machine(:attaching)
189
+ attached_message = Ably::Models::ProtocolMessage.new(action: 11, channel: channel_name, flags: 262144)
190
+ client.connection.__incoming_protocol_msgbus__.publish :protocol_message, attached_message
191
+ end
192
+
193
+ it 'set params as channel options params (#RTL4k1)' do
194
+ params = { param: :something }
195
+
196
+ channel.on(:attached) do
197
+ expect(channel.params).to eq(channel.options.params)
198
+ expect(channel.params).to eq(params)
199
+ stop_reactor
200
+ end
201
+
202
+ channel.transition_state_machine(:attaching)
203
+ attached_message = Ably::Models::ProtocolMessage.new(action: 11, channel: channel_name, params: params)
204
+ client.connection.__incoming_protocol_msgbus__.publish :protocol_message, attached_message
205
+ end
206
+ end
207
+
120
208
  it 'implicitly attaches the channel (#RTL7c)' do
121
209
  expect(channel).to be_initialized
122
210
  channel.subscribe { |message| }
@@ -368,6 +456,42 @@ describe Ably::Realtime::Channel, :event_machine do
368
456
  end
369
457
  end
370
458
  end
459
+
460
+ describe 'clean attach (RTL4j)' do
461
+ context "when channel wasn't previously attached" do
462
+ it "doesn't send ATTACH_RESUME" do
463
+ client.connection.__outgoing_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
464
+ next if protocol_message.action != :attach
465
+
466
+ expect(protocol_message.has_attach_resume_flag?).to eq(false)
467
+ stop_reactor
468
+ end
469
+
470
+ channel.attach
471
+ end
472
+ end
473
+
474
+ context "when channel was explicitly detached" do
475
+ it "doesn't send ATTACH_RESUME" do
476
+ channel.once(:detached) do
477
+ client.connection.__outgoing_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
478
+ next if protocol_message.action != :attach
479
+
480
+ expect(protocol_message.has_attach_resume_flag?).to eq(false)
481
+ stop_reactor
482
+ end
483
+
484
+ channel.attach
485
+ end
486
+
487
+ channel.once(:attached) do
488
+ channel.detach
489
+ end
490
+
491
+ channel.attach
492
+ end
493
+ end
494
+ end
371
495
  end
372
496
 
373
497
  describe '#detach' do
@@ -750,6 +874,107 @@ describe Ably::Realtime::Channel, :event_machine do
750
874
  end
751
875
  end
752
876
 
877
+ describe '#(RTL17)' do
878
+ context 'when channel is initialized' do
879
+ it 'sends messages only on attach' do
880
+ expect(channel).to be_initialized
881
+ channel.publish('event', payload)
882
+
883
+ channel.subscribe do |message|
884
+ stop_reactor if message.data == payload && channel.attached?
885
+ end
886
+
887
+ channel.attach
888
+ end
889
+ end
890
+
891
+ context 'when channel is attaching' do
892
+ it 'sends messages only on attach' do
893
+ channel.publish('event', payload)
894
+
895
+ sent_message = nil
896
+ channel.subscribe do |message|
897
+ return if message.data != payload
898
+ sent_message = message
899
+
900
+ stop_reactor if channel.attached?
901
+ end
902
+
903
+ channel.on(:attaching) do
904
+ expect(channel).to be_attaching
905
+ expect(sent_message).to be_nil
906
+ end
907
+
908
+ channel.attach
909
+ end
910
+ end
911
+
912
+ context 'when channel is detaching' do
913
+ 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
919
+
920
+ channel.on(:detaching) do
921
+ channel.publish('event', payload)
922
+ event_published = true
923
+ end
924
+
925
+ channel.on(:detaching) do
926
+ EventMachine.next_tick do
927
+ expect(sent_message).to be_nil
928
+ stop_reactor if event_published
929
+ end
930
+ end
931
+
932
+ channel.attach do
933
+ channel.detach
934
+ end
935
+ end
936
+ end
937
+
938
+ context 'when channel is detached' do
939
+ 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
945
+
946
+ channel.on(:detaching) do
947
+ channel.publish('event', payload)
948
+ event_published = true
949
+ end
950
+
951
+ channel.on(:detached) do
952
+ expect(sent_message).to be_nil
953
+ stop_reactor if event_published
954
+ end
955
+
956
+ channel.attach do
957
+ channel.detach
958
+ end
959
+ end
960
+ end
961
+
962
+ context 'when channel is failed' do
963
+ it 'errors when trying to send a message' do
964
+ channel.once(:failed) do
965
+ channel.publish('event', payload).errback do |error|
966
+ expect(error).to be_a(Ably::Exceptions::ChannelInactive)
967
+ stop_reactor
968
+ end
969
+ end
970
+
971
+ channel.attach do
972
+ channel.transition_state_machine(:failed)
973
+ end
974
+ end
975
+ end
976
+ end
977
+
753
978
  context 'when channel is not attached in state Initializing (#RTL6c1)' do
754
979
  it 'publishes messages immediately and does not implicitly attach (#RTL6c1)' do
755
980
  sub_channel.attach do
@@ -1181,7 +1406,7 @@ describe Ably::Realtime::Channel, :event_machine do
1181
1406
  end
1182
1407
 
1183
1408
  context 'with more than allowed messages in a single publish' do
1184
- let(:channel_name) { random_str }
1409
+ 65536
1185
1410
 
1186
1411
  it 'rejects the publish' do
1187
1412
  messages = (Ably::Realtime::Connection::MAX_PROTOCOL_MESSAGE_BATCH_SIZE + 1).times.map do
@@ -1403,6 +1628,103 @@ describe Ably::Realtime::Channel, :event_machine do
1403
1628
  end
1404
1629
  end
1405
1630
  end
1631
+
1632
+ context 'message size exceeded (#TO3l8)' do
1633
+ let(:client) { auto_close Ably::Realtime::Client.new(client_options) }
1634
+ let(:channel) { client.channels.get(channel_name) }
1635
+
1636
+ context 'and max_message_size is default (65536 bytes)' do
1637
+ let(:channel_name) { random_str }
1638
+ let(:max_message_size) { 65536 }
1639
+
1640
+ it 'should allow to send a message (32 bytes)' do
1641
+ client.connection.once(:connected) do
1642
+ channel.subscribe('event') do |msg|
1643
+ expect(msg.data).to eq('x' * 32)
1644
+ stop_reactor
1645
+ end
1646
+ channel.publish('event', 'x' * 32)
1647
+ end
1648
+ end
1649
+
1650
+ it 'should not allow to send a message (700000 bytes)' do
1651
+ client.connection.once(:connected) do
1652
+ connection_details = Ably::Models::ConnectionDetails.new(
1653
+ client.connection.details.attributes.attributes.merge('maxMessageSize' => max_message_size)
1654
+ )
1655
+ client.connection.set_connection_details(connection_details)
1656
+ expect(client.connection.details.max_message_size).to eq(65536)
1657
+ channel.publish('event', 'x' * 700000).errback do |error|
1658
+ expect(error).to be_instance_of(Ably::Exceptions::MaxMessageSizeExceeded)
1659
+ stop_reactor
1660
+ end
1661
+ end
1662
+ end
1663
+ end
1664
+
1665
+ context 'and max_message_size is customized (11 bytes)' do
1666
+ let(:max_message_size) { 11 }
1667
+
1668
+ context 'and the message size is 30 bytes' do
1669
+ let(:channel_name) { random_str }
1670
+
1671
+ it 'should not allow to send a message' do
1672
+ client.connection.once(:connected) do
1673
+ connection_details = Ably::Models::ConnectionDetails.new(
1674
+ client.connection.details.attributes.attributes.merge('maxMessageSize' => max_message_size)
1675
+ )
1676
+ client.connection.set_connection_details(connection_details)
1677
+ expect(client.connection.details.max_message_size).to eq(11)
1678
+ channel.publish('event', 'x' * 30).errback do |error|
1679
+ expect(error).to be_instance_of(Ably::Exceptions::MaxMessageSizeExceeded)
1680
+ stop_reactor
1681
+ end
1682
+ end
1683
+ end
1684
+ end
1685
+ end
1686
+
1687
+ context 'and max_message_size is nil' do
1688
+ let(:max_message_size) { nil }
1689
+
1690
+ context 'and the message size is 30 bytes' do
1691
+ let(:channel_name) { random_str }
1692
+
1693
+ it 'should allow to send a message' do
1694
+ client.connection.once(:connected) do
1695
+ connection_details = Ably::Models::ConnectionDetails.new(
1696
+ client.connection.details.attributes.attributes.merge('maxMessageSize' => max_message_size)
1697
+ )
1698
+ client.connection.set_connection_details(connection_details)
1699
+ expect(client.connection.details.max_message_size).to eq(65536)
1700
+ channel.subscribe('event') do |msg|
1701
+ expect(msg.data).to eq('x' * 30)
1702
+ stop_reactor
1703
+ end
1704
+ channel.publish('event', 'x' * 30)
1705
+ end
1706
+ end
1707
+ end
1708
+
1709
+ context 'and the message size is 65537 bytes' do
1710
+ let(:channel_name) { random_str }
1711
+
1712
+ it 'should not allow to send a message' do
1713
+ client.connection.once(:connected) do
1714
+ connection_details = Ably::Models::ConnectionDetails.new(
1715
+ client.connection.details.attributes.attributes.merge('maxMessageSize' => max_message_size)
1716
+ )
1717
+ client.connection.set_connection_details(connection_details)
1718
+ expect(client.connection.details.max_message_size).to eq(65536)
1719
+ channel.publish('event', 'x' * 65537).errback do |error|
1720
+ expect(error).to be_instance_of(Ably::Exceptions::MaxMessageSizeExceeded)
1721
+ stop_reactor
1722
+ end
1723
+ end
1724
+ end
1725
+ end
1726
+ end
1727
+ end
1406
1728
  end
1407
1729
 
1408
1730
  describe '#subscribe' do
@@ -1738,15 +2060,33 @@ describe Ably::Realtime::Channel, :event_machine do
1738
2060
  end
1739
2061
  end
1740
2062
 
1741
- it 'transitions state automatically to :attaching once the connection is re-established (#RTN15c3)' do
1742
- channel.attach do
1743
- channel.on(:suspended) do
1744
- client.connection.connect
1745
- channel.once(:attached) do
1746
- stop_reactor
2063
+ describe 'reattaching (#RTN15c3)' do
2064
+ it 'transitions state automatically to :attaching once the connection is re-established ' do
2065
+ channel.attach do
2066
+ channel.on(:suspended) do
2067
+ client.connection.connect
2068
+ channel.once(:attached) do
2069
+ stop_reactor
2070
+ end
1747
2071
  end
2072
+ client.connection.transition_state_machine :suspended
2073
+ end
2074
+ end
2075
+
2076
+ it 'sends ATTACH_RESUME flag when reattaching (RTL4j)' do
2077
+ channel.attach do
2078
+ channel.on(:suspended) do
2079
+ client.connection.__outgoing_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
2080
+ next if protocol_message.action != :attach
2081
+
2082
+ expect(protocol_message.has_attach_resume_flag?).to eq(true)
2083
+ stop_reactor
2084
+ end
2085
+
2086
+ client.connection.connect
2087
+ end
2088
+ client.connection.transition_state_machine :suspended
1748
2089
  end
1749
- client.connection.transition_state_machine :suspended
1750
2090
  end
1751
2091
  end
1752
2092
  end
@@ -1936,6 +2276,68 @@ describe Ably::Realtime::Channel, :event_machine do
1936
2276
  end
1937
2277
  end
1938
2278
 
2279
+ describe '#set_options (#RTL16a)' do
2280
+ let(:modes) { %i[subscribe] }
2281
+ let(:channel_options) do
2282
+ { modes: modes }
2283
+ end
2284
+
2285
+ def self.build_flags(flags)
2286
+ flags.map { |flag| Ably::Models::ProtocolMessage::ATTACH_FLAGS_MAPPING[flag] }.reduce(:|)
2287
+ end
2288
+
2289
+ shared_examples 'an update that sends ATTACH message' do |state, flags|
2290
+ it 'sends an ATTACH message on options change' do
2291
+ attach_sent = nil
2292
+
2293
+ client.connection.__outgoing_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
2294
+ if protocol_message.action == :attach && protocol_message.flags.nonzero?
2295
+ attach_sent = true
2296
+ expect(protocol_message.flags).to eq(flags)
2297
+ end
2298
+ end
2299
+
2300
+ channel.once(state) do
2301
+ channel.options = channel_options
2302
+ end
2303
+
2304
+ 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)
2309
+ stop_reactor
2310
+ end
2311
+ end
2312
+
2313
+ channel.attach
2314
+ end
2315
+ end
2316
+
2317
+ context 'when channel is attaching' do
2318
+ it_behaves_like 'an update that sends ATTACH message', :attaching, build_flags(%i[subscribe])
2319
+ end
2320
+
2321
+ context 'when channel is attaching' do
2322
+ it_behaves_like 'an update that sends ATTACH message', :attached, build_flags(%i[resume subscribe])
2323
+ end
2324
+
2325
+ context 'when channel is initialized' do
2326
+ it "doesn't send ATTACH message" do
2327
+ client.connection.__outgoing_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
2328
+ raise "Unexpected message" if protocol_message.action == :attach
2329
+ end
2330
+
2331
+ channel.options = channel_options
2332
+ expect(channel.options.modes.map(&:to_sym)).to eq(modes)
2333
+
2334
+ EventMachine.next_tick do
2335
+ stop_reactor
2336
+ end
2337
+ end
2338
+ end
2339
+ end
2340
+
1939
2341
  context 'channel state change' do
1940
2342
  it 'emits a ChannelStateChange object' do
1941
2343
  channel.on(:attached) do |channel_state_change|
@@ -2177,11 +2579,20 @@ describe Ably::Realtime::Channel, :event_machine do
2177
2579
  end
2178
2580
 
2179
2581
  context 'and channel is attached' do
2180
- it 'reattaches immediately (#RTL13a)' do
2181
- channel.attach do
2582
+ it 'reattaches immediately (#RTL13a) with ATTACH_RESUME flag(RTL4j)' do
2583
+ resume_flag = false
2584
+
2585
+ channel.once(:attached) do
2586
+ client.connection.__outgoing_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
2587
+ next if protocol_message.action != :attach
2588
+
2589
+ resume_flag = protocol_message.has_attach_resume_flag?
2590
+ end
2591
+
2182
2592
  channel.once(:attaching) do |state_change|
2183
2593
  expect(state_change.reason.code).to eql(50505)
2184
2594
  channel.once(:attached) do
2595
+ expect(resume_flag).to eq(true)
2185
2596
  stop_reactor
2186
2597
  end
2187
2598
  end
@@ -2189,25 +2600,59 @@ describe Ably::Realtime::Channel, :event_machine do
2189
2600
  detach_message = Ably::Models::ProtocolMessage.new(action: detached_action, channel: channel_name, error: { code: 50505 })
2190
2601
  client.connection.__incoming_protocol_msgbus__.publish :protocol_message, detach_message
2191
2602
  end
2603
+
2604
+ channel.attach
2192
2605
  end
2193
2606
  end
2194
2607
 
2195
2608
  context 'and channel is suspended' do
2196
- it 'reattaches immediately (#RTL13a)' do
2197
- channel.attach do
2198
- channel.once(:suspended) do
2199
- channel.once(:attaching) do |state_change|
2200
- expect(state_change.reason.code).to eql(50505)
2201
- channel.once(:attached) do
2202
- stop_reactor
2609
+ it 'reattaches immediately (#RTL13a) with ATTACH_RESUME flag(RTL4j)' do
2610
+ resume_flag = false
2611
+
2612
+ channel.once(:attached) do
2613
+ channel.transition_state_machine! :suspended
2614
+ end
2615
+
2616
+ channel.once(:suspended) do
2617
+ client.connection.__outgoing_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
2618
+ next if protocol_message.action != :attach
2619
+
2620
+ resume_flag = protocol_message.has_attach_resume_flag?
2621
+ end
2622
+
2623
+ channel.once(:attaching) do |state_change|
2624
+ expect(state_change.reason.code).to eql(50505)
2625
+ channel.once(:attached) do
2626
+ expect(resume_flag).to eq(true)
2627
+ stop_reactor
2628
+ end
2629
+ end
2630
+
2631
+ detach_message = Ably::Models::ProtocolMessage.new(action: detached_action, channel: channel_name, error: { code: 50505 })
2632
+ client.connection.__incoming_protocol_msgbus__.publish :protocol_message, detach_message
2633
+ end
2634
+
2635
+ channel.attach
2636
+ end
2637
+
2638
+ context 'when connection is no longer connected' do
2639
+ 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'
2203
2644
  end
2645
+
2646
+ channel.transition_state_machine! :suspended
2204
2647
  end
2205
2648
 
2206
- detach_message = Ably::Models::ProtocolMessage.new(action: detached_action, channel: channel_name, error: { code: 50505 })
2207
- client.connection.__incoming_protocol_msgbus__.publish :protocol_message, detach_message
2208
- end
2649
+ connection.once(:closed) do
2650
+ expect(channel).to be_suspended
2651
+ stop_reactor
2652
+ end
2209
2653
 
2210
- channel.transition_state_machine! :suspended
2654
+ connection.close
2655
+ end
2211
2656
  end
2212
2657
  end
2213
2658
  end
@@ -10,17 +10,56 @@ describe Ably::Realtime::Channels, :event_machine do
10
10
  end
11
11
 
12
12
  it 'returns channel object and passes the provided options' do
13
- expect(channel_with_options.options).to eql(options)
13
+ expect(channel_options).to be_a(Ably::Models::ChannelOptions)
14
+ expect(channel_options.to_h).to eq(options)
14
15
  stop_reactor
15
16
  end
16
17
  end
17
18
 
18
19
  vary_by_protocol do
20
+ let(:client_options) do
21
+ { key: api_key, environment: environment, protocol: protocol }
22
+ end
19
23
  let(:client) do
20
- auto_close Ably::Realtime::Client.new(key: api_key, environment: environment, protocol: protocol)
24
+ auto_close Ably::Realtime::Client.new(client_options)
21
25
  end
22
26
  let(:channel_name) { random_str }
23
- let(:options) { { key: 'value' } }
27
+ let(:options) do
28
+ { params: { key: 'value' } }
29
+ end
30
+
31
+ subject(:channel_options) { channel_with_options.options }
32
+
33
+ context 'when channel supposed to trigger reattachment per RTL16a (#RTS3c1)' do
34
+ it 'will raise an error' do
35
+ channel = client.channels.get(channel_name, options)
36
+
37
+ channel.on(:attached) do
38
+ expect { client.channels.get(channel_name, { modes: [] }) }.to raise_error ArgumentError, /use Channel#set_options directly/
39
+ stop_reactor
40
+ end
41
+
42
+ channel.attach
43
+ end
44
+
45
+ context 'params keys are the same but values are different' do
46
+ let(:options) do
47
+ { params: { x: '1' } }
48
+ end
49
+
50
+ it 'will raise an error' do
51
+ channel = client.channels.get(channel_name, options)
52
+
53
+ channel.on(:attached) do
54
+ expect { client.channels.get(channel_name, { params: { x: '2' } }) }.to raise_error ArgumentError, /use Channel#set_options directly/
55
+
56
+ stop_reactor
57
+ end
58
+
59
+ channel.attach
60
+ end
61
+ end
62
+ end
24
63
 
25
64
  describe 'using shortcut method #channel on the client object' do
26
65
  let(:channel) { client.channel(channel_name) }
@@ -35,26 +74,39 @@ describe Ably::Realtime::Channels, :event_machine do
35
74
  end
36
75
 
37
76
  describe 'accessing an existing channel object with different options' do
77
+ let(:client_options) { super().merge(logger: custom_logger_object) }
78
+ let(:custom_logger_object) { TestLogger.new }
38
79
  let(:new_channel_options) { { encrypted: true } }
39
- let(:original_channel) { client.channels.get(channel_name, options) }
80
+ let!(:original_channel) { client.channels.get(channel_name, options) }
40
81
 
41
82
  it 'overrides the existing channel options and returns the channel object' do
42
- expect(original_channel.options).to_not include(:encrypted)
83
+ expect(original_channel.options.to_h).to_not include(:encrypted)
43
84
  new_channel = client.channels.get(channel_name, new_channel_options)
44
85
  expect(new_channel).to be_a(Ably::Realtime::Channel)
45
86
  expect(new_channel.options[:encrypted]).to eql(true)
46
87
  stop_reactor
47
88
  end
89
+
90
+ it 'shows deprecation warning' do
91
+ client.channels.get(channel_name, new_channel_options)
92
+
93
+ warning = custom_logger_object.logs.find do |severity, message|
94
+ message.match(/Using this method to update channel options is deprecated and may be removed/)
95
+ end
96
+
97
+ expect(warning).to_not be_nil
98
+ stop_reactor
99
+ end
48
100
  end
49
101
 
50
102
  describe 'accessing an existing channel object without specifying any channel options' do
51
103
  let(:original_channel) { client.channels.get(channel_name, options) }
52
104
 
53
105
  it 'returns the existing channel without modifying the channel options' do
54
- expect(original_channel.options).to eql(options)
106
+ expect(original_channel.options.to_h).to eq(options)
55
107
  new_channel = client.channels.get(channel_name)
56
108
  expect(new_channel).to be_a(Ably::Realtime::Channel)
57
- expect(original_channel.options).to eql(options)
109
+ expect(original_channel.options.to_h).to eq(options)
58
110
  stop_reactor
59
111
  end
60
112
  end