ably-rest 0.8.5 → 0.8.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/SPEC.md +1380 -631
  4. data/ably-rest.gemspec +11 -5
  5. data/lib/submodules/ably-ruby/.travis.yml +1 -1
  6. data/lib/submodules/ably-ruby/CHANGELOG.md +42 -48
  7. data/lib/submodules/ably-ruby/ably.gemspec +7 -1
  8. data/lib/submodules/ably-ruby/lib/ably.rb +2 -0
  9. data/lib/submodules/ably-ruby/lib/ably/auth.rb +155 -47
  10. data/lib/submodules/ably-ruby/lib/ably/exceptions.rb +2 -0
  11. data/lib/submodules/ably-ruby/lib/ably/models/channel_state_change.rb +2 -3
  12. data/lib/submodules/ably-ruby/lib/ably/models/connection_details.rb +54 -0
  13. data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +14 -4
  14. data/lib/submodules/ably-ruby/lib/ably/models/token_details.rb +13 -7
  15. data/lib/submodules/ably-ruby/lib/ably/models/token_request.rb +1 -2
  16. data/lib/submodules/ably-ruby/lib/ably/modules/ably.rb +3 -2
  17. data/lib/submodules/ably-ruby/lib/ably/modules/message_emitter.rb +1 -3
  18. data/lib/submodules/ably-ruby/lib/ably/modules/state_emitter.rb +2 -2
  19. data/lib/submodules/ably-ruby/lib/ably/realtime/auth.rb +6 -0
  20. data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +15 -4
  21. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_manager.rb +2 -0
  22. data/lib/submodules/ably-ruby/lib/ably/realtime/client.rb +10 -3
  23. data/lib/submodules/ably-ruby/lib/ably/realtime/client/incoming_message_dispatcher.rb +11 -1
  24. data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +62 -6
  25. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_manager.rb +58 -54
  26. data/lib/submodules/ably-ruby/lib/ably/realtime/presence.rb +18 -5
  27. data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +9 -1
  28. data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +32 -14
  29. data/lib/submodules/ably-ruby/lib/ably/rest/presence.rb +1 -1
  30. data/lib/submodules/ably-ruby/lib/ably/version.rb +1 -1
  31. data/lib/submodules/ably-ruby/spec/acceptance/realtime/auth_spec.rb +251 -11
  32. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_history_spec.rb +12 -2
  33. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +316 -24
  34. data/lib/submodules/ably-ruby/spec/acceptance/realtime/client_spec.rb +93 -1
  35. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +177 -86
  36. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +284 -60
  37. data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +45 -6
  38. data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_history_spec.rb +4 -0
  39. data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +181 -49
  40. data/lib/submodules/ably-ruby/spec/acceptance/realtime/time_spec.rb +13 -0
  41. data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +222 -4
  42. data/lib/submodules/ably-ruby/spec/acceptance/rest/channel_spec.rb +132 -1
  43. data/lib/submodules/ably-ruby/spec/acceptance/rest/client_spec.rb +129 -28
  44. data/lib/submodules/ably-ruby/spec/acceptance/rest/presence_spec.rb +7 -7
  45. data/lib/submodules/ably-ruby/spec/acceptance/rest/time_spec.rb +10 -0
  46. data/lib/submodules/ably-ruby/spec/shared/client_initializer_behaviour.rb +41 -17
  47. data/lib/submodules/ably-ruby/spec/spec_helper.rb +1 -0
  48. data/lib/submodules/ably-ruby/spec/support/debug_failure_helper.rb +16 -0
  49. data/lib/submodules/ably-ruby/spec/unit/models/connection_details_spec.rb +60 -0
  50. data/lib/submodules/ably-ruby/spec/unit/models/protocol_message_spec.rb +45 -0
  51. data/lib/submodules/ably-ruby/spec/unit/modules/event_emitter_spec.rb +3 -1
  52. data/lib/submodules/ably-ruby/spec/unit/realtime/channel_spec.rb +6 -5
  53. data/lib/submodules/ably-ruby/spec/unit/realtime/client_spec.rb +5 -1
  54. data/lib/submodules/ably-ruby/spec/unit/realtime/connection_spec.rb +5 -1
  55. data/lib/submodules/ably-ruby/spec/unit/realtime/realtime_spec.rb +5 -1
  56. metadata +57 -13
@@ -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: :none) }
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 recently expired token' do
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 the token on connect without changing connection state' do
109
- connection.once(:connecting) do
110
- sleep ttl + 0.1
111
- expect(client.auth.current_token_details).to be_expired
112
- expect(client.rest_client.auth).to receive(:authorise).at_least(:once).and_call_original
113
- connection.once(:connected) do
114
- expect(client.auth.current_token_details).to_not be_expired
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 expiring token' do
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 only makes one subsequent attempt to obtain a new token' do
128
- expect(client.rest_client.auth).to receive(:authorise).at_least(:twice).and_call_original
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(:failed) do |connection_state_change|
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
- it 'uses the primary host for subsequent connection and auth requests' do
138
- EventMachine.add_timer(1) do # wait for token to expire
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
- at_least(:once).
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(:failed) do
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) { 5 }
161
- let(:channel) { client.channel(random_str) }
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
- skip 'retains connection state'
193
- skip 'changes state to failed if a new token cannot be issued'
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(:stubbed_timeout) { 2 }
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 >= stubbed_timeout
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
- let(:client_options) { default_options.merge(log_level: :fatal) }
584
-
585
- before do
586
- # Reconfigure client library retry periods and timeouts so that tests run quickly
587
- stub_const 'Ably::Realtime::Connection::ConnectionManager::CONNECT_RETRY_CONFIG',
588
- Ably::Realtime::Connection::ConnectionManager::CONNECT_RETRY_CONFIG.merge(
589
- disconnected: { retry_every: 0.1, max_time_in_state: 0.2 },
590
- suspended: { retry_every: 0.1, max_time_in_state: 0.2 },
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) { default_options.merge(:log_level => :fatal) }
947
-
948
- before do
949
- # Reconfigure client library retry periods so that client stays in suspended state
950
- stub_const 'Ably::Realtime::Connection::ConnectionManager::CONNECT_RETRY_CONFIG',
951
- Ably::Realtime::Connection::ConnectionManager::CONNECT_RETRY_CONFIG.merge(
952
- disconnected: { retry_every: 0.01, max_time_in_state: 0.05 },
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