ably 0.8.3 → 0.8.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -3
- data/lib/ably/auth.rb +1 -1
- data/lib/ably/exceptions.rb +3 -0
- data/lib/ably/models/channel_state_change.rb +41 -0
- data/lib/ably/models/connection_state_change.rb +43 -0
- data/lib/ably/models/message.rb +1 -1
- data/lib/ably/models/presence_message.rb +1 -1
- data/lib/ably/models/protocol_message.rb +2 -1
- data/lib/ably/modules/state_emitter.rb +4 -1
- data/lib/ably/modules/uses_state_machine.rb +28 -4
- data/lib/ably/realtime/channel.rb +11 -3
- data/lib/ably/realtime/channel/channel_manager.rb +24 -4
- data/lib/ably/realtime/channel/channel_state_machine.rb +20 -11
- data/lib/ably/realtime/client/incoming_message_dispatcher.rb +4 -4
- data/lib/ably/realtime/connection.rb +1 -0
- data/lib/ably/realtime/connection/connection_manager.rb +33 -21
- data/lib/ably/realtime/connection/connection_state_machine.rb +24 -16
- data/lib/ably/rest/channel.rb +3 -2
- data/lib/ably/util/crypto.rb +15 -0
- data/lib/ably/version.rb +1 -1
- data/spec/acceptance/realtime/channel_spec.rb +155 -9
- data/spec/acceptance/realtime/client_spec.rb +2 -2
- data/spec/acceptance/realtime/connection_failures_spec.rb +8 -4
- data/spec/acceptance/realtime/connection_spec.rb +122 -11
- data/spec/acceptance/realtime/message_spec.rb +119 -3
- data/spec/acceptance/realtime/presence_spec.rb +34 -13
- data/spec/acceptance/rest/channel_spec.rb +9 -0
- data/spec/acceptance/rest/client_spec.rb +10 -0
- data/spec/unit/models/channel_state_change_spec.rb +44 -0
- data/spec/unit/models/connection_state_change_spec.rb +54 -0
- data/spec/unit/util/crypto_spec.rb +18 -0
- metadata +8 -2
@@ -31,8 +31,8 @@ describe Ably::Realtime::Client, :event_machine do
|
|
31
31
|
it 'fails to connect because a private key cannot be sent over a non-secure connection' do
|
32
32
|
connection.on(:connected) { raise 'Should not have connected' }
|
33
33
|
|
34
|
-
connection.on(:failed) do |
|
35
|
-
expect(
|
34
|
+
connection.on(:failed) do |connection_state_change|
|
35
|
+
expect(connection_state_change.reason).to be_a(Ably::Exceptions::InsecureRequest)
|
36
36
|
stop_reactor
|
37
37
|
end
|
38
38
|
end
|
@@ -24,7 +24,8 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
|
|
24
24
|
let(:invalid_key) { 'not_an_app.invalid_key_name:invalid_key_value' }
|
25
25
|
|
26
26
|
it 'enters the failed state and returns a not found error' do
|
27
|
-
connection.on(:failed) do |
|
27
|
+
connection.on(:failed) do |connection_state_change|
|
28
|
+
error = connection_state_change.reason
|
28
29
|
expect(connection.state).to eq(:failed)
|
29
30
|
# TODO: Check error type is an InvalidToken exception
|
30
31
|
expect(error.status).to eq(404)
|
@@ -38,7 +39,8 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
|
|
38
39
|
let(:invalid_key) { "#{app_id}.invalid_key_name:invalid_key_value" }
|
39
40
|
|
40
41
|
it 'enters the failed state and returns an authorization error' do
|
41
|
-
connection.on(:failed) do |
|
42
|
+
connection.on(:failed) do |connection_state_change|
|
43
|
+
error = connection_state_change.reason
|
42
44
|
expect(connection.state).to eq(:failed)
|
43
45
|
# TODO: Check error type is a TokenNotFOund exception
|
44
46
|
expect(error.status).to eq(401)
|
@@ -182,7 +184,8 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
|
|
182
184
|
context '#error_reason' do
|
183
185
|
[:disconnected, :suspended, :failed].each do |state|
|
184
186
|
it "contains the error when state is #{state}" do
|
185
|
-
connection.on(state) do |
|
187
|
+
connection.on(state) do |connection_state_change|
|
188
|
+
error = connection_state_change.reason
|
186
189
|
expect(connection.error_reason).to eq(error)
|
187
190
|
expect(connection.error_reason.code).to eql(80000)
|
188
191
|
stop_reactor
|
@@ -488,7 +491,8 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
|
|
488
491
|
when_all(*channels.map(&:attach)) do
|
489
492
|
detached_channels = []
|
490
493
|
channels.each do |channel|
|
491
|
-
channel.on(:detached) do |
|
494
|
+
channel.on(:detached) do |channel_state_change|
|
495
|
+
error = channel_state_change.reason
|
492
496
|
expect(error.message).to match(/Invalid connection key/i)
|
493
497
|
detached_channels << channel
|
494
498
|
next unless detached_channels.count == channel_count
|
@@ -127,8 +127,8 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
127
127
|
it 'renews the token on connect, and only makes one subsequent attempt to obtain a new token' do
|
128
128
|
expect(client.rest_client.auth).to receive(:authorise).at_least(:twice).and_call_original
|
129
129
|
connection.once(:disconnected) do
|
130
|
-
connection.once(:failed) do |
|
131
|
-
expect(
|
130
|
+
connection.once(:failed) do |connection_state_change|
|
131
|
+
expect(connection_state_change.reason.code).to eql(40140) # token expired
|
132
132
|
stop_reactor
|
133
133
|
end
|
134
134
|
end
|
@@ -167,8 +167,8 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
167
167
|
|
168
168
|
connection.once(:connected) do
|
169
169
|
started_at = Time.now
|
170
|
-
connection.once(:disconnected) do |
|
171
|
-
expect(
|
170
|
+
connection.once(:disconnected) do |connection_state_change|
|
171
|
+
expect(connection_state_change.reason.code).to eq(40140) # Token expired
|
172
172
|
|
173
173
|
# Token has expired, so now ensure it is not used again
|
174
174
|
stub_const 'Ably::Models::TokenDetails::TOKEN_EXPIRY_BUFFER', original_token_expiry_buffer
|
@@ -178,7 +178,6 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
178
178
|
expect(client.auth.current_token_details).to_not be_expired
|
179
179
|
expect(Time.now - started_at >= ttl)
|
180
180
|
expect(original_token).to be_expired
|
181
|
-
expect(error.code).to eql(40140) # token expired
|
182
181
|
stop_reactor
|
183
182
|
end
|
184
183
|
end
|
@@ -922,12 +921,12 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
922
921
|
expect(connection.__outgoing_message_queue__).to be_empty
|
923
922
|
channel.publish 'test'
|
924
923
|
|
925
|
-
EventMachine.
|
924
|
+
EventMachine.next_tick do
|
926
925
|
expect(connection.__outgoing_message_queue__).to_not be_empty
|
927
926
|
end
|
928
927
|
|
929
928
|
connection.once(:connected) do
|
930
|
-
EventMachine.add_timer(0.
|
929
|
+
EventMachine.add_timer(0.1) do
|
931
930
|
expect(connection.__outgoing_message_queue__).to be_empty
|
932
931
|
stop_reactor
|
933
932
|
end
|
@@ -940,6 +939,8 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
940
939
|
end
|
941
940
|
|
942
941
|
context 'when connection enters the :suspended state' do
|
942
|
+
let(:client_options) { default_options.merge(:log_level => :fatal) }
|
943
|
+
|
943
944
|
before do
|
944
945
|
# Reconfigure client library retry periods so that client stays in suspended state
|
945
946
|
stub_const 'Ably::Realtime::Connection::ConnectionManager::CONNECT_RETRY_CONFIG',
|
@@ -956,13 +957,21 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
956
957
|
stop_reactor
|
957
958
|
end
|
958
959
|
|
960
|
+
close_connection_proc = Proc.new do
|
961
|
+
EventMachine.add_timer(0.001) do
|
962
|
+
if connection.transport.nil?
|
963
|
+
close_connection_proc.call
|
964
|
+
else
|
965
|
+
connection.transport.close_connection_after_writing
|
966
|
+
end
|
967
|
+
end
|
968
|
+
end
|
969
|
+
|
959
970
|
# Keep disconnecting the websocket transport after it attempts reconnection
|
960
|
-
connection.transport.close_connection_after_writing
|
961
971
|
connection.on(:connecting) do
|
962
|
-
|
963
|
-
connection.transport.close_connection_after_writing
|
964
|
-
end
|
972
|
+
close_connection_proc.call
|
965
973
|
end
|
974
|
+
close_connection_proc.call
|
966
975
|
end
|
967
976
|
end
|
968
977
|
end
|
@@ -979,5 +988,107 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
979
988
|
end
|
980
989
|
end
|
981
990
|
end
|
991
|
+
|
992
|
+
context 'connection state change' do
|
993
|
+
it 'emits a ConnectionStateChange object' do
|
994
|
+
connection.on(:connected) do |connection_state_change|
|
995
|
+
expect(connection_state_change).to be_a(Ably::Models::ConnectionStateChange)
|
996
|
+
stop_reactor
|
997
|
+
end
|
998
|
+
end
|
999
|
+
|
1000
|
+
context 'ConnectionStateChange object' do
|
1001
|
+
it 'has current state' do
|
1002
|
+
connection.on(:connected) do |connection_state_change|
|
1003
|
+
expect(connection_state_change.current).to eq(:connected)
|
1004
|
+
stop_reactor
|
1005
|
+
end
|
1006
|
+
end
|
1007
|
+
|
1008
|
+
it 'has a previous state' do
|
1009
|
+
connection.on(:connected) do |connection_state_change|
|
1010
|
+
expect(connection_state_change.previous).to eq(:connecting)
|
1011
|
+
stop_reactor
|
1012
|
+
end
|
1013
|
+
end
|
1014
|
+
|
1015
|
+
it 'contains a private API protocol_message attribute that is used for special state change events', :api_private do
|
1016
|
+
connection.on(:connected) do |connection_state_change|
|
1017
|
+
expect(connection_state_change.protocol_message).to be_a(Ably::Models::ProtocolMessage)
|
1018
|
+
expect(connection_state_change.reason).to be_nil
|
1019
|
+
stop_reactor
|
1020
|
+
end
|
1021
|
+
end
|
1022
|
+
|
1023
|
+
it 'has an empty reason when there is no error' do
|
1024
|
+
connection.on(:closed) do |connection_state_change|
|
1025
|
+
expect(connection_state_change.reason).to be_nil
|
1026
|
+
stop_reactor
|
1027
|
+
end
|
1028
|
+
connection.connect do
|
1029
|
+
connection.close
|
1030
|
+
end
|
1031
|
+
end
|
1032
|
+
|
1033
|
+
context 'on failure' do
|
1034
|
+
let(:client_options) { default_options.merge(log_level: :none) }
|
1035
|
+
|
1036
|
+
it 'has a reason Error object when there is an error on the connection' do
|
1037
|
+
connection.on(:failed) do |connection_state_change|
|
1038
|
+
expect(connection_state_change.reason).to be_a(Ably::Exceptions::BaseAblyException)
|
1039
|
+
stop_reactor
|
1040
|
+
end
|
1041
|
+
connection.connect do
|
1042
|
+
error = Ably::Exceptions::ConnectionFailed.new('forced failure', 500, 50000)
|
1043
|
+
client.connection.manager.error_received_from_server error
|
1044
|
+
end
|
1045
|
+
end
|
1046
|
+
end
|
1047
|
+
|
1048
|
+
context 'retry_in' do
|
1049
|
+
let(:client_options) { default_options.merge(log_level: :debug) }
|
1050
|
+
|
1051
|
+
it 'is nil when a retry is not required' do
|
1052
|
+
connection.on(:connected) do |connection_state_change|
|
1053
|
+
expect(connection_state_change.retry_in).to be_nil
|
1054
|
+
stop_reactor
|
1055
|
+
end
|
1056
|
+
end
|
1057
|
+
|
1058
|
+
it 'is 0 when first attempt to connect fails' do
|
1059
|
+
connection.once(:connecting) do
|
1060
|
+
connection.once(:disconnected) do |connection_state_change|
|
1061
|
+
expect(connection_state_change.retry_in).to eql(0)
|
1062
|
+
stop_reactor
|
1063
|
+
end
|
1064
|
+
EventMachine.add_timer(0.001) { connection.transport.unbind }
|
1065
|
+
end
|
1066
|
+
end
|
1067
|
+
|
1068
|
+
it 'is 0 when an immediate reconnect will occur' do
|
1069
|
+
connection.once(:connected) do
|
1070
|
+
connection.once(:disconnected) do |connection_state_change|
|
1071
|
+
expect(connection_state_change.retry_in).to eql(0)
|
1072
|
+
stop_reactor
|
1073
|
+
end
|
1074
|
+
connection.transport.unbind
|
1075
|
+
end
|
1076
|
+
end
|
1077
|
+
|
1078
|
+
it 'contains the next retry period when an immediate reconnect will not occur' do
|
1079
|
+
connection.once(:connected) do
|
1080
|
+
connection.once(:connecting) do
|
1081
|
+
connection.once(:disconnected) do |connection_state_change|
|
1082
|
+
expect(connection_state_change.retry_in).to be > 0
|
1083
|
+
stop_reactor
|
1084
|
+
end
|
1085
|
+
EventMachine.add_timer(0.001) { connection.transport.unbind }
|
1086
|
+
end
|
1087
|
+
connection.transport.unbind
|
1088
|
+
end
|
1089
|
+
end
|
1090
|
+
end
|
1091
|
+
end
|
1092
|
+
end
|
982
1093
|
end
|
983
1094
|
end
|
@@ -181,10 +181,14 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
|
|
181
181
|
|
182
182
|
context 'with :echo_messages option set to false' do
|
183
183
|
let(:no_echo_client) do
|
184
|
-
Ably::Realtime::Client.new(default_options.merge(echo_messages: false))
|
184
|
+
Ably::Realtime::Client.new(default_options.merge(echo_messages: false, log_level: :debug))
|
185
185
|
end
|
186
186
|
let(:no_echo_channel) { no_echo_client.channel(channel_name) }
|
187
187
|
|
188
|
+
let(:rest_client) do
|
189
|
+
Ably::Rest::Client.new(default_options.merge(log_level: :debug))
|
190
|
+
end
|
191
|
+
|
188
192
|
it 'will not echo messages to the client but will still broadcast messages to other connected clients', em_timeout: 10 do
|
189
193
|
channel.attach do |echo_channel|
|
190
194
|
no_echo_channel.attach do
|
@@ -196,13 +200,27 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
|
|
196
200
|
|
197
201
|
echo_channel.subscribe('test_event') do |message|
|
198
202
|
expect(message.data).to eql(payload)
|
199
|
-
EventMachine.add_timer(1) do
|
203
|
+
EventMachine.add_timer(1.5) do
|
200
204
|
stop_reactor
|
201
205
|
end
|
202
206
|
end
|
203
207
|
end
|
204
208
|
end
|
205
209
|
end
|
210
|
+
|
211
|
+
it 'will not echo messages to the client from other REST clients publishing using that connection_ID', em_timeout: 10 do
|
212
|
+
skip 'Waiting on realtime#285 to be resolved'
|
213
|
+
no_echo_channel.attach do
|
214
|
+
no_echo_channel.subscribe('test_event') do |message|
|
215
|
+
fail "Message should not have been echoed back"
|
216
|
+
end
|
217
|
+
|
218
|
+
rest_client.channel(channel_name).publish('test_event', nil, connection_id: no_echo_client.connection.id)
|
219
|
+
EventMachine.add_timer(1.5) do
|
220
|
+
stop_reactor
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
206
224
|
end
|
207
225
|
end
|
208
226
|
|
@@ -257,7 +275,7 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
|
|
257
275
|
|
258
276
|
context 'without suitable publishing permissions' do
|
259
277
|
let(:restricted_client) do
|
260
|
-
Ably::Realtime::Client.new(options.merge(key: restricted_api_key, environment: environment, protocol: protocol))
|
278
|
+
Ably::Realtime::Client.new(options.merge(key: restricted_api_key, environment: environment, protocol: protocol, :log_level => :error))
|
261
279
|
end
|
262
280
|
let(:restricted_channel) { restricted_client.channel("cansubscribe:example") }
|
263
281
|
let(:payload) { 'Test message without permission to publish' }
|
@@ -569,5 +587,103 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
|
|
569
587
|
end
|
570
588
|
end
|
571
589
|
end
|
590
|
+
|
591
|
+
describe 'when message is published, the connection disconnects before the ACK is received, and the connection is resumed' do
|
592
|
+
let(:event_name) { random_str }
|
593
|
+
let(:message_state) { [] }
|
594
|
+
let(:connection) { client.connection }
|
595
|
+
let(:client_options) { default_options.merge(:log_level => :debug) }
|
596
|
+
let(:msgs_received) { [] }
|
597
|
+
|
598
|
+
it 'publishes the message again, later receives the ACK and only one message is ever received from Ably' do
|
599
|
+
on_reconnected = Proc.new do
|
600
|
+
expect(message_state).to be_empty
|
601
|
+
EventMachine.add_timer(2) do
|
602
|
+
expect(message_state).to contain_exactly(:delivered)
|
603
|
+
# TODO: Uncomment once issue realtime#42 is resolved
|
604
|
+
# expect(msgs_received.length).to eql(1)
|
605
|
+
stop_reactor
|
606
|
+
end
|
607
|
+
end
|
608
|
+
|
609
|
+
connection.once(:connected) do
|
610
|
+
connection.transport.__outgoing_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
|
611
|
+
if protocol_message.messages.find { |message| message.name == event_name }
|
612
|
+
EventMachine.add_timer(0.001) do
|
613
|
+
connection.transport.unbind # trigger failure
|
614
|
+
expect(message_state).to be_empty
|
615
|
+
connection.once :connected, &on_reconnected
|
616
|
+
end
|
617
|
+
end
|
618
|
+
end
|
619
|
+
end
|
620
|
+
|
621
|
+
channel.publish(event_name).tap do |deferrable|
|
622
|
+
deferrable.callback { message_state << :delivered }
|
623
|
+
deferrable.errback do
|
624
|
+
raise 'Message delivery should not fail'
|
625
|
+
end
|
626
|
+
end
|
627
|
+
|
628
|
+
channel.subscribe do |message|
|
629
|
+
msgs_received << message
|
630
|
+
end
|
631
|
+
end
|
632
|
+
end
|
633
|
+
|
634
|
+
describe 'when message is published, the connection disconnects before the ACK is received' do
|
635
|
+
let(:connection) { client.connection }
|
636
|
+
let(:event_name) { random_str }
|
637
|
+
|
638
|
+
describe 'the connection becomes suspended' do
|
639
|
+
let(:client_options) { default_options.merge(:log_level => :fatal) }
|
640
|
+
|
641
|
+
it 'calls the errback for all messages' do
|
642
|
+
connection.once(:connected) do
|
643
|
+
connection.transport.__outgoing_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
|
644
|
+
if protocol_message.messages.find { |message| message.name == event_name }
|
645
|
+
EventMachine.add_timer(0.001) do
|
646
|
+
connection.transition_state_machine :suspended
|
647
|
+
end
|
648
|
+
end
|
649
|
+
end
|
650
|
+
end
|
651
|
+
|
652
|
+
channel.publish(event_name).tap do |deferrable|
|
653
|
+
deferrable.callback do
|
654
|
+
raise 'Message delivery should not happen'
|
655
|
+
end
|
656
|
+
deferrable.errback do
|
657
|
+
stop_reactor
|
658
|
+
end
|
659
|
+
end
|
660
|
+
end
|
661
|
+
end
|
662
|
+
|
663
|
+
describe 'the connection becomes failed' do
|
664
|
+
let(:client_options) { default_options.merge(:log_level => :none) }
|
665
|
+
|
666
|
+
it 'calls the errback for all messages' do
|
667
|
+
connection.once(:connected) do
|
668
|
+
connection.transport.__outgoing_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
|
669
|
+
if protocol_message.messages.find { |message| message.name == event_name }
|
670
|
+
EventMachine.add_timer(0.001) do
|
671
|
+
connection.transition_state_machine :failed, reason: RuntimeError.new
|
672
|
+
end
|
673
|
+
end
|
674
|
+
end
|
675
|
+
end
|
676
|
+
|
677
|
+
channel.publish(event_name).tap do |deferrable|
|
678
|
+
deferrable.callback do
|
679
|
+
raise 'Message delivery should not happen'
|
680
|
+
end
|
681
|
+
deferrable.errback do
|
682
|
+
stop_reactor
|
683
|
+
end
|
684
|
+
end
|
685
|
+
end
|
686
|
+
end
|
687
|
+
end
|
572
688
|
end
|
573
689
|
end
|
@@ -40,18 +40,29 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
40
40
|
end
|
41
41
|
|
42
42
|
unless expected_state == :left
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
channel_client_one.
|
47
|
-
|
48
|
-
expect { presence_client_one.public_send(method_name, args) }.to raise_error Ably::Exceptions::InvalidStateChange, /Operation is not allowed when channel is in STATE
|
43
|
+
it 'raise an exception if the channel is detached' do
|
44
|
+
setup_test(method_name, args, options) do
|
45
|
+
channel_client_one.attach do
|
46
|
+
channel_client_one.transition_state_machine :detaching
|
47
|
+
channel_client_one.once(:detached) do
|
48
|
+
expect { presence_client_one.public_send(method_name, args) }.to raise_error Ably::Exceptions::InvalidStateChange, /Operation is not allowed when channel is in STATE.detached/i
|
49
49
|
stop_reactor
|
50
50
|
end
|
51
51
|
end
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
|
+
it 'raise an exception if the channel is failed' do
|
56
|
+
setup_test(method_name, args, options) do
|
57
|
+
channel_client_one.attach do
|
58
|
+
channel_client_one.transition_state_machine :failed
|
59
|
+
expect(channel_client_one.state).to eq(:failed)
|
60
|
+
expect { presence_client_one.public_send(method_name, args) }.to raise_error Ably::Exceptions::InvalidStateChange, /Operation is not allowed when channel is in STATE.failed/i
|
61
|
+
stop_reactor
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
55
66
|
it 'implicitly attaches the channel' do
|
56
67
|
expect(channel_client_one).to_not be_attached
|
57
68
|
presence_client_one.public_send(method_name, args) do
|
@@ -1061,16 +1072,25 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
1061
1072
|
presence_client_one.get { raise 'Intentional exception' }
|
1062
1073
|
end
|
1063
1074
|
|
1064
|
-
|
1065
|
-
|
1066
|
-
channel_client_one.
|
1067
|
-
|
1068
|
-
expect { presence_client_one.get }.to raise_error Ably::Exceptions::InvalidStateChange, /Operation is not allowed when channel is in STATE
|
1075
|
+
it 'raise an exception if the channel is detached' do
|
1076
|
+
channel_client_one.attach do
|
1077
|
+
channel_client_one.transition_state_machine :detaching
|
1078
|
+
channel_client_one.once(:detached) do
|
1079
|
+
expect { presence_client_one.get }.to raise_error Ably::Exceptions::InvalidStateChange, /Operation is not allowed when channel is in STATE.detached/i
|
1069
1080
|
stop_reactor
|
1070
1081
|
end
|
1071
1082
|
end
|
1072
1083
|
end
|
1073
1084
|
|
1085
|
+
it 'raise an exception if the channel is failed' do
|
1086
|
+
channel_client_one.attach do
|
1087
|
+
channel_client_one.transition_state_machine :failed
|
1088
|
+
expect(channel_client_one.state).to eq(:failed)
|
1089
|
+
expect { presence_client_one.get }.to raise_error Ably::Exceptions::InvalidStateChange, /Operation is not allowed when channel is in STATE.failed/i
|
1090
|
+
stop_reactor
|
1091
|
+
end
|
1092
|
+
end
|
1093
|
+
|
1074
1094
|
context 'during a sync' do
|
1075
1095
|
let(:pages) { 2 }
|
1076
1096
|
let(:members_per_page) { 100 }
|
@@ -1120,8 +1140,8 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
1120
1140
|
if protocol_message.action == :sync
|
1121
1141
|
# prevent any more SYNC messages coming through
|
1122
1142
|
client_two.connection.transport.__incoming_protocol_msgbus__.unsubscribe
|
1123
|
-
channel_client_two.
|
1124
|
-
channel_client_two.
|
1143
|
+
channel_client_two.transition_state_machine :detaching
|
1144
|
+
channel_client_two.transition_state_machine :detached
|
1125
1145
|
end
|
1126
1146
|
end
|
1127
1147
|
end
|
@@ -1565,6 +1585,7 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
1565
1585
|
context 'connection failure mid-way through a large member sync' do
|
1566
1586
|
let(:members_count) { 400 }
|
1567
1587
|
let(:sync_pages_received) { [] }
|
1588
|
+
let(:client_options) { default_options.merge(log_level: :error) }
|
1568
1589
|
|
1569
1590
|
it 'resumes the SYNC operation', em_timeout: 15 do
|
1570
1591
|
when_all(*members_count.times.map do |index|
|