lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb in ably-rest-0.8.2 vs lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb in ably-rest-0.8.3
- old
+ new
@@ -262,11 +262,11 @@
it 'raises an exception' do
channel.attach do
channel.transition_state_machine :failed, RuntimeError.new
expect(channel).to be_failed
- expect { channel.detach }.to raise_error Ably::Exceptions::StateChangeError
+ expect { channel.detach }.to raise_error Ably::Exceptions::InvalidStateChange
stop_reactor
end
end
end
@@ -302,10 +302,28 @@
channel.attach do
channel.detach
end
end
end
+
+ context 'when state is :initialized' do
+ it 'does nothing as there is no channel to detach' do
+ expect(channel).to be_initialized
+ channel.detach do
+ expect(channel).to be_initialized
+ stop_reactor
+ end
+ end
+
+ it 'returns a valid deferrable' do
+ expect(channel).to be_initialized
+ channel.detach.callback do
+ expect(channel).to be_initialized
+ stop_reactor
+ end
+ end
+ end
end
describe 'channel recovery in :attaching state' do
context 'the transport is disconnected before the ATTACHED protocol message is received' do
skip 'attach times out and fails if not ATTACHED protocol message received'
@@ -313,10 +331,13 @@
skip 'sends an ATTACH protocol message in response to a channel message being received on the attaching channel'
end
end
context '#publish' do
+ let(:name) { random_str }
+ let(:data) { random_str }
+
context 'when attached' do
it 'publishes messages' do
channel.attach do
3.times { channel.publish('event', payload) }
end
@@ -352,11 +373,202 @@
message_indexes = messages.map { |msg| msg.id.split(':')[1] }
expect(message_indexes).to include("0", "1", "2")
stop_reactor
end
end
+
+ context 'with :queue_messages client option set to false' do
+ let(:client_options) { default_options.merge(queue_messages: false) }
+
+ context 'and connection state initialized' do
+ it 'raises an exception' do
+ expect { channel.publish('event') }.to raise_error Ably::Exceptions::MessageQueueingDisabled
+ expect(client.connection).to be_initialized
+ stop_reactor
+ end
+ end
+
+ context 'and connection state connecting' do
+ it 'raises an exception' do
+ client.connect
+ EventMachine.next_tick do
+ expect { channel.publish('event') }.to raise_error Ably::Exceptions::MessageQueueingDisabled
+ expect(client.connection).to be_connecting
+ stop_reactor
+ end
+ end
+ end
+
+ context 'and connection state disconnected' do
+ let(:client_options) { default_options.merge(queue_messages: false, :log_level => :error ) }
+ it 'raises an exception' do
+ client.connection.once(:connected) do
+ client.connection.once(:disconnected) do
+ expect { channel.publish('event') }.to raise_error Ably::Exceptions::MessageQueueingDisabled
+ expect(client.connection).to be_disconnected
+ stop_reactor
+ end
+ client.connection.transition_state_machine :disconnected
+ end
+ end
+ end
+
+ context 'and connection state connected' do
+ it 'publishes the message' do
+ client.connection.once(:connected) do
+ channel.publish('event')
+ stop_reactor
+ end
+ end
+ end
+ end
end
+
+ context 'with name and data arguments' do
+ it 'publishes the message and return true indicating success' do
+ channel.publish(name, data) do
+ channel.history do |page|
+ expect(page.items.first.name).to eql(name)
+ expect(page.items.first.data).to eql(data)
+ stop_reactor
+ end
+ end
+ end
+ end
+
+ context 'with an array of Hash objects with :name and :data attributes' do
+ let(:messages) do
+ 10.times.map do |index|
+ { name: index.to_s, data: { "index" => index + 10 } }
+ end
+ end
+
+ it 'publishes an array of messages in one ProtocolMessage' do
+ published = false
+
+ channel.attach do
+ client.connection.__outgoing_protocol_msgbus__.once(:protocol_message) do |protocol_message|
+ expect(protocol_message.messages.count).to eql(messages.count)
+ published = true
+ end
+
+ channel.publish(messages).callback do
+ channel.history do |page|
+ expect(page.items.map(&:name)).to match_array(messages.map { |message| message[:name] })
+ expect(page.items.map(&:data)).to match_array(messages.map { |message| message[:data] })
+ expect(published).to eql(true)
+ stop_reactor
+ end
+ end
+ end
+ end
+ end
+
+ context 'with an array of Message objects' do
+ let(:messages) do
+ 10.times.map do |index|
+ Ably::Models::Message(name: index.to_s, data: { "index" => index + 10 })
+ end
+ end
+
+ it 'publishes an array of messages in one ProtocolMessage' do
+ published = false
+
+ channel.attach do
+ client.connection.__outgoing_protocol_msgbus__.once(:protocol_message) do |protocol_message|
+ expect(protocol_message.messages.count).to eql(messages.count)
+ published = true
+ end
+
+ channel.publish(messages).callback do
+ channel.history do |page|
+ expect(page.items.map(&:name)).to match_array(messages.map { |message| message[:name] })
+ expect(page.items.map(&:data)).to match_array(messages.map { |message| message[:data] })
+ expect(published).to eql(true)
+ stop_reactor
+ end
+ end
+ end
+ end
+
+ context 'with two invalid message out of 12' do
+ let(:client_options) { default_options.merge(client_id: 'valid') }
+ let(:invalid_messages) do
+ 2.times.map do |index|
+ Ably::Models::Message(name: index.to_s, data: { "index" => index + 10 }, client_id: 'prohibited')
+ end
+ end
+
+ it 'calls the errback once' do
+ skip 'Waiting for issue #256 to be resolved'
+ channel.publish(messages + invalid_messages).tap do |deferrable|
+ deferrable.callback do
+ raise 'Publish should have failed'
+ end
+
+ deferrable.errback do |error, message|
+ # TODO: Review whether we should fail once or multiple times
+ channel.history do |page|
+ expect(page.items.count).to eql(0)
+ stop_reactor
+ end
+ end
+ end
+ end
+ end
+
+ context 'only invalid messages' do
+ let(:client_options) { default_options.merge(client_id: 'valid') }
+ let(:invalid_messages) do
+ 10.times.map do |index|
+ Ably::Models::Message(name: index.to_s, data: { "index" => index + 10 }, client_id: 'prohibited')
+ end
+ end
+
+ it 'calls the errback once' do
+ skip 'Waiting for issue #256 to be resolved'
+ channel.publish(invalid_messages).tap do |deferrable|
+ deferrable.callback do
+ raise 'Publish should have failed'
+ end
+
+ deferrable.errback do |error, message|
+ channel.history do |page|
+ expect(page.items.count).to eql(0)
+ stop_reactor
+ end
+ end
+ end
+ end
+ end
+ end
+
+ context 'with many many messages and many connections simultaneously' do
+ let(:connection_count) { 5 }
+ let(:messages) { 5.times.map { |index| { name: "test", data: "message-#{index}" } } }
+ let(:published) { [] }
+ let(:channel_name) { random_str }
+
+ it 'publishes all messages, all success callbacks are called, and a history request confirms all messages were published' do
+ connection_count.times.map do
+ Ably::Realtime::Client.new(client_options)
+ end.each do |client|
+ channel = client.channels.get(channel_name)
+ messages.each do |message|
+ channel.publish(message.fetch(:name), message.fetch(:data)) do
+ published << message
+ if published.count == connection_count * messages.count
+ channel.history do |history_page|
+ expect(history_page.items.count).to eql(connection_count * messages.count)
+ stop_reactor
+ end
+ end
+ end
+ end
+ end
+ end
+ end
end
describe '#subscribe' do
context 'with an event argument' do
it 'subscribes for a single event' do
@@ -366,10 +578,24 @@
end
channel.publish('click', 'data')
end
end
+ context 'before attach' do
+ it 'receives messages as soon as attached' do
+ channel.subscribe('click') do |message|
+ expect(channel).to be_attached
+ expect(message.data).to eql('data')
+ stop_reactor
+ end
+
+ channel.publish('click', 'data')
+
+ expect(channel).to be_attaching
+ end
+ end
+
context 'with no event argument' do
it 'subscribes for all events' do
channel.subscribe do |message|
expect(message.data).to eql('data')
stop_reactor
@@ -428,42 +654,45 @@
end
end
context 'when connection state changes to' do
context ':failed' do
- let(:connection_error) { Ably::Exceptions::ConnectionError.new('forced failure', 500, 50000) }
+ let(:connection_error) { Ably::Exceptions::ConnectionFailed.new('forced failure', 500, 50000) }
let(:client_options) { default_options.merge(log_level: :none) }
def fake_error(error)
client.connection.manager.error_received_from_server error
end
context 'an :attached channel' do
it 'transitions state to :failed' do
channel.attach do
channel.on(:failed) do |error|
- expect(error).to eql(connection_error)
+ expect(error).to be_a(Ably::Exceptions::ConnectionFailed)
+ expect(error.code).to eql(80002)
stop_reactor
end
fake_error connection_error
end
end
it 'emits an error event on the channel' do
channel.attach do
channel.on(:error) do |error|
- expect(error).to eql(connection_error)
+ expect(error).to be_a(Ably::Exceptions::ConnectionFailed)
+ expect(error.code).to eql(80002)
stop_reactor
end
fake_error connection_error
end
end
it 'updates the channel error_reason' do
channel.attach do
channel.on(:failed) do |error|
- expect(channel.error_reason).to eql(connection_error)
+ expect(error).to be_a(Ably::Exceptions::ConnectionFailed)
+ expect(error.code).to eql(80002)
stop_reactor
end
fake_error connection_error
end
end
@@ -507,10 +736,22 @@
channel.transition_state_machine :failed, original_error
end
end
end
+
+ context 'a channel ATTACH request' do
+ it 'raises an exception' do
+ client.connect do
+ client.connection.once(:failed) do
+ expect { channel.attach }.to raise_error Ably::Exceptions::InvalidStateChange
+ stop_reactor
+ end
+ fake_error connection_error
+ end
+ end
+ end
end
context ':closed' do
context 'an :attached channel' do
it 'transitions state to :detached' do
@@ -562,9 +803,40 @@
channel.transition_state_machine :failed, original_error
end
end
end
+
+ context 'a channel ATTACH request when connection CLOSED' do
+ it 'raises an exception' do
+ client.connect do
+ client.connection.once(:closed) do
+ expect { channel.attach }.to raise_error Ably::Exceptions::InvalidStateChange
+ stop_reactor
+ end
+ client.close
+ end
+ end
+ end
+
+ context 'a channel ATTACH request when connection CLOSING' do
+ it 'raises an exception' do
+ client.connect do
+ client.connection.once(:closing) do
+ expect { channel.attach }.to raise_error Ably::Exceptions::InvalidStateChange
+ stop_reactor
+ end
+ client.close
+ end
+ end
+ end
+ end
+ end
+
+ describe '#presence' do
+ it 'returns a Ably::Realtime::Presence object' do
+ expect(channel.presence).to be_a(Ably::Realtime::Presence)
+ stop_reactor
end
end
end
end