lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb in ably-rest-0.8.3 vs lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb in ably-rest-0.8.5

- old
+ new

@@ -4,20 +4,20 @@ describe Ably::Realtime::Channel, :event_machine do vary_by_protocol do let(:default_options) { { key: api_key, environment: environment, protocol: protocol } } let(:client_options) { default_options } - let(:client) { Ably::Realtime::Client.new(client_options) } + let(:client) { auto_close Ably::Realtime::Client.new(client_options) } let(:channel_name) { random_str } let(:payload) { random_str } let(:channel) { client.channel(channel_name) } let(:messages) { [] } describe 'initialization' do context 'with :auto_connect option set to false on connection' do let(:client) do - Ably::Realtime::Client.new(default_options.merge(auto_connect: false)) + auto_close Ably::Realtime::Client.new(default_options.merge(auto_connect: false)) end it 'remains initialized when accessing a channel' do client.channel('test') EventMachine.add_timer(2) do @@ -78,11 +78,11 @@ expect(channel.attach).to be_a(Ably::Util::SafeDeferrable) stop_reactor end it 'calls the SafeDeferrable callback on success' do - channel.attach.callback do |channel| + channel.attach.callback do expect(channel).to be_a(Ably::Realtime::Channel) expect(channel.state).to eq(:attached) stop_reactor end end @@ -90,11 +90,11 @@ context 'when state is :failed' do let(:client_options) { default_options.merge(log_level: :fatal) } it 'reattaches' do channel.attach do - channel.transition_state_machine :failed, RuntimeError.new + channel.transition_state_machine :failed, reason: RuntimeError.new expect(channel).to be_failed channel.attach do expect(channel).to be_attached stop_reactor end @@ -129,11 +129,11 @@ let(:permutation_count) { connection_count * channel_count } let(:channel_connection_ids) { [] } it 'attaches all channels', em_timeout: 15 do connection_count.times.map do - Ably::Realtime::Client.new(default_options) + auto_close Ably::Realtime::Client.new(default_options) end.each do |client| channel_count.times.map do |index| client.channel("channel-#{index}").attach do channel_connection_ids << "#{client.connection.id}:#{index}" next unless channel_connection_ids.count == permutation_count @@ -146,25 +146,25 @@ end end context 'failure as a result of insufficient key permissions' do let(:restricted_client) do - Ably::Realtime::Client.new(default_options.merge(key: restricted_api_key, log_level: :fatal)) + auto_close Ably::Realtime::Client.new(default_options.merge(key: restricted_api_key, log_level: :fatal)) end let(:restricted_channel) { restricted_client.channel("cannot_subscribe") } it 'emits failed event' do restricted_channel.attach - restricted_channel.on(:failed) do |error| + restricted_channel.on(:failed) do |connection_state| expect(restricted_channel.state).to eq(:failed) - expect(error.status).to eq(401) + expect(connection_state.reason.status).to eq(401) stop_reactor end end it 'calls the errback of the returned Deferrable' do - restricted_channel.attach.errback do |channel, error| + restricted_channel.attach.errback do |error| expect(restricted_channel.state).to eq(:failed) expect(error.status).to eq(401) stop_reactor end end @@ -190,11 +190,11 @@ it 'attaches to the channel successfully and resets the channel error_reason' do restricted_channel.attach restricted_channel.once(:failed) do restricted_client.close do # A direct call to #authorise is synchronous - restricted_client.auth.authorise(key: api_key) + restricted_client.auth.authorise({}, key: api_key) restricted_client.connect do restricted_channel.once(:attached) do expect(restricted_channel.error_reason).to be_nil stop_reactor @@ -218,13 +218,14 @@ end end end it 'detaches from a channel and calls the provided block' do - channel.attach do |chan| - chan.detach do |detached_chan| - expect(detached_chan.state).to eq(:detached) + channel.attach do + expect(channel.state).to eq(:attached) + channel.detach do + expect(channel.state).to eq(:detached) stop_reactor end end end @@ -247,11 +248,11 @@ end end it 'calls the Deferrable callback on success' do channel.attach do - channel.detach.callback do |channel| + channel.detach.callback do expect(channel).to be_a(Ably::Realtime::Channel) expect(channel.state).to eq(:detached) stop_reactor end end @@ -260,11 +261,11 @@ context 'when state is :failed' do let(:client_options) { default_options.merge(log_level: :fatal) } it 'raises an exception' do channel.attach do - channel.transition_state_machine :failed, RuntimeError.new + channel.transition_state_machine :failed, reason: RuntimeError.new expect(channel).to be_failed expect { channel.detach }.to raise_error Ably::Exceptions::InvalidStateChange stop_reactor end end @@ -431,10 +432,23 @@ expect(page.items.first.data).to eql(data) stop_reactor end end end + + context 'and additional attributes' do + let(:client_id) { random_str } + + it 'publishes the message with the attributes and return true indicating success' do + channel.publish(name, data, client_id: client_id) do + channel.history do |page| + expect(page.items.first.client_id).to eql(client_id) + stop_reactor + end + 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| @@ -548,11 +562,11 @@ 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) + auto_close 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 @@ -664,11 +678,12 @@ end context 'an :attached channel' do it 'transitions state to :failed' do channel.attach do - channel.on(:failed) do |error| + channel.on(:failed) do |connection_state_change| + error = connection_state_change.reason expect(error).to be_a(Ably::Exceptions::ConnectionFailed) expect(error.code).to eql(80002) stop_reactor end fake_error connection_error @@ -686,11 +701,12 @@ end end it 'updates the channel error_reason' do channel.attach do - channel.on(:failed) do |error| + channel.on(:failed) do |connection_state_change| + error = connection_state_change.reason expect(error).to be_a(Ably::Exceptions::ConnectionFailed) expect(error.code).to eql(80002) stop_reactor end fake_error connection_error @@ -732,11 +748,11 @@ end fake_error connection_error end - channel.transition_state_machine :failed, original_error + channel.transition_state_machine :failed, reason: original_error end end end context 'a channel ATTACH request' do @@ -781,12 +797,12 @@ end end end context 'a :failed channel' do - let(:original_error) { RuntimeError.new } let(:client_options) { default_options.merge(log_level: :fatal) } + let(:original_error) { Ably::Models::ErrorInfo.new(message: 'Error') } it 'remains in the :failed state and retains the error_reason' do channel.attach do channel.once(:error) do channel.on(:detached) { raise 'Detached state should not have been reached' } @@ -799,11 +815,11 @@ end client.connection.close end - channel.transition_state_machine :failed, original_error + channel.transition_state_machine :failed, reason: original_error end end end context 'a channel ATTACH request when connection CLOSED' do @@ -828,15 +844,146 @@ client.close end end end end + + context ':suspended' do + context 'an :attached channel' do + let(:client_options) { default_options.merge(log_level: :fatal) } + + it 'transitions state to :detached' do + channel.attach do + channel.on(:detached) do + stop_reactor + end + client.connection.transition_state_machine :suspended + end + end + end + + context 'a :detached channel' do + it 'remains in the :detached state' do + channel.attach do + channel.detach do + channel.on(:detached) { raise 'Detached state should not have been reached' } + channel.on(:error) { raise 'Error should not have been emitted' } + + EventMachine.add_timer(1) do + expect(channel).to be_detached + stop_reactor + end + + client.connection.transition_state_machine :suspended + end + end + end + end + + context 'a :failed channel' do + let(:original_error) { RuntimeError.new } + let(:client_options) { default_options.merge(log_level: :fatal) } + + it 'remains in the :failed state and retains the error_reason' do + channel.attach do + channel.once(:error) do + channel.on(:detached) { raise 'Detached state should not have been reached' } + channel.on(:error) { raise 'Error should not have been emitted' } + + EventMachine.add_timer(1) do + expect(channel).to be_failed + expect(channel.error_reason).to eql(original_error) + stop_reactor + end + + client.connection.transition_state_machine :suspended + end + + channel.transition_state_machine :failed, reason: original_error + end + end + end + + context 'a channel ATTACH request when connection SUSPENDED' do + it 'raises an exception' do + client.connect do + client.connection.once(:suspended) do + expect { channel.attach }.to raise_error Ably::Exceptions::InvalidStateChange + stop_reactor + end + client.connection.transition_state_machine :suspended + 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 + + context 'channel state change' do + it 'emits a ChannelStateChange object' do + channel.on(:attached) do |channel_state_change| + expect(channel_state_change).to be_a(Ably::Models::ChannelStateChange) + stop_reactor + end + channel.attach + end + + context 'ChannelStateChange object' do + it 'has current state' do + channel.on(:attached) do |channel_state_change| + expect(channel_state_change.current).to eq(:attached) + stop_reactor + end + channel.attach + end + + it 'has a previous state' do + channel.on(:attached) do |channel_state_change| + expect(channel_state_change.previous).to eq(:attaching) + stop_reactor + end + channel.attach + end + + it 'contains a private API protocol_message attribute that is used for special state change events', :api_private do + channel.on(:attached) do |channel_state_change| + expect(channel_state_change.protocol_message).to be_a(Ably::Models::ProtocolMessage) + expect(channel_state_change.reason).to be_nil + stop_reactor + end + channel.attach + end + + it 'has an empty reason when there is no error' do + channel.on(:detached) do |channel_state_change| + expect(channel_state_change.reason).to be_nil + stop_reactor + end + channel.attach do + channel.detach + end + end + + context 'on failure' do + let(:client_options) { default_options.merge(log_level: :none) } + + it 'has a reason Error object when there is an error on the channel' do + channel.on(:failed) do |channel_state_change| + expect(channel_state_change.reason).to be_a(Ably::Exceptions::BaseAblyException) + stop_reactor + end + channel.attach do + error = Ably::Exceptions::ConnectionFailed.new('forced failure', 500, 50000) + client.connection.manager.error_received_from_server error + end + end + end end end end end