ably-rest 1.1.0 → 1.1.2

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 (33) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +9 -1
  3. data/ably-rest.gemspec +1 -1
  4. data/lib/submodules/ably-ruby/.travis.yml +9 -6
  5. data/lib/submodules/ably-ruby/CHANGELOG.md +25 -2
  6. data/lib/submodules/ably-ruby/README.md +9 -1
  7. data/lib/submodules/ably-ruby/ably.gemspec +4 -4
  8. data/lib/submodules/ably-ruby/lib/ably/logger.rb +7 -1
  9. data/lib/submodules/ably-ruby/lib/ably/modules/state_machine.rb +1 -1
  10. data/lib/submodules/ably-ruby/lib/ably/realtime/client.rb +4 -3
  11. data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +26 -15
  12. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_manager.rb +19 -3
  13. data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +4 -2
  14. data/lib/submodules/ably-ruby/lib/ably/version.rb +1 -1
  15. data/lib/submodules/ably-ruby/spec/acceptance/realtime/auth_spec.rb +13 -10
  16. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_history_spec.rb +26 -20
  17. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +11 -8
  18. data/lib/submodules/ably-ruby/spec/acceptance/realtime/client_spec.rb +8 -4
  19. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +71 -5
  20. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +125 -14
  21. data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +17 -17
  22. data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +196 -162
  23. data/lib/submodules/ably-ruby/spec/acceptance/realtime/push_admin_spec.rb +46 -6
  24. data/lib/submodules/ably-ruby/spec/acceptance/rest/channel_spec.rb +37 -0
  25. data/lib/submodules/ably-ruby/spec/acceptance/rest/channels_spec.rb +6 -0
  26. data/lib/submodules/ably-ruby/spec/acceptance/rest/message_spec.rb +8 -27
  27. data/lib/submodules/ably-ruby/spec/acceptance/rest/push_admin_spec.rb +64 -8
  28. data/lib/submodules/ably-ruby/spec/spec_helper.rb +1 -1
  29. data/lib/submodules/ably-ruby/spec/support/debug_failure_helper.rb +9 -5
  30. data/lib/submodules/ably-ruby/spec/unit/modules/enum_spec.rb +1 -1
  31. data/lib/submodules/ably-ruby/spec/unit/realtime/client_spec.rb +1 -1
  32. data/lib/submodules/ably-ruby/spec/unit/realtime/connection_spec.rb +1 -1
  33. metadata +7 -7
@@ -112,22 +112,26 @@ describe Ably::Realtime::Channel, '#history', :event_machine do
112
112
 
113
113
  context 'in multiple ProtocolMessages', em_timeout: (30 / 10) + 5 do
114
114
  it 'retrieves limited history forwards with pagination' do
115
- messages_sent.times do |index|
116
- EventMachine.add_timer(index.to_f / rate_per_second) do
117
- channel.publish('event', "history#{index}") do
118
- next unless index == messages_sent - 1
119
- ensure_message_history_direction_and_paging_is_correct :forwards
115
+ channel.attach do
116
+ messages_sent.times do |index|
117
+ EventMachine.add_timer(index.to_f / rate_per_second) do
118
+ channel.publish('event', "history#{index}") do
119
+ next unless index == messages_sent - 1
120
+ ensure_message_history_direction_and_paging_is_correct :forwards
121
+ end
120
122
  end
121
123
  end
122
124
  end
123
125
  end
124
126
 
125
127
  it 'retrieves limited history backwards with pagination' do
126
- messages_sent.times.to_a.reverse.each do |index|
127
- EventMachine.add_timer((messages_sent - index).to_f / rate_per_second) do
128
- channel.publish('event', "history#{index}") do
129
- next unless index == 0
130
- ensure_message_history_direction_and_paging_is_correct :backwards if index == 0
128
+ channel.attach do
129
+ messages_sent.times.to_a.reverse.each do |index|
130
+ EventMachine.add_timer((messages_sent - index).to_f / rate_per_second) do
131
+ channel.publish('event', "history#{index}") do
132
+ next unless index == 0
133
+ ensure_message_history_direction_and_paging_is_correct :backwards if index == 0
134
+ end
131
135
  end
132
136
  end
133
137
  end
@@ -139,18 +143,20 @@ describe Ably::Realtime::Channel, '#history', :event_machine do
139
143
  let(:messages_per_batch) { 10 }
140
144
 
141
145
  it 'return the same results with unique matching message IDs' do
142
- batches.times do |batch|
143
- EventMachine.add_timer(batch.to_f / batches.to_f) do
144
- messages_per_batch.times { channel.publish('event', 'data') }
146
+ channel.attach do
147
+ batches.times do |batch|
148
+ EventMachine.add_timer(batch.to_f / batches.to_f) do
149
+ messages_per_batch.times { |index| channel.publish('event') }
150
+ end
145
151
  end
146
- end
147
152
 
148
- channel.subscribe('event') do |message|
149
- messages << message
150
- if messages.count == batches * messages_per_batch
151
- channel.history do |page|
152
- expect(page.items.map(&:id).sort).to eql(messages.map(&:id).sort)
153
- stop_reactor
153
+ channel.subscribe('event') do |message|
154
+ messages << message
155
+ if messages.count == batches * messages_per_batch
156
+ channel.history do |page|
157
+ expect(page.items.map(&:id).sort).to eql(messages.map(&:id).sort)
158
+ stop_reactor
159
+ end
154
160
  end
155
161
  end
156
162
  end
@@ -279,8 +279,7 @@ describe Ably::Realtime::Channel, :event_machine do
279
279
  key: restricted_api_key,
280
280
  log_level: :fatal,
281
281
  use_token_auth: true,
282
- # TODO: Use wildcard / default when intersection issue resolved, realtime#780
283
- default_token_params: { capability: { "canpublish:foo" => ["publish"] } }
282
+ default_token_params: { capability: { "canpublish:foo" => ["*"] } }
284
283
  )
285
284
  end
286
285
  let(:restricted_client) do
@@ -1009,9 +1008,6 @@ describe Ably::Realtime::Channel, :event_machine do
1009
1008
 
1010
1009
  it 'publishes the message without a name attribute in the payload' do
1011
1010
  published = false
1012
- channel.publish(nil, data) do
1013
- published = true
1014
- end
1015
1011
 
1016
1012
  channel.subscribe do |message|
1017
1013
  expect(message.name).to be_nil
@@ -1024,6 +1020,10 @@ describe Ably::Realtime::Channel, :event_machine do
1024
1020
  end
1025
1021
  end
1026
1022
  end
1023
+
1024
+ channel.publish(nil, data) do
1025
+ published = true
1026
+ end
1027
1027
  end
1028
1028
  end
1029
1029
 
@@ -1032,9 +1032,6 @@ describe Ably::Realtime::Channel, :event_machine do
1032
1032
 
1033
1033
  it 'publishes the message without a data attribute in the payload' do
1034
1034
  published = false
1035
- channel.publish(name, nil) do
1036
- published = true
1037
- end
1038
1035
 
1039
1036
  channel.subscribe do |message|
1040
1037
  expect(message.data).to be_nil
@@ -1047,6 +1044,10 @@ describe Ably::Realtime::Channel, :event_machine do
1047
1044
  end
1048
1045
  end
1049
1046
  end
1047
+
1048
+ channel.publish(name, nil) do
1049
+ published = true
1050
+ end
1050
1051
  end
1051
1052
  end
1052
1053
 
@@ -1997,6 +1998,8 @@ describe Ably::Realtime::Channel, :event_machine do
1997
1998
  end
1998
1999
 
1999
2000
  context '#resume (#RTL2f)' do
2001
+ let(:client_options) { default_options.merge(log_level: :fatal) }
2002
+
2000
2003
  it 'is false when a channel first attaches' do
2001
2004
  channel.attach
2002
2005
  channel.on(:attached) do |channel_state_change|
@@ -315,8 +315,9 @@ describe Ably::Realtime::Client, :event_machine do
315
315
  expect(msg.data).to eql(data)
316
316
  stop_reactor
317
317
  end
318
+
319
+ subject.publish channel_name, event_name, data
318
320
  end
319
- subject.publish channel_name, event_name, data
320
321
  end
321
322
 
322
323
  specify 'publishing does not result in a channel being created' do
@@ -341,8 +342,9 @@ describe Ably::Realtime::Client, :event_machine do
341
342
  expect(msg.extras).to eql(extras)
342
343
  stop_reactor
343
344
  end
345
+
346
+ subject.publish channel_name, event_name, {}, extras: extras
344
347
  end
345
- subject.publish channel_name, event_name, {}, extras: extras
346
348
  end
347
349
  end
348
350
 
@@ -353,8 +355,9 @@ describe Ably::Realtime::Client, :event_machine do
353
355
  expect(msg.data).to eql(data)
354
356
  stop_reactor
355
357
  end
358
+
359
+ subject.publish channel_name, [message]
356
360
  end
357
- subject.publish channel_name, [message]
358
361
  end
359
362
 
360
363
  specify 'publishing supports an array of Hash objects' do
@@ -364,8 +367,9 @@ describe Ably::Realtime::Client, :event_machine do
364
367
  expect(msg.data).to eql(data)
365
368
  stop_reactor
366
369
  end
370
+
371
+ subject.publish channel_name, [name: event_name, data: data]
367
372
  end
368
- subject.publish channel_name, [name: event_name, data: data]
369
373
  end
370
374
 
371
375
  specify 'publishing on a closed connection fails' do
@@ -45,7 +45,7 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
45
45
  connection.on(:failed) do |connection_state_change|
46
46
  error = connection_state_change.reason
47
47
  expect(connection.state).to eq(:failed)
48
- # TODO: Check error type is a TokenNotFOund exception
48
+ # TODO: Check error type is a TokenNotFound exception
49
49
  expect(error.status).to eq(401)
50
50
  expect(error.code).to eq(40400) # not found
51
51
  stop_reactor
@@ -110,6 +110,72 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
110
110
  end
111
111
  end
112
112
  end
113
+
114
+ context 'request fails due to slow response and subsequent timeout', :webmock, em_timeout: (Ably::Rest::Client::HTTP_DEFAULTS.fetch(:request_timeout) + 5) * 2 do
115
+ let(:auth_url) { "http://#{random_str}.domain.will.be.stubbed/path" }
116
+ let(:client_options) { default_options.reject { |k, v| k == :key }.merge(auth_url: auth_url, log_level: :fatal) }
117
+
118
+ # Timeout +5 seconds, beyond default allowed timeout
119
+ before do
120
+ stub_request(:get, auth_url).
121
+ to_return do |request|
122
+ sleep Ably::Rest::Client::HTTP_DEFAULTS.fetch(:request_timeout) + 5
123
+ { status: [500, "Internal Server Error"] }
124
+ end
125
+ end
126
+
127
+ specify 'the connection moves to the disconnected state and tries again, returning again to the disconnected state (#RSA4c, #RSA4c1, #RSA4c2)' do
128
+ states = Hash.new { |hash, key| hash[key] = [] }
129
+
130
+ connection.once(:connected) { raise "Connection can never move to connected because of auth failures" }
131
+
132
+ connection.on do |connection_state|
133
+ states[connection_state.current.to_sym] << Time.now
134
+ if states[:disconnected].count == 2 && connection_state.current == :disconnected
135
+ expect(connection.error_reason).to be_a(Ably::Exceptions::ConnectionError)
136
+ expect(connection.error_reason.message).to match(/auth_url/)
137
+ EventMachine.add_timer(2) do
138
+ expect(states.keys).to include(:connecting, :disconnected)
139
+ expect(states[:connecting].count).to eql(2)
140
+ expect(states[:connected].count).to eql(0)
141
+ stop_reactor
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
147
+
148
+ context 'request fails once due to slow response but succeeds the second time' do
149
+ let(:auth_url) { "http://#{random_str}.domain.will.be.stubbed/path" }
150
+ let(:client_options) { default_options.reject { |k, v| k == :key }.merge(auth_url: auth_url, log_level: :fatal) }
151
+
152
+ # Timeout +5 seconds, beyond default allowed timeout
153
+ before do
154
+ token_response = Ably::Rest::Client.new(default_options).auth.request_token
155
+ WebMock.enable!
156
+
157
+ stub_request(:get, auth_url).
158
+ to_return do |request|
159
+ sleep Ably::Rest::Client::HTTP_DEFAULTS.fetch(:request_timeout)
160
+ { status: [500, "Internal Server Error"] }
161
+ end.then.
162
+ to_return(:status => 201, :body => token_response.to_json, :headers => { 'Content-Type' => 'application/json' })
163
+ end
164
+
165
+ specify 'the connection moves to the disconnected state and tries again, returning again to the disconnected state (#RSA4c, #RSA4c1, #RSA4c2)' do
166
+ states = Hash.new { |hash, key| hash[key] = [] }
167
+
168
+ connection.once(:connected) do
169
+ expect(states[:disconnected].count).to eql(1)
170
+ expect(states[:connecting].count).to eql(2)
171
+ stop_reactor
172
+ end
173
+
174
+ connection.on do |connection_state|
175
+ states[connection_state.current.to_sym] << Time.now
176
+ end
177
+ end
178
+ end
113
179
  end
114
180
 
115
181
  context 'existing CONNECTED connection' do
@@ -425,7 +491,7 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
425
491
  let(:client_options) do
426
492
  default_options.merge(
427
493
  log_level: :none,
428
- realtime_request_timeout: timeout
494
+ realtime_request_timeout: timeout,
429
495
  )
430
496
  end
431
497
 
@@ -921,7 +987,7 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
921
987
  end
922
988
  end
923
989
 
924
- it 'retains the client_serial (#RTN15c2, #RTN15c3)' do
990
+ it 'retains the client_msg_serial (#RTN15c2, #RTN15c3)' do
925
991
  last_message = nil
926
992
  channel = client.channels.get("foo")
927
993
 
@@ -1103,7 +1169,7 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
1103
1169
  end
1104
1170
  end
1105
1171
 
1106
- it 'resets the client_serial (#RTN15c3)' do
1172
+ it 'continues to use the client_msg_serial (#RTN15c3)' do
1107
1173
  last_message = nil
1108
1174
  channel = client.channels.get("foo")
1109
1175
 
@@ -1121,7 +1187,7 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
1121
1187
  connection.once(:connected) do
1122
1188
  channel.publish("first on new connection") do
1123
1189
  # Message serial reset after failed resume
1124
- expect(last_message.message_serial).to eql(0)
1190
+ expect(last_message.message_serial).to eql(2)
1125
1191
  stop_reactor
1126
1192
  end
1127
1193
  end
@@ -27,6 +27,13 @@ describe Ably::Realtime::Connection, :event_machine do
27
27
  end
28
28
  end
29
29
 
30
+ context 'current_host' do
31
+ it 'is available immediately after the client is instanced' do
32
+ expect(connection.current_host.to_s).to match(/\.ably\.io$/)
33
+ stop_reactor
34
+ end
35
+ end
36
+
30
37
  context 'with :auto_connect option set to false' do
31
38
  let(:client) do
32
39
  auto_close Ably::Realtime::Client.new(default_options.merge(auto_connect: false))
@@ -264,7 +271,7 @@ describe Ably::Realtime::Connection, :event_machine do
264
271
  channel.subscribe('event') do |message|
265
272
  messages_received << message.data.to_i
266
273
  if messages_received.count == total_expected
267
- expect(messages_received).to match(total_expected.times)
274
+ expect(messages_received).to match(total_expected.times.to_a)
268
275
  expect(auth_requests.count).to eql(iteration + 1)
269
276
  EventMachine.add_timer(1) do
270
277
  channel.unsubscribe 'event'
@@ -649,16 +656,47 @@ describe Ably::Realtime::Connection, :event_machine do
649
656
  end
650
657
 
651
658
  it 'is set to 1 when the second message is received' do
652
- channel.publish('event', 'data') do
653
- channel.publish('event', 'data')
659
+ channel.attach do
660
+ messages = []
661
+ channel.subscribe do |message|
662
+ messages << message
663
+ if messages.length == 2
664
+ expect(connection.serial).to eql(1)
665
+ stop_reactor
666
+ end
667
+ end
668
+
669
+ channel.publish('event', 'data') do
670
+ channel.publish('event', 'data')
671
+ end
654
672
  end
673
+ end
674
+ end
655
675
 
656
- messages = []
657
- channel.subscribe do |message|
658
- messages << message
659
- if messages.length == 2
660
- expect(connection.serial).to eql(1)
661
- stop_reactor
676
+ describe '#msgSerial' do
677
+ context 'when messages are queued for publish before a connection is established' do
678
+ let(:batches) { 6 }
679
+ let(:messages_per_batch) { 10 }
680
+
681
+ let(:publishing_client) { auto_close Ably::Realtime::Client.new(default_options) }
682
+ let(:channel_name) { random_str }
683
+ let(:publishing_channel) { publishing_client.channels.get(channel_name) }
684
+ let(:receiving_channel) { client.channels.get(channel_name) }
685
+
686
+ it 'the msgSerial is always incrementing (and not reset when the new connection is established) ensuring messages are never de-duped by the realtime service' do
687
+ messages = []
688
+
689
+ receiving_channel.attach do
690
+ receiving_channel.subscribe('event') do |message|
691
+ messages << message
692
+ stop_reactor if messages.count == batches * messages_per_batch
693
+ end
694
+
695
+ batches.times do |batch|
696
+ EventMachine.add_timer(batch.to_f / batches.to_f) do
697
+ messages_per_batch.times { |index| publishing_channel.publish('event') }
698
+ end
699
+ end
662
700
  end
663
701
  end
664
702
  end
@@ -1005,10 +1043,9 @@ describe Ably::Realtime::Connection, :event_machine do
1005
1043
  let(:client_options) { default_options.merge(websocket_heartbeats_disabled: true) }
1006
1044
 
1007
1045
  it 'does not provide the heartbeats argument in the websocket connection params (#RTN23b)' do
1008
- skip 'Native heartbeats not yet supported in the WS driver https://github.com/ably/ably-ruby/issues/116'
1009
1046
  expect(EventMachine).to receive(:connect) do |host, port, transport, object, url|
1010
1047
  uri = URI.parse(url)
1011
- expect(CGI::parse(uri.query)['heartbeats'][0]).to be_nil
1048
+ expect(CGI::parse(uri.query)['heartbeats'][0]).to eql('true')
1012
1049
  stop_reactor
1013
1050
  end
1014
1051
  client
@@ -1126,7 +1163,7 @@ describe Ably::Realtime::Connection, :event_machine do
1126
1163
  expected_serial += 1 # attach message received
1127
1164
  expect(connection.serial).to eql(expected_serial)
1128
1165
 
1129
- expect(connection.recovery_key).to eql("#{connection.key}:#{connection.serial}")
1166
+ expect(connection.recovery_key).to eql("#{connection.key}:#{connection.serial}:#{connection.send(:client_msg_serial)}")
1130
1167
  stop_reactor
1131
1168
  end
1132
1169
  end
@@ -1237,6 +1274,80 @@ describe Ably::Realtime::Connection, :event_machine do
1237
1274
  end
1238
1275
  end
1239
1276
  end
1277
+
1278
+ context 'when messages have been published' do
1279
+ describe 'the new connection' do
1280
+ it 'uses the correct msgSerial from the old connection' do
1281
+ msg_serial, recovery_key, connection_id = nil, nil, nil
1282
+
1283
+ channel.attach do
1284
+ expect(connection.send(:client_msg_serial)).to eql(-1) # no messages published yet
1285
+ connection_id = client.connection.id
1286
+ connection.transport.__incoming_protocol_msgbus__
1287
+ channel.publish('event', 'message') do
1288
+ msg_serial = connection.send(:client_msg_serial)
1289
+ expect(msg_serial).to eql(0)
1290
+ recovery_key = client.connection.recovery_key
1291
+ connection.transition_state_machine! :failed
1292
+ end
1293
+ end
1294
+
1295
+ connection.on(:failed) do
1296
+ recover_client = auto_close Ably::Realtime::Client.new(default_options.merge(recover: recovery_key))
1297
+ recover_client_channel = recover_client.channel(channel_name)
1298
+ recover_client_channel.attach do
1299
+ expect(recover_client.connection.id).to eql(connection_id)
1300
+ expect(recover_client.connection.send(:client_msg_serial)).to eql(msg_serial)
1301
+ stop_reactor
1302
+ end
1303
+ end
1304
+ end
1305
+ end
1306
+ end
1307
+
1308
+ context 'when messages are published before the new connection is recovered' do
1309
+ describe 'the new connection' do
1310
+ it 'uses the correct msgSerial from the old connection for the queued messages' do
1311
+ msg_serial, recovery_key, connection_id = nil, nil, nil
1312
+
1313
+ channel.attach do
1314
+ expect(connection.send(:client_msg_serial)).to eql(-1) # no messages published yet
1315
+ connection_id = client.connection.id
1316
+ connection.transport.__incoming_protocol_msgbus__
1317
+ channel.subscribe('event') do |message|
1318
+ expect(message.data).to eql('message-1')
1319
+ msg_serial = connection.send(:client_msg_serial)
1320
+ expect(msg_serial).to eql(0)
1321
+ recovery_key = client.connection.recovery_key
1322
+ connection.transition_state_machine! :failed
1323
+ end
1324
+ channel.publish('event', 'message-1')
1325
+ end
1326
+
1327
+ connection.on(:failed) do
1328
+ recover_client = auto_close Ably::Realtime::Client.new(default_options.merge(recover: recovery_key))
1329
+ recover_client_channel = recover_client.channel(channel_name)
1330
+ expect(recover_client.connection.send(:client_msg_serial)).to eql(msg_serial)
1331
+
1332
+ recover_client.connection.once(:connecting) do
1333
+ recover_client_channel.publish('event', 'message-2')
1334
+ expect(recover_client.connection.send(:client_msg_serial)).to eql(msg_serial + 1)
1335
+ end
1336
+
1337
+ recover_client_channel.attach do
1338
+ expect(recover_client.connection.id).to eql(connection_id)
1339
+
1340
+ recover_client_channel.subscribe do |message|
1341
+ expect(message.data).to eql('message-2')
1342
+ EventMachine.add_timer(2) do
1343
+ stop_reactor
1344
+ end
1345
+ end
1346
+ end
1347
+ end
1348
+ end
1349
+ end
1350
+ end
1240
1351
  end
1241
1352
 
1242
1353
  context 'with :recover option' do
@@ -1250,7 +1361,7 @@ describe Ably::Realtime::Connection, :event_machine do
1250
1361
  end
1251
1362
 
1252
1363
  context 'with invalid formatted value sent to server' do
1253
- let(:client_options) { default_options.merge(recover: 'not-a-valid-connection-key:1', log_level: :none) }
1364
+ let(:client_options) { default_options.merge(recover: 'not-a-valid-connection-key:1:0', log_level: :none) }
1254
1365
 
1255
1366
  it 'sets the #error_reason and moves the connection to FAILED' do
1256
1367
  connection.once(:failed) do |state_change|
@@ -1265,7 +1376,7 @@ describe Ably::Realtime::Connection, :event_machine do
1265
1376
  end
1266
1377
 
1267
1378
  context 'with expired (missing) value sent to server' do
1268
- let(:client_options) { default_options.merge(recover: 'wVIsgTHAB1UvXh7z-1991d8586:0', log_level: :fatal) }
1379
+ let(:client_options) { default_options.merge(recover: 'wVIsgTHAB1UvXh7z-1991d8586:0:0', log_level: :fatal) }
1269
1380
 
1270
1381
  it 'connects but sets the error reason and includes the reason in the state change' do
1271
1382
  connection.once(:connected) do |state_change|