lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb in ably-rest-0.8.1 vs lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb in ably-rest-0.8.2
- old
+ new
@@ -51,10 +51,111 @@
end
end
end
end
+ context 'with supported data payload content type' do
+ def register_presence_and_check_data(method_name, data)
+ if method_name.to_s.match(/_client/)
+ presence_client_one.public_send(method_name, 'client_id', data: data)
+ else
+ presence_client_one.public_send(method_name, data: data)
+ end
+
+ presence_client_one.subscribe do |presence_message|
+ expect(presence_message.data).to eql(data)
+ stop_reactor
+ end
+ end
+
+ context 'JSON Object (Hash)' do
+ let(:data) { { 'Hash' => 'true' } }
+
+ it 'is encoded and decoded to the same hash' do
+ setup_test(method_name, args, options) do
+ register_presence_and_check_data method_name, data
+ end
+ end
+ end
+
+ context 'JSON Array' do
+ let(:data) { [ nil, true, false, 55, 'string', { 'Hash' => true }, ['array'] ] }
+
+ it 'is encoded and decoded to the same Array' do
+ setup_test(method_name, args, options) do
+ register_presence_and_check_data method_name, data
+ end
+ end
+ end
+
+ context 'String' do
+ let(:data) { random_str }
+
+ it 'is encoded and decoded to the same Array' do
+ setup_test(method_name, args, options) do
+ register_presence_and_check_data method_name, data
+ end
+ end
+ end
+
+ context 'Binary' do
+ let(:data) { Base64.encode64(random_str) }
+
+ it 'is encoded and decoded to the same Array' do
+ setup_test(method_name, args, options) do
+ register_presence_and_check_data method_name, data
+ end
+ end
+ end
+ end
+
+ context 'with unsupported data payload content type' do
+ def presence_action(method_name, data)
+ if method_name.to_s.match(/_client/)
+ presence_client_one.public_send(method_name, 'client_id', data: data)
+ else
+ presence_client_one.public_send(method_name, data: data)
+ end
+ end
+
+ context 'Integer' do
+ let(:data) { 1 }
+
+ it 'raises an UnsupportedDataTypeError 40011 exception' do
+ expect { presence_action(method_name, data) }.to raise_error(Ably::Exceptions::UnsupportedDataTypeError)
+ stop_reactor
+ end
+ end
+
+ context 'Float' do
+ let(:data) { 1.1 }
+
+ it 'raises an UnsupportedDataTypeError 40011 exception' do
+ expect { presence_action(method_name, data) }.to raise_error(Ably::Exceptions::UnsupportedDataTypeError)
+ stop_reactor
+ end
+ end
+
+ context 'Boolean' do
+ let(:data) { true }
+
+ it 'raises an UnsupportedDataTypeError 40011 exception' do
+ expect { presence_action(method_name, data) }.to raise_error(Ably::Exceptions::UnsupportedDataTypeError)
+ stop_reactor
+ end
+ end
+
+ context 'False' do
+ let(:data) { false }
+
+ it 'raises an UnsupportedDataTypeError 40011 exception' do
+ expect { presence_action(method_name, data) }.to raise_error(Ably::Exceptions::UnsupportedDataTypeError)
+ stop_reactor
+ end
+ end
+ end
+
it 'returns a SafeDeferrable that catches exceptions in callbacks and logs them' do
setup_test(method_name, args, options) do
expect(presence_client_one.public_send(method_name, args)).to be_a(Ably::Util::SafeDeferrable)
stop_reactor
end
@@ -151,17 +252,19 @@
it 'is not synchronised when initially created' do
expect(presence_anonymous_client.members).to_not be_sync_complete
stop_reactor
end
- it 'will trigger an :in_sync event when synchronisation is complete' do
+ it 'will emit an :in_sync event when synchronisation is complete' do
presence_client_one.enter
presence_client_two.enter
presence_anonymous_client.members.once(:in_sync) do
stop_reactor
end
+
+ channel_anonymous_client.attach
end
context 'before server sync complete' do
it 'behaves like an Enumerable allowing direct access to current members' do
expect(presence_anonymous_client.members.count).to eql(0)
@@ -178,10 +281,12 @@
member_ids = presence_anonymous_client.members.map(&:member_key)
expect(member_ids.count).to eql(2)
expect(member_ids.uniq.count).to eql(2)
stop_reactor
end
+
+ channel_anonymous_client.attach
end
end
end
end
@@ -198,11 +303,11 @@
context 'when attaching to a channel with members present' do
it 'is false and the presence channel will subsequently be synced' do
presence_client_one.enter do
channel_anonymous_client.attach do
expect(channel_anonymous_client.presence).to_not be_sync_complete
- channel_anonymous_client.presence.get do
+ channel_anonymous_client.presence.get(wait_for_sync: true) do
expect(channel_anonymous_client.presence).to be_sync_complete
stop_reactor
end
end
end
@@ -317,11 +422,11 @@
end
end
end
end
- 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
+ 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
left_client = 10
left_client_id = "client:#{left_client}"
setup_members_on(presence_client_one) do
member_left_emitted = false
@@ -339,11 +444,11 @@
end
expect(leave_message.client_id).to eql(left_client_id)
member_left_emitted = true
end
- presence_anonymous_client.get do |members|
+ presence_anonymous_client.get(wait_for_sync: true) do |members|
expect(members.count).to eql(enter_expected_count - 1)
expect(member_left_emitted).to eql(true)
expect(members.map(&:client_id)).to_not include(left_client_id)
stop_reactor
end
@@ -363,47 +468,44 @@
end
end
end
context '#get' do
- it 'waits until sync is complete', event_machine: 15 do
- enter_expected_count.times do |index|
- presence_client_one.enter_client("client:#{index}") do |message|
- entered << message
- next unless entered.count == enter_expected_count
+ context 'with :wait_for_sync option set to true' do
+ it 'waits until sync is complete', event_machine: 15 do
+ enter_expected_count.times do |index|
+ presence_client_one.enter_client("client:#{index}") do |message|
+ entered << message
+ next unless entered.count == enter_expected_count
- presence_anonymous_client.get do |members|
- expect(members.map(&:client_id).uniq.count).to eql(enter_expected_count)
- expect(members.count).to eql(enter_expected_count)
- stop_reactor
+ presence_anonymous_client.get(wait_for_sync: true) do |members|
+ expect(members.map(&:client_id).uniq.count).to eql(enter_expected_count)
+ expect(members.count).to eql(enter_expected_count)
+ stop_reactor
+ end
end
end
end
end
- end
- end
- end
- end
- context 'automatic attachment of channel on access to presence object' do
- it 'is implicit if presence state is initialized' do
- channel_client_one.presence
- channel_client_one.on(:attached) do
- expect(channel_client_one.state).to eq(:attached)
- stop_reactor
- end
- end
+ context 'by default' do
+ it 'it does not wait for sync', event_machine: 15 do
+ enter_expected_count.times do |index|
+ presence_client_one.enter_client("client:#{index}") do |message|
+ entered << message
+ next unless entered.count == enter_expected_count
- it 'is disabled if presence state is not initialized' do
- channel_client_one.attach do
- channel_client_one.detach do
- expect(channel_client_one.state).to eq(:detached)
-
- channel_client_one.presence # access the presence object
- EventMachine.add_timer(1) do
- expect(channel_client_one.state).to eq(:detached)
- stop_reactor
+ channel_anonymous_client.attach do
+ presence_anonymous_client.get do |members|
+ expect(presence_anonymous_client.members).to_not be_in_sync
+ expect(members.count).to eql(0)
+ stop_reactor
+ end
+ end
+ end
+ end
+ end
end
end
end
end
end
@@ -569,11 +671,11 @@
end
end
end
context 'when set to nil' do
- it 'emits the previously defined value as a convenience' do
+ it 'emits a nil value for the data attribute when leaving' do
presence_client_one.enter data: enter_data do
presence_client_one.leave data: nil
end
presence_client_one.subscribe(:leave) do |presence_message|
@@ -593,10 +695,26 @@
expect(presence_message.data).to eql(enter_data)
stop_reactor
end
end
end
+
+ context 'and sync is complete' do
+ it 'does not cache members that have left' do
+ presence_client_one.enter data: enter_data do
+ expect(presence_client_one.members).to be_in_sync
+ expect(presence_client_one.members.send(:members).count).to eql(1)
+ presence_client_one.leave data: data
+ end
+
+ presence_client_one.subscribe(:leave) do |presence_message|
+ expect(presence_message.data).to eql(data)
+ expect(presence_client_one.members.send(:members).count).to eql(0)
+ stop_reactor
+ end
+ end
+ end
end
it 'raises an exception if not entered' do
expect { channel_anonymous_client.presence.leave }.to raise_error(Ably::Exceptions::Standard, /Unable to leave presence channel that is not entered/)
stop_reactor
@@ -909,47 +1027,49 @@
disconnected: { retry_every: 0.1, max_time_in_state: 0 },
suspended: { retry_every: 0.1, max_time_in_state: 0 }
)
end
- it 'fails if the connection fails' do
- when_all(*connect_members_deferrables) do
- channel_client_two.attach do
- client_two.connection.transport.__incoming_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
- if protocol_message.action == :sync
- sync_pages_received << protocol_message
- force_connection_failure client_two if sync_pages_received.count == 1
+ context 'when :wait_for_sync is true' do
+ it 'fails if the connection fails' do
+ when_all(*connect_members_deferrables) do
+ channel_client_two.attach do
+ client_two.connection.transport.__incoming_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
+ if protocol_message.action == :sync
+ sync_pages_received << protocol_message
+ force_connection_failure client_two if sync_pages_received.count == 1
+ end
end
end
- end
- presence_client_two.get.tap do |deferrable|
- deferrable.callback { raise 'Get should not succeed' }
- deferrable.errback do |error|
- stop_reactor
+ presence_client_two.get(wait_for_sync: true).tap do |deferrable|
+ deferrable.callback { raise 'Get should not succeed' }
+ deferrable.errback do |error|
+ stop_reactor
+ end
end
end
end
- end
- it 'fails if the channel is detached' do
- when_all(*connect_members_deferrables) do
- channel_client_two.attach do
- client_two.connection.transport.__incoming_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
- if protocol_message.action == :sync
- # prevent any more SYNC messages coming through
- client_two.connection.transport.__incoming_protocol_msgbus__.unsubscribe
- channel_client_two.change_state :detaching
- channel_client_two.change_state :detached
+ it 'fails if the channel is detached' do
+ when_all(*connect_members_deferrables) do
+ channel_client_two.attach do
+ client_two.connection.transport.__incoming_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
+ if protocol_message.action == :sync
+ # prevent any more SYNC messages coming through
+ client_two.connection.transport.__incoming_protocol_msgbus__.unsubscribe
+ channel_client_two.change_state :detaching
+ channel_client_two.change_state :detached
+ end
end
end
- end
- presence_client_two.get.tap do |deferrable|
- deferrable.callback { raise 'Get should not succeed' }
- deferrable.errback do |error|
- stop_reactor
+ presence_client_two.get(wait_for_sync: true).tap do |deferrable|
+ deferrable.callback { raise 'Get should not succeed' }
+ deferrable.errback do |error|
+ stop_reactor
+ end
end
end
end
end
end
@@ -1057,16 +1177,16 @@
presence_client_two.subscribe(:enter) do
clients_entered[:client_two] += 1
end
wait_until(proc { clients_entered[:client_one] + clients_entered[:client_two] == total_members * 2 }) do
- presence_anonymous_client.get do |anonymous_members|
+ presence_anonymous_client.get(wait_for_sync: true) do |anonymous_members|
expect(anonymous_members.count).to eq(total_members)
expect(anonymous_members.map(&:client_id).uniq.count).to eq(total_members)
- presence_client_one.get do |client_one_members|
- presence_client_two.get do |client_two_members|
+ presence_client_one.get(wait_for_sync: true) do |client_one_members|
+ presence_client_two.get(wait_for_sync: true) do |client_two_members|
expect(client_one_members.count).to eq(total_members)
expect(client_one_members.count).to eq(client_two_members.count)
stop_reactor
end
end
@@ -1317,11 +1437,11 @@
end
end
specify 'expect :left event with client data from enter event' do
presence_client_one.subscribe(:leave) do |message|
- presence_client_one.get do |members|
+ presence_client_one.get(wait_for_sync: true) do |members|
expect(members.count).to eq(0)
expect(message.data).to eql(data_payload)
stop_reactor
end
end
@@ -1333,12 +1453,11 @@
context 'connection failure mid-way through a large member sync' do
let(:members_count) { 400 }
let(:sync_pages_received) { [] }
- # Will re-enable once https://github.com/ably/realtime/issues/91 is resolved
- skip 'resumes the SYNC operation', em_timeout: 15 do
+ it 'resumes the SYNC operation', em_timeout: 15 do
when_all(*members_count.times.map do |index|
presence_client_one.enter_client("client:#{index}")
end) do
channel_client_two.attach do
client_two.connection.transport.__incoming_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
@@ -1347,10 +1466,10 @@
force_connection_failure client_two if sync_pages_received.count == 2
end
end
end
- presence_client_two.get do |members|
+ presence_client_two.get(wait_for_sync: true) do |members|
expect(members.count).to eql(members_count)
expect(members.map(&:member_key).uniq.count).to eql(members_count)
stop_reactor
end
end