ably-rest 0.7.3 → 0.7.5
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 +8 -8
- data/.travis.yml +1 -0
- data/SPEC.md +480 -472
- data/lib/ably-rest.rb +1 -1
- data/lib/submodules/ably-ruby/LICENSE.txt +1 -1
- data/lib/submodules/ably-ruby/README.md +107 -24
- data/lib/submodules/ably-ruby/SPEC.md +531 -398
- data/lib/submodules/ably-ruby/lib/ably/auth.rb +24 -16
- data/lib/submodules/ably-ruby/lib/ably/exceptions.rb +9 -0
- data/lib/submodules/ably-ruby/lib/ably/models/message.rb +17 -9
- data/lib/submodules/ably-ruby/lib/ably/models/paginated_resource.rb +12 -8
- data/lib/submodules/ably-ruby/lib/ably/models/presence_message.rb +18 -10
- data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +15 -4
- data/lib/submodules/ably-ruby/lib/ably/modules/async_wrapper.rb +4 -3
- data/lib/submodules/ably-ruby/lib/ably/modules/event_emitter.rb +31 -2
- data/lib/submodules/ably-ruby/lib/ably/modules/message_emitter.rb +77 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/safe_deferrable.rb +71 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/safe_yield.rb +41 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/state_emitter.rb +28 -8
- data/lib/submodules/ably-ruby/lib/ably/realtime.rb +0 -5
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +24 -29
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_manager.rb +54 -11
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_state_machine.rb +21 -6
- data/lib/submodules/ably-ruby/lib/ably/realtime/client.rb +7 -2
- data/lib/submodules/ably-ruby/lib/ably/realtime/client/incoming_message_dispatcher.rb +29 -26
- data/lib/submodules/ably-ruby/lib/ably/realtime/client/outgoing_message_dispatcher.rb +4 -4
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +41 -9
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_manager.rb +72 -24
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_state_machine.rb +26 -4
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/websocket_transport.rb +19 -6
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence.rb +74 -208
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence/members_map.rb +264 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence/presence_manager.rb +59 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence/presence_state_machine.rb +64 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +6 -2
- data/lib/submodules/ably-ruby/lib/ably/rest/presence.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/util/pub_sub.rb +3 -1
- data/lib/submodules/ably-ruby/lib/ably/util/safe_deferrable.rb +18 -0
- data/lib/submodules/ably-ruby/lib/ably/version.rb +1 -1
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_history_spec.rb +2 -2
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +28 -6
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +116 -46
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +55 -10
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +32 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +456 -96
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/stats_spec.rb +2 -2
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/time_spec.rb +2 -2
- data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +96 -7
- data/lib/submodules/ably-ruby/spec/shared/client_initializer_behaviour.rb +8 -0
- data/lib/submodules/ably-ruby/spec/shared/safe_deferrable_behaviour.rb +71 -0
- data/lib/submodules/ably-ruby/spec/support/api_helper.rb +1 -1
- data/lib/submodules/ably-ruby/spec/support/event_machine_helper.rb +1 -1
- data/lib/submodules/ably-ruby/spec/support/test_app.rb +13 -7
- data/lib/submodules/ably-ruby/spec/unit/models/message_spec.rb +15 -14
- data/lib/submodules/ably-ruby/spec/unit/models/paginated_resource_spec.rb +4 -4
- data/lib/submodules/ably-ruby/spec/unit/models/presence_message_spec.rb +17 -17
- data/lib/submodules/ably-ruby/spec/unit/models/stat_spec.rb +4 -4
- data/lib/submodules/ably-ruby/spec/unit/modules/async_wrapper_spec.rb +28 -9
- data/lib/submodules/ably-ruby/spec/unit/modules/event_emitter_spec.rb +50 -0
- data/lib/submodules/ably-ruby/spec/unit/modules/state_emitter_spec.rb +76 -2
- data/lib/submodules/ably-ruby/spec/unit/realtime/channel_spec.rb +51 -20
- data/lib/submodules/ably-ruby/spec/unit/realtime/channels_spec.rb +3 -3
- data/lib/submodules/ably-ruby/spec/unit/realtime/connection_spec.rb +30 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/presence_spec.rb +52 -26
- data/lib/submodules/ably-ruby/spec/unit/realtime/safe_deferrable_spec.rb +12 -0
- data/spec/spec_helper.rb +5 -0
- metadata +12 -4
- data/lib/submodules/ably-ruby/.ruby-version.old +0 -1
@@ -17,10 +17,10 @@ describe Ably::Realtime::Channel, '#history', :event_machine do
|
|
17
17
|
|
18
18
|
let(:options) { { :protocol => :json } }
|
19
19
|
|
20
|
-
it 'returns a
|
20
|
+
it 'returns a SafeDeferrable that catches exceptions in callbacks and logs them' do
|
21
21
|
channel.publish('event', payload) do |message|
|
22
22
|
history = channel.history
|
23
|
-
expect(history).to be_a(
|
23
|
+
expect(history).to be_a(Ably::Util::SafeDeferrable)
|
24
24
|
history.callback do |messages|
|
25
25
|
expect(messages.count).to eql(1)
|
26
26
|
expect(messages).to be_a(Ably::Models::PaginatedResource)
|
@@ -84,12 +84,12 @@ describe Ably::Realtime::Channel, :event_machine do
|
|
84
84
|
end
|
85
85
|
end
|
86
86
|
|
87
|
-
it 'returns a
|
88
|
-
expect(channel.attach).to be_a(
|
87
|
+
it 'returns a SafeDeferrable that catches exceptions in callbacks and logs them' do
|
88
|
+
expect(channel.attach).to be_a(Ably::Util::SafeDeferrable)
|
89
89
|
stop_reactor
|
90
90
|
end
|
91
91
|
|
92
|
-
it 'calls the
|
92
|
+
it 'calls the SafeDeferrable callback on success' do
|
93
93
|
channel.attach.callback do |channel|
|
94
94
|
expect(channel).to be_a(Ably::Realtime::Channel)
|
95
95
|
expect(channel.state).to eq(:attached)
|
@@ -195,6 +195,26 @@ describe Ably::Realtime::Channel, :event_machine do
|
|
195
195
|
stop_reactor
|
196
196
|
end
|
197
197
|
end
|
198
|
+
|
199
|
+
context 'and subsequent authorisation with suitable permissions' do
|
200
|
+
it 'attaches to the channel successfully and resets the channel error_reason' do
|
201
|
+
restricted_channel.attach
|
202
|
+
restricted_channel.once(:failed) do
|
203
|
+
restricted_client.close do
|
204
|
+
# A direct call to #authorise is synchronous
|
205
|
+
restricted_client.auth.authorise(api_key: api_key)
|
206
|
+
|
207
|
+
restricted_client.connect do
|
208
|
+
restricted_channel.once(:attached) do
|
209
|
+
expect(restricted_channel.error_reason).to be_nil
|
210
|
+
stop_reactor
|
211
|
+
end
|
212
|
+
restricted_channel.attach
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
198
218
|
end
|
199
219
|
end
|
200
220
|
|
@@ -230,9 +250,11 @@ describe Ably::Realtime::Channel, :event_machine do
|
|
230
250
|
end
|
231
251
|
end
|
232
252
|
|
233
|
-
it 'returns a
|
234
|
-
|
235
|
-
|
253
|
+
it 'returns a SafeDeferrable that catches exceptions in callbacks and logs them' do
|
254
|
+
channel.attach do
|
255
|
+
expect(channel.detach).to be_a(Ably::Util::SafeDeferrable)
|
256
|
+
stop_reactor
|
257
|
+
end
|
236
258
|
end
|
237
259
|
|
238
260
|
it 'calls the Deferrable callback on success' do
|
@@ -66,7 +66,8 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
|
|
66
66
|
)
|
67
67
|
end
|
68
68
|
|
69
|
-
|
69
|
+
# retry immediately after failure, then one retry every :retry_every_for_tests
|
70
|
+
let(:expected_retry_attempts) { 1 + (max_time_in_state_for_tests / retry_every_for_tests).round }
|
70
71
|
let(:state_changes) { Hash.new { |hash, key| hash[key] = 0 } }
|
71
72
|
let(:timer) { Hash.new }
|
72
73
|
|
@@ -288,21 +289,76 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
|
|
288
289
|
end
|
289
290
|
|
290
291
|
context 'when DISCONNECTED ProtocolMessage received from the server' do
|
291
|
-
it 'reconnects automatically' do
|
292
|
+
it 'reconnects automatically and immediately' do
|
292
293
|
fail_if_suspended_or_failed
|
293
294
|
|
294
295
|
connection.once(:connected) do
|
295
296
|
connection.once(:disconnected) do
|
296
|
-
|
297
|
-
|
298
|
-
expect(
|
299
|
-
|
297
|
+
disconnected_at = Time.now.to_f
|
298
|
+
connection.once(:connecting) do
|
299
|
+
expect(Time.now.to_f).to be_within(0.25).of(disconnected_at)
|
300
|
+
connection.once(:connected) do
|
301
|
+
state_history = connection.state_history.map { |transition| transition[:state].to_sym }
|
302
|
+
expect(state_history).to eql([:connecting, :connected, :disconnected, :connecting, :connected])
|
303
|
+
stop_reactor
|
304
|
+
end
|
300
305
|
end
|
301
306
|
end
|
302
307
|
protocol_message = Ably::Models::ProtocolMessage.new(action: Ably::Models::ProtocolMessage::ACTION.Disconnected.to_i)
|
303
308
|
connection.__incoming_protocol_msgbus__.publish :protocol_message, protocol_message
|
304
309
|
end
|
305
310
|
end
|
311
|
+
|
312
|
+
context 'and subsequently fails to reconnect' do
|
313
|
+
let(:retry_every) { 1.5 }
|
314
|
+
|
315
|
+
before do
|
316
|
+
# Reconfigure client library retry periods and timeouts so that tests run quickly
|
317
|
+
stub_const 'Ably::Realtime::Connection::ConnectionManager::CONNECT_RETRY_CONFIG',
|
318
|
+
Ably::Realtime::Connection::ConnectionManager::CONNECT_RETRY_CONFIG.merge(
|
319
|
+
disconnected: { retry_every: retry_every, max_time_in_state: 60 })
|
320
|
+
end
|
321
|
+
|
322
|
+
it "retries every CONNECT_RETRY_CONFIG[:disconnected][:retry_every] seconds" do
|
323
|
+
fail_if_suspended_or_failed
|
324
|
+
|
325
|
+
stubbed_first_attempt = false
|
326
|
+
|
327
|
+
connection.once(:connected) do
|
328
|
+
connection.once(:disconnected) do
|
329
|
+
connection.once(:connecting) do
|
330
|
+
connection.once(:disconnected) do
|
331
|
+
disconnected_at = Time.now.to_f
|
332
|
+
connection.once(:connecting) do
|
333
|
+
expect(Time.now.to_f - disconnected_at).to be > retry_every
|
334
|
+
state_history = connection.state_history.map { |transition| transition[:state].to_sym }
|
335
|
+
expect(state_history).to eql([:connecting, :connected, :disconnected, :connecting, :disconnected, :connecting])
|
336
|
+
|
337
|
+
# allow one more recoonect when reactor stopped
|
338
|
+
expect(connection.manager).to receive(:reconnect_transport)
|
339
|
+
stop_reactor
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
# When reconnect called simply open the transport and close immediately
|
344
|
+
expect(connection.manager).to receive(:reconnect_transport) do
|
345
|
+
next if stubbed_first_attempt
|
346
|
+
|
347
|
+
connection.manager.setup_transport do
|
348
|
+
EventMachine.next_tick do
|
349
|
+
connection.transport.unbind
|
350
|
+
stubbed_first_attempt = true
|
351
|
+
end
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
protocol_message = Ably::Models::ProtocolMessage.new(action: Ably::Models::ProtocolMessage::ACTION.Disconnected.to_i)
|
358
|
+
connection.__incoming_protocol_msgbus__.publish :protocol_message, protocol_message
|
359
|
+
end
|
360
|
+
end
|
361
|
+
end
|
306
362
|
end
|
307
363
|
|
308
364
|
context 'when websocket transport is closed' do
|
@@ -359,6 +415,16 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
|
|
359
415
|
end
|
360
416
|
end
|
361
417
|
|
418
|
+
it 'triggers the resume callback', api_private: true do
|
419
|
+
channel.attach do
|
420
|
+
connection.transport.close_connection_after_writing
|
421
|
+
connection.on_resume do
|
422
|
+
expect(connection).to be_connected
|
423
|
+
stop_reactor
|
424
|
+
end
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
362
428
|
context 'when messages were published whilst the client was disconnected' do
|
363
429
|
it 'receives the messages published whilst offline' do
|
364
430
|
messages_received = false
|
@@ -394,55 +460,57 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
|
|
394
460
|
end
|
395
461
|
end
|
396
462
|
|
397
|
-
context 'when failing to resume
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
it 'updates the connection_id and connection_key' do
|
404
|
-
connection.once(:connected) do
|
405
|
-
previous_connection_id = connection.id
|
406
|
-
previous_connection_key = connection.key
|
463
|
+
context 'when failing to resume' do
|
464
|
+
context 'because the connection_key is not or no longer valid' do
|
465
|
+
def kill_connection_transport_and_prevent_valid_resume
|
466
|
+
connection.transport.close_connection_after_writing
|
467
|
+
connection.configure_new '0123456789abcdef', '0123456789abcdef', -1 # force the resume connection key to be invalid
|
468
|
+
end
|
407
469
|
|
470
|
+
it 'updates the connection_id and connection_key' do
|
408
471
|
connection.once(:connected) do
|
409
|
-
|
410
|
-
|
411
|
-
stop_reactor
|
412
|
-
end
|
413
|
-
|
414
|
-
kill_connection_transport_and_prevent_valid_resume
|
415
|
-
end
|
416
|
-
end
|
472
|
+
previous_connection_id = connection.id
|
473
|
+
previous_connection_key = connection.key
|
417
474
|
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
when_all(*channels.map(&:attach)) do
|
422
|
-
detached_channels = []
|
423
|
-
channels.each do |channel|
|
424
|
-
channel.on(:detached) do
|
425
|
-
detached_channels << channel
|
426
|
-
next unless detached_channels.count == channel_count
|
427
|
-
expect(detached_channels.count).to eql(channel_count)
|
475
|
+
connection.once(:connected) do
|
476
|
+
expect(connection.key).to_not eql(previous_connection_key)
|
477
|
+
expect(connection.id).to_not eql(previous_connection_id)
|
428
478
|
stop_reactor
|
429
479
|
end
|
430
|
-
end
|
431
480
|
|
432
|
-
|
481
|
+
kill_connection_transport_and_prevent_valid_resume
|
482
|
+
end
|
433
483
|
end
|
434
|
-
end
|
435
484
|
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
485
|
+
it 'detaches all channels' do
|
486
|
+
channel_count = 10
|
487
|
+
channels = channel_count.times.map { |index| client.channel("channel-#{index}") }
|
488
|
+
when_all(*channels.map(&:attach)) do
|
489
|
+
detached_channels = []
|
490
|
+
channels.each do |channel|
|
491
|
+
channel.on(:detached) do
|
492
|
+
detached_channels << channel
|
493
|
+
next unless detached_channels.count == channel_count
|
494
|
+
expect(detached_channels.count).to eql(channel_count)
|
495
|
+
stop_reactor
|
496
|
+
end
|
497
|
+
end
|
498
|
+
|
499
|
+
kill_connection_transport_and_prevent_valid_resume
|
443
500
|
end
|
501
|
+
end
|
444
502
|
|
445
|
-
|
503
|
+
it 'emits an error on the channel and sets the error reason' do
|
504
|
+
client.channel(random_str).attach do |channel|
|
505
|
+
channel.on(:error) do |error|
|
506
|
+
expect(error.message).to match(/Invalid connection key/i)
|
507
|
+
expect(error.code).to eql(80008)
|
508
|
+
expect(channel.error_reason).to eql(error)
|
509
|
+
stop_reactor
|
510
|
+
end
|
511
|
+
|
512
|
+
kill_connection_transport_and_prevent_valid_resume
|
513
|
+
end
|
446
514
|
end
|
447
515
|
end
|
448
516
|
end
|
@@ -461,7 +529,9 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
|
|
461
529
|
)
|
462
530
|
end
|
463
531
|
|
464
|
-
|
532
|
+
# Retry immediately and then wait retry_every before every subsequent attempt
|
533
|
+
let(:expected_retry_attempts) { 1 + (max_time_in_state_for_tests / retry_every_for_tests).round }
|
534
|
+
|
465
535
|
let(:retry_count_for_one_state) { 1 + expected_retry_attempts } # initial connect then disconnected
|
466
536
|
let(:retry_count_for_all_states) { 1 + expected_retry_attempts * 2 } # initial connection, disconnected & then suspended
|
467
537
|
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
require 'spec_helper'
|
3
|
+
require 'ostruct'
|
3
4
|
|
4
5
|
describe Ably::Realtime::Connection, :event_machine do
|
5
6
|
let(:connection) { client.connection }
|
@@ -148,14 +149,12 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
148
149
|
connection.once(:connected) do
|
149
150
|
started_at = Time.now
|
150
151
|
connection.once(:disconnected) do |error|
|
151
|
-
|
152
|
+
connection.once(:connected) do
|
153
|
+
expect(client.auth.current_token).to_not be_expired
|
152
154
|
expect(Time.now - started_at >= ttl)
|
153
155
|
expect(original_token).to be_expired
|
154
156
|
expect(error.code).to eql(40140) # token expired
|
155
|
-
|
156
|
-
expect(client.auth.current_token).to_not be_expired
|
157
|
-
stop_reactor
|
158
|
-
end
|
157
|
+
stop_reactor
|
159
158
|
end
|
160
159
|
end
|
161
160
|
end
|
@@ -234,8 +233,8 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
234
233
|
end
|
235
234
|
|
236
235
|
context '#connect' do
|
237
|
-
it 'returns a
|
238
|
-
expect(connection.connect).to be_a(
|
236
|
+
it 'returns a SafeDeferrable that catches exceptions in callbacks and logs them' do
|
237
|
+
expect(connection.connect).to be_a(Ably::Util::SafeDeferrable)
|
239
238
|
stop_reactor
|
240
239
|
end
|
241
240
|
|
@@ -372,9 +371,9 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
372
371
|
end
|
373
372
|
|
374
373
|
context '#close' do
|
375
|
-
it 'returns a
|
374
|
+
it 'returns a SafeDeferrable that catches exceptions in callbacks and logs them' do
|
376
375
|
connection.connect do
|
377
|
-
expect(connection.close).to be_a(
|
376
|
+
expect(connection.close).to be_a(Ably::Util::SafeDeferrable)
|
378
377
|
stop_reactor
|
379
378
|
end
|
380
379
|
end
|
@@ -504,6 +503,17 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
504
503
|
stop_reactor
|
505
504
|
end
|
506
505
|
end
|
506
|
+
|
507
|
+
context 'with a success block that raises an exception' do
|
508
|
+
it 'catches the exception and logs the error' do
|
509
|
+
connection.on(:connected) do
|
510
|
+
expect(connection.logger).to receive(:error).with(/Forced exception/) do
|
511
|
+
stop_reactor
|
512
|
+
end
|
513
|
+
connection.ping { raise 'Forced exception' }
|
514
|
+
end
|
515
|
+
end
|
516
|
+
end
|
507
517
|
end
|
508
518
|
|
509
519
|
context 'recovery' do
|
@@ -591,7 +601,7 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
591
601
|
context 'connection#id and connection#key after recovery' do
|
592
602
|
let(:client_options) { default_options.merge(log_level: :none) }
|
593
603
|
|
594
|
-
it '
|
604
|
+
it 'remains the same' do
|
595
605
|
previous_connection_id = nil
|
596
606
|
previous_connection_key = nil
|
597
607
|
|
@@ -610,6 +620,22 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
610
620
|
end
|
611
621
|
end
|
612
622
|
end
|
623
|
+
|
624
|
+
it 'does not trigger a resume callback', api_private: true do
|
625
|
+
connection.once(:connected) do
|
626
|
+
connection.transition_state_machine! :failed
|
627
|
+
end
|
628
|
+
|
629
|
+
connection.once(:failed) do
|
630
|
+
recover_client = Ably::Realtime::Client.new(default_options.merge(recover: client.connection.recovery_key))
|
631
|
+
recover_client.connection.on_resume do
|
632
|
+
raise 'Should not trigger resume callback'
|
633
|
+
end
|
634
|
+
recover_client.connection.on(:connected) do
|
635
|
+
EventMachine.add_timer(0.5) { stop_reactor }
|
636
|
+
end
|
637
|
+
end
|
638
|
+
end
|
613
639
|
end
|
614
640
|
|
615
641
|
context 'when messages have been sent whilst the old connection is disconnected' do
|
@@ -653,6 +679,7 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
653
679
|
it 'triggers a fatal error on the connection object, sets the #error_reason and disconnects' do
|
654
680
|
connection.once(:error) do |error|
|
655
681
|
expect(connection.state).to eq(:failed)
|
682
|
+
expect(error.message).to match(/Invalid connection key/)
|
656
683
|
expect(connection.error_reason.message).to match(/Invalid connection key/)
|
657
684
|
expect(connection.error_reason.code).to eql(40006)
|
658
685
|
expect(connection.error_reason).to eql(error)
|
@@ -667,6 +694,7 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
667
694
|
it 'triggers an error on the connection object, sets the #error_reason, yet will connect anyway' do
|
668
695
|
connection.once(:error) do |error|
|
669
696
|
expect(connection.state).to eq(:connected)
|
697
|
+
expect(error.message).to match(/Invalid connection key/i)
|
670
698
|
expect(connection.error_reason.message).to match(/Invalid connection key/i)
|
671
699
|
expect(connection.error_reason.code).to eql(80008)
|
672
700
|
expect(connection.error_reason).to eql(error)
|
@@ -714,6 +742,23 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
714
742
|
end
|
715
743
|
end
|
716
744
|
|
745
|
+
context 'protocol failure' do
|
746
|
+
let(:client_options) { default_options.merge(protocol: :json) }
|
747
|
+
|
748
|
+
context 'receiving an invalid ProtocolMessage' do
|
749
|
+
it 'emits an error on the connection and logs a fatal error message' do
|
750
|
+
connection.connect do
|
751
|
+
connection.transport.send(:driver).emit 'message', OpenStruct.new(data: { action: 500 }.to_json)
|
752
|
+
end
|
753
|
+
|
754
|
+
expect(client.logger).to receive(:fatal).with(/Invalid Protocol Message/)
|
755
|
+
connection.on(:error) do |error|
|
756
|
+
expect(error.message).to match(/Invalid Protocol Message/)
|
757
|
+
stop_reactor
|
758
|
+
end
|
759
|
+
end
|
760
|
+
end
|
761
|
+
end
|
717
762
|
|
718
763
|
context 'undocumented method' do
|
719
764
|
context '#internet_up?' do
|
@@ -195,6 +195,38 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
|
|
195
195
|
end
|
196
196
|
end
|
197
197
|
|
198
|
+
context 'server incorrectly resends a message that was already received by the client library' do
|
199
|
+
let(:messages_received) { [] }
|
200
|
+
let(:connection) { client.connection }
|
201
|
+
let(:client_options) { default_options.merge(log_level: :fatal) }
|
202
|
+
|
203
|
+
it 'discards the message and logs it as an error to the channel' do
|
204
|
+
first_message_protocol_message = nil
|
205
|
+
connection.__incoming_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
|
206
|
+
first_message_protocol_message ||= protocol_message unless protocol_message.messages.empty?
|
207
|
+
end
|
208
|
+
|
209
|
+
channel.subscribe do |message|
|
210
|
+
messages_received << message
|
211
|
+
if messages_received.count == 2
|
212
|
+
# simulate a duplicate protocol message being received
|
213
|
+
EventMachine.next_tick do
|
214
|
+
connection.__incoming_protocol_msgbus__.publish :protocol_message, first_message_protocol_message
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
2.times { |i| EventMachine.add_timer(i.to_f / 5) { channel.publish('event', 'data') } }
|
219
|
+
|
220
|
+
channel.on(:error) do |error|
|
221
|
+
expect(error.message).to match(/duplicate/)
|
222
|
+
EventMachine.add_timer(0.5) do
|
223
|
+
expect(messages_received.count).to eql(2)
|
224
|
+
stop_reactor
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
198
230
|
context 'encoding and decoding encrypted messages' do
|
199
231
|
shared_examples 'an Ably encrypter and decrypter' do |item, data|
|
200
232
|
let(:algorithm) { data['algorithm'].upcase }
|