ably 0.8.4 → 0.8.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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/Rakefile +1 -1
  4. data/lib/ably/auth.rb +23 -19
  5. data/lib/ably/models/token_details.rb +8 -6
  6. data/lib/ably/modules/conversions.rb +4 -0
  7. data/lib/ably/modules/state_emitter.rb +1 -1
  8. data/lib/ably/modules/uses_state_machine.rb +8 -1
  9. data/lib/ably/realtime/auth.rb +13 -13
  10. data/lib/ably/realtime/channel.rb +2 -2
  11. data/lib/ably/realtime/channel/channel_manager.rb +3 -3
  12. data/lib/ably/realtime/channel/channel_state_machine.rb +2 -1
  13. data/lib/ably/realtime/client/incoming_message_dispatcher.rb +13 -7
  14. data/lib/ably/realtime/client/outgoing_message_dispatcher.rb +6 -0
  15. data/lib/ably/realtime/connection.rb +4 -4
  16. data/lib/ably/realtime/connection/connection_manager.rb +9 -3
  17. data/lib/ably/realtime/connection/connection_state_machine.rb +1 -1
  18. data/lib/ably/realtime/presence.rb +4 -4
  19. data/lib/ably/rest/client.rb +2 -2
  20. data/lib/ably/version.rb +1 -1
  21. data/spec/acceptance/realtime/auth_spec.rb +9 -9
  22. data/spec/acceptance/realtime/channel_history_spec.rb +2 -2
  23. data/spec/acceptance/realtime/channel_spec.rb +13 -12
  24. data/spec/acceptance/realtime/channels_spec.rb +6 -2
  25. data/spec/acceptance/realtime/client_spec.rb +4 -3
  26. data/spec/acceptance/realtime/connection_failures_spec.rb +21 -15
  27. data/spec/acceptance/realtime/connection_spec.rb +31 -27
  28. data/spec/acceptance/realtime/message_spec.rb +31 -24
  29. data/spec/acceptance/realtime/presence_history_spec.rb +2 -2
  30. data/spec/acceptance/realtime/presence_spec.rb +10 -11
  31. data/spec/acceptance/realtime/stats_spec.rb +1 -1
  32. data/spec/acceptance/realtime/time_spec.rb +1 -1
  33. data/spec/acceptance/rest/auth_spec.rb +77 -46
  34. data/spec/acceptance/rest/channel_spec.rb +22 -3
  35. data/spec/acceptance/rest/client_spec.rb +6 -6
  36. data/spec/acceptance/rest/presence_spec.rb +9 -7
  37. data/spec/support/event_machine_helper.rb +30 -4
  38. data/spec/support/protocol_helper.rb +9 -6
  39. data/spec/unit/auth_spec.rb +1 -1
  40. data/spec/unit/models/token_details_spec.rb +8 -0
  41. data/spec/unit/modules/async_wrapper_spec.rb +1 -1
  42. metadata +2 -2
@@ -39,7 +39,7 @@ module Ably::Realtime
39
39
 
40
40
  EventMachine.next_tick do
41
41
  # Connect once Connection object is initialised
42
- connection.connect if client.auto_connect
42
+ connection.connect if client.auto_connect && connection.can_transition_to?(:connecting)
43
43
  end
44
44
  end
45
45
 
@@ -89,7 +89,7 @@ module Ably::Realtime
89
89
  # @api private
90
90
  def connected(protocol_message)
91
91
  if connection.key
92
- if protocol_message.connection_key == connection.key
92
+ if connection_key_shared(protocol_message.connection_key) == connection_key_shared(connection.key)
93
93
  logger.debug "ConnectionManager: Connection resumed successfully - ID #{connection.id} and key #{connection.key}"
94
94
  EventMachine.next_tick { connection.resumed }
95
95
  else
@@ -179,7 +179,7 @@ module Ably::Realtime
179
179
  #
180
180
  # @api private
181
181
  def respond_to_transport_disconnected_whilst_connected(error)
182
- logger.warn "ConnectionManager: Connection to #{connection.transport.url} was disconnected unexpectedly"
182
+ logger.warn "ConnectionManager: Connection #{"to #{connection.transport.url}" if connection.transport} was disconnected unexpectedly"
183
183
 
184
184
  if error.kind_of?(Ably::Models::ErrorInfo) && error.code != RESOLVABLE_ERROR_CODES.fetch(:token_expired)
185
185
  connection.emit :error, error
@@ -233,6 +233,12 @@ module Ably::Realtime
233
233
  client.channels
234
234
  end
235
235
 
236
+ # Connection key left part is consistent between connection resumes
237
+ # i.e. wVIsgTHAB1UvXh7z-1991d8586 becomes wVIsgTHAB1UvXh7z-1990d8586 after a resume
238
+ def connection_key_shared(connection_key)
239
+ (connection_key || '')[/^\w{5,}-/, 0]
240
+ end
241
+
236
242
  # Create a timer that will execute in timeout_in seconds.
237
243
  # If the connection state changes however, cancel the timer
238
244
  def create_timeout_timer_whilst_in_state(timer_id, timeout_in)
@@ -57,7 +57,7 @@ module Ably::Realtime
57
57
  connection.manager.respond_to_transport_disconnected_when_connecting err
58
58
  end
59
59
 
60
- after_transition(to: [:disconnected], from: [:connected]) do |connection, current_transition|
60
+ after_transition(to: [:disconnected, :suspended], from: [:connected]) do |connection, current_transition|
61
61
  err = error_from_state_change(current_transition)
62
62
  connection.manager.respond_to_transport_disconnected_whilst_connected err
63
63
  end
@@ -405,7 +405,7 @@ module Ably::Realtime
405
405
  deferrable_succeed deferrable, &success_block
406
406
  end
407
407
 
408
- protocol_message.errback do |message, error|
408
+ protocol_message.errback do |error|
409
409
  change_state failed_state, error if failed_state
410
410
  deferrable_fail deferrable, error
411
411
  end
@@ -419,8 +419,8 @@ module Ably::Realtime
419
419
  end
420
420
 
421
421
  def deferrable_fail(deferrable, *args, &block)
422
- safe_yield block, self, *args if block_given?
423
- EventMachine.next_tick { deferrable.fail self, *args } # allow errback to be added to the returned Deferrable
422
+ safe_yield block, *args if block_given?
423
+ EventMachine.next_tick { deferrable.fail *args } # allow errback to be added to the returned Deferrable
424
424
  deferrable
425
425
  end
426
426
 
@@ -431,7 +431,7 @@ module Ably::Realtime
431
431
  ensure_channel_attached(deferrable) do
432
432
  send_presence_protocol_message(action, client_id, options).tap do |protocol_message|
433
433
  protocol_message.callback { |message| deferrable_succeed deferrable, &success_block }
434
- protocol_message.errback { |message, error| deferrable_fail deferrable, error }
434
+ protocol_message.errback { |error| deferrable_fail deferrable, error }
435
435
  end
436
436
  end
437
437
  end
@@ -144,7 +144,7 @@ module Ably
144
144
 
145
145
  token_params = options.delete(:token_params) || {}
146
146
  @options = options
147
- @auth = Auth.new(self, options, token_params)
147
+ @auth = Auth.new(self, token_params, options)
148
148
  @channels = Ably::Rest::Channels.new(self)
149
149
  @encoders = []
150
150
 
@@ -358,7 +358,7 @@ module Ably
358
358
  yield
359
359
  rescue Ably::Exceptions::TokenExpired => e
360
360
  if auth.token_renewable?
361
- auth.authorise force: true
361
+ auth.authorise({}, force: true)
362
362
  yield
363
363
  else
364
364
  raise e
@@ -1,3 +1,3 @@
1
1
  module Ably
2
- VERSION = '0.8.4'
2
+ VERSION = '0.8.5'
3
3
  end
@@ -8,7 +8,7 @@ describe Ably::Realtime::Auth, :event_machine do
8
8
  vary_by_protocol do
9
9
  let(:default_options) { { key: api_key, environment: environment, protocol: protocol } }
10
10
  let(:client_options) { default_options }
11
- let(:client) { Ably::Realtime::Client.new(client_options) }
11
+ let(:client) { auto_close Ably::Realtime::Client.new(client_options) }
12
12
  let(:auth) { client.auth }
13
13
 
14
14
  context 'with basic auth' do
@@ -101,7 +101,7 @@ describe Ably::Realtime::Auth, :event_machine do
101
101
  let(:auth_params) { { :body => random_str } }
102
102
 
103
103
  it 'contains the configured auth options' do
104
- auth.authorise(auth_url: auth_url, auth_params: auth_params) do
104
+ auth.authorise({}, auth_url: auth_url, auth_params: auth_params) do
105
105
  expect(auth.options[:auth_url]).to eql(auth_url)
106
106
  stop_reactor
107
107
  end
@@ -112,7 +112,7 @@ describe Ably::Realtime::Auth, :event_machine do
112
112
  let(:custom_ttl) { 33 }
113
113
 
114
114
  it 'contains the configured auth options' do
115
- auth.authorise({}, ttl: custom_ttl) do
115
+ auth.authorise(ttl: custom_ttl) do
116
116
  expect(auth.token_params[:ttl]).to eql(custom_ttl)
117
117
  stop_reactor
118
118
  end
@@ -144,7 +144,7 @@ describe Ably::Realtime::Auth, :event_machine do
144
144
 
145
145
  context '#create_token_request' do
146
146
  it 'returns a token request asynchronously' do
147
- auth.create_token_request({}, { ttl: custom_ttl }) do |token_request|
147
+ auth.create_token_request(ttl: custom_ttl) do |token_request|
148
148
  expect(token_request).to be_a(Ably::Models::TokenRequest)
149
149
  expect(token_request.ttl).to eql(custom_ttl)
150
150
  stop_reactor
@@ -154,7 +154,7 @@ describe Ably::Realtime::Auth, :event_machine do
154
154
 
155
155
  context '#create_token_request_async' do
156
156
  it 'returns a token request synchronously' do
157
- auth.create_token_request_sync(token_params: { ttl: custom_ttl }).tap do |token_request|
157
+ auth.create_token_request_sync(ttl: custom_ttl).tap do |token_request|
158
158
  expect(token_request).to be_a(Ably::Models::TokenRequest)
159
159
  expect(token_request.ttl).to eql(custom_ttl)
160
160
  stop_reactor
@@ -164,7 +164,7 @@ describe Ably::Realtime::Auth, :event_machine do
164
164
 
165
165
  context '#request_token' do
166
166
  it 'returns a token asynchronously' do
167
- auth.request_token({ client_id: custom_client_id }, ttl: custom_ttl) do |token_details|
167
+ auth.request_token(client_id: custom_client_id, ttl: custom_ttl) do |token_details|
168
168
  expect(token_details).to be_a(Ably::Models::TokenDetails)
169
169
  expect(token_details.expires.to_i).to be_within(3).of(Time.now.to_i + custom_ttl)
170
170
  expect(token_details.client_id).to eql(custom_client_id)
@@ -175,7 +175,7 @@ describe Ably::Realtime::Auth, :event_machine do
175
175
 
176
176
  context '#request_token_async' do
177
177
  it 'returns a token synchronously' do
178
- auth.request_token_sync(client_id: custom_client_id, token_params: { ttl: custom_ttl }).tap do |token_details|
178
+ auth.request_token_sync(ttl: custom_ttl, client_id: custom_client_id).tap do |token_details|
179
179
  expect(token_details).to be_a(Ably::Models::TokenDetails)
180
180
  expect(token_details.expires.to_i).to be_within(3).of(Time.now.to_i + custom_ttl)
181
181
  expect(token_details.client_id).to eql(custom_client_id)
@@ -186,7 +186,7 @@ describe Ably::Realtime::Auth, :event_machine do
186
186
 
187
187
  context '#authorise' do
188
188
  it 'returns a token asynchronously' do
189
- auth.authorise({ client_id: custom_client_id }, ttl: custom_ttl) do |token_details|
189
+ auth.authorise(ttl: custom_ttl, client_id: custom_client_id) do |token_details|
190
190
  expect(token_details).to be_a(Ably::Models::TokenDetails)
191
191
  expect(token_details.expires.to_i).to be_within(3).of(Time.now.to_i + custom_ttl)
192
192
  expect(token_details.client_id).to eql(custom_client_id)
@@ -197,7 +197,7 @@ describe Ably::Realtime::Auth, :event_machine do
197
197
 
198
198
  context '#authorise_async' do
199
199
  it 'returns a token synchronously' do
200
- auth.authorise_sync(client_id: custom_client_id, token_params: { ttl: custom_ttl }).tap do |token_details|
200
+ auth.authorise_sync(ttl: custom_ttl, client_id: custom_client_id).tap do |token_details|
201
201
  expect(auth.authorise_sync).to be_a(Ably::Models::TokenDetails)
202
202
  expect(token_details.expires.to_i).to be_within(3).of(Time.now.to_i + custom_ttl)
203
203
  expect(token_details.client_id).to eql(custom_client_id)
@@ -5,11 +5,11 @@ describe Ably::Realtime::Channel, '#history', :event_machine do
5
5
  vary_by_protocol do
6
6
  let(:default_options) { options.merge(key: api_key, environment: environment, protocol: protocol) }
7
7
 
8
- let(:client) { Ably::Realtime::Client.new(default_options) }
8
+ let(:client) { auto_close Ably::Realtime::Client.new(default_options) }
9
9
  let(:channel) { client.channel(channel_name) }
10
10
  let(:rest_channel) { client.rest_client.channel(channel_name) }
11
11
 
12
- let(:client2) { Ably::Realtime::Client.new(default_options) }
12
+ let(:client2) { auto_close Ably::Realtime::Client.new(default_options) }
13
13
  let(:channel2) { client2.channel(channel_name) }
14
14
 
15
15
  let(:channel_name) { "persisted:#{random_str(2)}" }
@@ -6,7 +6,7 @@ describe Ably::Realtime::Channel, :event_machine do
6
6
  let(:default_options) { { key: api_key, environment: environment, protocol: protocol } }
7
7
  let(:client_options) { default_options }
8
8
 
9
- let(:client) { Ably::Realtime::Client.new(client_options) }
9
+ let(:client) { auto_close Ably::Realtime::Client.new(client_options) }
10
10
  let(:channel_name) { random_str }
11
11
  let(:payload) { random_str }
12
12
  let(:channel) { client.channel(channel_name) }
@@ -15,7 +15,7 @@ describe Ably::Realtime::Channel, :event_machine do
15
15
  describe 'initialization' do
16
16
  context 'with :auto_connect option set to false on connection' do
17
17
  let(:client) do
18
- Ably::Realtime::Client.new(default_options.merge(auto_connect: false))
18
+ auto_close Ably::Realtime::Client.new(default_options.merge(auto_connect: false))
19
19
  end
20
20
 
21
21
  it 'remains initialized when accessing a channel' do
@@ -80,7 +80,7 @@ describe Ably::Realtime::Channel, :event_machine do
80
80
  end
81
81
 
82
82
  it 'calls the SafeDeferrable callback on success' do
83
- channel.attach.callback do |channel|
83
+ channel.attach.callback do
84
84
  expect(channel).to be_a(Ably::Realtime::Channel)
85
85
  expect(channel.state).to eq(:attached)
86
86
  stop_reactor
@@ -131,7 +131,7 @@ describe Ably::Realtime::Channel, :event_machine do
131
131
 
132
132
  it 'attaches all channels', em_timeout: 15 do
133
133
  connection_count.times.map do
134
- Ably::Realtime::Client.new(default_options)
134
+ auto_close Ably::Realtime::Client.new(default_options)
135
135
  end.each do |client|
136
136
  channel_count.times.map do |index|
137
137
  client.channel("channel-#{index}").attach do
@@ -148,7 +148,7 @@ describe Ably::Realtime::Channel, :event_machine do
148
148
 
149
149
  context 'failure as a result of insufficient key permissions' do
150
150
  let(:restricted_client) do
151
- Ably::Realtime::Client.new(default_options.merge(key: restricted_api_key, log_level: :fatal))
151
+ auto_close Ably::Realtime::Client.new(default_options.merge(key: restricted_api_key, log_level: :fatal))
152
152
  end
153
153
  let(:restricted_channel) { restricted_client.channel("cannot_subscribe") }
154
154
 
@@ -162,7 +162,7 @@ describe Ably::Realtime::Channel, :event_machine do
162
162
  end
163
163
 
164
164
  it 'calls the errback of the returned Deferrable' do
165
- restricted_channel.attach.errback do |channel, error|
165
+ restricted_channel.attach.errback do |error|
166
166
  expect(restricted_channel.state).to eq(:failed)
167
167
  expect(error.status).to eq(401)
168
168
  stop_reactor
@@ -192,7 +192,7 @@ describe Ably::Realtime::Channel, :event_machine do
192
192
  restricted_channel.once(:failed) do
193
193
  restricted_client.close do
194
194
  # A direct call to #authorise is synchronous
195
- restricted_client.auth.authorise(key: api_key)
195
+ restricted_client.auth.authorise({}, key: api_key)
196
196
 
197
197
  restricted_client.connect do
198
198
  restricted_channel.once(:attached) do
@@ -220,9 +220,10 @@ describe Ably::Realtime::Channel, :event_machine do
220
220
  end
221
221
 
222
222
  it 'detaches from a channel and calls the provided block' do
223
- channel.attach do |chan|
224
- chan.detach do |detached_chan|
225
- expect(detached_chan.state).to eq(:detached)
223
+ channel.attach do
224
+ expect(channel.state).to eq(:attached)
225
+ channel.detach do
226
+ expect(channel.state).to eq(:detached)
226
227
  stop_reactor
227
228
  end
228
229
  end
@@ -249,7 +250,7 @@ describe Ably::Realtime::Channel, :event_machine do
249
250
 
250
251
  it 'calls the Deferrable callback on success' do
251
252
  channel.attach do
252
- channel.detach.callback do |channel|
253
+ channel.detach.callback do
253
254
  expect(channel).to be_a(Ably::Realtime::Channel)
254
255
  expect(channel.state).to eq(:detached)
255
256
  stop_reactor
@@ -563,7 +564,7 @@ describe Ably::Realtime::Channel, :event_machine do
563
564
 
564
565
  it 'publishes all messages, all success callbacks are called, and a history request confirms all messages were published' do
565
566
  connection_count.times.map do
566
- Ably::Realtime::Client.new(client_options)
567
+ auto_close Ably::Realtime::Client.new(client_options)
567
568
  end.each do |client|
568
569
  channel = client.channels.get(channel_name)
569
570
  messages.each do |message|
@@ -1,21 +1,23 @@
1
1
  # encoding: utf-8
2
2
  require 'spec_helper'
3
3
 
4
- describe Ably::Realtime::Channels do
4
+ describe Ably::Realtime::Channels, :event_machine do
5
5
  shared_examples 'a channel' do
6
6
  it 'returns a channel object' do
7
7
  expect(channel).to be_a Ably::Realtime::Channel
8
8
  expect(channel.name).to eql(channel_name)
9
+ stop_reactor
9
10
  end
10
11
 
11
12
  it 'returns channel object and passes the provided options' do
12
13
  expect(channel_with_options.options).to eql(options)
14
+ stop_reactor
13
15
  end
14
16
  end
15
17
 
16
18
  vary_by_protocol do
17
19
  let(:client) do
18
- Ably::Realtime::Client.new(key: api_key, environment: environment, protocol: protocol)
20
+ auto_close Ably::Realtime::Client.new(key: api_key, environment: environment, protocol: protocol)
19
21
  end
20
22
  let(:channel_name) { random_str }
21
23
  let(:options) { { key: 'value' } }
@@ -41,6 +43,7 @@ describe Ably::Realtime::Channels do
41
43
  new_channel = client.channels.get(channel_name, new_channel_options)
42
44
  expect(new_channel).to be_a(Ably::Realtime::Channel)
43
45
  expect(new_channel.options[:encrypted]).to eql(true)
46
+ stop_reactor
44
47
  end
45
48
  end
46
49
 
@@ -52,6 +55,7 @@ describe Ably::Realtime::Channels do
52
55
  new_channel = client.channels.get(channel_name)
53
56
  expect(new_channel).to be_a(Ably::Realtime::Channel)
54
57
  expect(original_channel.options).to eql(options)
58
+ stop_reactor
55
59
  end
56
60
  end
57
61
 
@@ -11,7 +11,7 @@ describe Ably::Realtime::Client, :event_machine do
11
11
  let(:connection) { subject.connection }
12
12
  let(:auth_params) { subject.auth.auth_params_sync }
13
13
 
14
- subject { Ably::Realtime::Client.new(client_options) }
14
+ subject { auto_close Ably::Realtime::Client.new(client_options) }
15
15
 
16
16
  context 'initialization' do
17
17
  context 'basic auth' do
@@ -44,7 +44,8 @@ describe Ably::Realtime::Client, :event_machine do
44
44
  [true, false].each do |tls_enabled|
45
45
  context "with TLS #{tls_enabled ? 'enabled' : 'disabled'}" do
46
46
  let(:capability) { { :foo => ["publish"] } }
47
- let(:token_details) { Ably::Realtime::Client.new(default_options).auth.request_token_sync(capability: capability) }
47
+ let(:token_client) { auto_close Ably::Realtime::Client.new(default_options) }
48
+ let(:token_details) { token_client.auth.request_token_sync(capability: capability) }
48
49
  let(:client_options) { default_options.merge(token: token_details.token) }
49
50
 
50
51
  context 'and a pre-generated Token provided with the :token option' do
@@ -93,7 +94,7 @@ describe Ably::Realtime::Client, :event_machine do
93
94
  let(:auth) { subject.auth }
94
95
 
95
96
  subject do
96
- Ably::Realtime::Client.new(client_options.merge(auth_callback: Proc.new do
97
+ auto_close Ably::Realtime::Client.new(client_options.merge(auth_callback: Proc.new do
97
98
  @block_called = true
98
99
  auth.create_token_request_sync(client_id: client_id)
99
100
  end))
@@ -11,7 +11,7 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
11
11
 
12
12
  let(:client_options) { default_options }
13
13
  let(:client) do
14
- Ably::Realtime::Client.new(client_options)
14
+ auto_close Ably::Realtime::Client.new(client_options)
15
15
  end
16
16
 
17
17
  context 'authentication failure' do
@@ -281,7 +281,7 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
281
281
  let(:channel_name) { random_str }
282
282
  let(:channel) { client.channel(channel_name) }
283
283
  let(:publishing_client) do
284
- Ably::Realtime::Client.new(client_options)
284
+ auto_close Ably::Realtime::Client.new(client_options)
285
285
  end
286
286
  let(:publishing_client_channel) { publishing_client.channel(channel_name) }
287
287
  let(:client_options) { default_options.merge(log_level: :none) }
@@ -392,7 +392,10 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
392
392
  connection.transport.close_connection_after_writing
393
393
 
394
394
  connection.once(:connected) do
395
- expect(connection.key).to eql(previous_connection_key)
395
+ # Connection key left part should match new connection key left part i.e.
396
+ # wVIsgTHAB1UvXh7z-1991d8586 becomes wVIsgTHAB1UvXh7z-1990d8586 after resume
397
+ expect(connection.key[/^\w{5,}-/, 0]).to_not be_nil
398
+ expect(connection.key[/^\w{5,}-/, 0]).to eql(previous_connection_key[/^\w{5,}-/, 0])
396
399
  expect(connection.id).to eql(previous_connection_id)
397
400
  stop_reactor
398
401
  end
@@ -465,9 +468,11 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
465
468
 
466
469
  context 'when failing to resume' do
467
470
  context 'because the connection_key is not or no longer valid' do
471
+ let(:channel) { client.channel(random_str) }
472
+
468
473
  def kill_connection_transport_and_prevent_valid_resume
469
474
  connection.transport.close_connection_after_writing
470
- connection.configure_new '0123456789abcdef', '0123456789abcdef', -1 # force the resume connection key to be invalid
475
+ connection.configure_new '0123456789abcdef', 'wVIsgTHAB1UvXh7z-1991d8586', -1 # force the resume connection key to be invalid
471
476
  end
472
477
 
473
478
  it 'updates the connection_id and connection_key' do
@@ -493,7 +498,7 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
493
498
  channels.each do |channel|
494
499
  channel.on(:detached) do |channel_state_change|
495
500
  error = channel_state_change.reason
496
- expect(error.message).to match(/Invalid connection key/i)
501
+ expect(error.message).to match(/Unable to recover connection/i)
497
502
  detached_channels << channel
498
503
  next unless detached_channels.count == channel_count
499
504
  expect(detached_channels.count).to eql(channel_count)
@@ -506,16 +511,16 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
506
511
  end
507
512
 
508
513
  it 'emits an error on the channel and sets the error reason' do
509
- client.channel(random_str).attach do |channel|
510
- channel.on(:error) do |error|
511
- expect(error.message).to match(/Invalid connection key/i)
512
- expect(error.code).to eql(80008)
513
- expect(channel.error_reason).to eql(error)
514
- stop_reactor
515
- end
516
-
514
+ channel.attach do
517
515
  kill_connection_transport_and_prevent_valid_resume
518
516
  end
517
+
518
+ channel.on(:error) do |error|
519
+ expect(error.message).to match(/Unable to recover connection/i)
520
+ expect(error.code).to eql(80008)
521
+ expect(channel.error_reason).to eql(error)
522
+ stop_reactor
523
+ end
519
524
  end
520
525
  end
521
526
  end
@@ -624,11 +629,11 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
624
629
 
625
630
  it 'uses a fallback host on every subsequent disconnected attempt until suspended' do
626
631
  request = 0
627
- expect(EventMachine).to receive(:connect).exactly(retry_count_for_one_state).times do |host|
632
+ # Expect retry attempts + 1 attempt for the next state
633
+ expect(EventMachine).to receive(:connect).exactly(retry_count_for_one_state + 1).times do |host|
628
634
  if request == 0
629
635
  expect(host).to eql(expected_host)
630
636
  else
631
- expect(custom_hosts).to include(host)
632
637
  fallback_hosts_used << host
633
638
  end
634
639
  request += 1
@@ -636,6 +641,7 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
636
641
  end
637
642
 
638
643
  connection.on(:suspended) do
644
+ fallback_hosts_used.pop # remove suspended attempt host
639
645
  expect(fallback_hosts_used.uniq).to match_array(custom_hosts)
640
646
  stop_reactor
641
647
  end