ably 1.0.5 → 1.0.6
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/CHANGELOG.md +26 -1
- data/ably.gemspec +4 -3
- data/lib/ably/auth.rb +4 -4
- data/lib/ably/logger.rb +1 -1
- data/lib/ably/models/idiomatic_ruby_wrapper.rb +8 -8
- data/lib/ably/models/message.rb +6 -4
- data/lib/ably/models/presence_message.rb +6 -4
- data/lib/ably/modules/async_wrapper.rb +2 -2
- data/lib/ably/modules/conversions.rb +1 -1
- data/lib/ably/modules/encodeable.rb +1 -1
- data/lib/ably/modules/event_emitter.rb +2 -2
- data/lib/ably/modules/safe_deferrable.rb +1 -1
- data/lib/ably/modules/safe_yield.rb +1 -1
- data/lib/ably/modules/state_emitter.rb +5 -5
- data/lib/ably/realtime/auth.rb +1 -1
- data/lib/ably/realtime/channel.rb +3 -3
- data/lib/ably/realtime/channel/channel_manager.rb +2 -2
- data/lib/ably/realtime/client/incoming_message_dispatcher.rb +3 -2
- data/lib/ably/realtime/connection.rb +11 -6
- data/lib/ably/realtime/connection/websocket_transport.rb +1 -1
- data/lib/ably/realtime/presence.rb +3 -3
- data/lib/ably/realtime/presence/members_map.rb +6 -6
- data/lib/ably/rest/channel.rb +2 -2
- data/lib/ably/rest/client.rb +20 -12
- data/lib/ably/version.rb +1 -1
- data/spec/acceptance/realtime/auth_spec.rb +13 -37
- data/spec/acceptance/realtime/channel_history_spec.rb +7 -1
- data/spec/acceptance/realtime/channel_spec.rb +3 -3
- data/spec/acceptance/realtime/client_spec.rb +2 -2
- data/spec/acceptance/realtime/connection_failures_spec.rb +221 -7
- data/spec/acceptance/realtime/connection_spec.rb +13 -21
- data/spec/acceptance/realtime/message_spec.rb +2 -2
- data/spec/acceptance/realtime/presence_history_spec.rb +12 -3
- data/spec/acceptance/realtime/presence_spec.rb +10 -10
- data/spec/acceptance/rest/auth_spec.rb +21 -48
- data/spec/acceptance/rest/client_spec.rb +193 -68
- data/spec/shared/client_initializer_behaviour.rb +1 -9
- data/spec/spec_helper.rb +2 -0
- data/spec/support/event_emitter_helper.rb +31 -0
- data/spec/support/event_machine_helper.rb +1 -1
- data/spec/support/test_logger_helper.rb +42 -0
- data/spec/unit/logger_spec.rb +1 -9
- data/spec/unit/modules/async_wrapper_spec.rb +2 -2
- data/spec/unit/modules/event_emitter_spec.rb +3 -3
- data/spec/unit/modules/state_emitter_spec.rb +10 -10
- data/spec/unit/realtime/channel_spec.rb +1 -1
- data/spec/unit/realtime/connection_spec.rb +1 -1
- data/spec/unit/realtime/presence_spec.rb +1 -1
- data/spec/unit/rest/channel_spec.rb +22 -0
- data/spec/unit/util/pub_sub_spec.rb +3 -3
- metadata +26 -8
@@ -71,7 +71,7 @@ module Ably::Realtime
|
|
71
71
|
|
72
72
|
ensure_channel_attached(deferrable) do
|
73
73
|
if entering?
|
74
|
-
once_or_if(STATE.Entered, else:
|
74
|
+
once_or_if(STATE.Entered, else: lambda { |args| deferrable_fail deferrable, *args }) do
|
75
75
|
deferrable_succeed deferrable, &success_block
|
76
76
|
end
|
77
77
|
else
|
@@ -132,7 +132,7 @@ module Ably::Realtime
|
|
132
132
|
|
133
133
|
ensure_channel_attached(deferrable) do
|
134
134
|
if leaving?
|
135
|
-
once_or_if(STATE.Left, else:
|
135
|
+
once_or_if(STATE.Left, else: lambda { |error|deferrable_fail deferrable, *args }) do
|
136
136
|
deferrable_succeed deferrable, &success_block
|
137
137
|
end
|
138
138
|
else
|
@@ -310,7 +310,7 @@ module Ably::Realtime
|
|
310
310
|
# @api private
|
311
311
|
def __incoming_msgbus__
|
312
312
|
@__incoming_msgbus__ ||= Ably::Util::PubSub.new(
|
313
|
-
coerce_into:
|
313
|
+
coerce_into: lambda { |event| Ably::Models::ProtocolMessage::ACTION(event) }
|
314
314
|
)
|
315
315
|
end
|
316
316
|
|
@@ -94,7 +94,7 @@ module Ably::Realtime
|
|
94
94
|
wait_for_sync = options.fetch(:wait_for_sync, true)
|
95
95
|
deferrable = Ably::Util::SafeDeferrable.new(logger)
|
96
96
|
|
97
|
-
result_block =
|
97
|
+
result_block = lambda do
|
98
98
|
present_members.tap do |members|
|
99
99
|
members.keep_if { |member| member.connection_id == options[:connection_id] } if options[:connection_id]
|
100
100
|
members.keep_if { |member| member.client_id == options[:client_id] } if options[:client_id]
|
@@ -110,17 +110,17 @@ module Ably::Realtime
|
|
110
110
|
# Must be defined before subsequent procs reference this callback
|
111
111
|
reset_callbacks = nil
|
112
112
|
|
113
|
-
in_sync_callback =
|
114
|
-
reset_callbacks
|
113
|
+
in_sync_callback = lambda do
|
114
|
+
reset_callbacks.call if reset_callbacks
|
115
115
|
result_block.call
|
116
116
|
end
|
117
117
|
|
118
|
-
failed_callback =
|
119
|
-
reset_callbacks
|
118
|
+
failed_callback = lambda do |error|
|
119
|
+
reset_callbacks.call if reset_callbacks
|
120
120
|
deferrable.fail error
|
121
121
|
end
|
122
122
|
|
123
|
-
reset_callbacks =
|
123
|
+
reset_callbacks = lambda do
|
124
124
|
off(&in_sync_callback)
|
125
125
|
off(&failed_callback)
|
126
126
|
channel.off(&failed_callback)
|
data/lib/ably/rest/channel.rb
CHANGED
@@ -22,7 +22,7 @@ module Ably
|
|
22
22
|
# @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
|
23
23
|
#
|
24
24
|
def initialize(client, name, channel_options = {})
|
25
|
-
ensure_utf_8 :name, name
|
25
|
+
name = (ensure_utf_8 :name, name)
|
26
26
|
|
27
27
|
update_options channel_options
|
28
28
|
@client = client
|
@@ -58,7 +58,7 @@ module Ably
|
|
58
58
|
messages = if name.kind_of?(Enumerable)
|
59
59
|
name
|
60
60
|
else
|
61
|
-
ensure_utf_8
|
61
|
+
name = ensure_utf_8(:name, name, allow_nil: true)
|
62
62
|
ensure_supported_payload data
|
63
63
|
[{ name: name, data: data }.merge(attributes)]
|
64
64
|
end
|
data/lib/ably/rest/client.rb
CHANGED
@@ -439,22 +439,15 @@ module Ably
|
|
439
439
|
max_retry_duration = http_defaults.fetch(:max_retry_duration)
|
440
440
|
requested_at = Time.now
|
441
441
|
retry_count = 0
|
442
|
-
|
443
|
-
if add_request_ids
|
444
|
-
params = if params.nil?
|
445
|
-
{}
|
446
|
-
else
|
447
|
-
params.dup
|
448
|
-
end
|
449
|
-
request_id = SecureRandom.urlsafe_base64(10)
|
450
|
-
params[:request_id] = request_id
|
451
|
-
end
|
442
|
+
retry_sequence_id = nil
|
443
|
+
request_id = SecureRandom.urlsafe_base64(10) if add_request_ids
|
452
444
|
|
453
445
|
begin
|
454
446
|
use_fallback = can_fallback_to_alternate_ably_host? && retry_count > 0
|
455
447
|
|
456
448
|
connection(use_fallback: use_fallback).send(method, path, params) do |request|
|
457
449
|
if add_request_ids
|
450
|
+
request.params[:request_id] = request_id
|
458
451
|
request.options.context = {} if request.options.context.nil?
|
459
452
|
request.options.context[:request_id] = request_id
|
460
453
|
end
|
@@ -466,15 +459,30 @@ module Ably
|
|
466
459
|
end
|
467
460
|
end
|
468
461
|
end
|
462
|
+
end.tap do
|
463
|
+
if retry_count > 0
|
464
|
+
logger.warn do
|
465
|
+
"Ably::Rest::Client - Request SUCCEEDED after #{retry_count} #{retry_count > 1 ? 'retries' : 'retry' } for" \
|
466
|
+
" #{method} #{path} #{params} (seq ##{retry_sequence_id}, time elapsed #{(Time.now.to_f - requested_at.to_f).round(2)}s)"
|
467
|
+
end
|
468
|
+
end
|
469
469
|
end
|
470
470
|
|
471
471
|
rescue Faraday::TimeoutError, Faraday::ClientError, Ably::Exceptions::ServerError => error
|
472
|
+
retry_sequence_id ||= SecureRandom.urlsafe_base64(4)
|
472
473
|
time_passed = Time.now - requested_at
|
474
|
+
|
473
475
|
if can_fallback_to_alternate_ably_host? && retry_count < max_retry_count && time_passed <= max_retry_duration
|
474
476
|
retry_count += 1
|
475
|
-
logger.warn { "Ably::Rest::Client - Retry #{retry_count} for #{method} #{path} #{params} as initial attempt failed: #{error}" }
|
477
|
+
logger.warn { "Ably::Rest::Client - Retry #{retry_count} for #{method} #{path} #{params} as initial attempt failed (seq ##{retry_sequence_id}): #{error}" }
|
476
478
|
retry
|
477
479
|
end
|
480
|
+
|
481
|
+
logger.error do
|
482
|
+
"Ably::Rest::Client - Request FAILED after #{retry_count} #{retry_count > 1 ? 'retries' : 'retry' } for" \
|
483
|
+
" #{method} #{path} #{params} (seq ##{retry_sequence_id}, time elapsed #{(Time.now.to_f - requested_at.to_f).round(2)}s)"
|
484
|
+
end
|
485
|
+
|
478
486
|
case error
|
479
487
|
when Faraday::TimeoutError
|
480
488
|
raise Ably::Exceptions::ConnectionTimeout.new(error.message, nil, 80014, error, { request_id: request_id })
|
@@ -549,7 +557,7 @@ module Ably
|
|
549
557
|
setup_incoming_middleware builder, logger, fail_if_unsupported_mime_type: true
|
550
558
|
|
551
559
|
# Set Faraday's HTTP adapter
|
552
|
-
builder.adapter
|
560
|
+
builder.adapter :excon
|
553
561
|
end
|
554
562
|
end
|
555
563
|
|
data/lib/ably/version.rb
CHANGED
@@ -206,7 +206,7 @@ describe Ably::Realtime::Auth, :event_machine do
|
|
206
206
|
|
207
207
|
context 'with a slow auth callback response' do
|
208
208
|
let(:auth_callback) do
|
209
|
-
|
209
|
+
lambda do |token_params|
|
210
210
|
sleep pause
|
211
211
|
rest_auth_client.auth.request_token
|
212
212
|
end
|
@@ -214,7 +214,7 @@ describe Ably::Realtime::Auth, :event_machine do
|
|
214
214
|
|
215
215
|
it 'asynchronously authenticates' do
|
216
216
|
timers_called = 0
|
217
|
-
block =
|
217
|
+
block = lambda do
|
218
218
|
timers_called += 1
|
219
219
|
EventMachine.add_timer(0.5, &block)
|
220
220
|
end
|
@@ -230,7 +230,7 @@ describe Ably::Realtime::Auth, :event_machine do
|
|
230
230
|
|
231
231
|
context 'when implicitly called, with an explicit ClientOptions client_id' do
|
232
232
|
let(:client_id) { random_str }
|
233
|
-
let(:client_options) { default_options.merge(auth_callback:
|
233
|
+
let(:client_options) { default_options.merge(auth_callback: lambda { |token_params| auth_token_object }, client_id: client_id, log_level: :none) }
|
234
234
|
let(:rest_auth_client) { Ably::Rest::Client.new(default_options.merge(key: api_key, client_id: 'invalid')) }
|
235
235
|
|
236
236
|
context 'and an incompatible client_id in a TokenDetails object passed to the auth callback' do
|
@@ -268,7 +268,7 @@ describe Ably::Realtime::Auth, :event_machine do
|
|
268
268
|
|
269
269
|
context 'when explicitly called, with an explicit ClientOptions client_id' do
|
270
270
|
let(:auth_proc) do
|
271
|
-
|
271
|
+
lambda do |token_params|
|
272
272
|
if !@requested
|
273
273
|
@requested = true
|
274
274
|
valid_auth_token
|
@@ -304,18 +304,18 @@ describe Ably::Realtime::Auth, :event_machine do
|
|
304
304
|
let(:rest_client) { Ably::Rest::Client.new(default_options) }
|
305
305
|
let(:client_publisher) { auto_close Ably::Realtime::Client.new(default_options) }
|
306
306
|
let(:basic_capability) { JSON.dump("foo" => ["subscribe"]) }
|
307
|
-
let(:basic_token_cb) {
|
307
|
+
let(:basic_token_cb) { lambda do |token_params|
|
308
308
|
rest_client.auth.create_token_request({ capability: basic_capability })
|
309
309
|
end }
|
310
310
|
let(:upgraded_capability) { JSON.dump({ "foo" => ["subscribe", "publish"] }) }
|
311
|
-
let(:upgraded_token_cb) {
|
311
|
+
let(:upgraded_token_cb) { lambda do |token_params|
|
312
312
|
rest_client.auth.create_token_request({ capability: upgraded_capability })
|
313
313
|
end }
|
314
|
-
let(:identified_token_cb) {
|
314
|
+
let(:identified_token_cb) { lambda do |token_params|
|
315
315
|
rest_client.auth.create_token_request({ client_id: 'bob' })
|
316
316
|
end }
|
317
317
|
let(:downgraded_capability) { JSON.dump({ "bar" => ["subscribe"] }) }
|
318
|
-
let(:downgraded_token_cb) {
|
318
|
+
let(:downgraded_token_cb) { lambda do |token_params|
|
319
319
|
rest_client.auth.create_token_request({ capability: downgraded_capability })
|
320
320
|
end }
|
321
321
|
|
@@ -589,7 +589,7 @@ describe Ably::Realtime::Auth, :event_machine do
|
|
589
589
|
context 'when client is identified' do
|
590
590
|
let(:client_options) { default_options.merge(auth_callback: basic_token_cb, log_level: :none) }
|
591
591
|
|
592
|
-
let(:basic_token_cb) {
|
592
|
+
let(:basic_token_cb) { lambda do |token_params|
|
593
593
|
rest_client.auth.create_token_request({ client_id: 'mike', capability: basic_capability })
|
594
594
|
end }
|
595
595
|
|
@@ -612,7 +612,7 @@ describe Ably::Realtime::Auth, :event_machine do
|
|
612
612
|
connection_failed = false
|
613
613
|
|
614
614
|
client.connection.once(:connected) do
|
615
|
-
client.auth.authorize(nil, auth_callback:
|
615
|
+
client.auth.authorize(nil, auth_callback: lambda { |token_params| 'invalid.token:will.cause.failure' }).tap do |deferrable|
|
616
616
|
deferrable.errback do |error|
|
617
617
|
EventMachine.add_timer(0.2) do
|
618
618
|
expect(connection_failed).to eql(true)
|
@@ -638,7 +638,7 @@ describe Ably::Realtime::Auth, :event_machine do
|
|
638
638
|
|
639
639
|
it 'calls the error callback of authorize and leaves the connection intact (#RSA4c3)' do
|
640
640
|
client.connection.once(:connected) do
|
641
|
-
client.auth.authorize(nil, auth_callback:
|
641
|
+
client.auth.authorize(nil, auth_callback: lambda { |token_params| raise 'Exception raised' }).errback do |error|
|
642
642
|
EventMachine.add_timer(0.2) do
|
643
643
|
expect(connection).to be_connected
|
644
644
|
expect(error.message).to match(/Exception raised/i)
|
@@ -1014,33 +1014,9 @@ describe Ably::Realtime::Auth, :event_machine do
|
|
1014
1014
|
end
|
1015
1015
|
end
|
1016
1016
|
|
1017
|
-
context 'deprecated #authorise' do
|
1017
|
+
context 'deprecated #authorise', :prevent_log_stubbing do
|
1018
1018
|
let(:client_options) { default_options.merge(key: api_key, logger: custom_logger_object, use_token_auth: true) }
|
1019
|
-
let(:
|
1020
|
-
Class.new do
|
1021
|
-
def initialize
|
1022
|
-
@messages = []
|
1023
|
-
end
|
1024
|
-
|
1025
|
-
[:fatal, :error, :warn, :info, :debug].each do |severity|
|
1026
|
-
define_method severity do |message|
|
1027
|
-
@messages << [severity, message]
|
1028
|
-
end
|
1029
|
-
end
|
1030
|
-
|
1031
|
-
def logs
|
1032
|
-
@messages
|
1033
|
-
end
|
1034
|
-
|
1035
|
-
def level
|
1036
|
-
1
|
1037
|
-
end
|
1038
|
-
|
1039
|
-
def level=(new_level)
|
1040
|
-
end
|
1041
|
-
end
|
1042
|
-
end
|
1043
|
-
let(:custom_logger_object) { custom_logger.new }
|
1019
|
+
let(:custom_logger_object) { TestLogger.new }
|
1044
1020
|
|
1045
1021
|
it 'logs a deprecation warning (#RSA10l)' do
|
1046
1022
|
client.auth.authorise
|
@@ -77,7 +77,13 @@ describe Ably::Realtime::Channel, '#history', :event_machine do
|
|
77
77
|
limit.times do |index|
|
78
78
|
expect(next_page.items[index].data).to eql("history#{index + limit}")
|
79
79
|
end
|
80
|
-
|
80
|
+
if next_page.has_next?
|
81
|
+
next_page.next do |last|
|
82
|
+
expect(last.items.length).to eql(0)
|
83
|
+
end
|
84
|
+
else
|
85
|
+
expect(next_page).to be_last
|
86
|
+
end
|
81
87
|
|
82
88
|
stop_reactor
|
83
89
|
end
|
@@ -1342,7 +1342,7 @@ describe Ably::Realtime::Channel, :event_machine do
|
|
1342
1342
|
|
1343
1343
|
context 'many times with different event names' do
|
1344
1344
|
it 'filters events accordingly to each callback' do
|
1345
|
-
click_callback =
|
1345
|
+
click_callback = lambda { |message| messages << message }
|
1346
1346
|
|
1347
1347
|
channel.subscribe('click', &click_callback)
|
1348
1348
|
channel.subscribe('move', &click_callback)
|
@@ -1958,7 +1958,7 @@ describe Ably::Realtime::Channel, :event_machine do
|
|
1958
1958
|
specify 'all queued messages fail with NACK (#RTL11)' do
|
1959
1959
|
channel.attach do
|
1960
1960
|
# Move to disconnected
|
1961
|
-
disconnect_transport_proc =
|
1961
|
+
disconnect_transport_proc = lambda do
|
1962
1962
|
if connection.transport
|
1963
1963
|
connection.transport.close_connection_after_writing
|
1964
1964
|
else
|
@@ -2090,7 +2090,7 @@ describe Ably::Realtime::Channel, :event_machine do
|
|
2090
2090
|
it 'will move to the SUSPENDED state and then attempt to ATTACH with the ATTACHING state (#RTL13b)' do
|
2091
2091
|
connection.once(:connected) do
|
2092
2092
|
# Prevent any incoming or outgoing ATTACH/ATTACHED message from Ably
|
2093
|
-
prevent_protocol_messages_proc =
|
2093
|
+
prevent_protocol_messages_proc = lambda do
|
2094
2094
|
if client.connection.transport
|
2095
2095
|
client.connection.transport.__incoming_protocol_msgbus__.unsubscribe
|
2096
2096
|
client.connection.transport.__outgoing_protocol_msgbus__.unsubscribe
|
@@ -134,7 +134,7 @@ describe Ably::Realtime::Client, :event_machine do
|
|
134
134
|
|
135
135
|
context 'with a wildcard client_id token' do
|
136
136
|
subject { auto_close Ably::Realtime::Client.new(client_options) }
|
137
|
-
let(:client_options) { default_options.merge(auth_callback:
|
137
|
+
let(:client_options) { default_options.merge(auth_callback: lambda { |token_params| auth_token_object }, client_id: client_id) }
|
138
138
|
let(:rest_auth_client) { Ably::Rest::Client.new(default_options.merge(key: api_key)) }
|
139
139
|
let(:auth_token_object) { rest_auth_client.auth.request_token(client_id: '*') }
|
140
140
|
|
@@ -155,7 +155,7 @@ describe Ably::Realtime::Client, :event_machine do
|
|
155
155
|
end
|
156
156
|
|
157
157
|
context 'and client_id omitted in ClientOptions' do
|
158
|
-
let(:client_options) { default_options.merge(auth_callback:
|
158
|
+
let(:client_options) { default_options.merge(auth_callback: lambda { |token_params| auth_token_object }) }
|
159
159
|
|
160
160
|
it 'uses the token provided clientId in the connection' do
|
161
161
|
connection.__incoming_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
|
@@ -143,7 +143,7 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
|
|
143
143
|
context 'with auth_callback' do
|
144
144
|
context 'opening a new connection' do
|
145
145
|
context 'when callback fails due to an exception' do
|
146
|
-
let(:client_options) { default_options.reject { |k, v| k == :key }.merge(auth_callback:
|
146
|
+
let(:client_options) { default_options.reject { |k, v| k == :key }.merge(auth_callback: lambda { |token_params| raise "Cannot issue token" }, log_level: :fatal) }
|
147
147
|
|
148
148
|
it 'the connection moves to the disconnected state and tries again, returning again to the disconnected state (#RSA4c, #RSA4c1, #RSA4c2)' do
|
149
149
|
states = Hash.new { |hash, key| hash[key] = [] }
|
@@ -174,7 +174,7 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
|
|
174
174
|
use_token_auth: true,
|
175
175
|
log_level: :fatal)
|
176
176
|
}
|
177
|
-
let(:auth_options) { { auth_callback:
|
177
|
+
let(:auth_options) { { auth_callback: lambda { |token_params| sleep 10 }, } }
|
178
178
|
|
179
179
|
it 'the authorization request fails as configured in the realtime_request_timeout (#RSA4c, #RSA4c1, #RSA4c3)' do
|
180
180
|
connection.once(:connected) do
|
@@ -514,6 +514,216 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
|
|
514
514
|
end
|
515
515
|
end
|
516
516
|
|
517
|
+
context 'connection state freshness is monitored' do
|
518
|
+
it 'resumes connections when disconnected within the connection_state_ttl period (#RTN15g)' do
|
519
|
+
connection.once(:connected) do
|
520
|
+
connection_id = connection.id
|
521
|
+
reconnected_with_resume = false
|
522
|
+
|
523
|
+
# Make sure the next connect has the resume param
|
524
|
+
allow(EventMachine).to receive(:connect).and_wrap_original do |original, *args, &block|
|
525
|
+
url = args[4]
|
526
|
+
uri = URI.parse(url)
|
527
|
+
expect(CGI::parse(uri.query)['resume'][0]).to_not be_empty
|
528
|
+
reconnected_with_resume = true
|
529
|
+
original.call(*args, &block)
|
530
|
+
end
|
531
|
+
|
532
|
+
connection.once(:disconnected) do
|
533
|
+
disconnected_at = Time.now
|
534
|
+
|
535
|
+
connection.once(:connecting) do
|
536
|
+
expect(Time.now.to_f - disconnected_at.to_f).to be < connection.connection_state_ttl
|
537
|
+
connection.once(:connected) do |state_change|
|
538
|
+
expect(connection.id).to eql(connection_id)
|
539
|
+
expect(reconnected_with_resume).to be_truthy
|
540
|
+
stop_reactor
|
541
|
+
end
|
542
|
+
end
|
543
|
+
end
|
544
|
+
|
545
|
+
connection.transport.unbind
|
546
|
+
end
|
547
|
+
end
|
548
|
+
|
549
|
+
context 'when connection_state_ttl period has passed since being disconnected' do
|
550
|
+
let(:client_options) do
|
551
|
+
default_options.merge(
|
552
|
+
disconnected_retry_timeout: 4,
|
553
|
+
suspended_retry_timeout: 8,
|
554
|
+
max_connection_state_ttl: 2,
|
555
|
+
)
|
556
|
+
end
|
557
|
+
|
558
|
+
it 'clears the local connection state and uses a new connection when the connection_state_ttl period has passed (#RTN15g)' do
|
559
|
+
connection.once(:connected) do
|
560
|
+
connection_id = connection.id
|
561
|
+
resumed_with_clean_connection = false
|
562
|
+
|
563
|
+
connection.once(:disconnected) do
|
564
|
+
disconnected_at = Time.now
|
565
|
+
|
566
|
+
connection.once(:connecting) do
|
567
|
+
connection.once(:disconnected) do
|
568
|
+
# Make sure the next connect does not have the resume param
|
569
|
+
allow(EventMachine).to receive(:connect).and_wrap_original do |original, *args, &block|
|
570
|
+
url = args[4]
|
571
|
+
uri = URI.parse(url)
|
572
|
+
expect(CGI::parse(uri.query)['resume']).to be_empty
|
573
|
+
resumed_with_clean_connection = true
|
574
|
+
original.call(*args, &block)
|
575
|
+
end
|
576
|
+
|
577
|
+
allow(connection.details).to receive(:max_idle_interval).and_return(0)
|
578
|
+
connection.__incoming_protocol_msgbus__.plugin_listeners
|
579
|
+
|
580
|
+
connection.once(:connecting) do
|
581
|
+
expect(Time.now.to_f - disconnected_at.to_f).to be > connection.connection_state_ttl
|
582
|
+
connection.once(:connected) do |state_change|
|
583
|
+
expect(connection.id).to_not eql(connection_id)
|
584
|
+
expect(resumed_with_clean_connection).to be_truthy
|
585
|
+
stop_reactor
|
586
|
+
end
|
587
|
+
end
|
588
|
+
end
|
589
|
+
|
590
|
+
# Disconnect the transport and trigger a new disconnected state
|
591
|
+
wait_until(lambda { connection.transport }) do
|
592
|
+
connection.transport.unbind
|
593
|
+
end
|
594
|
+
end
|
595
|
+
|
596
|
+
connection.__incoming_protocol_msgbus__.unplug_listeners
|
597
|
+
end
|
598
|
+
|
599
|
+
connection.transport.unbind
|
600
|
+
end
|
601
|
+
end
|
602
|
+
end
|
603
|
+
|
604
|
+
context 'when connection_state_ttl period has passed since last activity on the connection' do
|
605
|
+
let(:client_options) do
|
606
|
+
default_options.merge(
|
607
|
+
max_connection_state_ttl: 2,
|
608
|
+
)
|
609
|
+
end
|
610
|
+
|
611
|
+
it 'does not clear the local connection state when the connection_state_ttl period has passed since last activity, but the idle timeout has not passed (#RTN15g1, #RTN15g2)' do
|
612
|
+
expect(connection.connection_state_ttl).to eql(client_options.fetch(:max_connection_state_ttl))
|
613
|
+
|
614
|
+
connection.once(:connected) do
|
615
|
+
connection_id = connection.id
|
616
|
+
resumed_connection = false
|
617
|
+
|
618
|
+
connection.once(:disconnected) do
|
619
|
+
disconnected_at = Time.now
|
620
|
+
|
621
|
+
allow(connection).to receive(:time_since_connection_confirmed_alive?).and_return(connection.connection_state_ttl + 1)
|
622
|
+
|
623
|
+
# Make sure the next connect does not have the resume param
|
624
|
+
allow(EventMachine).to receive(:connect).and_wrap_original do |original, *args, &block|
|
625
|
+
url = args[4]
|
626
|
+
uri = URI.parse(url)
|
627
|
+
expect(CGI::parse(uri.query)['resume']).to_not be_empty
|
628
|
+
resumed_connection = true
|
629
|
+
original.call(*args, &block)
|
630
|
+
end
|
631
|
+
|
632
|
+
connection.once(:connecting) do
|
633
|
+
connection.once(:connected) do |state_change|
|
634
|
+
expect(connection.id).to eql(connection_id)
|
635
|
+
expect(resumed_connection).to be_truthy
|
636
|
+
stop_reactor
|
637
|
+
end
|
638
|
+
end
|
639
|
+
end
|
640
|
+
|
641
|
+
connection.transport.unbind
|
642
|
+
end
|
643
|
+
end
|
644
|
+
|
645
|
+
it 'clears the local connection state and uses a new connection when the connection_state_ttl + max_idle_interval period has passed since last activity (#RTN15g1, #RTN15g2)' do
|
646
|
+
expect(connection.connection_state_ttl).to eql(client_options.fetch(:max_connection_state_ttl))
|
647
|
+
|
648
|
+
connection.once(:connected) do
|
649
|
+
connection_id = connection.id
|
650
|
+
resumed_with_clean_connection = false
|
651
|
+
|
652
|
+
connection.once(:disconnected) do
|
653
|
+
disconnected_at = Time.now
|
654
|
+
|
655
|
+
pseudo_time_passed = connection.connection_state_ttl + connection.details.max_idle_interval + 1
|
656
|
+
allow(connection).to receive(:time_since_connection_confirmed_alive?).and_return(pseudo_time_passed)
|
657
|
+
|
658
|
+
# Make sure the next connect does not have the resume param
|
659
|
+
allow(EventMachine).to receive(:connect).and_wrap_original do |original, *args, &block|
|
660
|
+
url = args[4]
|
661
|
+
uri = URI.parse(url)
|
662
|
+
expect(CGI::parse(uri.query)['resume']).to be_empty
|
663
|
+
resumed_with_clean_connection = true
|
664
|
+
original.call(*args, &block)
|
665
|
+
end
|
666
|
+
|
667
|
+
connection.once(:connecting) do
|
668
|
+
connection.once(:connected) do |state_change|
|
669
|
+
expect(connection.id).to_not eql(connection_id)
|
670
|
+
expect(resumed_with_clean_connection).to be_truthy
|
671
|
+
stop_reactor
|
672
|
+
end
|
673
|
+
end
|
674
|
+
end
|
675
|
+
|
676
|
+
connection.transport.unbind
|
677
|
+
end
|
678
|
+
end
|
679
|
+
|
680
|
+
it 'still reattaches the channels automatically following a new connection being established (#RTN15g2)' do
|
681
|
+
connection.once(:connected) do
|
682
|
+
connection_id = connection.id
|
683
|
+
resumed_with_clean_connection = false
|
684
|
+
channel_emitted_an_attached = false
|
685
|
+
|
686
|
+
channel.attach do
|
687
|
+
channel.once(:attached) do |channel_state_change|
|
688
|
+
expect(channel_state_change.resumed).to be_falsey
|
689
|
+
channel_emitted_an_attached = true
|
690
|
+
end
|
691
|
+
|
692
|
+
connection.once(:disconnected) do
|
693
|
+
disconnected_at = Time.now
|
694
|
+
|
695
|
+
pseudo_time_passed = connection.connection_state_ttl + connection.details.max_idle_interval + 1
|
696
|
+
allow(connection).to receive(:time_since_connection_confirmed_alive?).and_return(pseudo_time_passed)
|
697
|
+
|
698
|
+
# Make sure the next connect does not have the resume param
|
699
|
+
allow(EventMachine).to receive(:connect).and_wrap_original do |original, *args, &block|
|
700
|
+
url = args[4]
|
701
|
+
uri = URI.parse(url)
|
702
|
+
expect(CGI::parse(uri.query)['resume']).to be_empty
|
703
|
+
resumed_with_clean_connection = true
|
704
|
+
original.call(*args, &block)
|
705
|
+
end
|
706
|
+
|
707
|
+
connection.once(:connecting) do
|
708
|
+
connection.once(:connected) do |state_change|
|
709
|
+
expect(connection.id).to_not eql(connection_id)
|
710
|
+
expect(resumed_with_clean_connection).to be_truthy
|
711
|
+
|
712
|
+
wait_until(lambda { channel.attached? }) do
|
713
|
+
expect(channel_emitted_an_attached).to be_truthy
|
714
|
+
stop_reactor
|
715
|
+
end
|
716
|
+
end
|
717
|
+
end
|
718
|
+
end
|
719
|
+
|
720
|
+
connection.transport.unbind
|
721
|
+
end
|
722
|
+
end
|
723
|
+
end
|
724
|
+
end
|
725
|
+
end
|
726
|
+
|
517
727
|
context 'and subsequently fails to reconnect' do
|
518
728
|
let(:retry_every) { 1.5 }
|
519
729
|
|
@@ -935,16 +1145,20 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
|
|
935
1145
|
previous_connection_id = connection.id
|
936
1146
|
previous_connection_key = connection.key
|
937
1147
|
|
938
|
-
five_minutes_time = Time.now + 5 * 60
|
939
|
-
allow(Time).to receive(:now) { five_minutes_time }
|
940
|
-
|
941
1148
|
connection.once(:connected) do
|
942
1149
|
expect(connection.key).to_not eql(previous_connection_key)
|
943
1150
|
expect(connection.id).to_not eql(previous_connection_id)
|
944
1151
|
stop_reactor
|
945
1152
|
end
|
946
1153
|
|
947
|
-
|
1154
|
+
# Wait until next tick before stubbing otherwise liveness test may
|
1155
|
+
# record the stubbed last contact time as the future time
|
1156
|
+
EventMachine.next_tick do
|
1157
|
+
five_minutes_time = Time.now + 5 * 60
|
1158
|
+
allow(Time).to receive(:now) { five_minutes_time }
|
1159
|
+
|
1160
|
+
kill_connection_transport_and_prevent_valid_resume
|
1161
|
+
end
|
948
1162
|
end
|
949
1163
|
end
|
950
1164
|
end
|
@@ -1017,7 +1231,7 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
|
|
1017
1231
|
}
|
1018
1232
|
|
1019
1233
|
let(:client_options) do
|
1020
|
-
default_options.merge(auth_callback:
|
1234
|
+
default_options.merge(auth_callback: lambda do |token_params|
|
1021
1235
|
@auth_requests ||= 0
|
1022
1236
|
@auth_requests += 1
|
1023
1237
|
|