ably 0.8.2 → 0.8.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/CHANGELOG.md +185 -0
- data/LICENSE +15 -0
- data/README.md +8 -4
- data/SPEC.md +999 -531
- data/ably.gemspec +1 -1
- data/lib/ably.rb +1 -1
- data/lib/ably/auth.rb +114 -87
- data/lib/ably/exceptions.rb +40 -14
- data/lib/ably/models/message.rb +3 -5
- data/lib/ably/models/paginated_result.rb +3 -12
- data/lib/ably/models/presence_message.rb +8 -2
- data/lib/ably/models/protocol_message.rb +15 -3
- data/lib/ably/models/stat.rb +1 -1
- data/lib/ably/models/token_details.rb +1 -1
- data/lib/ably/modules/channels_collection.rb +7 -1
- data/lib/ably/modules/conversions.rb +1 -1
- data/lib/ably/modules/encodeable.rb +6 -3
- data/lib/ably/modules/message_pack.rb +2 -2
- data/lib/ably/modules/model_common.rb +1 -1
- data/lib/ably/modules/state_machine.rb +2 -2
- data/lib/ably/realtime.rb +1 -0
- data/lib/ably/realtime/auth.rb +191 -0
- data/lib/ably/realtime/channel.rb +97 -25
- data/lib/ably/realtime/channel/channel_manager.rb +11 -3
- data/lib/ably/realtime/client.rb +22 -6
- data/lib/ably/realtime/connection.rb +74 -41
- data/lib/ably/realtime/connection/connection_manager.rb +48 -33
- data/lib/ably/realtime/presence.rb +17 -3
- data/lib/ably/rest/channel.rb +43 -16
- data/lib/ably/rest/client.rb +57 -26
- data/lib/ably/rest/middleware/exceptions.rb +3 -1
- data/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb +4 -2
- data/lib/ably/rest/presence.rb +1 -0
- data/lib/ably/version.rb +1 -1
- data/spec/acceptance/realtime/auth_spec.rb +242 -0
- data/spec/acceptance/realtime/channel_spec.rb +277 -5
- data/spec/acceptance/realtime/channels_spec.rb +64 -0
- data/spec/acceptance/realtime/client_spec.rb +26 -5
- data/spec/acceptance/realtime/connection_failures_spec.rb +23 -6
- data/spec/acceptance/realtime/connection_spec.rb +167 -16
- data/spec/acceptance/realtime/message_spec.rb +9 -8
- data/spec/acceptance/realtime/presence_history_spec.rb +1 -0
- data/spec/acceptance/realtime/presence_spec.rb +121 -10
- data/spec/acceptance/realtime/stats_spec.rb +13 -1
- data/spec/acceptance/rest/auth_spec.rb +161 -79
- data/spec/acceptance/rest/base_spec.rb +3 -3
- data/spec/acceptance/rest/channel_spec.rb +142 -15
- data/spec/acceptance/rest/channels_spec.rb +23 -0
- data/spec/acceptance/rest/client_spec.rb +180 -18
- data/spec/acceptance/rest/message_spec.rb +8 -8
- data/spec/acceptance/rest/presence_spec.rb +136 -25
- data/spec/acceptance/rest/stats_spec.rb +60 -4
- data/spec/shared/client_initializer_behaviour.rb +54 -3
- data/spec/unit/auth_spec.rb +7 -6
- data/spec/unit/models/message_spec.rb +1 -9
- data/spec/unit/models/paginated_result_spec.rb +1 -18
- data/spec/unit/models/presence_message_spec.rb +1 -1
- data/spec/unit/models/protocol_message_spec.rb +21 -1
- data/spec/unit/realtime/channel_spec.rb +10 -3
- data/spec/unit/realtime/channels_spec.rb +27 -8
- data/spec/unit/rest/channel_spec.rb +0 -8
- data/spec/unit/rest/client_spec.rb +7 -7
- metadata +13 -7
- data/LICENSE.txt +0 -22
@@ -167,12 +167,12 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
|
|
167
167
|
|
168
168
|
context 'when connection state is :failed' do
|
169
169
|
describe '#close' do
|
170
|
-
it 'will not transition state to :close and raises a
|
170
|
+
it 'will not transition state to :close and raises a InvalidStateChange exception' do
|
171
171
|
connection.on(:connected) { raise 'Connection should not have reached :connected state' }
|
172
172
|
|
173
173
|
connection.once(:failed) do
|
174
174
|
expect(connection.state).to eq(:failed)
|
175
|
-
expect { connection.close }.to raise_error Ably::Exceptions::
|
175
|
+
expect { connection.close }.to raise_error Ably::Exceptions::InvalidStateChange, /Unable to transition from failed => closing/
|
176
176
|
stop_reactor
|
177
177
|
end
|
178
178
|
end
|
@@ -228,6 +228,8 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
|
|
228
228
|
end
|
229
229
|
|
230
230
|
context 'connection opening times out' do
|
231
|
+
let(:client_options) { client_failure_options }
|
232
|
+
|
231
233
|
it 'attempts to reconnect' do
|
232
234
|
started_at = Time.now
|
233
235
|
|
@@ -249,8 +251,6 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
|
|
249
251
|
end
|
250
252
|
|
251
253
|
context 'when retry intervals are stubbed to attempt reconnection quickly' do
|
252
|
-
let(:client_options) { client_failure_options }
|
253
|
-
|
254
254
|
before do
|
255
255
|
# Reconfigure client library retry periods and timeouts so that tests run quickly
|
256
256
|
stub_const 'Ably::Realtime::Connection::ConnectionManager::CONNECT_RETRY_CONFIG',
|
@@ -488,7 +488,8 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
|
|
488
488
|
when_all(*channels.map(&:attach)) do
|
489
489
|
detached_channels = []
|
490
490
|
channels.each do |channel|
|
491
|
-
channel.on(:detached) do
|
491
|
+
channel.on(:detached) do |error|
|
492
|
+
expect(error.message).to match(/Invalid connection key/i)
|
492
493
|
detached_channels << channel
|
493
494
|
next unless detached_channels.count == channel_count
|
494
495
|
expect(detached_channels.count).to eql(channel_count)
|
@@ -537,7 +538,7 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
|
|
537
538
|
|
538
539
|
context 'with custom realtime websocket host option' do
|
539
540
|
let(:expected_host) { 'this.host.does.not.exist' }
|
540
|
-
let(:client_options) { default_options.merge(realtime_host: expected_host, log_level: :none) }
|
541
|
+
let(:client_options) { default_options.merge(realtime_host: expected_host, :environment => :production, log_level: :none) }
|
541
542
|
|
542
543
|
it 'never uses a fallback host' do
|
543
544
|
expect(EventMachine).to receive(:connect).exactly(retry_count_for_all_states).times do |host|
|
@@ -551,6 +552,22 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
|
|
551
552
|
end
|
552
553
|
end
|
553
554
|
|
555
|
+
context 'with custom realtime websocket port option' do
|
556
|
+
let(:custom_port) { 666}
|
557
|
+
let(:client_options) { default_options.merge(tls_port: custom_port, :environment => :production, log_level: :none) }
|
558
|
+
|
559
|
+
it 'never uses a fallback host' do
|
560
|
+
expect(EventMachine).to receive(:connect).exactly(retry_count_for_all_states).times do |host, port|
|
561
|
+
expect(port).to eql(custom_port)
|
562
|
+
raise EventMachine::ConnectionError
|
563
|
+
end
|
564
|
+
|
565
|
+
connection.on(:failed) do
|
566
|
+
stop_reactor
|
567
|
+
end
|
568
|
+
end
|
569
|
+
end
|
570
|
+
|
554
571
|
context 'with non-production environment' do
|
555
572
|
let(:environment) { 'sandbox' }
|
556
573
|
let(:expected_host) { "#{environment}-#{Ably::Realtime::Client::DOMAIN}" }
|
@@ -52,9 +52,12 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
52
52
|
before do
|
53
53
|
# Reduce token expiry buffer to zero so that a token expired? predicate is exact
|
54
54
|
# Normally there is a buffer so that a token expiring soon is considered expired
|
55
|
+
@original_token_expiry_buffer = Ably::Models::TokenDetails::TOKEN_EXPIRY_BUFFER
|
55
56
|
stub_const 'Ably::Models::TokenDetails::TOKEN_EXPIRY_BUFFER', 0
|
56
57
|
end
|
57
58
|
|
59
|
+
let(:original_token_expiry_buffer) { @original_token_expiry_buffer }
|
60
|
+
|
58
61
|
context 'for renewable tokens' do
|
59
62
|
context 'that are valid for the duration of the test' do
|
60
63
|
context 'with valid pre authorised token expiring in the future' do
|
@@ -71,7 +74,7 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
71
74
|
let(:client_options) { default_options.merge(client_id: 'force_token_auth') }
|
72
75
|
|
73
76
|
it 'uses the token created by the implicit authorisation' do
|
74
|
-
expect(client.auth).to receive(:request_token).once.and_call_original
|
77
|
+
expect(client.rest_client.auth).to receive(:request_token).once.and_call_original
|
75
78
|
|
76
79
|
connection.once(:connected) do
|
77
80
|
stop_reactor
|
@@ -84,20 +87,36 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
84
87
|
let(:client_options) { default_options.merge(log_level: :none) }
|
85
88
|
|
86
89
|
before do
|
87
|
-
client.
|
90
|
+
expect(client.rest_client.time.to_f).to be_within(2).of(Time.now.to_i), "Local clock is out of sync with Ably"
|
91
|
+
end
|
92
|
+
|
93
|
+
before do
|
94
|
+
# Ensure tokens issued expire immediately after issue
|
95
|
+
@original_renew_token_buffer = Ably::Auth::TOKEN_DEFAULTS.fetch(:renew_token_buffer)
|
96
|
+
stub_const 'Ably::Auth::TOKEN_DEFAULTS', Ably::Auth::TOKEN_DEFAULTS.merge(renew_token_buffer: 0)
|
97
|
+
|
98
|
+
# Authorise synchronously to ensure token has been issued
|
99
|
+
client.auth.authorise_sync(token_params: { ttl: ttl })
|
88
100
|
end
|
89
101
|
|
102
|
+
let(:original_renew_token_buffer) { @original_renew_token_buffer }
|
103
|
+
|
90
104
|
context 'opening a new connection' do
|
91
105
|
context 'with recently expired token' do
|
92
106
|
let(:ttl) { 2 }
|
93
107
|
|
94
|
-
it 'renews the token on connect' do
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
108
|
+
it 'renews the token on connect without changing connection state' do
|
109
|
+
connection.once(:connecting) do
|
110
|
+
sleep ttl + 0.1
|
111
|
+
expect(client.auth.current_token_details).to be_expired
|
112
|
+
expect(client.rest_client.auth).to receive(:authorise).at_least(:once).and_call_original
|
113
|
+
connection.once(:connected) do
|
114
|
+
expect(client.auth.current_token_details).to_not be_expired
|
115
|
+
stop_reactor
|
116
|
+
end
|
117
|
+
connection.once_state_changed do
|
118
|
+
raise "Invalid state #{connection.state}" unless connection.state == :connected
|
119
|
+
end
|
101
120
|
end
|
102
121
|
end
|
103
122
|
end
|
@@ -106,7 +125,7 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
106
125
|
let(:ttl) { 0.001 }
|
107
126
|
|
108
127
|
it 'renews the token on connect, and only makes one subsequent attempt to obtain a new token' do
|
109
|
-
expect(client.auth).to receive(:authorise).at_least(:twice).and_call_original
|
128
|
+
expect(client.rest_client.auth).to receive(:authorise).at_least(:twice).and_call_original
|
110
129
|
connection.once(:disconnected) do
|
111
130
|
connection.once(:failed) do |error|
|
112
131
|
expect(error.code).to eql(40140) # token expired
|
@@ -149,6 +168,12 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
149
168
|
connection.once(:connected) do
|
150
169
|
started_at = Time.now
|
151
170
|
connection.once(:disconnected) do |error|
|
171
|
+
expect(error.code).to eq(40140) # Token expired
|
172
|
+
|
173
|
+
# Token has expired, so now ensure it is not used again
|
174
|
+
stub_const 'Ably::Models::TokenDetails::TOKEN_EXPIRY_BUFFER', original_token_expiry_buffer
|
175
|
+
stub_const 'Ably::Auth::TOKEN_DEFAULTS', Ably::Auth::TOKEN_DEFAULTS.merge(renew_token_buffer: original_renew_token_buffer)
|
176
|
+
|
152
177
|
connection.once(:connected) do
|
153
178
|
expect(client.auth.current_token_details).to_not be_expired
|
154
179
|
expect(Time.now - started_at >= ttl)
|
@@ -159,6 +184,8 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
159
184
|
end
|
160
185
|
end
|
161
186
|
|
187
|
+
connection.unsafe_once(:failed) { |error| fail error.inspect }
|
188
|
+
|
162
189
|
channel.attach
|
163
190
|
end
|
164
191
|
end
|
@@ -172,8 +199,13 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
172
199
|
|
173
200
|
context 'for non-renewable tokens' do
|
174
201
|
context 'that are expired' do
|
202
|
+
before do
|
203
|
+
stub_const 'Ably::Auth::TOKEN_DEFAULTS', Ably::Auth::TOKEN_DEFAULTS.merge(renew_token_buffer: 0)
|
204
|
+
end
|
205
|
+
|
175
206
|
let!(:expired_token_details) do
|
176
|
-
|
207
|
+
# Request a token synchronously
|
208
|
+
Ably::Realtime::Client.new(default_options).auth.request_token_sync(token_params: { ttl: 0.01 })
|
177
209
|
end
|
178
210
|
|
179
211
|
context 'opening a new connection' do
|
@@ -260,6 +292,20 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
260
292
|
end
|
261
293
|
end
|
262
294
|
|
295
|
+
describe 'connection#id' do
|
296
|
+
it 'is null before connecting' do
|
297
|
+
expect(connection.id).to be_nil
|
298
|
+
stop_reactor
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
describe 'connection#key' do
|
303
|
+
it 'is null before connecting' do
|
304
|
+
expect(connection.key).to be_nil
|
305
|
+
stop_reactor
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
263
309
|
describe 'once connected' do
|
264
310
|
let(:connection2) { Ably::Realtime::Client.new(client_options).connection }
|
265
311
|
|
@@ -326,6 +372,18 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
326
372
|
end
|
327
373
|
end
|
328
374
|
end
|
375
|
+
|
376
|
+
context 'when closing' do
|
377
|
+
it 'raises an exception before the connection is closed' do
|
378
|
+
connection.connect do
|
379
|
+
connection.once(:closing) do
|
380
|
+
expect { connection.connect }.to raise_error Ably::Exceptions::InvalidStateChange
|
381
|
+
stop_reactor
|
382
|
+
end
|
383
|
+
connection.close
|
384
|
+
end
|
385
|
+
end
|
386
|
+
end
|
329
387
|
end
|
330
388
|
|
331
389
|
describe '#serial connection serial' do
|
@@ -339,7 +397,6 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
339
397
|
end
|
340
398
|
|
341
399
|
context 'when a message is sent but the ACK has not yet been received' do
|
342
|
-
|
343
400
|
it 'the sent message msgSerial is 0 but the connection serial remains at -1' do
|
344
401
|
channel.attach do
|
345
402
|
connection.__outgoing_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
|
@@ -732,13 +789,13 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
732
789
|
context 'when a state transition is unsupported' do
|
733
790
|
let(:client_options) { default_options.merge(log_level: :none) } # silence FATAL errors
|
734
791
|
|
735
|
-
it 'emits a
|
792
|
+
it 'emits a InvalidStateChange' do
|
736
793
|
connection.connect do
|
737
794
|
connection.transition_state_machine :initialized
|
738
795
|
end
|
739
796
|
|
740
797
|
connection.on(:error) do |error|
|
741
|
-
expect(error).to be_a(Ably::Exceptions::
|
798
|
+
expect(error).to be_a(Ably::Exceptions::InvalidStateChange)
|
742
799
|
stop_reactor
|
743
800
|
end
|
744
801
|
end
|
@@ -794,16 +851,41 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
794
851
|
end
|
795
852
|
|
796
853
|
context 'when the Internet is up' do
|
854
|
+
let(:client_options) { default_options.merge(tls: false, use_token_auth: true) }
|
855
|
+
|
856
|
+
context 'with a TLS connection' do
|
857
|
+
let(:client_options) { default_options.merge(tls: true) }
|
858
|
+
|
859
|
+
it 'checks the Internet up URL over TLS' do
|
860
|
+
expect(EventMachine::HttpRequest).to receive(:new).with("https:#{Ably::INTERNET_CHECK.fetch(:url)}").and_return(double('request', get: EventMachine::DefaultDeferrable.new))
|
861
|
+
connection.internet_up?
|
862
|
+
stop_reactor
|
863
|
+
end
|
864
|
+
end
|
865
|
+
|
866
|
+
context 'with a non-TLS connection' do
|
867
|
+
let(:client_options) { default_options.merge(tls: false, use_token_auth: true) }
|
868
|
+
|
869
|
+
it 'checks the Internet up URL over TLS' do
|
870
|
+
expect(EventMachine::HttpRequest).to receive(:new).with("http:#{Ably::INTERNET_CHECK.fetch(:url)}").and_return(double('request', get: EventMachine::DefaultDeferrable.new))
|
871
|
+
connection.internet_up?
|
872
|
+
stop_reactor
|
873
|
+
end
|
874
|
+
end
|
875
|
+
|
797
876
|
it 'calls the block with true' do
|
798
877
|
connection.internet_up? do |result|
|
799
878
|
expect(result).to be_truthy
|
800
|
-
stop_reactor
|
879
|
+
EventMachine.add_timer(0.2) { stop_reactor }
|
801
880
|
end
|
802
881
|
end
|
803
882
|
|
804
883
|
it 'calls the success callback of the Deferrable' do
|
805
884
|
connection.internet_up?.callback do
|
806
|
-
stop_reactor
|
885
|
+
EventMachine.add_timer(0.2) { stop_reactor }
|
886
|
+
end
|
887
|
+
connection.internet_up?.errback do |error|
|
888
|
+
raise "Could not perform the Internet up check. Are you connected to the Internet? #{error}"
|
807
889
|
end
|
808
890
|
end
|
809
891
|
end
|
@@ -828,5 +910,74 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
828
910
|
end
|
829
911
|
end
|
830
912
|
end
|
913
|
+
|
914
|
+
describe 'state change side effects' do
|
915
|
+
let(:channel) { client.channels.get(random_str) }
|
916
|
+
let(:client_options) { default_options.merge(:log_level => :error) }
|
917
|
+
|
918
|
+
context 'when connection enters the :disconnected state' do
|
919
|
+
it 'queues messages to be sent and all channels remain attached' do
|
920
|
+
channel.attach do
|
921
|
+
connection.once(:disconnected) do
|
922
|
+
expect(connection.__outgoing_message_queue__).to be_empty
|
923
|
+
channel.publish 'test'
|
924
|
+
|
925
|
+
EventMachine.add_timer(0.02) do
|
926
|
+
expect(connection.__outgoing_message_queue__).to_not be_empty
|
927
|
+
end
|
928
|
+
|
929
|
+
connection.once(:connected) do
|
930
|
+
EventMachine.add_timer(0.02) do
|
931
|
+
expect(connection.__outgoing_message_queue__).to be_empty
|
932
|
+
stop_reactor
|
933
|
+
end
|
934
|
+
end
|
935
|
+
end
|
936
|
+
|
937
|
+
connection.transport.close_connection_after_writing
|
938
|
+
end
|
939
|
+
end
|
940
|
+
end
|
941
|
+
|
942
|
+
context 'when connection enters the :suspended state' do
|
943
|
+
before do
|
944
|
+
# Reconfigure client library retry periods so that client stays in suspended state
|
945
|
+
stub_const 'Ably::Realtime::Connection::ConnectionManager::CONNECT_RETRY_CONFIG',
|
946
|
+
Ably::Realtime::Connection::ConnectionManager::CONNECT_RETRY_CONFIG.merge(
|
947
|
+
disconnected: { retry_every: 0.01, max_time_in_state: 0.05 },
|
948
|
+
suspended: { retry_every: 60, max_time_in_state: 60 }
|
949
|
+
)
|
950
|
+
end
|
951
|
+
|
952
|
+
it 'detaches the channels and prevents publishing of messages on those channels' do
|
953
|
+
channel.attach do
|
954
|
+
channel.once(:detached) do
|
955
|
+
expect { channel.publish 'test' }.to raise_error(Ably::Exceptions::ChannelInactive)
|
956
|
+
stop_reactor
|
957
|
+
end
|
958
|
+
|
959
|
+
# Keep disconnecting the websocket transport after it attempts reconnection
|
960
|
+
connection.transport.close_connection_after_writing
|
961
|
+
connection.on(:connecting) do
|
962
|
+
EventMachine.add_timer(0.03) do
|
963
|
+
connection.transport.close_connection_after_writing
|
964
|
+
end
|
965
|
+
end
|
966
|
+
end
|
967
|
+
end
|
968
|
+
end
|
969
|
+
|
970
|
+
context 'when connection enters the :failed state' do
|
971
|
+
let(:client_options) { default_options.merge(:key => 'will.not:authenticate', log_level: :none) }
|
972
|
+
|
973
|
+
it 'sets all channels to failed and prevents publishing of messages on those channels' do
|
974
|
+
channel.attach
|
975
|
+
channel.once(:failed) do
|
976
|
+
expect { channel.publish 'test' }.to raise_error(Ably::Exceptions::ChannelInactive)
|
977
|
+
stop_reactor
|
978
|
+
end
|
979
|
+
end
|
980
|
+
end
|
981
|
+
end
|
831
982
|
end
|
832
983
|
end
|
@@ -79,8 +79,8 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
|
|
79
79
|
context 'Integer' do
|
80
80
|
let(:data) { 1 }
|
81
81
|
|
82
|
-
it 'is raises an
|
83
|
-
expect { channel.publish 'event', data }.to raise_error(Ably::Exceptions::
|
82
|
+
it 'is raises an UnsupportedDataType 40011 exception' do
|
83
|
+
expect { channel.publish 'event', data }.to raise_error(Ably::Exceptions::UnsupportedDataType)
|
84
84
|
stop_reactor
|
85
85
|
end
|
86
86
|
end
|
@@ -88,8 +88,8 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
|
|
88
88
|
context 'Float' do
|
89
89
|
let(:data) { 1.1 }
|
90
90
|
|
91
|
-
it 'is raises an
|
92
|
-
expect { channel.publish 'event', data }.to raise_error(Ably::Exceptions::
|
91
|
+
it 'is raises an UnsupportedDataType 40011 exception' do
|
92
|
+
expect { channel.publish 'event', data }.to raise_error(Ably::Exceptions::UnsupportedDataType)
|
93
93
|
stop_reactor
|
94
94
|
end
|
95
95
|
end
|
@@ -97,8 +97,8 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
|
|
97
97
|
context 'Boolean' do
|
98
98
|
let(:data) { true }
|
99
99
|
|
100
|
-
it 'is raises an
|
101
|
-
expect { channel.publish 'event', data }.to raise_error(Ably::Exceptions::
|
100
|
+
it 'is raises an UnsupportedDataType 40011 exception' do
|
101
|
+
expect { channel.publish 'event', data }.to raise_error(Ably::Exceptions::UnsupportedDataType)
|
102
102
|
stop_reactor
|
103
103
|
end
|
104
104
|
end
|
@@ -106,8 +106,8 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
|
|
106
106
|
context 'False' do
|
107
107
|
let(:data) { false }
|
108
108
|
|
109
|
-
it 'is raises an
|
110
|
-
expect { channel.publish 'event', data }.to raise_error(Ably::Exceptions::
|
109
|
+
it 'is raises an UnsupportedDataType 40011 exception' do
|
110
|
+
expect { channel.publish 'event', data }.to raise_error(Ably::Exceptions::UnsupportedDataType)
|
111
111
|
stop_reactor
|
112
112
|
end
|
113
113
|
end
|
@@ -132,6 +132,7 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
|
|
132
132
|
let(:client_options) { default_options.merge(client_id: client_id) }
|
133
133
|
|
134
134
|
it 'contains a #client_id attribute' do
|
135
|
+
skip 'Waiting for issue #256 to be resolved'
|
135
136
|
when_all(channel.attach, other_client_channel.attach) do
|
136
137
|
other_client_channel.subscribe('event') do |message|
|
137
138
|
expect(message.client_id).to eql(client_id)
|
@@ -22,6 +22,7 @@ describe Ably::Realtime::Presence, 'history', :event_machine do
|
|
22
22
|
presence_client_one.enter(data: data) do
|
23
23
|
presence_client_one.leave(data: leave_data) do
|
24
24
|
presence_client_one.history do |history_page|
|
25
|
+
expect(history_page).to be_a(Ably::Models::PaginatedResult)
|
25
26
|
expect(history_page.items.count).to eql(2)
|
26
27
|
|
27
28
|
expect(history_page.items[1].action).to eq(:enter)
|
@@ -45,7 +45,62 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
45
45
|
setup_test(method_name, args, options) do
|
46
46
|
channel_client_one.attach do
|
47
47
|
channel_client_one.change_state state.to_sym
|
48
|
-
expect { presence_client_one.public_send(method_name, args) }.to raise_error Ably::Exceptions::
|
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.#{state}/i
|
49
|
+
stop_reactor
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'implicitly attaches the channel' do
|
56
|
+
expect(channel_client_one).to_not be_attached
|
57
|
+
presence_client_one.public_send(method_name, args) do
|
58
|
+
expect(channel_client_one).to be_attached
|
59
|
+
stop_reactor
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'when :queue_messages client option is false' do
|
64
|
+
let(:client_one) { Ably::Realtime::Client.new(default_options.merge(queue_messages: false, client_id: random_str)) }
|
65
|
+
|
66
|
+
context 'and connection state initialized' do
|
67
|
+
it 'raises an exception' do
|
68
|
+
expect { presence_client_one.public_send(method_name, args) }.to raise_error Ably::Exceptions::MessageQueueingDisabled
|
69
|
+
expect(client_one.connection).to be_initialized
|
70
|
+
stop_reactor
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'and connection state connecting' do
|
75
|
+
it 'raises an exception' do
|
76
|
+
client_one.connect
|
77
|
+
EventMachine.next_tick do
|
78
|
+
expect { presence_client_one.public_send(method_name, args) }.to raise_error Ably::Exceptions::MessageQueueingDisabled
|
79
|
+
expect(client_one.connection).to be_connecting
|
80
|
+
stop_reactor
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context 'and connection state disconnected' do
|
86
|
+
let(:client_one) { Ably::Realtime::Client.new(default_options.merge(queue_messages: false, client_id: random_str, :log_level => :error)) }
|
87
|
+
|
88
|
+
it 'raises an exception' do
|
89
|
+
client_one.connection.once(:connected) do
|
90
|
+
client_one.connection.once(:disconnected) do
|
91
|
+
expect { presence_client_one.public_send(method_name, args) }.to raise_error Ably::Exceptions::MessageQueueingDisabled
|
92
|
+
expect(client_one.connection).to be_disconnected
|
93
|
+
stop_reactor
|
94
|
+
end
|
95
|
+
client_one.connection.transition_state_machine :disconnected
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context 'and connection state connected' do
|
101
|
+
it 'publishes the message' do
|
102
|
+
client_one.connection.once(:connected) do
|
103
|
+
presence_client_one.public_send(method_name, args)
|
49
104
|
stop_reactor
|
50
105
|
end
|
51
106
|
end
|
@@ -120,8 +175,8 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
120
175
|
context 'Integer' do
|
121
176
|
let(:data) { 1 }
|
122
177
|
|
123
|
-
it 'raises an
|
124
|
-
expect { presence_action(method_name, data) }.to raise_error(Ably::Exceptions::
|
178
|
+
it 'raises an UnsupportedDataType 40011 exception' do
|
179
|
+
expect { presence_action(method_name, data) }.to raise_error(Ably::Exceptions::UnsupportedDataType)
|
125
180
|
stop_reactor
|
126
181
|
end
|
127
182
|
end
|
@@ -129,8 +184,8 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
129
184
|
context 'Float' do
|
130
185
|
let(:data) { 1.1 }
|
131
186
|
|
132
|
-
it 'raises an
|
133
|
-
expect { presence_action(method_name, data) }.to raise_error(Ably::Exceptions::
|
187
|
+
it 'raises an UnsupportedDataType 40011 exception' do
|
188
|
+
expect { presence_action(method_name, data) }.to raise_error(Ably::Exceptions::UnsupportedDataType)
|
134
189
|
stop_reactor
|
135
190
|
end
|
136
191
|
end
|
@@ -138,8 +193,8 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
138
193
|
context 'Boolean' do
|
139
194
|
let(:data) { true }
|
140
195
|
|
141
|
-
it 'raises an
|
142
|
-
expect { presence_action(method_name, data) }.to raise_error(Ably::Exceptions::
|
196
|
+
it 'raises an UnsupportedDataType 40011 exception' do
|
197
|
+
expect { presence_action(method_name, data) }.to raise_error(Ably::Exceptions::UnsupportedDataType)
|
143
198
|
stop_reactor
|
144
199
|
end
|
145
200
|
end
|
@@ -147,8 +202,8 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
147
202
|
context 'False' do
|
148
203
|
let(:data) { false }
|
149
204
|
|
150
|
-
it 'raises an
|
151
|
-
expect { presence_action(method_name, data) }.to raise_error(Ably::Exceptions::
|
205
|
+
it 'raises an UnsupportedDataType 40011 exception' do
|
206
|
+
expect { presence_action(method_name, data) }.to raise_error(Ably::Exceptions::UnsupportedDataType)
|
152
207
|
stop_reactor
|
153
208
|
end
|
154
209
|
end
|
@@ -161,6 +216,14 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
161
216
|
end
|
162
217
|
end
|
163
218
|
|
219
|
+
it 'allows a block to be passed in that is executed upon success' do
|
220
|
+
setup_test(method_name, args, options) do
|
221
|
+
presence_client_one.public_send(method_name, args) do
|
222
|
+
stop_reactor
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
164
227
|
it 'calls the Deferrable callback on success' do
|
165
228
|
setup_test(method_name, args, options) do
|
166
229
|
presence_client_one.public_send(method_name, args).callback do |presence|
|
@@ -1002,7 +1065,7 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
1002
1065
|
it "raise an exception if the channel is #{state}" do
|
1003
1066
|
channel_client_one.attach do
|
1004
1067
|
channel_client_one.change_state state.to_sym
|
1005
|
-
expect { presence_client_one.get }.to raise_error Ably::Exceptions::
|
1068
|
+
expect { presence_client_one.get }.to raise_error Ably::Exceptions::InvalidStateChange, /Operation is not allowed when channel is in STATE.#{state}/i
|
1006
1069
|
stop_reactor
|
1007
1070
|
end
|
1008
1071
|
end
|
@@ -1218,6 +1281,36 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
1218
1281
|
end
|
1219
1282
|
end
|
1220
1283
|
end
|
1284
|
+
|
1285
|
+
context 'with event name' do
|
1286
|
+
it 'calls the callback for specified presence event' do
|
1287
|
+
when_all(channel_client_one.attach, channel_client_two.attach) do
|
1288
|
+
presence_client_two.subscribe(:leave) do |presence_message|
|
1289
|
+
messages << presence_message
|
1290
|
+
next unless messages.count == 1
|
1291
|
+
|
1292
|
+
expect(messages.map(&:action).map(&:to_sym)).to contain_exactly(:leave)
|
1293
|
+
stop_reactor
|
1294
|
+
end
|
1295
|
+
|
1296
|
+
presence_client_one.enter do
|
1297
|
+
presence_client_one.update do
|
1298
|
+
presence_client_one.leave
|
1299
|
+
end
|
1300
|
+
end
|
1301
|
+
end
|
1302
|
+
end
|
1303
|
+
end
|
1304
|
+
|
1305
|
+
it 'implicitly attaches' do
|
1306
|
+
expect(client_one.connection).to be_initialized
|
1307
|
+
presence_client_one.subscribe { true }
|
1308
|
+
channel_client_one.on(:attached) do
|
1309
|
+
expect(client_one.connection).to be_connected
|
1310
|
+
expect(channel_client_one).to be_attached
|
1311
|
+
stop_reactor
|
1312
|
+
end
|
1313
|
+
end
|
1221
1314
|
end
|
1222
1315
|
|
1223
1316
|
context '#unsubscribe' do
|
@@ -1238,6 +1331,24 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
1238
1331
|
end
|
1239
1332
|
end
|
1240
1333
|
end
|
1334
|
+
|
1335
|
+
context 'with event name' do
|
1336
|
+
it 'removes the callback for specified presence event' do
|
1337
|
+
when_all(channel_client_one.attach, channel_client_two.attach) do
|
1338
|
+
subscribe_callback = proc { raise 'Should not be called' }
|
1339
|
+
presence_client_two.subscribe :leave, &subscribe_callback
|
1340
|
+
presence_client_two.unsubscribe :leave, &subscribe_callback
|
1341
|
+
|
1342
|
+
presence_client_one.enter do
|
1343
|
+
presence_client_one.leave do
|
1344
|
+
EventMachine.add_timer(1) do
|
1345
|
+
stop_reactor
|
1346
|
+
end
|
1347
|
+
end
|
1348
|
+
end
|
1349
|
+
end
|
1350
|
+
end
|
1351
|
+
end
|
1241
1352
|
end
|
1242
1353
|
|
1243
1354
|
context 'REST #get' do
|