ably 0.8.15 → 1.0.0
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.
- 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
|