ably 0.8.1 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -13
- data/README.md +11 -11
- data/SPEC.md +87 -87
- data/ably.gemspec +1 -1
- data/lib/ably/exceptions.rb +4 -1
- data/lib/ably/models/{paginated_resource.rb → paginated_result.rb} +8 -8
- data/lib/ably/models/presence_message.rb +1 -1
- data/lib/ably/modules/conversions.rb +15 -0
- data/lib/ably/modules/encodeable.rb +2 -2
- data/lib/ably/modules/event_emitter.rb +8 -8
- data/lib/ably/modules/safe_deferrable.rb +15 -3
- data/lib/ably/modules/state_emitter.rb +2 -2
- data/lib/ably/modules/state_machine.rb +1 -1
- data/lib/ably/realtime/channel.rb +2 -4
- data/lib/ably/realtime/channel/channel_manager.rb +1 -1
- data/lib/ably/realtime/client.rb +4 -4
- data/lib/ably/realtime/client/incoming_message_dispatcher.rb +2 -2
- data/lib/ably/realtime/connection.rb +1 -1
- data/lib/ably/realtime/connection/connection_manager.rb +3 -3
- data/lib/ably/realtime/connection/connection_state_machine.rb +1 -1
- data/lib/ably/realtime/connection/websocket_transport.rb +2 -2
- data/lib/ably/realtime/presence.rb +23 -5
- data/lib/ably/realtime/presence/members_map.rb +16 -13
- data/lib/ably/rest/channel.rb +3 -2
- data/lib/ably/rest/client.rb +2 -2
- data/lib/ably/rest/presence.rb +4 -4
- data/lib/ably/util/pub_sub.rb +1 -1
- data/lib/ably/util/safe_deferrable.rb +1 -1
- data/lib/ably/version.rb +1 -1
- data/spec/acceptance/realtime/channel_history_spec.rb +1 -1
- data/spec/acceptance/realtime/channel_spec.rb +5 -15
- data/spec/acceptance/realtime/connection_failures_spec.rb +2 -2
- data/spec/acceptance/realtime/connection_spec.rb +16 -14
- data/spec/acceptance/realtime/message_spec.rb +91 -8
- data/spec/acceptance/realtime/presence_spec.rb +190 -71
- data/spec/acceptance/realtime/stats_spec.rb +2 -2
- data/spec/acceptance/rest/channel_spec.rb +1 -1
- data/spec/acceptance/rest/encoders_spec.rb +1 -1
- data/spec/acceptance/rest/message_spec.rb +73 -1
- data/spec/acceptance/rest/presence_spec.rb +4 -2
- data/spec/unit/models/{paginated_resource_spec.rb → paginated_result_spec.rb} +18 -18
- data/spec/unit/modules/event_emitter_spec.rb +27 -27
- data/spec/unit/modules/state_emitter_spec.rb +1 -1
- data/spec/unit/realtime/channel_spec.rb +2 -2
- data/spec/unit/realtime/connection_spec.rb +3 -3
- data/spec/unit/realtime/presence_spec.rb +2 -2
- metadata +44 -44
data/lib/ably/rest/channel.rb
CHANGED
@@ -37,6 +37,7 @@ module Ably
|
|
37
37
|
# @return [Boolean] true if the message was published, otherwise false
|
38
38
|
def publish(name, data)
|
39
39
|
ensure_utf_8 :name, name
|
40
|
+
ensure_supported_payload data
|
40
41
|
|
41
42
|
payload = {
|
42
43
|
name: name,
|
@@ -60,7 +61,7 @@ module Ably
|
|
60
61
|
# @option options [Symbol] :direction +:forwards+ or +:backwards+, defaults to +:backwards+
|
61
62
|
# @option options [Integer] :limit Maximum number of messages to retrieve up to 1,000, defaults to 100
|
62
63
|
#
|
63
|
-
# @return [Ably::Models::
|
64
|
+
# @return [Ably::Models::PaginatedResult<Ably::Models::Message>] First {Ably::Models::PaginatedResult page} of {Ably::Models::Message} objects accessible with {Ably::Models::PaginatedResult#items #items}.
|
64
65
|
#
|
65
66
|
def history(options = {})
|
66
67
|
url = "#{base_path}/messages"
|
@@ -78,7 +79,7 @@ module Ably
|
|
78
79
|
|
79
80
|
response = client.get(url, options)
|
80
81
|
|
81
|
-
Ably::Models::
|
82
|
+
Ably::Models::PaginatedResult.new(response, url, client, paginated_options) do |message|
|
82
83
|
message.tap do |message|
|
83
84
|
decode_message message
|
84
85
|
end
|
data/lib/ably/rest/client.rb
CHANGED
@@ -150,7 +150,7 @@ module Ably
|
|
150
150
|
# @option options [Integer] :limit Maximum number of messages to retrieve up to 1,000, defaults to 100
|
151
151
|
# @option options [Symbol] :unit `:minute`, `:hour`, `:day` or `:month`. Defaults to `:minute`
|
152
152
|
#
|
153
|
-
# @return [Ably::Models::
|
153
|
+
# @return [Ably::Models::PaginatedResult<Ably::Models::Stats>] An Array of Stats
|
154
154
|
#
|
155
155
|
def stats(options = {})
|
156
156
|
options = {
|
@@ -168,7 +168,7 @@ module Ably
|
|
168
168
|
url = '/stats'
|
169
169
|
response = get(url, options)
|
170
170
|
|
171
|
-
Ably::Models::
|
171
|
+
Ably::Models::PaginatedResult.new(response, url, self, paginated_options)
|
172
172
|
end
|
173
173
|
|
174
174
|
# Retrieve the Ably service time
|
data/lib/ably/rest/presence.rb
CHANGED
@@ -25,7 +25,7 @@ module Ably
|
|
25
25
|
# @param [Hash] options the options for the set of members present
|
26
26
|
# @option options [Integer] :limit Maximum number of members to retrieve up to 1,000, defaults to 100
|
27
27
|
#
|
28
|
-
# @return [Ably::Models::
|
28
|
+
# @return [Ably::Models::PaginatedResult<Ably::Models::PresenceMessage>] First {Ably::Models::PaginatedResult page} of {Ably::Models::PresenceMessage} objects accessible with {Ably::Models::PaginatedResult#items #items}.
|
29
29
|
#
|
30
30
|
def get(options = {})
|
31
31
|
options = options = {
|
@@ -39,7 +39,7 @@ module Ably
|
|
39
39
|
|
40
40
|
response = client.get(base_path, options)
|
41
41
|
|
42
|
-
Ably::Models::
|
42
|
+
Ably::Models::PaginatedResult.new(response, base_path, client, paginated_options) do |presence_message|
|
43
43
|
presence_message.tap do |presence_message|
|
44
44
|
decode_message presence_message
|
45
45
|
end
|
@@ -54,7 +54,7 @@ module Ably
|
|
54
54
|
# @option options [Symbol] :direction +:forwards+ or +:backwards+, defaults to +:backwards+
|
55
55
|
# @option options [Integer] :limit Maximum number of messages to retrieve up to 1,000, defaults to 100
|
56
56
|
#
|
57
|
-
# @return [Ably::Models::
|
57
|
+
# @return [Ably::Models::PaginatedResult<Ably::Models::PresenceMessage>] First {Ably::Models::PaginatedResult page} of {Ably::Models::PresenceMessage} objects accessible with {Ably::Models::PaginatedResult#items #items}.
|
58
58
|
#
|
59
59
|
def history(options = {})
|
60
60
|
url = "#{base_path}/history"
|
@@ -72,7 +72,7 @@ module Ably
|
|
72
72
|
|
73
73
|
response = client.get(url, options)
|
74
74
|
|
75
|
-
Ably::Models::
|
75
|
+
Ably::Models::PaginatedResult.new(response, url, client, paginated_options) do |presence_message|
|
76
76
|
presence_message.tap do |presence_message|
|
77
77
|
decode_message presence_message
|
78
78
|
end
|
data/lib/ably/util/pub_sub.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Ably::Util
|
2
2
|
# SafeDeferrable class provides a Deferrable that is safe to use for for public interfaces
|
3
|
-
# of this client library. Any exceptions raised in the success or failure callbacks
|
3
|
+
# of this client library. Any exceptions raised in the success or failure callbacks are
|
4
4
|
# caught and logged to the provided logger.
|
5
5
|
#
|
6
6
|
# An exception in a callback provided by a developer should not break this client library
|
data/lib/ably/version.rb
CHANGED
@@ -24,7 +24,7 @@ describe Ably::Realtime::Channel, '#history', :event_machine do
|
|
24
24
|
expect(history).to be_a(Ably::Util::SafeDeferrable)
|
25
25
|
history.callback do |page|
|
26
26
|
expect(page.items.count).to eql(1)
|
27
|
-
expect(page).to be_a(Ably::Models::
|
27
|
+
expect(page).to be_a(Ably::Models::PaginatedResult)
|
28
28
|
stop_reactor
|
29
29
|
end
|
30
30
|
end
|
@@ -13,9 +13,9 @@ describe Ably::Realtime::Channel, :event_machine do
|
|
13
13
|
let(:messages) { [] }
|
14
14
|
|
15
15
|
describe 'initialization' do
|
16
|
-
context 'with :
|
16
|
+
context 'with :auto_connect option set to false on connection' do
|
17
17
|
let(:client) do
|
18
|
-
Ably::Realtime::Client.new(default_options.merge(
|
18
|
+
Ably::Realtime::Client.new(default_options.merge(auto_connect: false))
|
19
19
|
end
|
20
20
|
|
21
21
|
it 'remains initialized when accessing a channel' do
|
@@ -32,16 +32,6 @@ describe Ably::Realtime::Channel, :event_machine do
|
|
32
32
|
stop_reactor
|
33
33
|
end
|
34
34
|
end
|
35
|
-
|
36
|
-
it 'opens a connection implicitly when accessing #presence' do
|
37
|
-
client.channel('test').tap do |channel|
|
38
|
-
channel.on(:attached) do
|
39
|
-
expect(client.connection).to be_connected
|
40
|
-
stop_reactor
|
41
|
-
end
|
42
|
-
channel.presence
|
43
|
-
end
|
44
|
-
end
|
45
35
|
end
|
46
36
|
end
|
47
37
|
|
@@ -162,7 +152,7 @@ describe Ably::Realtime::Channel, :event_machine do
|
|
162
152
|
end
|
163
153
|
let(:restricted_channel) { restricted_client.channel("cannot_subscribe") }
|
164
154
|
|
165
|
-
it '
|
155
|
+
it 'emits failed event' do
|
166
156
|
restricted_channel.attach
|
167
157
|
restricted_channel.on(:failed) do |error|
|
168
158
|
expect(restricted_channel.state).to eq(:failed)
|
@@ -179,7 +169,7 @@ describe Ably::Realtime::Channel, :event_machine do
|
|
179
169
|
end
|
180
170
|
end
|
181
171
|
|
182
|
-
it '
|
172
|
+
it 'emits an error event' do
|
183
173
|
restricted_channel.attach
|
184
174
|
restricted_channel.on(:error) do |error|
|
185
175
|
expect(restricted_channel.state).to eq(:failed)
|
@@ -458,7 +448,7 @@ describe Ably::Realtime::Channel, :event_machine do
|
|
458
448
|
end
|
459
449
|
end
|
460
450
|
|
461
|
-
it '
|
451
|
+
it 'emits an error event on the channel' do
|
462
452
|
channel.attach do
|
463
453
|
channel.on(:error) do |error|
|
464
454
|
expect(error).to eql(connection_error)
|
@@ -319,7 +319,7 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
|
|
319
319
|
disconnected: { retry_every: retry_every, max_time_in_state: 60 })
|
320
320
|
end
|
321
321
|
|
322
|
-
it "retries every CONNECT_RETRY_CONFIG[:disconnected][:retry_every] seconds" do
|
322
|
+
it "retries every #{Ably::Realtime::Connection::ConnectionManager::CONNECT_RETRY_CONFIG[:disconnected][:retry_every]} seconds" do
|
323
323
|
fail_if_suspended_or_failed
|
324
324
|
|
325
325
|
stubbed_first_attempt = false
|
@@ -415,7 +415,7 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
|
|
415
415
|
end
|
416
416
|
end
|
417
417
|
|
418
|
-
it '
|
418
|
+
it 'executes the resume callback', api_private: true do
|
419
419
|
channel.attach do
|
420
420
|
connection.transport.close_connection_after_writing
|
421
421
|
connection.on_resume do
|
@@ -27,9 +27,9 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
-
context 'with :
|
30
|
+
context 'with :auto_connect option set to false' do
|
31
31
|
let(:client) do
|
32
|
-
Ably::Realtime::Client.new(default_options.merge(
|
32
|
+
Ably::Realtime::Client.new(default_options.merge(auto_connect: false))
|
33
33
|
end
|
34
34
|
|
35
35
|
it 'does not connect automatically' do
|
@@ -201,10 +201,10 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
201
201
|
|
202
202
|
context 'initialization state changes' do
|
203
203
|
let(:phases) { [:connecting, :connected] }
|
204
|
-
let(:
|
204
|
+
let(:events_emitted) { [] }
|
205
205
|
let(:test_expectation) do
|
206
206
|
Proc.new do
|
207
|
-
expect(
|
207
|
+
expect(events_emitted).to eq(phases)
|
208
208
|
stop_reactor
|
209
209
|
end
|
210
210
|
end
|
@@ -212,20 +212,20 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
212
212
|
def expect_ordered_phases
|
213
213
|
phases.each do |phase|
|
214
214
|
connection.on(phase) do
|
215
|
-
|
216
|
-
test_expectation.call if
|
215
|
+
events_emitted << phase
|
216
|
+
test_expectation.call if events_emitted.length == phases.length
|
217
217
|
end
|
218
218
|
end
|
219
219
|
end
|
220
220
|
|
221
221
|
context 'with implicit #connect' do
|
222
|
-
it 'are
|
222
|
+
it 'are emitted in order' do
|
223
223
|
expect_ordered_phases
|
224
224
|
end
|
225
225
|
end
|
226
226
|
|
227
227
|
context 'with explicit #connect' do
|
228
|
-
it 'are
|
228
|
+
it 'are emitted in order' do
|
229
229
|
expect_ordered_phases
|
230
230
|
connection.connect
|
231
231
|
end
|
@@ -542,10 +542,10 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
542
542
|
let(:states) { Hash.new }
|
543
543
|
let(:client_options) { default_options.merge(log_level: :none) }
|
544
544
|
|
545
|
-
it 'is composed of connection
|
545
|
+
it 'is composed of connection key and serial that is kept up to date with each message ACK received' do
|
546
546
|
connection.on(:connected) do
|
547
547
|
expected_serial = -1
|
548
|
-
expect(connection.
|
548
|
+
expect(connection.key).to_not be_nil
|
549
549
|
expect(connection.serial).to eql(expected_serial)
|
550
550
|
|
551
551
|
client.channel('test').attach do |channel|
|
@@ -556,6 +556,8 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
556
556
|
channel.publish('event', 'data') do
|
557
557
|
expected_serial += 1 # attach message received
|
558
558
|
expect(connection.serial).to eql(expected_serial)
|
559
|
+
|
560
|
+
expect(connection.recovery_key).to eql("#{connection.key}:#{connection.serial}")
|
559
561
|
stop_reactor
|
560
562
|
end
|
561
563
|
end
|
@@ -621,7 +623,7 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
621
623
|
end
|
622
624
|
end
|
623
625
|
|
624
|
-
it 'does not
|
626
|
+
it 'does not call a resume callback', api_private: true do
|
625
627
|
connection.once(:connected) do
|
626
628
|
connection.transition_state_machine! :failed
|
627
629
|
end
|
@@ -629,7 +631,7 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
629
631
|
connection.once(:failed) do
|
630
632
|
recover_client = Ably::Realtime::Client.new(default_options.merge(recover: client.connection.recovery_key))
|
631
633
|
recover_client.connection.on_resume do
|
632
|
-
raise 'Should not
|
634
|
+
raise 'Should not call the resume callback'
|
633
635
|
end
|
634
636
|
recover_client.connection.on(:connected) do
|
635
637
|
EventMachine.add_timer(0.5) { stop_reactor }
|
@@ -676,7 +678,7 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
676
678
|
context 'with invalid formatted value sent to server' do
|
677
679
|
let(:client_options) { default_options.merge(recover: 'not-a-valid-connection-key:1', log_level: :none) }
|
678
680
|
|
679
|
-
it '
|
681
|
+
it 'emits a fatal error on the connection object, sets the #error_reason and disconnects' do
|
680
682
|
connection.once(:error) do |error|
|
681
683
|
expect(connection.state).to eq(:failed)
|
682
684
|
expect(error.message).to match(/Invalid connection key/)
|
@@ -691,7 +693,7 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
691
693
|
context 'with expired (missing) value sent to server' do
|
692
694
|
let(:client_options) { default_options.merge(recover: '0123456789abcdef:0', log_level: :fatal) }
|
693
695
|
|
694
|
-
it '
|
696
|
+
it 'emits an error on the connection object, sets the #error_reason, yet will connect anyway' do
|
695
697
|
connection.once(:error) do |error|
|
696
698
|
expect(connection.state).to eq(:connected)
|
697
699
|
expect(error.message).to match(/Invalid connection key/i)
|
@@ -32,6 +32,87 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
+
context 'with supported data payload content type' do
|
36
|
+
def publish_and_check_data(data)
|
37
|
+
channel.attach
|
38
|
+
channel.publish 'event', data
|
39
|
+
channel.subscribe do |message|
|
40
|
+
expect(message.data).to eql(data)
|
41
|
+
stop_reactor
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'JSON Object (Hash)' do
|
46
|
+
let(:data) { { 'Hash' => 'true' } }
|
47
|
+
|
48
|
+
it 'is encoded and decoded to the same hash' do
|
49
|
+
publish_and_check_data data
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'JSON Array' do
|
54
|
+
let(:data) { [ nil, true, false, 55, 'string', { 'Hash' => true }, ['array'] ] }
|
55
|
+
|
56
|
+
it 'is encoded and decoded to the same Array' do
|
57
|
+
publish_and_check_data data
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'String' do
|
62
|
+
let(:data) { random_str }
|
63
|
+
|
64
|
+
it 'is encoded and decoded to the same Array' do
|
65
|
+
publish_and_check_data data
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context 'Binary' do
|
70
|
+
let(:data) { Base64.encode64(random_str) }
|
71
|
+
|
72
|
+
it 'is encoded and decoded to the same Array' do
|
73
|
+
publish_and_check_data data
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context 'with unsupported data payload content type' do
|
79
|
+
context 'Integer' do
|
80
|
+
let(:data) { 1 }
|
81
|
+
|
82
|
+
it 'is raises an UnsupportedDataTypeError 40011 exception' do
|
83
|
+
expect { channel.publish 'event', data }.to raise_error(Ably::Exceptions::UnsupportedDataTypeError)
|
84
|
+
stop_reactor
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
context 'Float' do
|
89
|
+
let(:data) { 1.1 }
|
90
|
+
|
91
|
+
it 'is raises an UnsupportedDataTypeError 40011 exception' do
|
92
|
+
expect { channel.publish 'event', data }.to raise_error(Ably::Exceptions::UnsupportedDataTypeError)
|
93
|
+
stop_reactor
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context 'Boolean' do
|
98
|
+
let(:data) { true }
|
99
|
+
|
100
|
+
it 'is raises an UnsupportedDataTypeError 40011 exception' do
|
101
|
+
expect { channel.publish 'event', data }.to raise_error(Ably::Exceptions::UnsupportedDataTypeError)
|
102
|
+
stop_reactor
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
context 'False' do
|
107
|
+
let(:data) { false }
|
108
|
+
|
109
|
+
it 'is raises an UnsupportedDataTypeError 40011 exception' do
|
110
|
+
expect { channel.publish 'event', data }.to raise_error(Ably::Exceptions::UnsupportedDataTypeError)
|
111
|
+
stop_reactor
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
35
116
|
context 'with ASCII_8BIT message name' do
|
36
117
|
let(:message_name) { random_str.encode(Encoding::ASCII_8BIT) }
|
37
118
|
it 'is converted into UTF_8' do
|
@@ -410,7 +491,7 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
|
|
410
491
|
end
|
411
492
|
end
|
412
493
|
|
413
|
-
it '
|
494
|
+
it 'emits a Cipher error on the channel' do
|
414
495
|
unencrypted_channel_client2.attach do
|
415
496
|
encrypted_channel_client1.publish 'example', payload
|
416
497
|
unencrypted_channel_client2.on(:error) do |error|
|
@@ -441,7 +522,7 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
|
|
441
522
|
end
|
442
523
|
end
|
443
524
|
|
444
|
-
it '
|
525
|
+
it 'emits a Cipher error on the channel' do
|
445
526
|
encrypted_channel_client2.attach do
|
446
527
|
encrypted_channel_client1.publish 'example', payload
|
447
528
|
encrypted_channel_client2.on(:error) do |error|
|
@@ -464,15 +545,17 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
|
|
464
545
|
let(:payload) { MessagePack.pack({ 'key' => random_str }) }
|
465
546
|
|
466
547
|
it 'delivers the message but still encrypted with the cipher details in the #encoding attribute' do
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
548
|
+
encrypted_channel_client2.attach do
|
549
|
+
encrypted_channel_client1.publish 'example', payload
|
550
|
+
encrypted_channel_client2.subscribe do |message|
|
551
|
+
expect(message.data).to_not eql(payload)
|
552
|
+
expect(message.encoding).to match(/^cipher\+aes-256-cbc/)
|
553
|
+
stop_reactor
|
554
|
+
end
|
472
555
|
end
|
473
556
|
end
|
474
557
|
|
475
|
-
it '
|
558
|
+
it 'emits a Cipher error on the channel' do
|
476
559
|
encrypted_channel_client2.attach do
|
477
560
|
encrypted_channel_client1.publish 'example', payload
|
478
561
|
encrypted_channel_client2.on(:error) do |error|
|
@@ -53,6 +53,107 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
56
|
+
context 'with supported data payload content type' do
|
57
|
+
def register_presence_and_check_data(method_name, data)
|
58
|
+
if method_name.to_s.match(/_client/)
|
59
|
+
presence_client_one.public_send(method_name, 'client_id', data: data)
|
60
|
+
else
|
61
|
+
presence_client_one.public_send(method_name, data: data)
|
62
|
+
end
|
63
|
+
|
64
|
+
presence_client_one.subscribe do |presence_message|
|
65
|
+
expect(presence_message.data).to eql(data)
|
66
|
+
stop_reactor
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'JSON Object (Hash)' do
|
71
|
+
let(:data) { { 'Hash' => 'true' } }
|
72
|
+
|
73
|
+
it 'is encoded and decoded to the same hash' do
|
74
|
+
setup_test(method_name, args, options) do
|
75
|
+
register_presence_and_check_data method_name, data
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context 'JSON Array' do
|
81
|
+
let(:data) { [ nil, true, false, 55, 'string', { 'Hash' => true }, ['array'] ] }
|
82
|
+
|
83
|
+
it 'is encoded and decoded to the same Array' do
|
84
|
+
setup_test(method_name, args, options) do
|
85
|
+
register_presence_and_check_data method_name, data
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context 'String' do
|
91
|
+
let(:data) { random_str }
|
92
|
+
|
93
|
+
it 'is encoded and decoded to the same Array' do
|
94
|
+
setup_test(method_name, args, options) do
|
95
|
+
register_presence_and_check_data method_name, data
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context 'Binary' do
|
101
|
+
let(:data) { Base64.encode64(random_str) }
|
102
|
+
|
103
|
+
it 'is encoded and decoded to the same Array' do
|
104
|
+
setup_test(method_name, args, options) do
|
105
|
+
register_presence_and_check_data method_name, data
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
context 'with unsupported data payload content type' do
|
112
|
+
def presence_action(method_name, data)
|
113
|
+
if method_name.to_s.match(/_client/)
|
114
|
+
presence_client_one.public_send(method_name, 'client_id', data: data)
|
115
|
+
else
|
116
|
+
presence_client_one.public_send(method_name, data: data)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
context 'Integer' do
|
121
|
+
let(:data) { 1 }
|
122
|
+
|
123
|
+
it 'raises an UnsupportedDataTypeError 40011 exception' do
|
124
|
+
expect { presence_action(method_name, data) }.to raise_error(Ably::Exceptions::UnsupportedDataTypeError)
|
125
|
+
stop_reactor
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
context 'Float' do
|
130
|
+
let(:data) { 1.1 }
|
131
|
+
|
132
|
+
it 'raises an UnsupportedDataTypeError 40011 exception' do
|
133
|
+
expect { presence_action(method_name, data) }.to raise_error(Ably::Exceptions::UnsupportedDataTypeError)
|
134
|
+
stop_reactor
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
context 'Boolean' do
|
139
|
+
let(:data) { true }
|
140
|
+
|
141
|
+
it 'raises an UnsupportedDataTypeError 40011 exception' do
|
142
|
+
expect { presence_action(method_name, data) }.to raise_error(Ably::Exceptions::UnsupportedDataTypeError)
|
143
|
+
stop_reactor
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
context 'False' do
|
148
|
+
let(:data) { false }
|
149
|
+
|
150
|
+
it 'raises an UnsupportedDataTypeError 40011 exception' do
|
151
|
+
expect { presence_action(method_name, data) }.to raise_error(Ably::Exceptions::UnsupportedDataTypeError)
|
152
|
+
stop_reactor
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
56
157
|
it 'returns a SafeDeferrable that catches exceptions in callbacks and logs them' do
|
57
158
|
setup_test(method_name, args, options) do
|
58
159
|
expect(presence_client_one.public_send(method_name, args)).to be_a(Ably::Util::SafeDeferrable)
|
@@ -153,13 +254,15 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
153
254
|
stop_reactor
|
154
255
|
end
|
155
256
|
|
156
|
-
it 'will
|
257
|
+
it 'will emit an :in_sync event when synchronisation is complete' do
|
157
258
|
presence_client_one.enter
|
158
259
|
presence_client_two.enter
|
159
260
|
|
160
261
|
presence_anonymous_client.members.once(:in_sync) do
|
161
262
|
stop_reactor
|
162
263
|
end
|
264
|
+
|
265
|
+
channel_anonymous_client.attach
|
163
266
|
end
|
164
267
|
|
165
268
|
context 'before server sync complete' do
|
@@ -180,6 +283,8 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
180
283
|
expect(member_ids.uniq.count).to eql(2)
|
181
284
|
stop_reactor
|
182
285
|
end
|
286
|
+
|
287
|
+
channel_anonymous_client.attach
|
183
288
|
end
|
184
289
|
end
|
185
290
|
end
|
@@ -200,7 +305,7 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
200
305
|
presence_client_one.enter do
|
201
306
|
channel_anonymous_client.attach do
|
202
307
|
expect(channel_anonymous_client.presence).to_not be_sync_complete
|
203
|
-
channel_anonymous_client.presence.get do
|
308
|
+
channel_anonymous_client.presence.get(wait_for_sync: true) do
|
204
309
|
expect(channel_anonymous_client.presence).to be_sync_complete
|
205
310
|
stop_reactor
|
206
311
|
end
|
@@ -319,7 +424,7 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
319
424
|
end
|
320
425
|
end
|
321
426
|
|
322
|
-
it 'does not emit :present after the :leave event has been emitted, and that member is not included in the list of members via #get' do
|
427
|
+
it 'does not emit :present after the :leave event has been emitted, and that member is not included in the list of members via #get with :wait_for_sync' do
|
323
428
|
left_client = 10
|
324
429
|
left_client_id = "client:#{left_client}"
|
325
430
|
|
@@ -341,7 +446,7 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
341
446
|
member_left_emitted = true
|
342
447
|
end
|
343
448
|
|
344
|
-
presence_anonymous_client.get do |members|
|
449
|
+
presence_anonymous_client.get(wait_for_sync: true) do |members|
|
345
450
|
expect(members.count).to eql(enter_expected_count - 1)
|
346
451
|
expect(member_left_emitted).to eql(true)
|
347
452
|
expect(members.map(&:client_id)).to_not include(left_client_id)
|
@@ -365,43 +470,40 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
365
470
|
end
|
366
471
|
|
367
472
|
context '#get' do
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
473
|
+
context 'with :wait_for_sync option set to true' do
|
474
|
+
it 'waits until sync is complete', event_machine: 15 do
|
475
|
+
enter_expected_count.times do |index|
|
476
|
+
presence_client_one.enter_client("client:#{index}") do |message|
|
477
|
+
entered << message
|
478
|
+
next unless entered.count == enter_expected_count
|
479
|
+
|
480
|
+
presence_anonymous_client.get(wait_for_sync: true) do |members|
|
481
|
+
expect(members.map(&:client_id).uniq.count).to eql(enter_expected_count)
|
482
|
+
expect(members.count).to eql(enter_expected_count)
|
483
|
+
stop_reactor
|
484
|
+
end
|
378
485
|
end
|
379
486
|
end
|
380
487
|
end
|
381
488
|
end
|
382
|
-
end
|
383
|
-
end
|
384
|
-
end
|
385
|
-
end
|
386
489
|
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
stop_reactor
|
490
|
+
context 'by default' do
|
491
|
+
it 'it does not wait for sync', event_machine: 15 do
|
492
|
+
enter_expected_count.times do |index|
|
493
|
+
presence_client_one.enter_client("client:#{index}") do |message|
|
494
|
+
entered << message
|
495
|
+
next unless entered.count == enter_expected_count
|
496
|
+
|
497
|
+
channel_anonymous_client.attach do
|
498
|
+
presence_anonymous_client.get do |members|
|
499
|
+
expect(presence_anonymous_client.members).to_not be_in_sync
|
500
|
+
expect(members.count).to eql(0)
|
501
|
+
stop_reactor
|
502
|
+
end
|
503
|
+
end
|
504
|
+
end
|
505
|
+
end
|
506
|
+
end
|
405
507
|
end
|
406
508
|
end
|
407
509
|
end
|
@@ -571,7 +673,7 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
571
673
|
end
|
572
674
|
|
573
675
|
context 'when set to nil' do
|
574
|
-
it 'emits
|
676
|
+
it 'emits a nil value for the data attribute when leaving' do
|
575
677
|
presence_client_one.enter data: enter_data do
|
576
678
|
presence_client_one.leave data: nil
|
577
679
|
end
|
@@ -595,6 +697,22 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
595
697
|
end
|
596
698
|
end
|
597
699
|
end
|
700
|
+
|
701
|
+
context 'and sync is complete' do
|
702
|
+
it 'does not cache members that have left' do
|
703
|
+
presence_client_one.enter data: enter_data do
|
704
|
+
expect(presence_client_one.members).to be_in_sync
|
705
|
+
expect(presence_client_one.members.send(:members).count).to eql(1)
|
706
|
+
presence_client_one.leave data: data
|
707
|
+
end
|
708
|
+
|
709
|
+
presence_client_one.subscribe(:leave) do |presence_message|
|
710
|
+
expect(presence_message.data).to eql(data)
|
711
|
+
expect(presence_client_one.members.send(:members).count).to eql(0)
|
712
|
+
stop_reactor
|
713
|
+
end
|
714
|
+
end
|
715
|
+
end
|
598
716
|
end
|
599
717
|
|
600
718
|
it 'raises an exception if not entered' do
|
@@ -911,43 +1029,45 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
911
1029
|
)
|
912
1030
|
end
|
913
1031
|
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
|
1032
|
+
context 'when :wait_for_sync is true' do
|
1033
|
+
it 'fails if the connection fails' do
|
1034
|
+
when_all(*connect_members_deferrables) do
|
1035
|
+
channel_client_two.attach do
|
1036
|
+
client_two.connection.transport.__incoming_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
|
1037
|
+
if protocol_message.action == :sync
|
1038
|
+
sync_pages_received << protocol_message
|
1039
|
+
force_connection_failure client_two if sync_pages_received.count == 1
|
1040
|
+
end
|
921
1041
|
end
|
922
1042
|
end
|
923
|
-
end
|
924
1043
|
|
925
|
-
|
926
|
-
|
927
|
-
|
928
|
-
|
1044
|
+
presence_client_two.get(wait_for_sync: true).tap do |deferrable|
|
1045
|
+
deferrable.callback { raise 'Get should not succeed' }
|
1046
|
+
deferrable.errback do |error|
|
1047
|
+
stop_reactor
|
1048
|
+
end
|
929
1049
|
end
|
930
1050
|
end
|
931
1051
|
end
|
932
|
-
end
|
933
1052
|
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
|
1053
|
+
it 'fails if the channel is detached' do
|
1054
|
+
when_all(*connect_members_deferrables) do
|
1055
|
+
channel_client_two.attach do
|
1056
|
+
client_two.connection.transport.__incoming_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
|
1057
|
+
if protocol_message.action == :sync
|
1058
|
+
# prevent any more SYNC messages coming through
|
1059
|
+
client_two.connection.transport.__incoming_protocol_msgbus__.unsubscribe
|
1060
|
+
channel_client_two.change_state :detaching
|
1061
|
+
channel_client_two.change_state :detached
|
1062
|
+
end
|
943
1063
|
end
|
944
1064
|
end
|
945
|
-
end
|
946
1065
|
|
947
|
-
|
948
|
-
|
949
|
-
|
950
|
-
|
1066
|
+
presence_client_two.get(wait_for_sync: true).tap do |deferrable|
|
1067
|
+
deferrable.callback { raise 'Get should not succeed' }
|
1068
|
+
deferrable.errback do |error|
|
1069
|
+
stop_reactor
|
1070
|
+
end
|
951
1071
|
end
|
952
1072
|
end
|
953
1073
|
end
|
@@ -1059,12 +1179,12 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
1059
1179
|
end
|
1060
1180
|
|
1061
1181
|
wait_until(proc { clients_entered[:client_one] + clients_entered[:client_two] == total_members * 2 }) do
|
1062
|
-
presence_anonymous_client.get do |anonymous_members|
|
1182
|
+
presence_anonymous_client.get(wait_for_sync: true) do |anonymous_members|
|
1063
1183
|
expect(anonymous_members.count).to eq(total_members)
|
1064
1184
|
expect(anonymous_members.map(&:client_id).uniq.count).to eq(total_members)
|
1065
1185
|
|
1066
|
-
presence_client_one.get do |client_one_members|
|
1067
|
-
presence_client_two.get do |client_two_members|
|
1186
|
+
presence_client_one.get(wait_for_sync: true) do |client_one_members|
|
1187
|
+
presence_client_two.get(wait_for_sync: true) do |client_two_members|
|
1068
1188
|
expect(client_one_members.count).to eq(total_members)
|
1069
1189
|
expect(client_one_members.count).to eq(client_two_members.count)
|
1070
1190
|
stop_reactor
|
@@ -1319,7 +1439,7 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
1319
1439
|
|
1320
1440
|
specify 'expect :left event with client data from enter event' do
|
1321
1441
|
presence_client_one.subscribe(:leave) do |message|
|
1322
|
-
presence_client_one.get do |members|
|
1442
|
+
presence_client_one.get(wait_for_sync: true) do |members|
|
1323
1443
|
expect(members.count).to eq(0)
|
1324
1444
|
expect(message.data).to eql(data_payload)
|
1325
1445
|
stop_reactor
|
@@ -1335,8 +1455,7 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
1335
1455
|
let(:members_count) { 400 }
|
1336
1456
|
let(:sync_pages_received) { [] }
|
1337
1457
|
|
1338
|
-
|
1339
|
-
skip 'resumes the SYNC operation', em_timeout: 15 do
|
1458
|
+
it 'resumes the SYNC operation', em_timeout: 15 do
|
1340
1459
|
when_all(*members_count.times.map do |index|
|
1341
1460
|
presence_client_one.enter_client("client:#{index}")
|
1342
1461
|
end) do
|
@@ -1349,7 +1468,7 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
1349
1468
|
end
|
1350
1469
|
end
|
1351
1470
|
|
1352
|
-
presence_client_two.get do |members|
|
1471
|
+
presence_client_two.get(wait_for_sync: true) do |members|
|
1353
1472
|
expect(members.count).to eql(members_count)
|
1354
1473
|
expect(members.map(&:member_key).uniq.count).to eql(members_count)
|
1355
1474
|
stop_reactor
|