ably 0.8.4 → 0.8.5

Sign up to get free protection for your applications and to get access to all the features.
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