ably-rest 0.9.3 → 1.0.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.
- checksums.yaml +4 -4
- data/ably-rest.gemspec +2 -1
- data/lib/submodules/ably-ruby/.travis.yml +6 -4
- data/lib/submodules/ably-ruby/CHANGELOG.md +52 -61
- data/lib/submodules/ably-ruby/README.md +10 -0
- data/lib/submodules/ably-ruby/SPEC.md +1473 -852
- data/lib/submodules/ably-ruby/ably.gemspec +2 -1
- data/lib/submodules/ably-ruby/lib/ably/auth.rb +57 -25
- data/lib/submodules/ably-ruby/lib/ably/exceptions.rb +34 -8
- data/lib/submodules/ably-ruby/lib/ably/logger.rb +10 -1
- data/lib/submodules/ably-ruby/lib/ably/models/auth_details.rb +42 -0
- data/lib/submodules/ably-ruby/lib/ably/models/channel_state_change.rb +18 -4
- data/lib/submodules/ably-ruby/lib/ably/models/connection_details.rb +6 -3
- data/lib/submodules/ably-ruby/lib/ably/models/connection_state_change.rb +4 -3
- data/lib/submodules/ably-ruby/lib/ably/models/error_info.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/models/message.rb +12 -1
- data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/base.rb +101 -97
- data/lib/submodules/ably-ruby/lib/ably/models/presence_message.rb +13 -1
- data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +20 -3
- data/lib/submodules/ably-ruby/lib/ably/modules/async_wrapper.rb +7 -3
- data/lib/submodules/ably-ruby/lib/ably/modules/enum.rb +17 -7
- data/lib/submodules/ably-ruby/lib/ably/modules/event_emitter.rb +29 -14
- data/lib/submodules/ably-ruby/lib/ably/modules/state_emitter.rb +7 -4
- data/lib/submodules/ably-ruby/lib/ably/modules/state_machine.rb +2 -4
- data/lib/submodules/ably-ruby/lib/ably/modules/uses_state_machine.rb +7 -3
- data/lib/submodules/ably-ruby/lib/ably/realtime.rb +2 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/auth.rb +79 -31
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +62 -26
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_manager.rb +154 -65
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_state_machine.rb +14 -15
- data/lib/submodules/ably-ruby/lib/ably/realtime/client.rb +16 -3
- data/lib/submodules/ably-ruby/lib/ably/realtime/client/incoming_message_dispatcher.rb +38 -29
- data/lib/submodules/ably-ruby/lib/ably/realtime/client/outgoing_message_dispatcher.rb +6 -1
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +108 -49
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_manager.rb +165 -59
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_state_machine.rb +22 -3
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/websocket_transport.rb +19 -10
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence.rb +67 -45
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence/members_map.rb +198 -36
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence/presence_manager.rb +30 -6
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence/presence_state_machine.rb +5 -12
- data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +3 -3
- data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +21 -8
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/exceptions.rb +1 -3
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/logger.rb +2 -2
- data/lib/submodules/ably-ruby/lib/ably/rest/presence.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/util/pub_sub.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/util/safe_deferrable.rb +26 -0
- data/lib/submodules/ably-ruby/lib/ably/version.rb +2 -2
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/auth_spec.rb +416 -99
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_history_spec.rb +5 -3
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +1011 -160
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/client_spec.rb +2 -2
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +458 -27
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +436 -97
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +52 -23
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_history_spec.rb +5 -3
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +1160 -105
- data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +151 -22
- data/lib/submodules/ably-ruby/spec/acceptance/rest/channel_spec.rb +1 -1
- data/lib/submodules/ably-ruby/spec/acceptance/rest/client_spec.rb +88 -27
- data/lib/submodules/ably-ruby/spec/acceptance/rest/message_spec.rb +42 -15
- data/lib/submodules/ably-ruby/spec/acceptance/rest/presence_spec.rb +4 -4
- data/lib/submodules/ably-ruby/spec/rspec_config.rb +2 -1
- data/lib/submodules/ably-ruby/spec/shared/client_initializer_behaviour.rb +2 -2
- data/lib/submodules/ably-ruby/spec/shared/safe_deferrable_behaviour.rb +6 -2
- data/lib/submodules/ably-ruby/spec/support/debug_failure_helper.rb +20 -4
- data/lib/submodules/ably-ruby/spec/support/event_machine_helper.rb +32 -1
- data/lib/submodules/ably-ruby/spec/unit/auth_spec.rb +4 -11
- data/lib/submodules/ably-ruby/spec/unit/logger_spec.rb +28 -2
- data/lib/submodules/ably-ruby/spec/unit/models/auth_details_spec.rb +49 -0
- data/lib/submodules/ably-ruby/spec/unit/models/channel_state_change_spec.rb +23 -3
- data/lib/submodules/ably-ruby/spec/unit/models/connection_details_spec.rb +12 -1
- data/lib/submodules/ably-ruby/spec/unit/models/connection_state_change_spec.rb +15 -4
- data/lib/submodules/ably-ruby/spec/unit/models/message_spec.rb +34 -2
- data/lib/submodules/ably-ruby/spec/unit/models/presence_message_spec.rb +73 -2
- data/lib/submodules/ably-ruby/spec/unit/models/protocol_message_spec.rb +64 -6
- data/lib/submodules/ably-ruby/spec/unit/models/token_details_spec.rb +1 -1
- data/lib/submodules/ably-ruby/spec/unit/models/token_request_spec.rb +1 -1
- data/lib/submodules/ably-ruby/spec/unit/modules/async_wrapper_spec.rb +2 -1
- data/lib/submodules/ably-ruby/spec/unit/modules/enum_spec.rb +69 -0
- data/lib/submodules/ably-ruby/spec/unit/modules/event_emitter_spec.rb +149 -22
- data/lib/submodules/ably-ruby/spec/unit/modules/state_emitter_spec.rb +9 -3
- data/lib/submodules/ably-ruby/spec/unit/realtime/client_spec.rb +1 -1
- data/lib/submodules/ably-ruby/spec/unit/realtime/connection_spec.rb +8 -5
- data/lib/submodules/ably-ruby/spec/unit/realtime/incoming_message_dispatcher_spec.rb +1 -1
- data/lib/submodules/ably-ruby/spec/unit/realtime/presence_spec.rb +4 -3
- data/lib/submodules/ably-ruby/spec/unit/rest/client_spec.rb +1 -1
- data/lib/submodules/ably-ruby/spec/unit/util/crypto_spec.rb +3 -3
- metadata +7 -5
|
@@ -61,6 +61,7 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
|
61
61
|
context 'for renewable tokens' do
|
|
62
62
|
context 'that are valid for the duration of the test' do
|
|
63
63
|
context 'with valid pre authorized token expiring in the future' do
|
|
64
|
+
let(:client_options) { default_options.merge(use_token_auth: true) }
|
|
64
65
|
it 'uses the existing token created by Auth' do
|
|
65
66
|
client.auth.authorize(ttl: 300)
|
|
66
67
|
expect(client.auth).to_not receive(:request_token)
|
|
@@ -137,7 +138,7 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
|
137
138
|
end
|
|
138
139
|
let(:client_options) { default_options.merge(auth_callback: token_callback) }
|
|
139
140
|
|
|
140
|
-
it 'renews the token on connect, and makes one immediate subsequent attempt to obtain a new token' do
|
|
141
|
+
it 'renews the token on connect, and makes one immediate subsequent attempt to obtain a new token (#RSA4b)' do
|
|
141
142
|
started_at = Time.now.to_f
|
|
142
143
|
connection.once(:disconnected) do
|
|
143
144
|
connection.once(:disconnected) do |connection_state_change|
|
|
@@ -150,25 +151,33 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
|
150
151
|
end
|
|
151
152
|
|
|
152
153
|
context 'when disconnected_retry_timeout is 0.5 seconds' do
|
|
153
|
-
let(:client_options) { default_options.merge(disconnected_retry_timeout: 0.5, auth_callback: token_callback
|
|
154
|
+
let(:client_options) { default_options.merge(disconnected_retry_timeout: 0.5, auth_callback: token_callback) }
|
|
154
155
|
|
|
155
156
|
it 'renews the token on connect, and continues to attempt renew based on the retry schedule' do
|
|
156
|
-
started_at = Time.now.to_f
|
|
157
157
|
disconnect_count = 0
|
|
158
|
+
first_disconnected_at = nil
|
|
158
159
|
connection.on(:disconnected) do |connection_state_change|
|
|
160
|
+
first_disconnected_at ||= begin
|
|
161
|
+
Time.now.to_f
|
|
162
|
+
end
|
|
159
163
|
expect(connection_state_change.reason.code).to eql(40142) # token expired
|
|
160
|
-
disconnect_count
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
+
if disconnect_count == 4 # 3 attempts to reconnect after initial
|
|
165
|
+
# First disconnect reattempts immediately as part of connect sequence
|
|
166
|
+
# Second disconnect reattempt immediately as part of disconnected retry sequence
|
|
167
|
+
# Following two take 0.5 second each
|
|
168
|
+
# Not convinced two immediate retries is necessary, but not worth engineering effort to fix given
|
|
169
|
+
# it's only one extra retry
|
|
170
|
+
expect(Time.now.to_f - first_disconnected_at).to be > 2 * 0.5
|
|
171
|
+
expect(Time.now.to_f - first_disconnected_at).to be < 9 # allow 1.5 seconds for each authentication cycle
|
|
164
172
|
stop_reactor
|
|
165
173
|
end
|
|
174
|
+
disconnect_count += 1
|
|
166
175
|
end
|
|
167
176
|
end
|
|
168
177
|
end
|
|
169
178
|
|
|
170
179
|
context 'using implicit token auth' do
|
|
171
|
-
let(:client_options) { default_options.merge(use_token_auth: true,
|
|
180
|
+
let(:client_options) { default_options.merge(use_token_auth: true, default_token_params: { ttl: ttl }) }
|
|
172
181
|
|
|
173
182
|
before do
|
|
174
183
|
stub_const 'Ably::Models::TokenDetails::TOKEN_EXPIRY_BUFFER', -10 # ensure client lib thinks token is still valid
|
|
@@ -178,14 +187,18 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
|
178
187
|
connection.once(:disconnected) do
|
|
179
188
|
expect(client.rest_client.connection).to receive(:post).
|
|
180
189
|
with(/requestToken$/, anything).
|
|
181
|
-
exactly(:
|
|
190
|
+
exactly(:twice). # it retries an expired token request immediately
|
|
182
191
|
and_call_original
|
|
183
192
|
|
|
184
193
|
expect(client.rest_client).to_not receive(:fallback_connection)
|
|
185
194
|
expect(client).to_not receive(:fallback_endpoint)
|
|
186
195
|
|
|
196
|
+
# Connection will go into :disconnected, then back to
|
|
197
|
+
# :connecting, then :disconnected again
|
|
187
198
|
connection.once(:disconnected) do
|
|
188
|
-
|
|
199
|
+
connection.once(:disconnected) do
|
|
200
|
+
stop_reactor
|
|
201
|
+
end
|
|
189
202
|
end
|
|
190
203
|
end
|
|
191
204
|
end
|
|
@@ -198,7 +211,7 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
|
198
211
|
let(:ttl) { 5 }
|
|
199
212
|
let(:channel_name) { random_str }
|
|
200
213
|
let(:channel) { client.channel(channel_name) }
|
|
201
|
-
let(:client_options) { default_options.merge(use_token_auth: true,
|
|
214
|
+
let(:client_options) { default_options.merge(use_token_auth: true, default_token_params: { ttl: ttl }) }
|
|
202
215
|
|
|
203
216
|
context 'the server' do
|
|
204
217
|
it 'disconnects the client, and the client automatically renews the token and then reconnects', em_timeout: 15 do
|
|
@@ -229,6 +242,7 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
|
229
242
|
end
|
|
230
243
|
|
|
231
244
|
context 'connection state' do
|
|
245
|
+
let(:publish_count) { 10 }
|
|
232
246
|
let(:ttl) { 4 }
|
|
233
247
|
let(:auth_requests) { [] }
|
|
234
248
|
let(:token_callback) do
|
|
@@ -243,13 +257,15 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
|
243
257
|
let(:publishing_channel) { publishing_client.channels.get(channel_name) }
|
|
244
258
|
let(:messages_received) { [] }
|
|
245
259
|
|
|
246
|
-
def
|
|
247
|
-
|
|
260
|
+
def publish_and_check_disconnect(options = {})
|
|
261
|
+
iteration = options.fetch(:iteration) { 1 }
|
|
262
|
+
total_expected = publish_count * iteration
|
|
263
|
+
publish_count.times.each { |index| publishing_channel.publish('event', (total_expected - publish_count + index).to_s) }
|
|
248
264
|
channel.subscribe('event') do |message|
|
|
249
265
|
messages_received << message.data.to_i
|
|
250
|
-
if messages_received.count ==
|
|
251
|
-
expect(messages_received).to match(
|
|
252
|
-
expect(auth_requests.count).to eql(
|
|
266
|
+
if messages_received.count == total_expected
|
|
267
|
+
expect(messages_received).to match(total_expected.times)
|
|
268
|
+
expect(auth_requests.count).to eql(iteration + 1)
|
|
253
269
|
EventMachine.add_timer(1) do
|
|
254
270
|
channel.unsubscribe 'event'
|
|
255
271
|
yield
|
|
@@ -258,25 +274,19 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
|
258
274
|
end
|
|
259
275
|
end
|
|
260
276
|
|
|
261
|
-
|
|
262
|
-
10.times.each { |index| publishing_channel.publish('event', (index + 10).to_s) }
|
|
263
|
-
channel.subscribe('event') do |message|
|
|
264
|
-
messages_received << message.data.to_i
|
|
265
|
-
if messages_received.count == 20
|
|
266
|
-
expect(messages_received).to match(20.times)
|
|
267
|
-
expect(auth_requests.count).to eql(3)
|
|
268
|
-
stop_reactor
|
|
269
|
-
end
|
|
270
|
-
end
|
|
271
|
-
end
|
|
272
|
-
|
|
273
|
-
it 'retains messages published when disconnected twice during authentication', em_timeout: 20 do
|
|
277
|
+
it 'retains messages published when disconnected three times during authentication', em_timeout: 30 do
|
|
274
278
|
publishing_channel.attach do
|
|
275
279
|
channel.attach do
|
|
276
280
|
connection.once(:disconnected) do
|
|
277
|
-
|
|
281
|
+
publish_and_check_disconnect(iteration: 1) do
|
|
278
282
|
connection.once(:disconnected) do
|
|
279
|
-
|
|
283
|
+
publish_and_check_disconnect(iteration: 2) do
|
|
284
|
+
connection.once(:disconnected) do
|
|
285
|
+
publish_and_check_disconnect(iteration: 3) do
|
|
286
|
+
stop_reactor
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
end
|
|
280
290
|
end
|
|
281
291
|
end
|
|
282
292
|
end
|
|
@@ -322,13 +332,14 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
|
322
332
|
let!(:expired_token_details) do
|
|
323
333
|
# Request a token synchronously
|
|
324
334
|
token_client = auto_close Ably::Realtime::Client.new(default_options)
|
|
325
|
-
token_client.auth.request_token_sync(ttl:
|
|
335
|
+
token_client.auth.request_token_sync(ttl: ttl)
|
|
326
336
|
end
|
|
327
337
|
|
|
328
338
|
context 'opening a new connection' do
|
|
329
339
|
let(:client_options) { default_options.merge(key: nil, token: expired_token_details.token, log_level: :none) }
|
|
340
|
+
let(:ttl) { 0.01 }
|
|
330
341
|
|
|
331
|
-
it 'transitions state to failed', em_timeout: 10 do
|
|
342
|
+
it 'transitions state to failed (#RSA4a)', em_timeout: 10 do
|
|
332
343
|
EventMachine.add_timer(1) do # wait for token to expire
|
|
333
344
|
expect(expired_token_details).to be_expired
|
|
334
345
|
connection.once(:connected) { raise 'Connection should never connect as token has expired' }
|
|
@@ -341,7 +352,17 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
|
341
352
|
end
|
|
342
353
|
|
|
343
354
|
context 'when connected' do
|
|
344
|
-
|
|
355
|
+
let(:client_options) { default_options.merge(key: nil, token: expired_token_details.token, log_level: :none) }
|
|
356
|
+
let(:ttl) { 4 }
|
|
357
|
+
|
|
358
|
+
it 'transitions state to failed (#RSA4a)' do
|
|
359
|
+
connection.once(:connected) do
|
|
360
|
+
connection.once(:failed) do
|
|
361
|
+
expect(client.connection.error_reason.code).to eql(40142)
|
|
362
|
+
stop_reactor
|
|
363
|
+
end
|
|
364
|
+
end
|
|
365
|
+
end
|
|
345
366
|
end
|
|
346
367
|
end
|
|
347
368
|
end
|
|
@@ -579,11 +600,13 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
|
579
600
|
end
|
|
580
601
|
|
|
581
602
|
context 'when closing' do
|
|
582
|
-
it '
|
|
603
|
+
it 'fails the deferrable before the connection is closed' do
|
|
583
604
|
connection.connect do
|
|
584
605
|
connection.once(:closing) do
|
|
585
|
-
|
|
586
|
-
|
|
606
|
+
connection.connect.errback do |error|
|
|
607
|
+
expect(error).to be_a(Ably::Exceptions::InvalidStateChange)
|
|
608
|
+
stop_reactor
|
|
609
|
+
end
|
|
587
610
|
end
|
|
588
611
|
connection.close
|
|
589
612
|
end
|
|
@@ -605,26 +628,35 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
|
605
628
|
it 'the sent message msgSerial is 0 but the connection serial remains at -1' do
|
|
606
629
|
channel.attach do
|
|
607
630
|
connection.__outgoing_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
631
|
+
if protocol_message.action == :message
|
|
632
|
+
connection.__outgoing_protocol_msgbus__.unsubscribe
|
|
633
|
+
expect(protocol_message['msgSerial']).to eql(0)
|
|
634
|
+
expect(connection.serial).to eql(-1)
|
|
635
|
+
stop_reactor
|
|
636
|
+
end
|
|
612
637
|
end
|
|
613
638
|
channel.publish('event', 'data')
|
|
614
639
|
end
|
|
615
640
|
end
|
|
616
641
|
end
|
|
617
642
|
|
|
618
|
-
it 'is set to 0 when a message
|
|
619
|
-
channel.publish('event', 'data')
|
|
643
|
+
it 'is set to 0 when a message is received back' do
|
|
644
|
+
channel.publish('event', 'data')
|
|
645
|
+
channel.subscribe do
|
|
620
646
|
expect(connection.serial).to eql(0)
|
|
621
647
|
stop_reactor
|
|
622
648
|
end
|
|
623
649
|
end
|
|
624
650
|
|
|
625
|
-
it 'is set to 1 when the second message
|
|
651
|
+
it 'is set to 1 when the second message is received' do
|
|
626
652
|
channel.publish('event', 'data') do
|
|
627
|
-
channel.publish('event', 'data')
|
|
653
|
+
channel.publish('event', 'data')
|
|
654
|
+
end
|
|
655
|
+
|
|
656
|
+
messages = []
|
|
657
|
+
channel.subscribe do |message|
|
|
658
|
+
messages << message
|
|
659
|
+
if messages.length == 2
|
|
628
660
|
expect(connection.serial).to eql(1)
|
|
629
661
|
stop_reactor
|
|
630
662
|
end
|
|
@@ -671,7 +703,6 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
|
671
703
|
|
|
672
704
|
def log_connection_changes
|
|
673
705
|
connection.on(:closing) { events[:closing_emitted] = true }
|
|
674
|
-
connection.on(:error) { events[:error_emitted] = true }
|
|
675
706
|
|
|
676
707
|
connection.__incoming_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
|
|
677
708
|
events[:closed_message_from_server_received] = true if protocol_message.action == :closed
|
|
@@ -684,7 +715,6 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
|
684
715
|
expect(connection.state).to eq(:closed)
|
|
685
716
|
|
|
686
717
|
EventMachine.add_timer(1) do # allow for all subscribers on incoming message bes
|
|
687
|
-
expect(events[:error_emitted]).to_not eql(true)
|
|
688
718
|
expect(events[:closed_message_from_server_received]).to_not eql(true)
|
|
689
719
|
expect(events[:closing_emitted]).to eql(true)
|
|
690
720
|
stop_reactor
|
|
@@ -701,7 +731,6 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
|
701
731
|
connection.on(:connected) do
|
|
702
732
|
connection.on(:closed) do
|
|
703
733
|
EventMachine.add_timer(1) do # allow for all subscribers on incoming message bus
|
|
704
|
-
expect(events[:error_emitted]).to_not eql(true)
|
|
705
734
|
expect(events[:closed_message_from_server_received]).to eql(true)
|
|
706
735
|
expect(events[:closing_emitted]).to eql(true)
|
|
707
736
|
stop_reactor
|
|
@@ -732,14 +761,13 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
|
732
761
|
connection.on(:closed) do
|
|
733
762
|
expect(Time.now - close_requested_at).to be >= custom_timeout
|
|
734
763
|
expect(connection.state).to eq(:closed)
|
|
735
|
-
expect(events[:error_emitted]).to_not eql(true)
|
|
736
764
|
expect(events[:closed_message_from_server_received]).to_not eql(true)
|
|
737
765
|
expect(events[:closing_emitted]).to eql(true)
|
|
738
766
|
stop_reactor
|
|
739
767
|
end
|
|
740
768
|
|
|
741
769
|
log_connection_changes
|
|
742
|
-
connection.close
|
|
770
|
+
EventMachine.next_tick { connection.close }
|
|
743
771
|
end
|
|
744
772
|
end
|
|
745
773
|
end
|
|
@@ -748,26 +776,117 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
|
748
776
|
end
|
|
749
777
|
|
|
750
778
|
context '#ping' do
|
|
751
|
-
it 'echoes a heart beat' do
|
|
779
|
+
it 'echoes a heart beat (#RTN13a)' do
|
|
752
780
|
connection.on(:connected) do
|
|
753
781
|
connection.ping do |time_elapsed|
|
|
754
782
|
expect(time_elapsed).to be > 0
|
|
783
|
+
expect(time_elapsed).to be < 3
|
|
755
784
|
stop_reactor
|
|
756
785
|
end
|
|
757
786
|
end
|
|
758
787
|
end
|
|
759
788
|
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
789
|
+
it 'sends a unique ID in each protocol message (#RTN13e)' do
|
|
790
|
+
connection.on(:connected) do
|
|
791
|
+
heartbeat_ids = []
|
|
792
|
+
pings_complete = []
|
|
793
|
+
connection.__outgoing_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
|
|
794
|
+
if protocol_message.action == :heartbeat
|
|
795
|
+
heartbeat_ids << protocol_message.id
|
|
796
|
+
end
|
|
797
|
+
end
|
|
798
|
+
|
|
799
|
+
ping_block = Proc.new do
|
|
800
|
+
pings_complete << true
|
|
801
|
+
if pings_complete.length == 3
|
|
802
|
+
expect(heartbeat_ids.uniq.length).to eql(3)
|
|
803
|
+
stop_reactor
|
|
804
|
+
end
|
|
805
|
+
end
|
|
806
|
+
|
|
807
|
+
connection.ping(&ping_block)
|
|
808
|
+
connection.ping(&ping_block)
|
|
809
|
+
connection.ping(&ping_block)
|
|
810
|
+
end
|
|
811
|
+
end
|
|
812
|
+
|
|
813
|
+
it 'waits until the connection becomes CONNECTED when in the CONNETING state' do
|
|
814
|
+
connection.once(:connecting) do
|
|
815
|
+
connection.ping do |time_elapsed|
|
|
816
|
+
expect(connection.state).to eq(:connected)
|
|
817
|
+
stop_reactor
|
|
818
|
+
end
|
|
819
|
+
end
|
|
820
|
+
end
|
|
821
|
+
|
|
822
|
+
context 'with incompatible states' do
|
|
823
|
+
let(:client_options) { default_options.merge(log_level: :none) }
|
|
824
|
+
|
|
825
|
+
context 'when not connected' do
|
|
826
|
+
it 'fails the deferrable (#RTN13b)' do
|
|
827
|
+
connection.ping.errback do |error|
|
|
828
|
+
expect(error.message).to match(/Cannot send a ping when.*initialized/i)
|
|
829
|
+
stop_reactor
|
|
830
|
+
end
|
|
831
|
+
end
|
|
832
|
+
end
|
|
833
|
+
|
|
834
|
+
context 'when suspended' do
|
|
835
|
+
it 'fails the deferrable (#RTN13b)' do
|
|
836
|
+
connection.once(:connected) do
|
|
837
|
+
connection.transition_state_machine! :suspended
|
|
838
|
+
connection.ping.errback do |error|
|
|
839
|
+
expect(error.message).to match(/Cannot send a ping when.*suspended/i)
|
|
840
|
+
stop_reactor
|
|
841
|
+
end
|
|
842
|
+
end
|
|
843
|
+
end
|
|
844
|
+
end
|
|
845
|
+
|
|
846
|
+
context 'when failed' do
|
|
847
|
+
it 'fails the deferrable (#RTN13b)' do
|
|
848
|
+
connection.once(:connected) do
|
|
849
|
+
connection.transition_state_machine! :failed
|
|
850
|
+
connection.ping.errback do |error|
|
|
851
|
+
expect(error.message).to match(/Cannot send a ping when.*failed/i)
|
|
852
|
+
stop_reactor
|
|
853
|
+
end
|
|
854
|
+
end
|
|
855
|
+
end
|
|
856
|
+
end
|
|
857
|
+
|
|
858
|
+
context 'when closed' do
|
|
859
|
+
it 'fails the deferrable (#RTN13b)' do
|
|
860
|
+
connection.once(:connected) do
|
|
861
|
+
connection.close
|
|
862
|
+
connection.once(:closed) do
|
|
863
|
+
connection.ping.errback do |error|
|
|
864
|
+
expect(error.message).to match(/Cannot send a ping when.*closed/i)
|
|
865
|
+
stop_reactor
|
|
866
|
+
end
|
|
867
|
+
end
|
|
868
|
+
end
|
|
869
|
+
end
|
|
870
|
+
end
|
|
871
|
+
|
|
872
|
+
context 'when it becomes closed' do
|
|
873
|
+
it 'fails the deferrable (#RTN13b)' do
|
|
874
|
+
connection.once(:connected) do
|
|
875
|
+
connection.ping.errback do |error|
|
|
876
|
+
expect(error.message).to match(/Ping failed as connection has changed state to.*closing/i)
|
|
877
|
+
stop_reactor
|
|
878
|
+
end
|
|
879
|
+
connection.close
|
|
880
|
+
end
|
|
881
|
+
end
|
|
764
882
|
end
|
|
765
883
|
end
|
|
766
884
|
|
|
767
885
|
context 'with a success block that raises an exception' do
|
|
768
886
|
it 'catches the exception and logs the error' do
|
|
769
887
|
connection.on(:connected) do
|
|
770
|
-
expect(connection.logger).to receive(:error)
|
|
888
|
+
expect(connection.logger).to receive(:error) do |*args, &block|
|
|
889
|
+
expect(args.concat([block ? block.call : nil]).join(',')).to match(/Forced exception/)
|
|
771
890
|
stop_reactor
|
|
772
891
|
end
|
|
773
892
|
connection.ping { raise 'Forced exception' }
|
|
@@ -778,13 +897,22 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
|
778
897
|
context 'when ping times out' do
|
|
779
898
|
let(:client_options) { default_options.merge(log_level: :error) }
|
|
780
899
|
|
|
781
|
-
it 'logs a warning' do
|
|
900
|
+
it 'fails the deferrable logs a warning (#RTN13a, #RTN13c)' do
|
|
901
|
+
message_logged = false
|
|
782
902
|
connection.once(:connected) do
|
|
783
903
|
allow(connection).to receive(:defaults).and_return(connection.defaults.merge(realtime_request_timeout: 0.0001))
|
|
784
|
-
expect(connection.logger).to receive(:warn)
|
|
785
|
-
|
|
904
|
+
expect(connection.logger).to receive(:warn) do |*args, &block|
|
|
905
|
+
expect(block.call).to match(/Ping timed out/)
|
|
906
|
+
message_logged = true
|
|
907
|
+
end
|
|
908
|
+
connection.ping.errback do |error|
|
|
909
|
+
EventMachine.add_timer(0.1) do
|
|
910
|
+
expect(error.message).to match(/Ping timed out/)
|
|
911
|
+
expect(error.code).to eql(50003)
|
|
912
|
+
expect(message_logged).to be_truthy
|
|
913
|
+
stop_reactor
|
|
914
|
+
end
|
|
786
915
|
end
|
|
787
|
-
connection.ping
|
|
788
916
|
end
|
|
789
917
|
end
|
|
790
918
|
|
|
@@ -800,6 +928,107 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
|
800
928
|
end
|
|
801
929
|
end
|
|
802
930
|
|
|
931
|
+
context 'Heartbeats (#RTN23)' do
|
|
932
|
+
context 'heartbeat interval' do
|
|
933
|
+
context 'when reduced artificially' do
|
|
934
|
+
let(:protocol_message_attributes) do
|
|
935
|
+
{
|
|
936
|
+
action: Ably::Models::ProtocolMessage::ACTION.Connected.to_i,
|
|
937
|
+
connection_serial: 55,
|
|
938
|
+
connection_details: {
|
|
939
|
+
max_idle_interval: 2 * 1000
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
end
|
|
943
|
+
let(:client_options) { default_options.merge(realtime_request_timeout: 3) }
|
|
944
|
+
let(:expected_heartbeat_interval) { 5 }
|
|
945
|
+
|
|
946
|
+
it 'is the sum of the max_idle_interval and realtime_request_timeout (#RTN23a)' do
|
|
947
|
+
connection.once(:connected) do
|
|
948
|
+
connection.__incoming_protocol_msgbus__.publish :protocol_message, Ably::Models::ProtocolMessage.new(protocol_message_attributes)
|
|
949
|
+
EventMachine.next_tick do
|
|
950
|
+
expect(connection.heartbeat_interval).to eql(expected_heartbeat_interval)
|
|
951
|
+
stop_reactor
|
|
952
|
+
end
|
|
953
|
+
end
|
|
954
|
+
end
|
|
955
|
+
|
|
956
|
+
it 'disconnects the transport if no heartbeat received since connected (#RTN23a)' do
|
|
957
|
+
connection.once(:connected) do
|
|
958
|
+
connection.__incoming_protocol_msgbus__.publish :protocol_message, Ably::Models::ProtocolMessage.new(protocol_message_attributes)
|
|
959
|
+
last_received_at = Time.now
|
|
960
|
+
connection.once(:disconnected) do
|
|
961
|
+
expect(Time.now.to_i - last_received_at.to_i).to be_within(2).of(expected_heartbeat_interval)
|
|
962
|
+
stop_reactor
|
|
963
|
+
end
|
|
964
|
+
end
|
|
965
|
+
end
|
|
966
|
+
|
|
967
|
+
it 'disconnects the transport if no heartbeat received since last event received (#RTN23a)' do
|
|
968
|
+
connection.once(:connected) do
|
|
969
|
+
connection.__incoming_protocol_msgbus__.publish :protocol_message, Ably::Models::ProtocolMessage.new(protocol_message_attributes)
|
|
970
|
+
last_received_at = Time.now
|
|
971
|
+
EventMachine.add_timer(3) { client.channels.get('foo').attach }
|
|
972
|
+
connection.once(:disconnected) do
|
|
973
|
+
expect(Time.now.to_i - last_received_at.to_i).to be_within(2).of(expected_heartbeat_interval + 3)
|
|
974
|
+
stop_reactor
|
|
975
|
+
end
|
|
976
|
+
end
|
|
977
|
+
end
|
|
978
|
+
end
|
|
979
|
+
end
|
|
980
|
+
|
|
981
|
+
context 'transport-level heartbeats are supported in the websocket transport' do
|
|
982
|
+
it 'provides the heartbeats argument in the websocket connection params (#RTN23b)' do
|
|
983
|
+
expect(EventMachine).to receive(:connect) do |host, port, transport, object, url|
|
|
984
|
+
uri = URI.parse(url)
|
|
985
|
+
expect(CGI::parse(uri.query)['heartbeats'][0]).to eql('false')
|
|
986
|
+
stop_reactor
|
|
987
|
+
end
|
|
988
|
+
client
|
|
989
|
+
end
|
|
990
|
+
|
|
991
|
+
it 'receives websocket heartbeat messages (#RTN23b) [slow test as need to wait for heartbeat]', em_timeout: 45 do
|
|
992
|
+
skip "Heartbeats param is missing from realtime implementation, see https://github.com/ably/realtime/issues/656"
|
|
993
|
+
|
|
994
|
+
connection.once(:connected) do
|
|
995
|
+
connection.__incoming_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
|
|
996
|
+
if protocol_message.action == :heartbeat
|
|
997
|
+
expect(protocol_message.attributes[:source]).to eql('websocket')
|
|
998
|
+
expect(connection.time_since_connection_confirmed_alive?).to be_within(1).of(0)
|
|
999
|
+
stop_reactor
|
|
1000
|
+
end
|
|
1001
|
+
end
|
|
1002
|
+
end
|
|
1003
|
+
end
|
|
1004
|
+
end
|
|
1005
|
+
|
|
1006
|
+
context 'with websocket heartbeats disabled (undocumented)' do
|
|
1007
|
+
let(:client_options) { default_options.merge(websocket_heartbeats_disabled: true) }
|
|
1008
|
+
|
|
1009
|
+
it 'does not provide the heartbeats argument in the websocket connection params (#RTN23b)' do
|
|
1010
|
+
expect(EventMachine).to receive(:connect) do |host, port, transport, object, url|
|
|
1011
|
+
uri = URI.parse(url)
|
|
1012
|
+
expect(CGI::parse(uri.query)['heartbeats'][0]).to be_nil
|
|
1013
|
+
stop_reactor
|
|
1014
|
+
end
|
|
1015
|
+
client
|
|
1016
|
+
end
|
|
1017
|
+
|
|
1018
|
+
it 'receives websocket protocol messages (#RTN23b) [slow test as need to wait for heartbeat]', em_timeout: 45 do
|
|
1019
|
+
connection.once(:connected) do
|
|
1020
|
+
connection.__incoming_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
|
|
1021
|
+
if protocol_message.action == :heartbeat
|
|
1022
|
+
expect(protocol_message.attributes[:source]).to_not eql('websocket')
|
|
1023
|
+
expect(connection.time_since_connection_confirmed_alive?).to be_within(1).of(0)
|
|
1024
|
+
stop_reactor
|
|
1025
|
+
end
|
|
1026
|
+
end
|
|
1027
|
+
end
|
|
1028
|
+
end
|
|
1029
|
+
end
|
|
1030
|
+
end
|
|
1031
|
+
|
|
803
1032
|
context '#details' do
|
|
804
1033
|
let(:connection) { client.connection }
|
|
805
1034
|
|
|
@@ -810,7 +1039,7 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
|
810
1039
|
end
|
|
811
1040
|
end
|
|
812
1041
|
|
|
813
|
-
it 'contains the ConnectionDetails object once connected' do
|
|
1042
|
+
it 'contains the ConnectionDetails object once connected (#RTN21)' do
|
|
814
1043
|
connection.on(:connected) do
|
|
815
1044
|
expect(connection.details).to be_a(Ably::Models::ConnectionDetails)
|
|
816
1045
|
expect(connection.details.connection_key).to_not be_nil
|
|
@@ -819,7 +1048,7 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
|
819
1048
|
end
|
|
820
1049
|
end
|
|
821
1050
|
|
|
822
|
-
it 'contains the new ConnectionDetails object once a subsequent connection is created' do
|
|
1051
|
+
it 'contains the new ConnectionDetails object once a subsequent connection is created (#RTN21)' do
|
|
823
1052
|
connection.once(:connected) do
|
|
824
1053
|
expect(connection.details.connection_key).to_not be_nil
|
|
825
1054
|
old_key = connection.details.connection_key
|
|
@@ -834,13 +1063,13 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
|
834
1063
|
end
|
|
835
1064
|
end
|
|
836
1065
|
|
|
837
|
-
context 'with a different connection_state_ttl' do
|
|
1066
|
+
context 'with a different default connection_state_ttl' do
|
|
838
1067
|
before do
|
|
839
1068
|
old_defaults = Ably::Realtime::Connection::DEFAULTS
|
|
840
1069
|
stub_const 'Ably::Realtime::Connection::DEFAULTS', old_defaults.merge(connection_state_ttl: 15)
|
|
841
1070
|
end
|
|
842
1071
|
|
|
843
|
-
it 'updates the private Connection#connection_state_ttl' do
|
|
1072
|
+
it 'updates the private Connection#connection_state_ttl when received from Ably in ConnectionDetails' do
|
|
844
1073
|
expect(connection.connection_state_ttl).to eql(15)
|
|
845
1074
|
|
|
846
1075
|
connection.once(:connected) do
|
|
@@ -884,11 +1113,16 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
|
884
1113
|
expect(connection.serial).to eql(expected_serial)
|
|
885
1114
|
|
|
886
1115
|
channel.attach do
|
|
887
|
-
channel.publish('event', 'data')
|
|
1116
|
+
channel.publish('event', 'data')
|
|
1117
|
+
channel.subscribe do
|
|
1118
|
+
channel.unsubscribe
|
|
1119
|
+
|
|
888
1120
|
expected_serial += 1 # attach message received
|
|
889
1121
|
expect(connection.serial).to eql(expected_serial)
|
|
890
1122
|
|
|
891
|
-
channel.publish('event', 'data')
|
|
1123
|
+
channel.publish('event', 'data')
|
|
1124
|
+
channel.subscribe do
|
|
1125
|
+
channel.unsubscribe
|
|
892
1126
|
expected_serial += 1 # attach message received
|
|
893
1127
|
expect(connection.serial).to eql(expected_serial)
|
|
894
1128
|
|
|
@@ -942,7 +1176,7 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
|
942
1176
|
context "opening a new connection using a recently disconnected connection's #recovery_key" do
|
|
943
1177
|
context 'connection#id and connection#key after recovery' do
|
|
944
1178
|
it 'remains the same for id and party for key' do
|
|
945
|
-
connection_key_consistent_part_regex = /.*?!(\w{5,})
|
|
1179
|
+
connection_key_consistent_part_regex = /.*?!([\w-]{5,})-\w+/
|
|
946
1180
|
previous_connection_id = nil
|
|
947
1181
|
previous_connection_key = nil
|
|
948
1182
|
|
|
@@ -1024,13 +1258,13 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
|
1024
1258
|
context 'with invalid formatted value sent to server' do
|
|
1025
1259
|
let(:client_options) { default_options.merge(recover: 'not-a-valid-connection-key:1', log_level: :none) }
|
|
1026
1260
|
|
|
1027
|
-
it '
|
|
1028
|
-
connection.once(:
|
|
1261
|
+
it 'sets the #error_reason and moves the connection to FAILED' do
|
|
1262
|
+
connection.once(:failed) do |state_change|
|
|
1029
1263
|
expect(connection.state).to eq(:failed)
|
|
1030
|
-
expect(
|
|
1264
|
+
expect(state_change.reason.message).to match(/Invalid connectionKey/i)
|
|
1031
1265
|
expect(connection.error_reason.message).to match(/Invalid connectionKey/i)
|
|
1032
1266
|
expect(connection.error_reason.code).to eql(80018)
|
|
1033
|
-
expect(connection.error_reason).to eql(
|
|
1267
|
+
expect(connection.error_reason).to eql(state_change.reason)
|
|
1034
1268
|
stop_reactor
|
|
1035
1269
|
end
|
|
1036
1270
|
end
|
|
@@ -1039,13 +1273,13 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
|
1039
1273
|
context 'with expired (missing) value sent to server' do
|
|
1040
1274
|
let(:client_options) { default_options.merge(recover: 'wVIsgTHAB1UvXh7z-1991d8586:0', log_level: :fatal) }
|
|
1041
1275
|
|
|
1042
|
-
it '
|
|
1043
|
-
connection.once(:
|
|
1276
|
+
it 'connects but sets the error reason and includes the reason in the state change' do
|
|
1277
|
+
connection.once(:connected) do |state_change|
|
|
1044
1278
|
expect(connection.state).to eq(:connected)
|
|
1045
|
-
expect(
|
|
1279
|
+
expect(state_change.reason.message).to match(/Unable to recover connection/i)
|
|
1046
1280
|
expect(connection.error_reason.message).to match(/Unable to recover connection/i)
|
|
1047
1281
|
expect(connection.error_reason.code).to eql(80008)
|
|
1048
|
-
expect(connection.error_reason).to eql(
|
|
1282
|
+
expect(connection.error_reason).to eql(state_change.reason)
|
|
1049
1283
|
stop_reactor
|
|
1050
1284
|
end
|
|
1051
1285
|
end
|
|
@@ -1076,22 +1310,22 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
|
1076
1310
|
end
|
|
1077
1311
|
|
|
1078
1312
|
context 'when a state transition is unsupported' do
|
|
1079
|
-
let(:client_options) { default_options.merge(log_level: :
|
|
1313
|
+
let(:client_options) { default_options.merge(log_level: :fatal) } # silence FATAL errors
|
|
1080
1314
|
|
|
1081
|
-
it '
|
|
1315
|
+
it 'logs the invalid state change as fatal' do
|
|
1082
1316
|
connection.connect do
|
|
1083
1317
|
connection.transition_state_machine :initialized
|
|
1318
|
+
EventMachine.add_timer(1) { stop_reactor }
|
|
1084
1319
|
end
|
|
1085
1320
|
|
|
1086
|
-
|
|
1087
|
-
expect(
|
|
1088
|
-
stop_reactor
|
|
1321
|
+
expect(client.logger).to receive(:fatal).at_least(:once) do |*args, &block|
|
|
1322
|
+
expect(args.concat([block ? block.call : nil]).join(',')).to match(/Unable to transition/)
|
|
1089
1323
|
end
|
|
1090
1324
|
end
|
|
1091
1325
|
end
|
|
1092
1326
|
|
|
1093
1327
|
context 'protocol failure' do
|
|
1094
|
-
let(:client_options) { default_options.merge(protocol: :json) }
|
|
1328
|
+
let(:client_options) { default_options.merge(protocol: :json, log_level: :none) }
|
|
1095
1329
|
|
|
1096
1330
|
context 'receiving an invalid ProtocolMessage' do
|
|
1097
1331
|
it 'emits an error on the connection and logs a fatal error message' do
|
|
@@ -1099,9 +1333,11 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
|
1099
1333
|
connection.transport.send(:driver).emit 'message', OpenStruct.new(data: { action: 500 }.to_json)
|
|
1100
1334
|
end
|
|
1101
1335
|
|
|
1102
|
-
expect(client.logger).to receive(:fatal).
|
|
1103
|
-
|
|
1104
|
-
|
|
1336
|
+
expect(client.logger).to receive(:fatal).at_least(:once) do |*args, &block|
|
|
1337
|
+
expect(args.concat([block ? block.call : nil]).join(',')).to match(/Invalid Protocol Message/)
|
|
1338
|
+
end
|
|
1339
|
+
connection.on(:failed) do |state_change|
|
|
1340
|
+
expect(state_change.reason.message).to match(/Invalid Protocol Message/)
|
|
1105
1341
|
stop_reactor
|
|
1106
1342
|
end
|
|
1107
1343
|
end
|
|
@@ -1238,11 +1474,13 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
|
1238
1474
|
)
|
|
1239
1475
|
end
|
|
1240
1476
|
|
|
1241
|
-
it '
|
|
1477
|
+
it 'moves the channels into the suspended state and prevents publishing of messages on those channels' do
|
|
1242
1478
|
channel.attach do
|
|
1243
|
-
channel.once(:
|
|
1244
|
-
|
|
1245
|
-
|
|
1479
|
+
channel.once(:suspended) do
|
|
1480
|
+
channel.publish('test').errback do |error|
|
|
1481
|
+
expect(error).to be_a(Ably::Exceptions::MessageQueueingDisabled)
|
|
1482
|
+
stop_reactor
|
|
1483
|
+
end
|
|
1246
1484
|
end
|
|
1247
1485
|
|
|
1248
1486
|
close_connection_proc = Proc.new do
|
|
@@ -1270,8 +1508,10 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
|
1270
1508
|
it 'sets all channels to failed and prevents publishing of messages on those channels' do
|
|
1271
1509
|
channel.attach
|
|
1272
1510
|
channel.once(:failed) do
|
|
1273
|
-
|
|
1274
|
-
|
|
1511
|
+
channel.publish('test').errback do |error|
|
|
1512
|
+
expect(error).to be_a(Ably::Exceptions::ChannelInactive)
|
|
1513
|
+
stop_reactor
|
|
1514
|
+
end
|
|
1275
1515
|
end
|
|
1276
1516
|
end
|
|
1277
1517
|
end
|
|
@@ -1304,6 +1544,7 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
|
1304
1544
|
context 'ConnectionStateChange object' do
|
|
1305
1545
|
it 'has current state' do
|
|
1306
1546
|
connection.on(:connected) do |connection_state_change|
|
|
1547
|
+
expect(connection_state_change.current).to be_a(Ably::Realtime::Connection::STATE)
|
|
1307
1548
|
expect(connection_state_change.current).to eq(:connected)
|
|
1308
1549
|
stop_reactor
|
|
1309
1550
|
end
|
|
@@ -1311,11 +1552,20 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
|
1311
1552
|
|
|
1312
1553
|
it 'has a previous state' do
|
|
1313
1554
|
connection.on(:connected) do |connection_state_change|
|
|
1555
|
+
expect(connection_state_change.previous).to be_a(Ably::Realtime::Connection::STATE)
|
|
1314
1556
|
expect(connection_state_change.previous).to eq(:connecting)
|
|
1315
1557
|
stop_reactor
|
|
1316
1558
|
end
|
|
1317
1559
|
end
|
|
1318
1560
|
|
|
1561
|
+
it 'has the event that generated the state change (#TH5)' do
|
|
1562
|
+
connection.on(:connected) do |connection_state_change|
|
|
1563
|
+
expect(connection_state_change.event).to be_a(Ably::Realtime::Connection::EVENT)
|
|
1564
|
+
expect(connection_state_change.event).to eq(:connected)
|
|
1565
|
+
stop_reactor
|
|
1566
|
+
end
|
|
1567
|
+
end
|
|
1568
|
+
|
|
1319
1569
|
it 'contains a private API protocol_message attribute that is used for special state change events', :api_private do
|
|
1320
1570
|
connection.on(:connected) do |connection_state_change|
|
|
1321
1571
|
expect(connection_state_change.protocol_message).to be_a(Ably::Models::ProtocolMessage)
|
|
@@ -1393,29 +1643,118 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
|
1393
1643
|
end
|
|
1394
1644
|
end
|
|
1395
1645
|
end
|
|
1646
|
+
|
|
1647
|
+
context 'whilst CONNECTED' do
|
|
1648
|
+
context 'when a CONNECTED message is received (#RTN24)' do
|
|
1649
|
+
let(:connection_key) { random_str(32) }
|
|
1650
|
+
let(:protocol_message_attributes) do
|
|
1651
|
+
{
|
|
1652
|
+
action: Ably::Models::ProtocolMessage::ACTION.Connected.to_i,
|
|
1653
|
+
connection_serial: 55,
|
|
1654
|
+
connection_details: {
|
|
1655
|
+
client_id: 'bob',
|
|
1656
|
+
connection_key: connection_key,
|
|
1657
|
+
connection_state_ttl: 33 * 1000,
|
|
1658
|
+
max_frame_size: 555,
|
|
1659
|
+
max_inbound_rate: 999,
|
|
1660
|
+
max_message_size: 1310,
|
|
1661
|
+
server_id: 'us-east-1-a.foo.com',
|
|
1662
|
+
max_idle_interval: 4 * 1000
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
end
|
|
1666
|
+
|
|
1667
|
+
it 'emits an UPDATE event' do
|
|
1668
|
+
connection.once(:connected) do
|
|
1669
|
+
connection.once(:update) do |connection_state_change|
|
|
1670
|
+
expect(connection_state_change.current).to eq(:connected)
|
|
1671
|
+
expect(connection_state_change.previous).to eq(:connected)
|
|
1672
|
+
expect(connection_state_change.retry_in).to be_nil
|
|
1673
|
+
expect(connection_state_change.reason).to be_nil
|
|
1674
|
+
expect(connection.state).to eq(:connected)
|
|
1675
|
+
stop_reactor
|
|
1676
|
+
end
|
|
1677
|
+
|
|
1678
|
+
connection.__incoming_protocol_msgbus__.publish :protocol_message, Ably::Models::ProtocolMessage.new(protocol_message_attributes)
|
|
1679
|
+
end
|
|
1680
|
+
end
|
|
1681
|
+
|
|
1682
|
+
it 'updates the ConnectionDetail and Connection attributes (#RTC8a1)' do
|
|
1683
|
+
connection.once(:connected) do
|
|
1684
|
+
expect(client.auth.client_id).to eql('*')
|
|
1685
|
+
|
|
1686
|
+
connection.once(:update) do |connection_state_change|
|
|
1687
|
+
expect(client.auth.client_id).to eql('bob')
|
|
1688
|
+
expect(connection.key).to eql(connection_key)
|
|
1689
|
+
expect(connection.serial).to eql(55)
|
|
1690
|
+
expect(connection.connection_state_ttl).to eql(33)
|
|
1691
|
+
|
|
1692
|
+
expect(connection.details.client_id).to eql('bob')
|
|
1693
|
+
expect(connection.details.connection_key).to eql(connection_key)
|
|
1694
|
+
expect(connection.details.connection_state_ttl).to eql(33)
|
|
1695
|
+
expect(connection.details.max_frame_size).to eql(555)
|
|
1696
|
+
expect(connection.details.max_inbound_rate).to eql(999)
|
|
1697
|
+
expect(connection.details.max_message_size).to eql(1310)
|
|
1698
|
+
expect(connection.details.server_id).to eql('us-east-1-a.foo.com')
|
|
1699
|
+
expect(connection.details.max_idle_interval).to eql(4)
|
|
1700
|
+
stop_reactor
|
|
1701
|
+
end
|
|
1702
|
+
|
|
1703
|
+
connection.__incoming_protocol_msgbus__.publish :protocol_message, Ably::Models::ProtocolMessage.new(protocol_message_attributes)
|
|
1704
|
+
end
|
|
1705
|
+
end
|
|
1706
|
+
end
|
|
1707
|
+
|
|
1708
|
+
context 'when a CONNECTED message with an error is received' do
|
|
1709
|
+
let(:protocol_message_attributes) do
|
|
1710
|
+
{
|
|
1711
|
+
action: Ably::Models::ProtocolMessage::ACTION.Connected.to_i,
|
|
1712
|
+
connection_serial: 22,
|
|
1713
|
+
error: { code: 50000, message: 'Internal failure' },
|
|
1714
|
+
}
|
|
1715
|
+
end
|
|
1716
|
+
|
|
1717
|
+
it 'emits an UPDATE event' do
|
|
1718
|
+
connection.once(:connected) do
|
|
1719
|
+
connection.on(:update) do |connection_state_change|
|
|
1720
|
+
expect(connection_state_change.current).to eq(:connected)
|
|
1721
|
+
expect(connection_state_change.previous).to eq(:connected)
|
|
1722
|
+
expect(connection_state_change.retry_in).to be_nil
|
|
1723
|
+
expect(connection_state_change.reason).to be_a(Ably::Models::ErrorInfo)
|
|
1724
|
+
expect(connection_state_change.reason.code).to eql(50000)
|
|
1725
|
+
expect(connection_state_change.reason.message).to match(/Internal failure/)
|
|
1726
|
+
expect(connection.state).to eq(:connected)
|
|
1727
|
+
stop_reactor
|
|
1728
|
+
end
|
|
1729
|
+
|
|
1730
|
+
connection.__incoming_protocol_msgbus__.publish :protocol_message, Ably::Models::ProtocolMessage.new(protocol_message_attributes)
|
|
1731
|
+
end
|
|
1732
|
+
end
|
|
1733
|
+
end
|
|
1734
|
+
end
|
|
1396
1735
|
end
|
|
1397
1736
|
|
|
1398
1737
|
context 'version params' do
|
|
1399
|
-
it 'sends the protocol version param v' do
|
|
1738
|
+
it 'sends the protocol version param v (#G4, #RTN2f)' do
|
|
1400
1739
|
expect(EventMachine).to receive(:connect) do |host, port, transport, object, url|
|
|
1401
1740
|
uri = URI.parse(url)
|
|
1402
|
-
expect(CGI::parse(uri.query)['v'][0]).to eql(
|
|
1741
|
+
expect(CGI::parse(uri.query)['v'][0]).to eql('1.0')
|
|
1403
1742
|
stop_reactor
|
|
1404
1743
|
end
|
|
1405
1744
|
client
|
|
1406
1745
|
end
|
|
1407
1746
|
|
|
1408
|
-
it 'sends the lib version param lib' do
|
|
1747
|
+
it 'sends the lib version param lib (#RTN2g)' do
|
|
1409
1748
|
expect(EventMachine).to receive(:connect) do |host, port, transport, object, url|
|
|
1410
1749
|
uri = URI.parse(url)
|
|
1411
|
-
expect(CGI::parse(uri.query)['lib'][0]).to
|
|
1750
|
+
expect(CGI::parse(uri.query)['lib'][0]).to match(/^ruby-1\.0\.\d+(-[\w\.]+)?+$/)
|
|
1412
1751
|
stop_reactor
|
|
1413
1752
|
end
|
|
1414
1753
|
client
|
|
1415
1754
|
end
|
|
1416
1755
|
|
|
1417
1756
|
context 'with variant' do
|
|
1418
|
-
let(:variant) { 'foo
|
|
1757
|
+
let(:variant) { 'foo' }
|
|
1419
1758
|
|
|
1420
1759
|
before do
|
|
1421
1760
|
Ably.lib_variant = variant
|
|
@@ -1425,10 +1764,10 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
|
1425
1764
|
Ably.lib_variant = nil
|
|
1426
1765
|
end
|
|
1427
1766
|
|
|
1428
|
-
it 'sends the lib version param lib with the variant' do
|
|
1767
|
+
it 'sends the lib version param lib with the variant (#RTN2g + #RSC7b)' do
|
|
1429
1768
|
expect(EventMachine).to receive(:connect) do |host, port, transport, object, url|
|
|
1430
1769
|
uri = URI.parse(url)
|
|
1431
|
-
expect(CGI::parse(uri.query)['lib'][0]).to
|
|
1770
|
+
expect(CGI::parse(uri.query)['lib'][0]).to match(/^ruby-#{variant}-1\.0\.\d+(-[\w\.]+)?$/)
|
|
1432
1771
|
stop_reactor
|
|
1433
1772
|
end
|
|
1434
1773
|
client
|