From 5c43029dee961a2e00dafa461c3a54afe3a556f3 Mon Sep 17 00:00:00 2001 From: Brian Jones Date: Fri, 9 Dec 2016 15:48:13 -0500 Subject: [PATCH] Fix deadlocking when sending an action in a response --- lib/ruby_ami/stream.rb | 4 ++-- spec/ruby_ami/stream_spec.rb | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/lib/ruby_ami/stream.rb b/lib/ruby_ami/stream.rb index 44635d5..3c9fcb5 100644 --- a/lib/ruby_ami/stream.rb +++ b/lib/ruby_ami/stream.rb @@ -54,7 +54,7 @@ def run def post_init @state = :started - fire_event Connected.new + async.fire_event Connected.new login @username, @password if @username && @password end @@ -93,7 +93,7 @@ def message_received(message) action << message complete_causal_action_for_event message if action.complete? else - fire_event message + async.fire_event message end when Response, Error action = sent_action_for_response message diff --git a/spec/ruby_ami/stream_spec.rb b/spec/ruby_ami/stream_spec.rb index 1c1c8e5..5faf40d 100644 --- a/spec/ruby_ami/stream_spec.rb +++ b/spec/ruby_ami/stream_spec.rb @@ -42,6 +42,19 @@ def mocked_server(times = nil, fake_client = nil, &block) rescue Timeout::Error end + def mocked_server2(times = nil, fake_client = nil, handle_event = lambda { |m, stream| client.message_received m, stream }, &block) + mock_target = MockServer.new + mock_target.should_receive(:receive_data).send(*(times ? [:exactly, times] : [:at_least, 1]), &block) + s = ServerMock.new '127.0.0.1', server_port, mock_target + @stream = Stream.new '127.0.0.1', server_port, username, password, handle_event + fake_client.call if fake_client.respond_to? :call + Timeout.timeout 60 do + Celluloid::Actor.join s + Celluloid::Actor.join @stream + end + rescue Timeout::Error + end + before { @sequence = 1 } describe "after connection" do @@ -204,6 +217,26 @@ def mocked_server(times = nil, fake_client = nil, &block) response.should == Response.new('ActionID' => RubyAMI.new_uuid, 'Message' => 'Thanks for all the fish.') end + it 'should not deadlock when sending an action after receiving a response' do + response = nil + + handle_event = lambda do |m, stream| + client.message_received m, stream + response = stream.send_action 'Command', 'Command' => 'RECORD FILE evil' if m.is_a? RubyAMI::Stream::Connected + end + + mocked_server2(1, lambda {}, handle_event) do |val, server| + server.send_data <<-EVENT +Response: Success +ActionID: #{RubyAMI.new_uuid} +Message: Recording started + + EVENT + end + + response.should == Response.new('ActionID' => RubyAMI.new_uuid, 'Message' => 'Recording started') + end + describe 'when it is an error' do describe 'when there is no error handler' do it 'should be raised by #send_action, but not kill the stream' do