ably 0.8.15 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +6 -4
- data/CHANGELOG.md +6 -2
- data/README.md +5 -1
- data/SPEC.md +1473 -852
- data/ably.gemspec +11 -8
- data/lib/ably/auth.rb +90 -53
- data/lib/ably/exceptions.rb +37 -8
- data/lib/ably/logger.rb +10 -1
- data/lib/ably/models/auth_details.rb +42 -0
- data/lib/ably/models/channel_state_change.rb +18 -4
- data/lib/ably/models/connection_details.rb +6 -3
- data/lib/ably/models/connection_state_change.rb +4 -3
- data/lib/ably/models/error_info.rb +1 -1
- data/lib/ably/models/message.rb +17 -1
- data/lib/ably/models/message_encoders/base.rb +103 -82
- data/lib/ably/models/message_encoders/base64.rb +1 -1
- data/lib/ably/models/presence_message.rb +16 -1
- data/lib/ably/models/protocol_message.rb +20 -3
- data/lib/ably/models/token_details.rb +11 -1
- data/lib/ably/models/token_request.rb +16 -6
- data/lib/ably/modules/async_wrapper.rb +7 -3
- data/lib/ably/modules/encodeable.rb +51 -12
- data/lib/ably/modules/enum.rb +17 -7
- data/lib/ably/modules/event_emitter.rb +29 -14
- data/lib/ably/modules/model_common.rb +13 -21
- data/lib/ably/modules/state_emitter.rb +7 -4
- data/lib/ably/modules/state_machine.rb +2 -4
- data/lib/ably/modules/uses_state_machine.rb +7 -3
- data/lib/ably/realtime.rb +2 -0
- data/lib/ably/realtime/auth.rb +102 -42
- data/lib/ably/realtime/channel.rb +68 -26
- data/lib/ably/realtime/channel/channel_manager.rb +154 -65
- data/lib/ably/realtime/channel/channel_state_machine.rb +14 -15
- data/lib/ably/realtime/client.rb +18 -3
- data/lib/ably/realtime/client/incoming_message_dispatcher.rb +38 -29
- data/lib/ably/realtime/client/outgoing_message_dispatcher.rb +6 -1
- data/lib/ably/realtime/connection.rb +108 -49
- data/lib/ably/realtime/connection/connection_manager.rb +167 -61
- data/lib/ably/realtime/connection/connection_state_machine.rb +22 -3
- data/lib/ably/realtime/connection/websocket_transport.rb +19 -10
- data/lib/ably/realtime/presence.rb +70 -45
- data/lib/ably/realtime/presence/members_map.rb +201 -36
- data/lib/ably/realtime/presence/presence_manager.rb +30 -6
- data/lib/ably/realtime/presence/presence_state_machine.rb +5 -12
- data/lib/ably/rest.rb +2 -2
- data/lib/ably/rest/channel.rb +5 -5
- data/lib/ably/rest/client.rb +31 -27
- data/lib/ably/rest/middleware/exceptions.rb +1 -3
- data/lib/ably/rest/middleware/logger.rb +2 -2
- data/lib/ably/rest/presence.rb +2 -2
- data/lib/ably/util/pub_sub.rb +1 -1
- data/lib/ably/util/safe_deferrable.rb +26 -0
- data/lib/ably/version.rb +2 -2
- data/spec/acceptance/realtime/auth_spec.rb +470 -111
- data/spec/acceptance/realtime/channel_history_spec.rb +5 -3
- data/spec/acceptance/realtime/channel_spec.rb +1017 -168
- data/spec/acceptance/realtime/client_spec.rb +6 -6
- data/spec/acceptance/realtime/connection_failures_spec.rb +458 -27
- data/spec/acceptance/realtime/connection_spec.rb +424 -105
- data/spec/acceptance/realtime/message_spec.rb +52 -23
- data/spec/acceptance/realtime/presence_history_spec.rb +5 -3
- data/spec/acceptance/realtime/presence_spec.rb +1110 -96
- data/spec/acceptance/rest/auth_spec.rb +222 -59
- data/spec/acceptance/rest/base_spec.rb +1 -1
- data/spec/acceptance/rest/channel_spec.rb +1 -2
- data/spec/acceptance/rest/client_spec.rb +104 -48
- data/spec/acceptance/rest/message_spec.rb +42 -15
- data/spec/acceptance/rest/presence_spec.rb +4 -11
- data/spec/rspec_config.rb +2 -1
- data/spec/shared/client_initializer_behaviour.rb +2 -2
- data/spec/shared/safe_deferrable_behaviour.rb +6 -2
- data/spec/spec_helper.rb +4 -2
- data/spec/support/debug_failure_helper.rb +20 -4
- data/spec/support/event_machine_helper.rb +32 -1
- data/spec/unit/auth_spec.rb +4 -11
- data/spec/unit/logger_spec.rb +28 -2
- data/spec/unit/models/auth_details_spec.rb +49 -0
- data/spec/unit/models/channel_state_change_spec.rb +23 -3
- data/spec/unit/models/connection_details_spec.rb +12 -1
- data/spec/unit/models/connection_state_change_spec.rb +15 -4
- data/spec/unit/models/message_encoders/base64_spec.rb +2 -1
- data/spec/unit/models/message_spec.rb +153 -0
- data/spec/unit/models/presence_message_spec.rb +192 -0
- data/spec/unit/models/protocol_message_spec.rb +64 -6
- data/spec/unit/models/token_details_spec.rb +75 -0
- data/spec/unit/models/token_request_spec.rb +74 -0
- data/spec/unit/modules/async_wrapper_spec.rb +2 -1
- data/spec/unit/modules/enum_spec.rb +69 -0
- data/spec/unit/modules/event_emitter_spec.rb +149 -22
- data/spec/unit/modules/state_emitter_spec.rb +9 -3
- data/spec/unit/realtime/client_spec.rb +1 -1
- data/spec/unit/realtime/connection_spec.rb +8 -5
- data/spec/unit/realtime/incoming_message_dispatcher_spec.rb +1 -1
- data/spec/unit/realtime/presence_spec.rb +4 -3
- data/spec/unit/rest/client_spec.rb +1 -1
- data/spec/unit/util/crypto_spec.rb +3 -3
- metadata +22 -19
@@ -60,9 +60,10 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
60
60
|
|
61
61
|
context 'for renewable tokens' do
|
62
62
|
context 'that are valid for the duration of the test' do
|
63
|
-
context 'with valid pre
|
63
|
+
context 'with valid pre authorized token expiring in the future' do
|
64
|
+
let(:client_options) { default_options.merge(use_token_auth: true) }
|
64
65
|
it 'uses the existing token created by Auth' do
|
65
|
-
client.auth.
|
66
|
+
client.auth.authorize(ttl: 300)
|
66
67
|
expect(client.auth).to_not receive(:request_token)
|
67
68
|
connection.once(:connected) do
|
68
69
|
stop_reactor
|
@@ -101,8 +102,8 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
101
102
|
context 'opening a new connection' do
|
102
103
|
context 'with almost expired tokens' do
|
103
104
|
before do
|
104
|
-
#
|
105
|
-
client.auth.
|
105
|
+
# Authorize synchronously to ensure token has been issued
|
106
|
+
client.auth.authorize_sync(ttl: ttl)
|
106
107
|
end
|
107
108
|
|
108
109
|
let(:ttl) { 2 }
|
@@ -137,7 +138,7 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
137
138
|
end
|
138
139
|
let(:client_options) { default_options.merge(auth_callback: token_callback) }
|
139
140
|
|
140
|
-
it 'renews the token on connect, and makes one immediate subsequent attempt to obtain a new token' do
|
141
|
+
it 'renews the token on connect, and makes one immediate subsequent attempt to obtain a new token (#RSA4b)' do
|
141
142
|
started_at = Time.now.to_f
|
142
143
|
connection.once(:disconnected) do
|
143
144
|
connection.once(:disconnected) do |connection_state_change|
|
@@ -150,25 +151,33 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
150
151
|
end
|
151
152
|
|
152
153
|
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
|
154
|
+
let(:client_options) { default_options.merge(disconnected_retry_timeout: 0.5, auth_callback: token_callback) }
|
154
155
|
|
155
156
|
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
157
|
disconnect_count = 0
|
158
|
+
first_disconnected_at = nil
|
158
159
|
connection.on(:disconnected) do |connection_state_change|
|
160
|
+
first_disconnected_at ||= begin
|
161
|
+
Time.now.to_f
|
162
|
+
end
|
159
163
|
expect(connection_state_change.reason.code).to eql(40142) # token expired
|
160
|
-
disconnect_count
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
+
if disconnect_count == 4 # 3 attempts to reconnect after initial
|
165
|
+
# First disconnect reattempts immediately as part of connect sequence
|
166
|
+
# Second disconnect reattempt immediately as part of disconnected retry sequence
|
167
|
+
# Following two take 0.5 second each
|
168
|
+
# Not convinced two immediate retries is necessary, but not worth engineering effort to fix given
|
169
|
+
# it's only one extra retry
|
170
|
+
expect(Time.now.to_f - first_disconnected_at).to be > 2 * 0.5
|
171
|
+
expect(Time.now.to_f - first_disconnected_at).to be < 9 # allow 1.5 seconds for each authentication cycle
|
164
172
|
stop_reactor
|
165
173
|
end
|
174
|
+
disconnect_count += 1
|
166
175
|
end
|
167
176
|
end
|
168
177
|
end
|
169
178
|
|
170
179
|
context 'using implicit token auth' do
|
171
|
-
let(:client_options) { default_options.merge(use_token_auth: true,
|
180
|
+
let(:client_options) { default_options.merge(use_token_auth: true, default_token_params: { ttl: ttl }) }
|
172
181
|
|
173
182
|
before do
|
174
183
|
stub_const 'Ably::Models::TokenDetails::TOKEN_EXPIRY_BUFFER', -10 # ensure client lib thinks token is still valid
|
@@ -178,14 +187,18 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
178
187
|
connection.once(:disconnected) do
|
179
188
|
expect(client.rest_client.connection).to receive(:post).
|
180
189
|
with(/requestToken$/, anything).
|
181
|
-
exactly(:
|
190
|
+
exactly(:twice). # it retries an expired token request immediately
|
182
191
|
and_call_original
|
183
192
|
|
184
193
|
expect(client.rest_client).to_not receive(:fallback_connection)
|
185
194
|
expect(client).to_not receive(:fallback_endpoint)
|
186
195
|
|
196
|
+
# Connection will go into :disconnected, then back to
|
197
|
+
# :connecting, then :disconnected again
|
187
198
|
connection.once(:disconnected) do
|
188
|
-
|
199
|
+
connection.once(:disconnected) do
|
200
|
+
stop_reactor
|
201
|
+
end
|
189
202
|
end
|
190
203
|
end
|
191
204
|
end
|
@@ -198,7 +211,7 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
198
211
|
let(:ttl) { 5 }
|
199
212
|
let(:channel_name) { random_str }
|
200
213
|
let(:channel) { client.channel(channel_name) }
|
201
|
-
let(:client_options) { default_options.merge(use_token_auth: true,
|
214
|
+
let(:client_options) { default_options.merge(use_token_auth: true, default_token_params: { ttl: ttl }) }
|
202
215
|
|
203
216
|
context 'the server' do
|
204
217
|
it 'disconnects the client, and the client automatically renews the token and then reconnects', em_timeout: 15 do
|
@@ -229,6 +242,7 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
229
242
|
end
|
230
243
|
|
231
244
|
context 'connection state' do
|
245
|
+
let(:publish_count) { 10 }
|
232
246
|
let(:ttl) { 4 }
|
233
247
|
let(:auth_requests) { [] }
|
234
248
|
let(:token_callback) do
|
@@ -243,13 +257,15 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
243
257
|
let(:publishing_channel) { publishing_client.channels.get(channel_name) }
|
244
258
|
let(:messages_received) { [] }
|
245
259
|
|
246
|
-
def
|
247
|
-
|
260
|
+
def publish_and_check_disconnect(options = {})
|
261
|
+
iteration = options.fetch(:iteration) { 1 }
|
262
|
+
total_expected = publish_count * iteration
|
263
|
+
publish_count.times.each { |index| publishing_channel.publish('event', (total_expected - publish_count + index).to_s) }
|
248
264
|
channel.subscribe('event') do |message|
|
249
265
|
messages_received << message.data.to_i
|
250
|
-
if messages_received.count ==
|
251
|
-
expect(messages_received).to match(
|
252
|
-
expect(auth_requests.count).to eql(
|
266
|
+
if messages_received.count == total_expected
|
267
|
+
expect(messages_received).to match(total_expected.times)
|
268
|
+
expect(auth_requests.count).to eql(iteration + 1)
|
253
269
|
EventMachine.add_timer(1) do
|
254
270
|
channel.unsubscribe 'event'
|
255
271
|
yield
|
@@ -258,25 +274,19 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
258
274
|
end
|
259
275
|
end
|
260
276
|
|
261
|
-
|
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
|
277
|
+
it 'retains messages published when disconnected three times during authentication', em_timeout: 30 do
|
274
278
|
publishing_channel.attach do
|
275
279
|
channel.attach do
|
276
280
|
connection.once(:disconnected) do
|
277
|
-
|
281
|
+
publish_and_check_disconnect(iteration: 1) do
|
278
282
|
connection.once(:disconnected) do
|
279
|
-
|
283
|
+
publish_and_check_disconnect(iteration: 2) do
|
284
|
+
connection.once(:disconnected) do
|
285
|
+
publish_and_check_disconnect(iteration: 3) do
|
286
|
+
stop_reactor
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
280
290
|
end
|
281
291
|
end
|
282
292
|
end
|
@@ -322,13 +332,14 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
322
332
|
let!(:expired_token_details) do
|
323
333
|
# Request a token synchronously
|
324
334
|
token_client = auto_close Ably::Realtime::Client.new(default_options)
|
325
|
-
token_client.auth.request_token_sync(ttl:
|
335
|
+
token_client.auth.request_token_sync(ttl: ttl)
|
326
336
|
end
|
327
337
|
|
328
338
|
context 'opening a new connection' do
|
329
339
|
let(:client_options) { default_options.merge(key: nil, token: expired_token_details.token, log_level: :none) }
|
340
|
+
let(:ttl) { 0.01 }
|
330
341
|
|
331
|
-
it 'transitions state to failed', em_timeout: 10 do
|
342
|
+
it 'transitions state to failed (#RSA4a)', em_timeout: 10 do
|
332
343
|
EventMachine.add_timer(1) do # wait for token to expire
|
333
344
|
expect(expired_token_details).to be_expired
|
334
345
|
connection.once(:connected) { raise 'Connection should never connect as token has expired' }
|
@@ -341,7 +352,17 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
341
352
|
end
|
342
353
|
|
343
354
|
context 'when connected' do
|
344
|
-
|
355
|
+
let(:client_options) { default_options.merge(key: nil, token: expired_token_details.token, log_level: :none) }
|
356
|
+
let(:ttl) { 4 }
|
357
|
+
|
358
|
+
it 'transitions state to failed (#RSA4a)' do
|
359
|
+
connection.once(:connected) do
|
360
|
+
connection.once(:failed) do
|
361
|
+
expect(client.connection.error_reason.code).to eql(40142)
|
362
|
+
stop_reactor
|
363
|
+
end
|
364
|
+
end
|
365
|
+
end
|
345
366
|
end
|
346
367
|
end
|
347
368
|
end
|
@@ -579,11 +600,13 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
579
600
|
end
|
580
601
|
|
581
602
|
context 'when closing' do
|
582
|
-
it '
|
603
|
+
it 'fails the deferrable before the connection is closed' do
|
583
604
|
connection.connect do
|
584
605
|
connection.once(:closing) do
|
585
|
-
|
586
|
-
|
606
|
+
connection.connect.errback do |error|
|
607
|
+
expect(error).to be_a(Ably::Exceptions::InvalidStateChange)
|
608
|
+
stop_reactor
|
609
|
+
end
|
587
610
|
end
|
588
611
|
connection.close
|
589
612
|
end
|
@@ -605,10 +628,12 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
605
628
|
it 'the sent message msgSerial is 0 but the connection serial remains at -1' do
|
606
629
|
channel.attach do
|
607
630
|
connection.__outgoing_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
631
|
+
if protocol_message.action == :message
|
632
|
+
connection.__outgoing_protocol_msgbus__.unsubscribe
|
633
|
+
expect(protocol_message['msgSerial']).to eql(0)
|
634
|
+
expect(connection.serial).to eql(-1)
|
635
|
+
stop_reactor
|
636
|
+
end
|
612
637
|
end
|
613
638
|
channel.publish('event', 'data')
|
614
639
|
end
|
@@ -678,7 +703,6 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
678
703
|
|
679
704
|
def log_connection_changes
|
680
705
|
connection.on(:closing) { events[:closing_emitted] = true }
|
681
|
-
connection.on(:error) { events[:error_emitted] = true }
|
682
706
|
|
683
707
|
connection.__incoming_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
|
684
708
|
events[:closed_message_from_server_received] = true if protocol_message.action == :closed
|
@@ -691,7 +715,6 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
691
715
|
expect(connection.state).to eq(:closed)
|
692
716
|
|
693
717
|
EventMachine.add_timer(1) do # allow for all subscribers on incoming message bes
|
694
|
-
expect(events[:error_emitted]).to_not eql(true)
|
695
718
|
expect(events[:closed_message_from_server_received]).to_not eql(true)
|
696
719
|
expect(events[:closing_emitted]).to eql(true)
|
697
720
|
stop_reactor
|
@@ -708,7 +731,6 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
708
731
|
connection.on(:connected) do
|
709
732
|
connection.on(:closed) do
|
710
733
|
EventMachine.add_timer(1) do # allow for all subscribers on incoming message bus
|
711
|
-
expect(events[:error_emitted]).to_not eql(true)
|
712
734
|
expect(events[:closed_message_from_server_received]).to eql(true)
|
713
735
|
expect(events[:closing_emitted]).to eql(true)
|
714
736
|
stop_reactor
|
@@ -739,14 +761,13 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
739
761
|
connection.on(:closed) do
|
740
762
|
expect(Time.now - close_requested_at).to be >= custom_timeout
|
741
763
|
expect(connection.state).to eq(:closed)
|
742
|
-
expect(events[:error_emitted]).to_not eql(true)
|
743
764
|
expect(events[:closed_message_from_server_received]).to_not eql(true)
|
744
765
|
expect(events[:closing_emitted]).to eql(true)
|
745
766
|
stop_reactor
|
746
767
|
end
|
747
768
|
|
748
769
|
log_connection_changes
|
749
|
-
connection.close
|
770
|
+
EventMachine.next_tick { connection.close }
|
750
771
|
end
|
751
772
|
end
|
752
773
|
end
|
@@ -755,26 +776,117 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
755
776
|
end
|
756
777
|
|
757
778
|
context '#ping' do
|
758
|
-
it 'echoes a heart beat' do
|
779
|
+
it 'echoes a heart beat (#RTN13a)' do
|
759
780
|
connection.on(:connected) do
|
760
781
|
connection.ping do |time_elapsed|
|
761
782
|
expect(time_elapsed).to be > 0
|
783
|
+
expect(time_elapsed).to be < 3
|
762
784
|
stop_reactor
|
763
785
|
end
|
764
786
|
end
|
765
787
|
end
|
766
788
|
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
789
|
+
it 'sends a unique ID in each protocol message (#RTN13e)' do
|
790
|
+
connection.on(:connected) do
|
791
|
+
heartbeat_ids = []
|
792
|
+
pings_complete = []
|
793
|
+
connection.__outgoing_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
|
794
|
+
if protocol_message.action == :heartbeat
|
795
|
+
heartbeat_ids << protocol_message.id
|
796
|
+
end
|
797
|
+
end
|
798
|
+
|
799
|
+
ping_block = Proc.new do
|
800
|
+
pings_complete << true
|
801
|
+
if pings_complete.length == 3
|
802
|
+
expect(heartbeat_ids.uniq.length).to eql(3)
|
803
|
+
stop_reactor
|
804
|
+
end
|
805
|
+
end
|
806
|
+
|
807
|
+
connection.ping(&ping_block)
|
808
|
+
connection.ping(&ping_block)
|
809
|
+
connection.ping(&ping_block)
|
810
|
+
end
|
811
|
+
end
|
812
|
+
|
813
|
+
it 'waits until the connection becomes CONNECTED when in the CONNETING state' do
|
814
|
+
connection.once(:connecting) do
|
815
|
+
connection.ping do |time_elapsed|
|
816
|
+
expect(connection.state).to eq(:connected)
|
817
|
+
stop_reactor
|
818
|
+
end
|
819
|
+
end
|
820
|
+
end
|
821
|
+
|
822
|
+
context 'with incompatible states' do
|
823
|
+
let(:client_options) { default_options.merge(log_level: :none) }
|
824
|
+
|
825
|
+
context 'when not connected' do
|
826
|
+
it 'fails the deferrable (#RTN13b)' do
|
827
|
+
connection.ping.errback do |error|
|
828
|
+
expect(error.message).to match(/Cannot send a ping when.*initialized/i)
|
829
|
+
stop_reactor
|
830
|
+
end
|
831
|
+
end
|
832
|
+
end
|
833
|
+
|
834
|
+
context 'when suspended' do
|
835
|
+
it 'fails the deferrable (#RTN13b)' do
|
836
|
+
connection.once(:connected) do
|
837
|
+
connection.transition_state_machine! :suspended
|
838
|
+
connection.ping.errback do |error|
|
839
|
+
expect(error.message).to match(/Cannot send a ping when.*suspended/i)
|
840
|
+
stop_reactor
|
841
|
+
end
|
842
|
+
end
|
843
|
+
end
|
844
|
+
end
|
845
|
+
|
846
|
+
context 'when failed' do
|
847
|
+
it 'fails the deferrable (#RTN13b)' do
|
848
|
+
connection.once(:connected) do
|
849
|
+
connection.transition_state_machine! :failed
|
850
|
+
connection.ping.errback do |error|
|
851
|
+
expect(error.message).to match(/Cannot send a ping when.*failed/i)
|
852
|
+
stop_reactor
|
853
|
+
end
|
854
|
+
end
|
855
|
+
end
|
856
|
+
end
|
857
|
+
|
858
|
+
context 'when closed' do
|
859
|
+
it 'fails the deferrable (#RTN13b)' do
|
860
|
+
connection.once(:connected) do
|
861
|
+
connection.close
|
862
|
+
connection.once(:closed) do
|
863
|
+
connection.ping.errback do |error|
|
864
|
+
expect(error.message).to match(/Cannot send a ping when.*closed/i)
|
865
|
+
stop_reactor
|
866
|
+
end
|
867
|
+
end
|
868
|
+
end
|
869
|
+
end
|
870
|
+
end
|
871
|
+
|
872
|
+
context 'when it becomes closed' do
|
873
|
+
it 'fails the deferrable (#RTN13b)' do
|
874
|
+
connection.once(:connected) do
|
875
|
+
connection.ping.errback do |error|
|
876
|
+
expect(error.message).to match(/Ping failed as connection has changed state to.*closing/i)
|
877
|
+
stop_reactor
|
878
|
+
end
|
879
|
+
connection.close
|
880
|
+
end
|
881
|
+
end
|
771
882
|
end
|
772
883
|
end
|
773
884
|
|
774
885
|
context 'with a success block that raises an exception' do
|
775
886
|
it 'catches the exception and logs the error' do
|
776
887
|
connection.on(:connected) do
|
777
|
-
expect(connection.logger).to receive(:error)
|
888
|
+
expect(connection.logger).to receive(:error) do |*args, &block|
|
889
|
+
expect(args.concat([block ? block.call : nil]).join(',')).to match(/Forced exception/)
|
778
890
|
stop_reactor
|
779
891
|
end
|
780
892
|
connection.ping { raise 'Forced exception' }
|
@@ -785,13 +897,22 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
785
897
|
context 'when ping times out' do
|
786
898
|
let(:client_options) { default_options.merge(log_level: :error) }
|
787
899
|
|
788
|
-
it 'logs a warning' do
|
900
|
+
it 'fails the deferrable logs a warning (#RTN13a, #RTN13c)' do
|
901
|
+
message_logged = false
|
789
902
|
connection.once(:connected) do
|
790
903
|
allow(connection).to receive(:defaults).and_return(connection.defaults.merge(realtime_request_timeout: 0.0001))
|
791
|
-
expect(connection.logger).to receive(:warn)
|
792
|
-
|
904
|
+
expect(connection.logger).to receive(:warn) do |*args, &block|
|
905
|
+
expect(block.call).to match(/Ping timed out/)
|
906
|
+
message_logged = true
|
907
|
+
end
|
908
|
+
connection.ping.errback do |error|
|
909
|
+
EventMachine.add_timer(0.1) do
|
910
|
+
expect(error.message).to match(/Ping timed out/)
|
911
|
+
expect(error.code).to eql(50003)
|
912
|
+
expect(message_logged).to be_truthy
|
913
|
+
stop_reactor
|
914
|
+
end
|
793
915
|
end
|
794
|
-
connection.ping
|
795
916
|
end
|
796
917
|
end
|
797
918
|
|
@@ -807,6 +928,107 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
807
928
|
end
|
808
929
|
end
|
809
930
|
|
931
|
+
context 'Heartbeats (#RTN23)' do
|
932
|
+
context 'heartbeat interval' do
|
933
|
+
context 'when reduced artificially' do
|
934
|
+
let(:protocol_message_attributes) do
|
935
|
+
{
|
936
|
+
action: Ably::Models::ProtocolMessage::ACTION.Connected.to_i,
|
937
|
+
connection_serial: 55,
|
938
|
+
connection_details: {
|
939
|
+
max_idle_interval: 2 * 1000
|
940
|
+
}
|
941
|
+
}
|
942
|
+
end
|
943
|
+
let(:client_options) { default_options.merge(realtime_request_timeout: 3) }
|
944
|
+
let(:expected_heartbeat_interval) { 5 }
|
945
|
+
|
946
|
+
it 'is the sum of the max_idle_interval and realtime_request_timeout (#RTN23a)' do
|
947
|
+
connection.once(:connected) do
|
948
|
+
connection.__incoming_protocol_msgbus__.publish :protocol_message, Ably::Models::ProtocolMessage.new(protocol_message_attributes)
|
949
|
+
EventMachine.next_tick do
|
950
|
+
expect(connection.heartbeat_interval).to eql(expected_heartbeat_interval)
|
951
|
+
stop_reactor
|
952
|
+
end
|
953
|
+
end
|
954
|
+
end
|
955
|
+
|
956
|
+
it 'disconnects the transport if no heartbeat received since connected (#RTN23a)' do
|
957
|
+
connection.once(:connected) do
|
958
|
+
connection.__incoming_protocol_msgbus__.publish :protocol_message, Ably::Models::ProtocolMessage.new(protocol_message_attributes)
|
959
|
+
last_received_at = Time.now
|
960
|
+
connection.once(:disconnected) do
|
961
|
+
expect(Time.now.to_i - last_received_at.to_i).to be_within(2).of(expected_heartbeat_interval)
|
962
|
+
stop_reactor
|
963
|
+
end
|
964
|
+
end
|
965
|
+
end
|
966
|
+
|
967
|
+
it 'disconnects the transport if no heartbeat received since last event received (#RTN23a)' do
|
968
|
+
connection.once(:connected) do
|
969
|
+
connection.__incoming_protocol_msgbus__.publish :protocol_message, Ably::Models::ProtocolMessage.new(protocol_message_attributes)
|
970
|
+
last_received_at = Time.now
|
971
|
+
EventMachine.add_timer(3) { client.channels.get('foo').attach }
|
972
|
+
connection.once(:disconnected) do
|
973
|
+
expect(Time.now.to_i - last_received_at.to_i).to be_within(2).of(expected_heartbeat_interval + 3)
|
974
|
+
stop_reactor
|
975
|
+
end
|
976
|
+
end
|
977
|
+
end
|
978
|
+
end
|
979
|
+
end
|
980
|
+
|
981
|
+
context 'transport-level heartbeats are supported in the websocket transport' do
|
982
|
+
it 'provides the heartbeats argument in the websocket connection params (#RTN23b)' do
|
983
|
+
expect(EventMachine).to receive(:connect) do |host, port, transport, object, url|
|
984
|
+
uri = URI.parse(url)
|
985
|
+
expect(CGI::parse(uri.query)['heartbeats'][0]).to eql('false')
|
986
|
+
stop_reactor
|
987
|
+
end
|
988
|
+
client
|
989
|
+
end
|
990
|
+
|
991
|
+
it 'receives websocket heartbeat messages (#RTN23b) [slow test as need to wait for heartbeat]', em_timeout: 45 do
|
992
|
+
skip "Heartbeats param is missing from realtime implementation, see https://github.com/ably/realtime/issues/656"
|
993
|
+
|
994
|
+
connection.once(:connected) do
|
995
|
+
connection.__incoming_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
|
996
|
+
if protocol_message.action == :heartbeat
|
997
|
+
expect(protocol_message.attributes[:source]).to eql('websocket')
|
998
|
+
expect(connection.time_since_connection_confirmed_alive?).to be_within(1).of(0)
|
999
|
+
stop_reactor
|
1000
|
+
end
|
1001
|
+
end
|
1002
|
+
end
|
1003
|
+
end
|
1004
|
+
end
|
1005
|
+
|
1006
|
+
context 'with websocket heartbeats disabled (undocumented)' do
|
1007
|
+
let(:client_options) { default_options.merge(websocket_heartbeats_disabled: true) }
|
1008
|
+
|
1009
|
+
it 'does not provide the heartbeats argument in the websocket connection params (#RTN23b)' do
|
1010
|
+
expect(EventMachine).to receive(:connect) do |host, port, transport, object, url|
|
1011
|
+
uri = URI.parse(url)
|
1012
|
+
expect(CGI::parse(uri.query)['heartbeats'][0]).to be_nil
|
1013
|
+
stop_reactor
|
1014
|
+
end
|
1015
|
+
client
|
1016
|
+
end
|
1017
|
+
|
1018
|
+
it 'receives websocket protocol messages (#RTN23b) [slow test as need to wait for heartbeat]', em_timeout: 45 do
|
1019
|
+
connection.once(:connected) do
|
1020
|
+
connection.__incoming_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
|
1021
|
+
if protocol_message.action == :heartbeat
|
1022
|
+
expect(protocol_message.attributes[:source]).to_not eql('websocket')
|
1023
|
+
expect(connection.time_since_connection_confirmed_alive?).to be_within(1).of(0)
|
1024
|
+
stop_reactor
|
1025
|
+
end
|
1026
|
+
end
|
1027
|
+
end
|
1028
|
+
end
|
1029
|
+
end
|
1030
|
+
end
|
1031
|
+
|
810
1032
|
context '#details' do
|
811
1033
|
let(:connection) { client.connection }
|
812
1034
|
|
@@ -817,7 +1039,7 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
817
1039
|
end
|
818
1040
|
end
|
819
1041
|
|
820
|
-
it 'contains the ConnectionDetails object once connected' do
|
1042
|
+
it 'contains the ConnectionDetails object once connected (#RTN21)' do
|
821
1043
|
connection.on(:connected) do
|
822
1044
|
expect(connection.details).to be_a(Ably::Models::ConnectionDetails)
|
823
1045
|
expect(connection.details.connection_key).to_not be_nil
|
@@ -826,7 +1048,7 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
826
1048
|
end
|
827
1049
|
end
|
828
1050
|
|
829
|
-
it 'contains the new ConnectionDetails object once a subsequent connection is created' do
|
1051
|
+
it 'contains the new ConnectionDetails object once a subsequent connection is created (#RTN21)' do
|
830
1052
|
connection.once(:connected) do
|
831
1053
|
expect(connection.details.connection_key).to_not be_nil
|
832
1054
|
old_key = connection.details.connection_key
|
@@ -841,13 +1063,13 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
841
1063
|
end
|
842
1064
|
end
|
843
1065
|
|
844
|
-
context 'with a different connection_state_ttl' do
|
1066
|
+
context 'with a different default connection_state_ttl' do
|
845
1067
|
before do
|
846
1068
|
old_defaults = Ably::Realtime::Connection::DEFAULTS
|
847
1069
|
stub_const 'Ably::Realtime::Connection::DEFAULTS', old_defaults.merge(connection_state_ttl: 15)
|
848
1070
|
end
|
849
1071
|
|
850
|
-
it 'updates the private Connection#connection_state_ttl' do
|
1072
|
+
it 'updates the private Connection#connection_state_ttl when received from Ably in ConnectionDetails' do
|
851
1073
|
expect(connection.connection_state_ttl).to eql(15)
|
852
1074
|
|
853
1075
|
connection.once(:connected) do
|
@@ -954,7 +1176,7 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
954
1176
|
context "opening a new connection using a recently disconnected connection's #recovery_key" do
|
955
1177
|
context 'connection#id and connection#key after recovery' do
|
956
1178
|
it 'remains the same for id and party for key' do
|
957
|
-
connection_key_consistent_part_regex = /.*?!(\w{5,})
|
1179
|
+
connection_key_consistent_part_regex = /.*?!([\w-]{5,})-\w+/
|
958
1180
|
previous_connection_id = nil
|
959
1181
|
previous_connection_key = nil
|
960
1182
|
|
@@ -1036,13 +1258,13 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
1036
1258
|
context 'with invalid formatted value sent to server' do
|
1037
1259
|
let(:client_options) { default_options.merge(recover: 'not-a-valid-connection-key:1', log_level: :none) }
|
1038
1260
|
|
1039
|
-
it '
|
1040
|
-
connection.once(:
|
1261
|
+
it 'sets the #error_reason and moves the connection to FAILED' do
|
1262
|
+
connection.once(:failed) do |state_change|
|
1041
1263
|
expect(connection.state).to eq(:failed)
|
1042
|
-
expect(
|
1264
|
+
expect(state_change.reason.message).to match(/Invalid connectionKey/i)
|
1043
1265
|
expect(connection.error_reason.message).to match(/Invalid connectionKey/i)
|
1044
1266
|
expect(connection.error_reason.code).to eql(80018)
|
1045
|
-
expect(connection.error_reason).to eql(
|
1267
|
+
expect(connection.error_reason).to eql(state_change.reason)
|
1046
1268
|
stop_reactor
|
1047
1269
|
end
|
1048
1270
|
end
|
@@ -1051,13 +1273,13 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
1051
1273
|
context 'with expired (missing) value sent to server' do
|
1052
1274
|
let(:client_options) { default_options.merge(recover: 'wVIsgTHAB1UvXh7z-1991d8586:0', log_level: :fatal) }
|
1053
1275
|
|
1054
|
-
it '
|
1055
|
-
connection.once(:
|
1276
|
+
it 'connects but sets the error reason and includes the reason in the state change' do
|
1277
|
+
connection.once(:connected) do |state_change|
|
1056
1278
|
expect(connection.state).to eq(:connected)
|
1057
|
-
expect(
|
1279
|
+
expect(state_change.reason.message).to match(/Unable to recover connection/i)
|
1058
1280
|
expect(connection.error_reason.message).to match(/Unable to recover connection/i)
|
1059
1281
|
expect(connection.error_reason.code).to eql(80008)
|
1060
|
-
expect(connection.error_reason).to eql(
|
1282
|
+
expect(connection.error_reason).to eql(state_change.reason)
|
1061
1283
|
stop_reactor
|
1062
1284
|
end
|
1063
1285
|
end
|
@@ -1088,22 +1310,22 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
1088
1310
|
end
|
1089
1311
|
|
1090
1312
|
context 'when a state transition is unsupported' do
|
1091
|
-
let(:client_options) { default_options.merge(log_level: :
|
1313
|
+
let(:client_options) { default_options.merge(log_level: :fatal) } # silence FATAL errors
|
1092
1314
|
|
1093
|
-
it '
|
1315
|
+
it 'logs the invalid state change as fatal' do
|
1094
1316
|
connection.connect do
|
1095
1317
|
connection.transition_state_machine :initialized
|
1318
|
+
EventMachine.add_timer(1) { stop_reactor }
|
1096
1319
|
end
|
1097
1320
|
|
1098
|
-
|
1099
|
-
expect(
|
1100
|
-
stop_reactor
|
1321
|
+
expect(client.logger).to receive(:fatal).at_least(:once) do |*args, &block|
|
1322
|
+
expect(args.concat([block ? block.call : nil]).join(',')).to match(/Unable to transition/)
|
1101
1323
|
end
|
1102
1324
|
end
|
1103
1325
|
end
|
1104
1326
|
|
1105
1327
|
context 'protocol failure' do
|
1106
|
-
let(:client_options) { default_options.merge(protocol: :json) }
|
1328
|
+
let(:client_options) { default_options.merge(protocol: :json, log_level: :none) }
|
1107
1329
|
|
1108
1330
|
context 'receiving an invalid ProtocolMessage' do
|
1109
1331
|
it 'emits an error on the connection and logs a fatal error message' do
|
@@ -1111,9 +1333,11 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
1111
1333
|
connection.transport.send(:driver).emit 'message', OpenStruct.new(data: { action: 500 }.to_json)
|
1112
1334
|
end
|
1113
1335
|
|
1114
|
-
expect(client.logger).to receive(:fatal).
|
1115
|
-
|
1116
|
-
|
1336
|
+
expect(client.logger).to receive(:fatal).at_least(:once) do |*args, &block|
|
1337
|
+
expect(args.concat([block ? block.call : nil]).join(',')).to match(/Invalid Protocol Message/)
|
1338
|
+
end
|
1339
|
+
connection.on(:failed) do |state_change|
|
1340
|
+
expect(state_change.reason.message).to match(/Invalid Protocol Message/)
|
1117
1341
|
stop_reactor
|
1118
1342
|
end
|
1119
1343
|
end
|
@@ -1250,11 +1474,13 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
1250
1474
|
)
|
1251
1475
|
end
|
1252
1476
|
|
1253
|
-
it '
|
1477
|
+
it 'moves the channels into the suspended state and prevents publishing of messages on those channels' do
|
1254
1478
|
channel.attach do
|
1255
|
-
channel.once(:
|
1256
|
-
|
1257
|
-
|
1479
|
+
channel.once(:suspended) do
|
1480
|
+
channel.publish('test').errback do |error|
|
1481
|
+
expect(error).to be_a(Ably::Exceptions::MessageQueueingDisabled)
|
1482
|
+
stop_reactor
|
1483
|
+
end
|
1258
1484
|
end
|
1259
1485
|
|
1260
1486
|
close_connection_proc = Proc.new do
|
@@ -1282,8 +1508,10 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
1282
1508
|
it 'sets all channels to failed and prevents publishing of messages on those channels' do
|
1283
1509
|
channel.attach
|
1284
1510
|
channel.once(:failed) do
|
1285
|
-
|
1286
|
-
|
1511
|
+
channel.publish('test').errback do |error|
|
1512
|
+
expect(error).to be_a(Ably::Exceptions::ChannelInactive)
|
1513
|
+
stop_reactor
|
1514
|
+
end
|
1287
1515
|
end
|
1288
1516
|
end
|
1289
1517
|
end
|
@@ -1314,16 +1542,9 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
1314
1542
|
end
|
1315
1543
|
|
1316
1544
|
context 'ConnectionStateChange object' do
|
1317
|
-
def unbind
|
1318
|
-
if connection.transport
|
1319
|
-
connection.transport.unbind
|
1320
|
-
else
|
1321
|
-
EventMachine.add_timer(0.005) { unbind }
|
1322
|
-
end
|
1323
|
-
end
|
1324
|
-
|
1325
1545
|
it 'has current state' do
|
1326
1546
|
connection.on(:connected) do |connection_state_change|
|
1547
|
+
expect(connection_state_change.current).to be_a(Ably::Realtime::Connection::STATE)
|
1327
1548
|
expect(connection_state_change.current).to eq(:connected)
|
1328
1549
|
stop_reactor
|
1329
1550
|
end
|
@@ -1331,11 +1552,20 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
1331
1552
|
|
1332
1553
|
it 'has a previous state' do
|
1333
1554
|
connection.on(:connected) do |connection_state_change|
|
1555
|
+
expect(connection_state_change.previous).to be_a(Ably::Realtime::Connection::STATE)
|
1334
1556
|
expect(connection_state_change.previous).to eq(:connecting)
|
1335
1557
|
stop_reactor
|
1336
1558
|
end
|
1337
1559
|
end
|
1338
1560
|
|
1561
|
+
it 'has the event that generated the state change (#TH5)' do
|
1562
|
+
connection.on(:connected) do |connection_state_change|
|
1563
|
+
expect(connection_state_change.event).to be_a(Ably::Realtime::Connection::EVENT)
|
1564
|
+
expect(connection_state_change.event).to eq(:connected)
|
1565
|
+
stop_reactor
|
1566
|
+
end
|
1567
|
+
end
|
1568
|
+
|
1339
1569
|
it 'contains a private API protocol_message attribute that is used for special state change events', :api_private do
|
1340
1570
|
connection.on(:connected) do |connection_state_change|
|
1341
1571
|
expect(connection_state_change.protocol_message).to be_a(Ably::Models::ProtocolMessage)
|
@@ -1385,7 +1615,7 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
1385
1615
|
expect(connection_state_change.retry_in).to eql(0)
|
1386
1616
|
stop_reactor
|
1387
1617
|
end
|
1388
|
-
unbind
|
1618
|
+
EventMachine.add_timer(0.005) { connection.transport.unbind }
|
1389
1619
|
end
|
1390
1620
|
end
|
1391
1621
|
|
@@ -1406,36 +1636,125 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
1406
1636
|
expect(connection_state_change.retry_in).to be > 0
|
1407
1637
|
stop_reactor
|
1408
1638
|
end
|
1409
|
-
unbind
|
1639
|
+
EventMachine.add_timer(0.005) { connection.transport.unbind }
|
1410
1640
|
end
|
1411
1641
|
connection.transport.unbind
|
1412
1642
|
end
|
1413
1643
|
end
|
1414
1644
|
end
|
1415
1645
|
end
|
1646
|
+
|
1647
|
+
context 'whilst CONNECTED' do
|
1648
|
+
context 'when a CONNECTED message is received (#RTN24)' do
|
1649
|
+
let(:connection_key) { random_str(32) }
|
1650
|
+
let(:protocol_message_attributes) do
|
1651
|
+
{
|
1652
|
+
action: Ably::Models::ProtocolMessage::ACTION.Connected.to_i,
|
1653
|
+
connection_serial: 55,
|
1654
|
+
connection_details: {
|
1655
|
+
client_id: 'bob',
|
1656
|
+
connection_key: connection_key,
|
1657
|
+
connection_state_ttl: 33 * 1000,
|
1658
|
+
max_frame_size: 555,
|
1659
|
+
max_inbound_rate: 999,
|
1660
|
+
max_message_size: 1310,
|
1661
|
+
server_id: 'us-east-1-a.foo.com',
|
1662
|
+
max_idle_interval: 4 * 1000
|
1663
|
+
}
|
1664
|
+
}
|
1665
|
+
end
|
1666
|
+
|
1667
|
+
it 'emits an UPDATE event' do
|
1668
|
+
connection.once(:connected) do
|
1669
|
+
connection.once(:update) do |connection_state_change|
|
1670
|
+
expect(connection_state_change.current).to eq(:connected)
|
1671
|
+
expect(connection_state_change.previous).to eq(:connected)
|
1672
|
+
expect(connection_state_change.retry_in).to be_nil
|
1673
|
+
expect(connection_state_change.reason).to be_nil
|
1674
|
+
expect(connection.state).to eq(:connected)
|
1675
|
+
stop_reactor
|
1676
|
+
end
|
1677
|
+
|
1678
|
+
connection.__incoming_protocol_msgbus__.publish :protocol_message, Ably::Models::ProtocolMessage.new(protocol_message_attributes)
|
1679
|
+
end
|
1680
|
+
end
|
1681
|
+
|
1682
|
+
it 'updates the ConnectionDetail and Connection attributes (#RTC8a1)' do
|
1683
|
+
connection.once(:connected) do
|
1684
|
+
expect(client.auth.client_id).to eql('*')
|
1685
|
+
|
1686
|
+
connection.once(:update) do |connection_state_change|
|
1687
|
+
expect(client.auth.client_id).to eql('bob')
|
1688
|
+
expect(connection.key).to eql(connection_key)
|
1689
|
+
expect(connection.serial).to eql(55)
|
1690
|
+
expect(connection.connection_state_ttl).to eql(33)
|
1691
|
+
|
1692
|
+
expect(connection.details.client_id).to eql('bob')
|
1693
|
+
expect(connection.details.connection_key).to eql(connection_key)
|
1694
|
+
expect(connection.details.connection_state_ttl).to eql(33)
|
1695
|
+
expect(connection.details.max_frame_size).to eql(555)
|
1696
|
+
expect(connection.details.max_inbound_rate).to eql(999)
|
1697
|
+
expect(connection.details.max_message_size).to eql(1310)
|
1698
|
+
expect(connection.details.server_id).to eql('us-east-1-a.foo.com')
|
1699
|
+
expect(connection.details.max_idle_interval).to eql(4)
|
1700
|
+
stop_reactor
|
1701
|
+
end
|
1702
|
+
|
1703
|
+
connection.__incoming_protocol_msgbus__.publish :protocol_message, Ably::Models::ProtocolMessage.new(protocol_message_attributes)
|
1704
|
+
end
|
1705
|
+
end
|
1706
|
+
end
|
1707
|
+
|
1708
|
+
context 'when a CONNECTED message with an error is received' do
|
1709
|
+
let(:protocol_message_attributes) do
|
1710
|
+
{
|
1711
|
+
action: Ably::Models::ProtocolMessage::ACTION.Connected.to_i,
|
1712
|
+
connection_serial: 22,
|
1713
|
+
error: { code: 50000, message: 'Internal failure' },
|
1714
|
+
}
|
1715
|
+
end
|
1716
|
+
|
1717
|
+
it 'emits an UPDATE event' do
|
1718
|
+
connection.once(:connected) do
|
1719
|
+
connection.on(:update) do |connection_state_change|
|
1720
|
+
expect(connection_state_change.current).to eq(:connected)
|
1721
|
+
expect(connection_state_change.previous).to eq(:connected)
|
1722
|
+
expect(connection_state_change.retry_in).to be_nil
|
1723
|
+
expect(connection_state_change.reason).to be_a(Ably::Models::ErrorInfo)
|
1724
|
+
expect(connection_state_change.reason.code).to eql(50000)
|
1725
|
+
expect(connection_state_change.reason.message).to match(/Internal failure/)
|
1726
|
+
expect(connection.state).to eq(:connected)
|
1727
|
+
stop_reactor
|
1728
|
+
end
|
1729
|
+
|
1730
|
+
connection.__incoming_protocol_msgbus__.publish :protocol_message, Ably::Models::ProtocolMessage.new(protocol_message_attributes)
|
1731
|
+
end
|
1732
|
+
end
|
1733
|
+
end
|
1734
|
+
end
|
1416
1735
|
end
|
1417
1736
|
|
1418
1737
|
context 'version params' do
|
1419
|
-
it 'sends the protocol version param v' do
|
1738
|
+
it 'sends the protocol version param v (#G4, #RTN2f)' do
|
1420
1739
|
expect(EventMachine).to receive(:connect) do |host, port, transport, object, url|
|
1421
1740
|
uri = URI.parse(url)
|
1422
|
-
expect(CGI::parse(uri.query)['v'][0]).to eql(
|
1741
|
+
expect(CGI::parse(uri.query)['v'][0]).to eql('1.0')
|
1423
1742
|
stop_reactor
|
1424
1743
|
end
|
1425
1744
|
client
|
1426
1745
|
end
|
1427
1746
|
|
1428
|
-
it 'sends the lib version param lib' do
|
1747
|
+
it 'sends the lib version param lib (#RTN2g)' do
|
1429
1748
|
expect(EventMachine).to receive(:connect) do |host, port, transport, object, url|
|
1430
1749
|
uri = URI.parse(url)
|
1431
|
-
expect(CGI::parse(uri.query)['lib'][0]).to
|
1750
|
+
expect(CGI::parse(uri.query)['lib'][0]).to match(/^ruby-1\.0\.\d+(-[\w\.]+)?+$/)
|
1432
1751
|
stop_reactor
|
1433
1752
|
end
|
1434
1753
|
client
|
1435
1754
|
end
|
1436
1755
|
|
1437
1756
|
context 'with variant' do
|
1438
|
-
let(:variant) { 'foo
|
1757
|
+
let(:variant) { 'foo' }
|
1439
1758
|
|
1440
1759
|
before do
|
1441
1760
|
Ably.lib_variant = variant
|
@@ -1445,10 +1764,10 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
1445
1764
|
Ably.lib_variant = nil
|
1446
1765
|
end
|
1447
1766
|
|
1448
|
-
it 'sends the lib version param lib with the variant' do
|
1767
|
+
it 'sends the lib version param lib with the variant (#RTN2g + #RSC7b)' do
|
1449
1768
|
expect(EventMachine).to receive(:connect) do |host, port, transport, object, url|
|
1450
1769
|
uri = URI.parse(url)
|
1451
|
-
expect(CGI::parse(uri.query)['lib'][0]).to
|
1770
|
+
expect(CGI::parse(uri.query)['lib'][0]).to match(/^ruby-#{variant}-1\.0\.\d+(-[\w\.]+)?$/)
|
1452
1771
|
stop_reactor
|
1453
1772
|
end
|
1454
1773
|
client
|