ably-rest 1.1.8 → 1.2.0

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 (37) hide show
  1. checksums.yaml +4 -4
  2. data/ably-rest.gemspec +0 -4
  3. data/lib/submodules/ably-ruby/CHANGELOG.md +46 -0
  4. data/lib/submodules/ably-ruby/README.md +1 -1
  5. data/lib/submodules/ably-ruby/UPDATING.md +30 -0
  6. data/lib/submodules/ably-ruby/lib/ably/auth.rb +3 -3
  7. data/lib/submodules/ably-ruby/lib/ably/models/channel_options.rb +97 -0
  8. data/lib/submodules/ably-ruby/lib/ably/models/idiomatic_ruby_wrapper.rb +4 -0
  9. data/lib/submodules/ably-ruby/lib/ably/models/message.rb +4 -4
  10. data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +17 -5
  11. data/lib/submodules/ably-ruby/lib/ably/models/token_details.rb +7 -2
  12. data/lib/submodules/ably-ruby/lib/ably/modules/channels_collection.rb +22 -2
  13. data/lib/submodules/ably-ruby/lib/ably/modules/conversions.rb +34 -0
  14. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_manager.rb +16 -4
  15. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_state_machine.rb +5 -0
  16. data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +54 -24
  17. data/lib/submodules/ably-ruby/lib/ably/realtime/channels.rb +1 -1
  18. data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +26 -34
  19. data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +4 -1
  20. data/lib/submodules/ably-ruby/lib/ably/util/crypto.rb +1 -1
  21. data/lib/submodules/ably-ruby/lib/ably/version.rb +2 -2
  22. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +247 -21
  23. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channels_spec.rb +59 -7
  24. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +1 -1
  25. data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +77 -0
  26. data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +18 -0
  27. data/lib/submodules/ably-ruby/spec/acceptance/rest/channel_spec.rb +1 -1
  28. data/lib/submodules/ably-ruby/spec/acceptance/rest/channels_spec.rb +22 -5
  29. data/lib/submodules/ably-ruby/spec/acceptance/rest/client_spec.rb +2 -2
  30. data/lib/submodules/ably-ruby/spec/acceptance/rest/message_spec.rb +61 -3
  31. data/lib/submodules/ably-ruby/spec/lib/unit/models/channel_options_spec.rb +52 -0
  32. data/lib/submodules/ably-ruby/spec/unit/models/message_spec.rb +14 -0
  33. data/lib/submodules/ably-ruby/spec/unit/models/protocol_message_spec.rb +53 -7
  34. data/lib/submodules/ably-ruby/spec/unit/models/token_details_spec.rb +14 -0
  35. data/lib/submodules/ably-ruby/spec/unit/realtime/channels_spec.rb +52 -14
  36. data/lib/submodules/ably-ruby/spec/unit/rest/channels_spec.rb +81 -14
  37. metadata +6 -3
@@ -28,21 +28,20 @@ module Ably
28
28
  #
29
29
  # @param client [Ably::Rest::Client]
30
30
  # @param name [String] The name of the channel
31
- # @param channel_options [Hash] Channel options, currently reserved for Encryption options
32
- # @option channel_options [Hash,Ably::Models::CipherParams] :cipher A hash of options or a {Ably::Models::CipherParams} to configure the encryption. *:key* is required, all other options are optional. See {Ably::Util::Crypto#initialize} for a list of +:cipher+ options
31
+ # @param channel_options [Hash, Ably::Models::ChannelOptions] A hash of options or a {Ably::Models::ChannelOptions}
33
32
  #
34
33
  def initialize(client, name, channel_options = {})
35
34
  name = (ensure_utf_8 :name, name)
36
35
 
37
- update_options channel_options
36
+ @options = Ably::Models::ChannelOptions(channel_options)
38
37
  @client = client
39
38
  @name = name
40
39
  @push = PushChannel.new(self)
41
40
  end
42
41
 
43
- # Publish one or more messages to the channel. Three overloaded forms
42
+ # Publish one or more messages to the channel. Five overloaded forms
44
43
  # @param name [String, Array<Ably::Models::Message|Hash>, Ably::Models::Message, nil] The event name of the message to publish, or an Array of [Ably::Model::Message] objects or [Hash] objects with +:name+ and +:data+ pairs, or a single Ably::Model::Message object
45
- # @param data [String, ByteArray, Hash, nil] The message payload unless an Array of [Ably::Model::Message] objects passed in the first argument, in which case an optional hash of query parameters
44
+ # @param data [String, Array, Hash, nil] The message payload unless an Array of [Ably::Model::Message] objects passed in the first argument, in which case an optional hash of query parameters
46
45
  # @param attributes [Hash, nil] Optional additional message attributes such as :extras, :id, :client_id or :connection_id, applied when name attribute is nil or a string (Deprecated, will be removed in 2.0 in favour of constructing a Message object)
47
46
  # @return [Boolean] true if the message was published, otherwise false
48
47
  #
@@ -50,42 +49,33 @@ module Ably
50
49
  # # Publish a single message with (name, data) form
51
50
  # channel.publish 'click', { x: 1, y: 2 }
52
51
  #
53
- # # Publish an array of message Hashes
52
+ # # Publish a single message with single Hash form
53
+ # message = { name: 'click', data: { x: 1, y: 2 } }
54
+ # channel.publish message
55
+ #
56
+ # # Publish an array of message Hashes form
54
57
  # messages = [
55
58
  # { name: 'click', data: { x: 1, y: 2 } },
56
59
  # { name: 'click', data: { x: 2, y: 3 } }
57
60
  # ]
58
61
  # channel.publish messages
59
62
  #
60
- # # Publish an array of Ably::Models::Message objects
63
+ # # Publish an array of Ably::Models::Message objects form
61
64
  # messages = [
62
- # Ably::Models::Message(name: 'click', { x: 1, y: 2 })
63
- # Ably::Models::Message(name: 'click', { x: 2, y: 3 })
65
+ # Ably::Models::Message(name: 'click', data: { x: 1, y: 2 })
66
+ # Ably::Models::Message(name: 'click', data: { x: 2, y: 3 })
64
67
  # ]
65
68
  # channel.publish messages
66
69
  #
67
- # # Publish a single Ably::Models::Message object, with a query params
68
- # # specifying quickAck: true
69
- # message = Ably::Models::Message(name: 'click', { x: 1, y: 2 })
70
- # channel.publish message, quickAck: 'true'
70
+ # # Publish a single Ably::Models::Message object form
71
+ # message = Ably::Models::Message(name: 'click', data: { x: 1, y: 2 })
72
+ # channel.publish message
71
73
  #
72
- def publish(first, second = nil, third = {})
73
- messages, qs_params = if first.kind_of?(Enumerable)
74
- # ([Message], qs_params) form
75
- [first, second]
76
- elsif first.kind_of?(Ably::Models::Message)
77
- # (Message, qs_params) form
78
- [[first], second]
79
- else
80
- # (name, data, attributes) form
81
- first = ensure_utf_8(:name, first, allow_nil: true)
82
- ensure_supported_payload second
83
- # RSL1h - attributes as an extra method parameter is extra-spec but need to
84
- # keep it for backcompat until version 2
85
- [[{ name: first, data: second }.merge(third)], nil]
86
- end
74
+ def publish(name, data = nil, attributes = {})
75
+ qs_params = nil
76
+ qs_params = data if name.kind_of?(Enumerable) || name.kind_of?(Ably::Models::Message)
87
77
 
88
- messages.map! { |message| Ably::Models::Message(message.dup) }
78
+ messages = build_messages(name, data, attributes) # (RSL1a, RSL1b)
89
79
 
90
80
  if messages.sum(&:size) > (max_message_size = client.max_message_size || Ably::Rest::Client::MAX_MESSAGE_SIZE)
91
81
  raise Ably::Exceptions::MaxMessageSizeExceeded.new("Maximum message size exceeded #{max_message_size} bytes.")
@@ -163,14 +153,16 @@ module Ably
163
153
  @presence ||= Presence.new(client, self)
164
154
  end
165
155
 
166
- # @api private
167
- def update_options(channel_options)
168
- @options = channel_options.clone.freeze
156
+ # Sets or updates the stored channel options. (#RSL7)
157
+ # @param channel_options [Hash, Ably::Models::ChannelOptions] A hash of options or a {Ably::Models::ChannelOptions}
158
+ # @return [Ably::Models::ChannelOptions]
159
+ def set_options(channel_options)
160
+ @options = Ably::Models::ChannelOptions(channel_options)
169
161
  end
170
- alias set_options update_options # (RSL7)
171
- alias options= update_options
162
+ alias options= set_options
172
163
 
173
164
  private
165
+
174
166
  def base_path
175
167
  "/channels/#{URI.encode_www_form_component(name)}"
176
168
  end
@@ -199,10 +199,13 @@ module Ably
199
199
  @custom_tls_port = options.delete(:tls_port)
200
200
  @add_request_ids = options.delete(:add_request_ids)
201
201
  @log_retries_as_info = options.delete(:log_retries_as_info)
202
- @idempotent_rest_publishing = options.delete(:idempotent_rest_publishing) || Ably.major_minor_version_numeric > 1.1
203
202
  @max_message_size = options.delete(:max_message_size) || MAX_MESSAGE_SIZE
204
203
  @max_frame_size = options.delete(:max_frame_size) || MAX_FRAME_SIZE
205
204
 
205
+ if (@idempotent_rest_publishing = options.delete(:idempotent_rest_publishing)).nil?
206
+ @idempotent_rest_publishing = Ably::PROTOCOL_VERSION.to_f > 1.1
207
+ end
208
+
206
209
  if options[:fallback_hosts_use_default] && options[:fallback_hosts]
207
210
  raise ArgumentError, "fallback_hosts_use_default cannot be set to try when fallback_hosts is also provided"
208
211
  end
@@ -30,7 +30,7 @@ module Ably::Util
30
30
  # crypto.decrypt(decrypted) # => 'secret text'
31
31
  #
32
32
  def initialize(params)
33
- @fixed_iv = params.delete(:fixed_iv) if params.kind_of?(Hash)
33
+ @fixed_iv = params[:fixed_iv]
34
34
  @cipher_params = Ably::Models::CipherParams(params)
35
35
  end
36
36
 
@@ -1,6 +1,6 @@
1
1
  module Ably
2
- VERSION = '1.1.8'
3
- PROTOCOL_VERSION = '1.1'
2
+ VERSION = '1.2.0'
3
+ PROTOCOL_VERSION = '1.2'
4
4
 
5
5
  # @api private
6
6
  def self.major_minor_version_numeric
@@ -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
@@ -1936,15 +2060,33 @@ describe Ably::Realtime::Channel, :event_machine do
1936
2060
  end
1937
2061
  end
1938
2062
 
1939
- it 'transitions state automatically to :attaching once the connection is re-established (#RTN15c3)' do
1940
- channel.attach do
1941
- channel.on(:suspended) do
1942
- client.connection.connect
1943
- channel.once(:attached) do
1944
- 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
1945
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
1946
2089
  end
1947
- client.connection.transition_state_machine :suspended
1948
2090
  end
1949
2091
  end
1950
2092
  end
@@ -2134,6 +2276,68 @@ describe Ably::Realtime::Channel, :event_machine do
2134
2276
  end
2135
2277
  end
2136
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
+
2137
2341
  context 'channel state change' do
2138
2342
  it 'emits a ChannelStateChange object' do
2139
2343
  channel.on(:attached) do |channel_state_change|
@@ -2375,11 +2579,20 @@ describe Ably::Realtime::Channel, :event_machine do
2375
2579
  end
2376
2580
 
2377
2581
  context 'and channel is attached' do
2378
- it 'reattaches immediately (#RTL13a)' do
2379
- 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
+
2380
2592
  channel.once(:attaching) do |state_change|
2381
2593
  expect(state_change.reason.code).to eql(50505)
2382
2594
  channel.once(:attached) do
2595
+ expect(resume_flag).to eq(true)
2383
2596
  stop_reactor
2384
2597
  end
2385
2598
  end
@@ -2387,26 +2600,39 @@ describe Ably::Realtime::Channel, :event_machine do
2387
2600
  detach_message = Ably::Models::ProtocolMessage.new(action: detached_action, channel: channel_name, error: { code: 50505 })
2388
2601
  client.connection.__incoming_protocol_msgbus__.publish :protocol_message, detach_message
2389
2602
  end
2603
+
2604
+ channel.attach
2390
2605
  end
2391
2606
  end
2392
2607
 
2393
2608
  context 'and channel is suspended' do
2394
- it 'reattaches immediately (#RTL13a)' do
2395
- channel.attach do
2396
- channel.once(:suspended) do
2397
- channel.once(:attaching) do |state_change|
2398
- expect(state_change.reason.code).to eql(50505)
2399
- channel.once(:attached) do
2400
- stop_reactor
2401
- end
2402
- end
2609
+ it 'reattaches immediately (#RTL13a) with ATTACH_RESUME flag(RTL4j)' do
2610
+ resume_flag = false
2403
2611
 
2404
- detach_message = Ably::Models::ProtocolMessage.new(action: detached_action, channel: channel_name, error: { code: 50505 })
2405
- client.connection.__incoming_protocol_msgbus__.publish :protocol_message, detach_message
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?
2406
2621
  end
2407
2622
 
2408
- channel.transition_state_machine! :suspended
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
2409
2633
  end
2634
+
2635
+ channel.attach
2410
2636
  end
2411
2637
 
2412
2638
  context 'when connection is no longer connected' do
@@ -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
@@ -2083,7 +2083,7 @@ describe Ably::Realtime::Connection, :event_machine do
2083
2083
  it 'sends the protocol version param v (#G4, #RTN2f)' do
2084
2084
  expect(EventMachine).to receive(:connect) do |host, port, transport, object, url|
2085
2085
  uri = URI.parse(url)
2086
- expect(CGI::parse(uri.query)['v'][0]).to eql('1.1')
2086
+ expect(CGI::parse(uri.query)['v'][0]).to eql('1.2')
2087
2087
  stop_reactor
2088
2088
  end
2089
2089
  client
@@ -75,6 +75,83 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
75
75
  end
76
76
  end
77
77
 
78
+ context 'a single Message object (#RSL1a)' do
79
+ let(:name) { random_str }
80
+ let(:data) { random_str }
81
+ let(:message) { Ably::Models::Message.new(name: name, data: data) }
82
+
83
+ it 'publishes the message' do
84
+ channel.attach
85
+ channel.publish(message)
86
+ channel.subscribe do |msg|
87
+ expect(msg.name).to eq(message.name)
88
+ expect(msg.data).to eq(message.data)
89
+ stop_reactor
90
+ end
91
+ end
92
+ end
93
+
94
+ context 'an array of Message objects (#RSL1a)' do
95
+ let(:data) { random_str }
96
+ let(:message1) { Ably::Models::Message.new(name: random_str, data: data) }
97
+ let(:message2) { Ably::Models::Message.new(name: random_str, data: data) }
98
+ let(:message3) { Ably::Models::Message.new(name: random_str, data: data) }
99
+
100
+ it 'publishes three messages' do
101
+ channel.attach
102
+ channel.publish([message1, message2, message3])
103
+ counter = 0
104
+ channel.subscribe do |message|
105
+ counter += 1
106
+ expect(message.data).to eq(data)
107
+ expect(message.name).to eq(message1.name) if counter == 1
108
+ expect(message.name).to eq(message2.name) if counter == 2
109
+ if counter == 3
110
+ expect(message.name).to eq(message3.name)
111
+ stop_reactor
112
+ end
113
+ end
114
+ end
115
+ end
116
+
117
+ context 'an array of hashes (#RSL1a)' do
118
+ let(:data) { random_str }
119
+ let(:message1) { { name: random_str, data: data } }
120
+ let(:message2) { { name: random_str, data: data } }
121
+ let(:message3) { { name: random_str, data: data } }
122
+
123
+ it 'publishes three messages' do
124
+ channel.attach
125
+ channel.publish([message1, message2, message3])
126
+ counter = 0
127
+ channel.subscribe do |message|
128
+ counter += 1
129
+ expect(message.data).to eq(data)
130
+ expect(message.name).to eq(message1[:name]) if counter == 1
131
+ expect(message.name).to eq(message2[:name]) if counter == 2
132
+ if counter == 3
133
+ expect(message.name).to eq(message3[:name])
134
+ stop_reactor
135
+ end
136
+ end
137
+ end
138
+ end
139
+
140
+ context 'a name with data payload (#RSL1a, #RSL1b)' do
141
+ let(:name) { random_str }
142
+ let(:data) { random_str }
143
+
144
+ it 'publishes a message' do
145
+ channel.attach
146
+ channel.publish(name, data)
147
+ channel.subscribe do |message|
148
+ expect(message.name).to eql(name)
149
+ expect(message.data).to eq(data)
150
+ stop_reactor
151
+ end
152
+ end
153
+ end
154
+
78
155
  context 'with supported extra payload content type (#RTL6h, #RSL6a2)' do
79
156
  let(:channel) { client.channel("pushenabled:#{random_str}") }
80
157