ably 1.1.7 → 1.2.1

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 (69) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/check.yml +1 -1
  3. data/CHANGELOG.md +99 -0
  4. data/COPYRIGHT +1 -1
  5. data/README.md +2 -2
  6. data/SPEC.md +0 -7
  7. data/UPDATING.md +30 -0
  8. data/ably.gemspec +11 -24
  9. data/lib/ably/auth.rb +8 -8
  10. data/lib/ably/logger.rb +4 -4
  11. data/lib/ably/models/channel_options.rb +97 -0
  12. data/lib/ably/models/connection_details.rb +8 -2
  13. data/lib/ably/models/delta_extras.rb +29 -0
  14. data/lib/ably/models/device_details.rb +1 -1
  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 +14 -3
  18. data/lib/ably/models/protocol_message.rb +23 -14
  19. data/lib/ably/models/token_details.rb +7 -2
  20. data/lib/ably/models/token_request.rb +1 -1
  21. data/lib/ably/modules/ably.rb +1 -1
  22. data/lib/ably/modules/channels_collection.rb +22 -2
  23. data/lib/ably/modules/conversions.rb +34 -0
  24. data/lib/ably/realtime/auth.rb +2 -2
  25. data/lib/ably/realtime/channel/channel_manager.rb +16 -4
  26. data/lib/ably/realtime/channel/channel_state_machine.rb +10 -1
  27. data/lib/ably/realtime/channel/publisher.rb +3 -2
  28. data/lib/ably/realtime/channel.rb +54 -22
  29. data/lib/ably/realtime/channels.rb +1 -1
  30. data/lib/ably/realtime/connection/connection_manager.rb +13 -4
  31. data/lib/ably/realtime/connection/connection_state_machine.rb +4 -0
  32. data/lib/ably/realtime/connection.rb +0 -3
  33. data/lib/ably/rest/channel.rb +28 -35
  34. data/lib/ably/rest/client.rb +23 -8
  35. data/lib/ably/rest/middleware/encoder.rb +1 -1
  36. data/lib/ably/rest/middleware/exceptions.rb +1 -1
  37. data/lib/ably/rest/middleware/external_exceptions.rb +1 -1
  38. data/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb +1 -1
  39. data/lib/ably/rest/middleware/logger.rb +1 -1
  40. data/lib/ably/rest/middleware/parse_json.rb +1 -1
  41. data/lib/ably/rest/middleware/parse_message_pack.rb +1 -1
  42. data/lib/ably/util/crypto.rb +1 -1
  43. data/lib/ably/version.rb +2 -2
  44. data/spec/acceptance/realtime/channel_spec.rb +458 -27
  45. data/spec/acceptance/realtime/channels_spec.rb +59 -7
  46. data/spec/acceptance/realtime/connection_failures_spec.rb +56 -1
  47. data/spec/acceptance/realtime/connection_spec.rb +270 -1
  48. data/spec/acceptance/realtime/message_spec.rb +77 -0
  49. data/spec/acceptance/realtime/presence_spec.rb +18 -1
  50. data/spec/acceptance/rest/auth_spec.rb +18 -0
  51. data/spec/acceptance/rest/channel_spec.rb +73 -11
  52. data/spec/acceptance/rest/channels_spec.rb +23 -6
  53. data/spec/acceptance/rest/client_spec.rb +3 -3
  54. data/spec/acceptance/rest/message_spec.rb +61 -3
  55. data/spec/lib/unit/models/channel_options_spec.rb +52 -0
  56. data/spec/run_parallel_tests +2 -7
  57. data/spec/support/test_app.rb +1 -1
  58. data/spec/unit/logger_spec.rb +6 -14
  59. data/spec/unit/models/delta_extras_spec.rb +14 -0
  60. data/spec/unit/models/error_info_spec.rb +17 -1
  61. data/spec/unit/models/message_spec.rb +38 -0
  62. data/spec/unit/models/protocol_message_spec.rb +77 -27
  63. data/spec/unit/models/token_details_spec.rb +14 -0
  64. data/spec/unit/realtime/channel_spec.rb +2 -1
  65. data/spec/unit/realtime/channels_spec.rb +53 -15
  66. data/spec/unit/rest/channel_spec.rb +40 -7
  67. data/spec/unit/rest/channels_spec.rb +81 -14
  68. data/spec/unit/rest/client_spec.rb +27 -0
  69. metadata +46 -11
@@ -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
@@ -1405,15 +1630,98 @@ describe Ably::Realtime::Channel, :event_machine do
1405
1630
  end
1406
1631
 
1407
1632
  context 'message size exceeded (#TO3l8)' do
1408
- let(:message) { 'x' * 700000 }
1409
-
1410
1633
  let(:client) { auto_close Ably::Realtime::Client.new(client_options) }
1411
1634
  let(:channel) { client.channels.get(channel_name) }
1412
1635
 
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
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
1417
1725
  end
1418
1726
  end
1419
1727
  end
@@ -1752,15 +2060,33 @@ describe Ably::Realtime::Channel, :event_machine do
1752
2060
  end
1753
2061
  end
1754
2062
 
1755
- it 'transitions state automatically to :attaching once the connection is re-established (#RTN15c3)' do
1756
- channel.attach do
1757
- channel.on(:suspended) do
1758
- client.connection.connect
1759
- channel.once(:attached) do
1760
- 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
1761
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
1762
2089
  end
1763
- client.connection.transition_state_machine :suspended
1764
2090
  end
1765
2091
  end
1766
2092
  end
@@ -1950,6 +2276,68 @@ describe Ably::Realtime::Channel, :event_machine do
1950
2276
  end
1951
2277
  end
1952
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
+
1953
2341
  context 'channel state change' do
1954
2342
  it 'emits a ChannelStateChange object' do
1955
2343
  channel.on(:attached) do |channel_state_change|
@@ -2191,11 +2579,20 @@ describe Ably::Realtime::Channel, :event_machine do
2191
2579
  end
2192
2580
 
2193
2581
  context 'and channel is attached' do
2194
- it 'reattaches immediately (#RTL13a)' do
2195
- 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
+
2196
2592
  channel.once(:attaching) do |state_change|
2197
2593
  expect(state_change.reason.code).to eql(50505)
2198
2594
  channel.once(:attached) do
2595
+ expect(resume_flag).to eq(true)
2199
2596
  stop_reactor
2200
2597
  end
2201
2598
  end
@@ -2203,25 +2600,59 @@ describe Ably::Realtime::Channel, :event_machine do
2203
2600
  detach_message = Ably::Models::ProtocolMessage.new(action: detached_action, channel: channel_name, error: { code: 50505 })
2204
2601
  client.connection.__incoming_protocol_msgbus__.publish :protocol_message, detach_message
2205
2602
  end
2603
+
2604
+ channel.attach
2206
2605
  end
2207
2606
  end
2208
2607
 
2209
2608
  context 'and channel is suspended' do
2210
- it 'reattaches immediately (#RTL13a)' do
2211
- channel.attach do
2212
- channel.once(:suspended) do
2213
- channel.once(:attaching) do |state_change|
2214
- expect(state_change.reason.code).to eql(50505)
2215
- channel.once(:attached) do
2216
- 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'
2217
2644
  end
2645
+
2646
+ channel.transition_state_machine! :suspended
2218
2647
  end
2219
2648
 
2220
- detach_message = Ably::Models::ProtocolMessage.new(action: detached_action, channel: channel_name, error: { code: 50505 })
2221
- client.connection.__incoming_protocol_msgbus__.publish :protocol_message, detach_message
2222
- end
2649
+ connection.once(:closed) do
2650
+ expect(channel).to be_suspended
2651
+ stop_reactor
2652
+ end
2223
2653
 
2224
- channel.transition_state_machine! :suspended
2654
+ connection.close
2655
+ end
2225
2656
  end
2226
2657
  end
2227
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