ably 0.8.5 → 0.8.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/.travis.yml +1 -1
- data/CHANGELOG.md +42 -48
- data/SPEC.md +1099 -640
- data/ably.gemspec +10 -4
- data/lib/ably/auth.rb +155 -47
- data/lib/ably/exceptions.rb +2 -0
- data/lib/ably/models/channel_state_change.rb +2 -3
- data/lib/ably/models/connection_details.rb +54 -0
- data/lib/ably/models/protocol_message.rb +14 -4
- data/lib/ably/models/token_details.rb +13 -7
- data/lib/ably/models/token_request.rb +1 -2
- data/lib/ably/modules/ably.rb +3 -2
- data/lib/ably/modules/message_emitter.rb +1 -3
- data/lib/ably/modules/state_emitter.rb +2 -2
- data/lib/ably/realtime/auth.rb +6 -0
- data/lib/ably/realtime/channel/channel_manager.rb +2 -0
- data/lib/ably/realtime/channel.rb +15 -4
- data/lib/ably/realtime/client/incoming_message_dispatcher.rb +11 -1
- data/lib/ably/realtime/client.rb +10 -3
- data/lib/ably/realtime/connection/connection_manager.rb +58 -54
- data/lib/ably/realtime/connection.rb +62 -6
- data/lib/ably/realtime/presence.rb +18 -5
- data/lib/ably/rest/channel.rb +9 -1
- data/lib/ably/rest/client.rb +32 -14
- data/lib/ably/rest/presence.rb +1 -1
- data/lib/ably/version.rb +1 -1
- data/lib/ably.rb +2 -0
- data/spec/acceptance/realtime/auth_spec.rb +251 -11
- data/spec/acceptance/realtime/channel_history_spec.rb +12 -2
- data/spec/acceptance/realtime/channel_spec.rb +316 -24
- data/spec/acceptance/realtime/client_spec.rb +93 -1
- data/spec/acceptance/realtime/connection_failures_spec.rb +177 -86
- data/spec/acceptance/realtime/connection_spec.rb +284 -60
- data/spec/acceptance/realtime/message_spec.rb +45 -6
- data/spec/acceptance/realtime/presence_history_spec.rb +4 -0
- data/spec/acceptance/realtime/presence_spec.rb +181 -49
- data/spec/acceptance/realtime/time_spec.rb +13 -0
- data/spec/acceptance/rest/auth_spec.rb +222 -4
- data/spec/acceptance/rest/channel_spec.rb +132 -1
- data/spec/acceptance/rest/client_spec.rb +129 -28
- data/spec/acceptance/rest/presence_spec.rb +7 -7
- data/spec/acceptance/rest/time_spec.rb +10 -0
- data/spec/shared/client_initializer_behaviour.rb +41 -17
- data/spec/spec_helper.rb +1 -0
- data/spec/support/debug_failure_helper.rb +16 -0
- data/spec/unit/models/connection_details_spec.rb +60 -0
- data/spec/unit/models/protocol_message_spec.rb +45 -0
- data/spec/unit/modules/event_emitter_spec.rb +3 -1
- data/spec/unit/realtime/channel_spec.rb +6 -5
- data/spec/unit/realtime/client_spec.rb +5 -1
- data/spec/unit/realtime/connection_spec.rb +5 -1
- data/spec/unit/realtime/realtime_spec.rb +5 -1
- metadata +54 -7
@@ -84,7 +84,7 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
84
84
|
end
|
85
85
|
|
86
86
|
context 'that expire' do
|
87
|
-
let(:client_options) { default_options.merge(log_level: :
|
87
|
+
let(:client_options) { default_options.merge(log_level: :error) }
|
88
88
|
|
89
89
|
before do
|
90
90
|
expect(client.rest_client.time.to_f).to be_within(2).of(Time.now.to_i), "Local clock is out of sync with Ably"
|
@@ -94,59 +94,97 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
94
94
|
# Ensure tokens issued expire immediately after issue
|
95
95
|
@original_renew_token_buffer = Ably::Auth::TOKEN_DEFAULTS.fetch(:renew_token_buffer)
|
96
96
|
stub_const 'Ably::Auth::TOKEN_DEFAULTS', Ably::Auth::TOKEN_DEFAULTS.merge(renew_token_buffer: 0)
|
97
|
-
|
98
|
-
# Authorise synchronously to ensure token has been issued
|
99
|
-
client.auth.authorise_sync(ttl: ttl)
|
100
97
|
end
|
101
98
|
|
102
99
|
let(:original_renew_token_buffer) { @original_renew_token_buffer }
|
103
100
|
|
104
101
|
context 'opening a new connection' do
|
105
|
-
context 'with
|
102
|
+
context 'with almost expired tokens' do
|
103
|
+
before do
|
104
|
+
# Authorise synchronously to ensure token has been issued
|
105
|
+
client.auth.authorise_sync(ttl: ttl)
|
106
|
+
end
|
107
|
+
|
106
108
|
let(:ttl) { 2 }
|
107
109
|
|
108
|
-
it 'renews
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
110
|
+
it 'renews token every time after it expires' do
|
111
|
+
started_at = Time.now.to_f
|
112
|
+
connected_times = 0
|
113
|
+
disconnected_times = 0
|
114
|
+
connection.on(:connected) do
|
115
|
+
connected_times += 1
|
116
|
+
end
|
117
|
+
connection.on(:disconnected) do
|
118
|
+
disconnected_times += 1
|
119
|
+
if disconnected_times == 3
|
120
|
+
expect(connected_times).to eql(3)
|
121
|
+
expect(Time.now.to_f - started_at).to be > ttl * 3
|
122
|
+
expect(Time.now.to_f - started_at).to be < (ttl * 2) * 3
|
115
123
|
stop_reactor
|
116
124
|
end
|
117
|
-
connection.once_state_changed do
|
118
|
-
raise "Invalid state #{connection.state}" unless connection.state == :connected
|
119
|
-
end
|
120
125
|
end
|
121
126
|
end
|
122
127
|
end
|
123
128
|
|
124
|
-
context 'with immediately
|
129
|
+
context 'with immediately expired token' do
|
125
130
|
let(:ttl) { 0.001 }
|
131
|
+
let(:auth_requests) { [] }
|
132
|
+
let(:token_callback) do
|
133
|
+
Proc.new do
|
134
|
+
auth_requests << Time.now
|
135
|
+
Ably::Rest::Client.new(default_options).auth.request_token(ttl: ttl).token
|
136
|
+
end
|
137
|
+
end
|
138
|
+
let(:client_options) { default_options.merge(auth_callback: token_callback) }
|
126
139
|
|
127
|
-
it 'renews the token on connect, and
|
128
|
-
|
140
|
+
it 'renews the token on connect, and makes one immediate subsequent attempt to obtain a new token' do
|
141
|
+
started_at = Time.now.to_f
|
129
142
|
connection.once(:disconnected) do
|
130
|
-
connection.once(:
|
143
|
+
connection.once(:disconnected) do |connection_state_change|
|
131
144
|
expect(connection_state_change.reason.code).to eql(40140) # token expired
|
145
|
+
expect(Time.now.to_f - started_at).to be < 1000
|
146
|
+
expect(auth_requests.count).to eql(2)
|
132
147
|
stop_reactor
|
133
148
|
end
|
134
149
|
end
|
135
150
|
end
|
136
151
|
|
137
|
-
|
138
|
-
|
152
|
+
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, log_level: :error) }
|
154
|
+
|
155
|
+
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
|
+
disconnect_count = 0
|
158
|
+
connection.on(:disconnected) do |connection_state_change|
|
159
|
+
expect(connection_state_change.reason.code).to eql(40140) # token expired
|
160
|
+
disconnect_count += 1
|
161
|
+
if disconnect_count == 6
|
162
|
+
expect(Time.now.to_f - started_at).to be > 4 * 0.5 # at least 4 0.5 second pauses should have happened
|
163
|
+
expect(Time.now.to_f - started_at).to be < 9 # allow 1.5 seconds for each authentication cycle
|
164
|
+
stop_reactor
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
context 'using implicit token auth' do
|
171
|
+
let(:client_options) { default_options.merge(use_token_auth: true, token_params: { ttl: ttl }) }
|
172
|
+
|
173
|
+
before do
|
174
|
+
stub_const 'Ably::Models::TokenDetails::TOKEN_EXPIRY_BUFFER', -10 # ensure client lib thinks token is still valid
|
175
|
+
end
|
176
|
+
|
177
|
+
it 'uses the primary host for subsequent connection and auth requests' do
|
139
178
|
connection.once(:disconnected) do
|
140
179
|
expect(client.rest_client.connection).to receive(:post).
|
141
180
|
with(/requestToken$/, anything).
|
142
|
-
|
181
|
+
exactly(:once).
|
143
182
|
and_call_original
|
144
183
|
|
145
184
|
expect(client.rest_client).to_not receive(:fallback_connection)
|
146
185
|
expect(client).to_not receive(:fallback_endpoint)
|
147
186
|
|
148
|
-
connection.once(:
|
149
|
-
connection.off
|
187
|
+
connection.once(:disconnected) do
|
150
188
|
stop_reactor
|
151
189
|
end
|
152
190
|
end
|
@@ -157,15 +195,16 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
157
195
|
|
158
196
|
context 'when connected with a valid non-expired token' do
|
159
197
|
context 'that then expires following the connection being opened' do
|
160
|
-
let(:ttl)
|
161
|
-
let(:
|
198
|
+
let(:ttl) { 5 }
|
199
|
+
let(:channel_name) { random_str }
|
200
|
+
let(:channel) { client.channel(channel_name) }
|
201
|
+
let(:client_options) { default_options.merge(use_token_auth: true, token_params: { ttl: ttl }) }
|
162
202
|
|
163
203
|
context 'the server' do
|
164
204
|
it 'disconnects the client, and the client automatically renews the token and then reconnects', em_timeout: 15 do
|
165
|
-
original_token = client.auth.current_token_details
|
166
|
-
expect(original_token).to_not be_expired
|
167
|
-
|
168
205
|
connection.once(:connected) do
|
206
|
+
original_token = client.auth.current_token_details
|
207
|
+
expect(original_token).to_not be_expired
|
169
208
|
started_at = Time.now
|
170
209
|
connection.once(:disconnected) do |connection_state_change|
|
171
210
|
expect(connection_state_change.reason.code).to eq(40140) # Token expired
|
@@ -189,8 +228,86 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
189
228
|
end
|
190
229
|
end
|
191
230
|
|
192
|
-
|
193
|
-
|
231
|
+
context 'connection state' do
|
232
|
+
let(:ttl) { 4 }
|
233
|
+
let(:auth_requests) { [] }
|
234
|
+
let(:token_callback) do
|
235
|
+
Proc.new do
|
236
|
+
sleep 2
|
237
|
+
auth_requests << Time.now
|
238
|
+
Ably::Rest::Client.new(default_options).auth.request_token(ttl: ttl).token
|
239
|
+
end
|
240
|
+
end
|
241
|
+
let(:client_options) { default_options.merge(auth_callback: token_callback) }
|
242
|
+
let(:publishing_client) { auto_close Ably::Realtime::Client.new(default_options) }
|
243
|
+
let(:publishing_channel) { publishing_client.channels.get(channel_name) }
|
244
|
+
let(:messages_received) { [] }
|
245
|
+
|
246
|
+
def publish_and_check_first_disconnect
|
247
|
+
10.times.each { |index| publishing_channel.publish('event', index.to_s) }
|
248
|
+
channel.subscribe('event') do |message|
|
249
|
+
messages_received << message.data.to_i
|
250
|
+
if messages_received.count == 10
|
251
|
+
expect(messages_received).to match(10.times)
|
252
|
+
expect(auth_requests.count).to eql(2)
|
253
|
+
EventMachine.add_timer(1) do
|
254
|
+
channel.unsubscribe 'event'
|
255
|
+
yield
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
def publish_and_check_second_disconnect
|
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
|
274
|
+
publishing_channel.attach do
|
275
|
+
channel.attach do
|
276
|
+
connection.once(:disconnected) do
|
277
|
+
publish_and_check_first_disconnect do
|
278
|
+
connection.once(:disconnected) do
|
279
|
+
publish_and_check_second_disconnect
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
context 'and subsequent token is invalid' do
|
289
|
+
let(:ttl) { 2 }
|
290
|
+
let(:token_callback) do
|
291
|
+
Proc.new do
|
292
|
+
if @token_issued
|
293
|
+
"#{app_id}.invalid-token-invalid-token-invalid-token"
|
294
|
+
else
|
295
|
+
@token_issued = true
|
296
|
+
Ably::Rest::Client.new(default_options).auth.request_token(ttl: ttl).token
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
300
|
+
let(:client_options) { default_options.merge(auth_callback: token_callback, log_level: :none) }
|
301
|
+
|
302
|
+
it 'transitions the connection to the failed state' do
|
303
|
+
connection.once(:disconnected) do
|
304
|
+
connection.once(:failed) do
|
305
|
+
expect(connection.error_reason.code).to eql(40101)
|
306
|
+
stop_reactor
|
307
|
+
end
|
308
|
+
end
|
309
|
+
end
|
310
|
+
end
|
194
311
|
end
|
195
312
|
end
|
196
313
|
end
|
@@ -228,6 +345,50 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
228
345
|
end
|
229
346
|
end
|
230
347
|
end
|
348
|
+
|
349
|
+
context 'with opaque token string that contain an implicit client_id' do
|
350
|
+
let(:client_options) { default_options.merge(token: token_string, key: nil) }
|
351
|
+
let(:rest_auth_client) { Ably::Rest::Client.new(default_options.merge(key: api_key)) }
|
352
|
+
let(:token_string) { rest_auth_client.auth.request_token(client_id: client_id).token }
|
353
|
+
|
354
|
+
context 'string' do
|
355
|
+
let(:client_id) { random_str }
|
356
|
+
|
357
|
+
it 'sets the Client#client_id and Auth#client_id once CONNECTED' do
|
358
|
+
expect(client.client_id).to be_nil
|
359
|
+
client.connection.once(:connected) do
|
360
|
+
expect(client.client_id).to eql(client_id)
|
361
|
+
stop_reactor
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
context 'that is incompatible with the current client client_id' do
|
366
|
+
let(:client_id) { random_str }
|
367
|
+
let(:client_options) { default_options.merge(client_id: 'incompatible', token: token_string, key: nil, log_level: :none) }
|
368
|
+
|
369
|
+
it 'fails the connection' do
|
370
|
+
expect(client.client_id).to eql('incompatible')
|
371
|
+
client.connection.once(:failed) do
|
372
|
+
expect(client.client_id).to eql('incompatible')
|
373
|
+
expect(client.connection.error_reason.code).to eql(40101) # Invalid clientId for credentials
|
374
|
+
stop_reactor
|
375
|
+
end
|
376
|
+
end
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
context 'wildcard' do
|
381
|
+
let(:client_id) { '*' }
|
382
|
+
|
383
|
+
it 'configures the Client#client_id and Auth#client_id with a wildcard once CONNECTED' do
|
384
|
+
expect(client.client_id).to be_nil
|
385
|
+
client.connection.once(:connected) do
|
386
|
+
expect(client.client_id).to eql('*')
|
387
|
+
stop_reactor
|
388
|
+
end
|
389
|
+
end
|
390
|
+
end
|
391
|
+
end
|
231
392
|
end
|
232
393
|
end
|
233
394
|
|
@@ -277,6 +438,50 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
277
438
|
end
|
278
439
|
end
|
279
440
|
|
441
|
+
it 'calls the provided block on success even if state changes to disconnected first' do
|
442
|
+
been_disconnected = false
|
443
|
+
|
444
|
+
connection.once(:disconnected) do
|
445
|
+
been_disconnected = true
|
446
|
+
end
|
447
|
+
connection.once(:connecting) do
|
448
|
+
close_if_transport_available = proc do
|
449
|
+
EventMachine.add_timer(0.001) do
|
450
|
+
if connection.transport
|
451
|
+
connection.transport.close_connection_after_writing
|
452
|
+
else
|
453
|
+
close_if_transport_available.call
|
454
|
+
end
|
455
|
+
end
|
456
|
+
end
|
457
|
+
close_if_transport_available.call
|
458
|
+
end
|
459
|
+
|
460
|
+
connection.connect do
|
461
|
+
expect(connection.state).to eq(:connected)
|
462
|
+
expect(been_disconnected).to be_truthy
|
463
|
+
stop_reactor
|
464
|
+
end
|
465
|
+
end
|
466
|
+
|
467
|
+
context 'with invalid auth details' do
|
468
|
+
let(:client_options) { default_options.merge(key: 'this.is:invalid', log_level: :none) }
|
469
|
+
|
470
|
+
it 'calls the Deferrable errback only once on connection failure' do
|
471
|
+
errback_called = false
|
472
|
+
connection.connect.errback do
|
473
|
+
expect(connection.state).to eq(:failed)
|
474
|
+
|
475
|
+
raise 'Errback already called' if errback_called
|
476
|
+
errback_called = true
|
477
|
+
|
478
|
+
connection.connect.errback do
|
479
|
+
EventMachine.add_timer(0.5) { stop_reactor }
|
480
|
+
end
|
481
|
+
end
|
482
|
+
end
|
483
|
+
end
|
484
|
+
|
280
485
|
context 'when already connected' do
|
281
486
|
it 'does nothing and no further state changes are emitted' do
|
282
487
|
connection.once(:connected) do
|
@@ -509,12 +714,10 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
509
714
|
end
|
510
715
|
|
511
716
|
context 'with an unresponsive connection' do
|
512
|
-
let(:
|
717
|
+
let(:custom_timeout) { 2 }
|
718
|
+
let(:client_options) { default_options.merge(realtime_request_timeout: custom_timeout) }
|
513
719
|
|
514
720
|
before do
|
515
|
-
stub_const 'Ably::Realtime::Connection::ConnectionManager::TIMEOUTS',
|
516
|
-
Ably::Realtime::Connection::ConnectionManager::TIMEOUTS.merge(close: stubbed_timeout)
|
517
|
-
|
518
721
|
connection.on(:connected) do
|
519
722
|
# Prevent all incoming & outgoing ProtocolMessages from being processed by the client library
|
520
723
|
connection.__outgoing_protocol_msgbus__.unsubscribe
|
@@ -527,7 +730,7 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
527
730
|
close_requested_at = Time.now
|
528
731
|
|
529
732
|
connection.on(:closed) do
|
530
|
-
expect(Time.now - close_requested_at).to be >=
|
733
|
+
expect(Time.now - close_requested_at).to be >= custom_timeout
|
531
734
|
expect(connection.state).to eq(:closed)
|
532
735
|
expect(events[:error_emitted]).to_not eql(true)
|
533
736
|
expect(events[:closed_message_from_server_received]).to_not eql(true)
|
@@ -571,6 +774,30 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
571
774
|
end
|
572
775
|
end
|
573
776
|
end
|
777
|
+
|
778
|
+
context 'when ping times out' do
|
779
|
+
let(:client_options) { default_options.merge(log_level: :error) }
|
780
|
+
|
781
|
+
it 'logs a warning' do
|
782
|
+
connection.once(:connected) do
|
783
|
+
allow(connection).to receive(:defaults).and_return(connection.defaults.merge(realtime_request_timeout: 0.0001))
|
784
|
+
expect(connection.logger).to receive(:warn).with(/Ping timed out/) do
|
785
|
+
stop_reactor
|
786
|
+
end
|
787
|
+
connection.ping
|
788
|
+
end
|
789
|
+
end
|
790
|
+
|
791
|
+
it 'yields to the block with a nil value' do
|
792
|
+
connection.once(:connected) do
|
793
|
+
allow(connection).to receive(:defaults).and_return(connection.defaults.merge(realtime_request_timeout: 0.0001))
|
794
|
+
connection.ping do |time_elapsed|
|
795
|
+
expect(time_elapsed).to be_nil
|
796
|
+
stop_reactor
|
797
|
+
end
|
798
|
+
end
|
799
|
+
end
|
800
|
+
end
|
574
801
|
end
|
575
802
|
|
576
803
|
context 'recovery' do
|
@@ -580,15 +807,14 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
580
807
|
auto_close Ably::Realtime::Client.new(client_options)
|
581
808
|
end
|
582
809
|
let(:publishing_client_channel) { publishing_client.channel(channel_name) }
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
)
|
810
|
+
|
811
|
+
let(:client_options) do
|
812
|
+
default_options.merge(
|
813
|
+
log_level: :none,
|
814
|
+
disconnected_retry_timeout: 0.1,
|
815
|
+
suspended_retry_timeout: 0.1,
|
816
|
+
connection_state_ttl: 0.2
|
817
|
+
)
|
592
818
|
end
|
593
819
|
|
594
820
|
describe '#recovery_key' do
|
@@ -597,7 +823,6 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
597
823
|
end
|
598
824
|
let(:available_states) { self.class.available_states }
|
599
825
|
let(:states) { Hash.new }
|
600
|
-
let(:client_options) { default_options.merge(log_level: :none) }
|
601
826
|
let(:channel) { client.channel(random_str) }
|
602
827
|
|
603
828
|
it 'is composed of connection key and serial that is kept up to date with each message ACK received' do
|
@@ -641,6 +866,11 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
641
866
|
end
|
642
867
|
end
|
643
868
|
|
869
|
+
connection.once(:suspended) do
|
870
|
+
error_message = Ably::Models::ProtocolMessage.new(action: 9, error: { message: 'force failure' })
|
871
|
+
connection.__incoming_protocol_msgbus__.publish :protocol_message, error_message
|
872
|
+
end
|
873
|
+
|
644
874
|
connection.once(:failed) do
|
645
875
|
expect(states.keys).to match_array(available_states)
|
646
876
|
stop_reactor
|
@@ -659,8 +889,6 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
659
889
|
|
660
890
|
context "opening a new connection using a recently disconnected connection's #recovery_key" do
|
661
891
|
context 'connection#id and connection#key after recovery' do
|
662
|
-
let(:client_options) { default_options.merge(log_level: :none) }
|
663
|
-
|
664
892
|
it 'remains the same' do
|
665
893
|
previous_connection_id = nil
|
666
894
|
previous_connection_key = nil
|
@@ -701,8 +929,6 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
701
929
|
|
702
930
|
context 'when messages have been sent whilst the old connection is disconnected' do
|
703
931
|
describe 'the new connection' do
|
704
|
-
let(:client_options) { default_options.merge(log_level: :none) }
|
705
|
-
|
706
932
|
it 'recovers server-side queued messages' do
|
707
933
|
channel.attach do
|
708
934
|
connection.transition_state_machine! :failed
|
@@ -774,7 +1000,7 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
774
1000
|
|
775
1001
|
it 'opens each with a unique connection#id and connection#key' do
|
776
1002
|
connection_count.times.map do
|
777
|
-
Ably::Realtime::Client.new(client_options)
|
1003
|
+
auto_close Ably::Realtime::Client.new(client_options)
|
778
1004
|
end.each do |client|
|
779
1005
|
client.connection.on(:connected) do
|
780
1006
|
connection_ids << client.connection.id
|
@@ -943,15 +1169,13 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
943
1169
|
end
|
944
1170
|
|
945
1171
|
context 'when connection enters the :suspended state' do
|
946
|
-
let(:client_options)
|
947
|
-
|
948
|
-
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
suspended: { retry_every: 60, max_time_in_state: 60 }
|
954
|
-
)
|
1172
|
+
let(:client_options) do
|
1173
|
+
default_options.merge(
|
1174
|
+
log_level: :fatal,
|
1175
|
+
disconnected_retry_timeout: 0.02,
|
1176
|
+
suspended_retry_timeout: 60,
|
1177
|
+
connection_state_ttl: 0.05
|
1178
|
+
)
|
955
1179
|
end
|
956
1180
|
|
957
1181
|
it 'detaches the channels and prevents publishing of messages on those channels' do
|
@@ -132,7 +132,6 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
|
|
132
132
|
let(:client_options) { default_options.merge(client_id: client_id) }
|
133
133
|
|
134
134
|
it 'contains a #client_id attribute' do
|
135
|
-
skip 'Waiting for issue #256 to be resolved'
|
136
135
|
when_all(channel.attach, other_client_channel.attach) do
|
137
136
|
other_client_channel.subscribe('event') do |message|
|
138
137
|
expect(message.client_id).to eql(client_id)
|
@@ -208,14 +207,26 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
|
|
208
207
|
end
|
209
208
|
end
|
210
209
|
|
211
|
-
it 'will not echo messages to the client from other REST clients publishing using that
|
212
|
-
skip 'Waiting on realtime#285 to be resolved'
|
210
|
+
it 'will not echo messages to the client from other REST clients publishing using that connection_key', em_timeout: 10 do
|
213
211
|
no_echo_channel.attach do
|
214
212
|
no_echo_channel.subscribe('test_event') do |message|
|
215
213
|
fail "Message should not have been echoed back"
|
216
214
|
end
|
217
215
|
|
218
|
-
rest_client.channel(channel_name).publish('test_event', nil,
|
216
|
+
rest_client.channel(channel_name).publish('test_event', nil, connection_key: no_echo_client.connection.key)
|
217
|
+
EventMachine.add_timer(1.5) do
|
218
|
+
stop_reactor
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
it 'will echo messages with a valid connection_id to the client from other REST clients publishing using that connection_key', em_timeout: 10 do
|
224
|
+
channel.attach do
|
225
|
+
channel.subscribe('test_event') do |message|
|
226
|
+
expect(message.connection_id).to eql(client.connection.id)
|
227
|
+
end
|
228
|
+
|
229
|
+
rest_client.channel(channel_name).publish('test_event', nil, connection_key: client.connection.key)
|
219
230
|
EventMachine.add_timer(1.5) do
|
220
231
|
stop_reactor
|
221
232
|
end
|
@@ -599,7 +610,7 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
|
|
599
610
|
let(:event_name) { random_str }
|
600
611
|
let(:message_state) { [] }
|
601
612
|
let(:connection) { client.connection }
|
602
|
-
let(:client_options) { default_options.merge(:log_level => :
|
613
|
+
let(:client_options) { default_options.merge(:log_level => :fatal) }
|
603
614
|
let(:msgs_received) { [] }
|
604
615
|
|
605
616
|
it 'publishes the message again, later receives the ACK and only one message is ever received from Ably' do
|
@@ -642,6 +653,32 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
|
|
642
653
|
let(:connection) { client.connection }
|
643
654
|
let(:event_name) { random_str }
|
644
655
|
|
656
|
+
describe 'the connection is not resumed' do
|
657
|
+
let(:client_options) { default_options.merge(:log_level => :fatal) }
|
658
|
+
|
659
|
+
it 'calls the errback for all messages' do
|
660
|
+
connection.once(:connected) do
|
661
|
+
connection.transport.__outgoing_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
|
662
|
+
if protocol_message.messages.find { |message| message.name == event_name }
|
663
|
+
EventMachine.add_timer(0.0001) do
|
664
|
+
connection.transport.unbind # trigger failure
|
665
|
+
connection.configure_new '0123456789abcdef', 'wVIsgTHAB1UvXh7z-1991d8586', -1 # force the resume connection key to be invalid
|
666
|
+
end
|
667
|
+
end
|
668
|
+
end
|
669
|
+
end
|
670
|
+
|
671
|
+
channel.publish(event_name).tap do |deferrable|
|
672
|
+
deferrable.callback do
|
673
|
+
raise 'Message delivery should not happen'
|
674
|
+
end
|
675
|
+
deferrable.errback do
|
676
|
+
stop_reactor
|
677
|
+
end
|
678
|
+
end
|
679
|
+
end
|
680
|
+
end
|
681
|
+
|
645
682
|
describe 'the connection becomes suspended' do
|
646
683
|
let(:client_options) { default_options.merge(:log_level => :fatal) }
|
647
684
|
|
@@ -649,8 +686,10 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
|
|
649
686
|
connection.once(:connected) do
|
650
687
|
connection.transport.__outgoing_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
|
651
688
|
if protocol_message.messages.find { |message| message.name == event_name }
|
652
|
-
EventMachine.add_timer(0.
|
689
|
+
EventMachine.add_timer(0.0001) do
|
653
690
|
connection.transition_state_machine :suspended
|
691
|
+
stub_const 'Ably::FALLBACK_HOSTS', []
|
692
|
+
allow(client).to receive(:endpoint).and_return(URI::Generic.build(scheme: 'wss', host: 'does.not.exist.com'))
|
654
693
|
end
|
655
694
|
end
|
656
695
|
end
|
@@ -71,6 +71,10 @@ describe Ably::Realtime::Presence, 'history', :event_machine do
|
|
71
71
|
end
|
72
72
|
|
73
73
|
context 'and two pages of messages' do
|
74
|
+
let(:wildcard_token) { Proc.new { Ably::Rest::Client.new(default_options).auth.request_token(client_id: '*') } }
|
75
|
+
let(:client_one) { auto_close Ably::Realtime::Client.new(default_options.merge(auth_callback: wildcard_token)) }
|
76
|
+
let(:client_two) { auto_close Ably::Realtime::Client.new(default_options.merge(auth_callback: wildcard_token)) }
|
77
|
+
|
74
78
|
it 'retrieves two pages of messages before channel was attached' do
|
75
79
|
when_all(*10.times.map { |i| presence_client_two.enter_client("client:#{i}", data: presence_data_before_attach) }) do
|
76
80
|
when_all(*10.times.map { |i| presence_client_one.enter_client("client:#{i}", data: presence_data_after_attach) }) do
|