spec/punchblock/translator/asterisk/call_spec.rb in punchblock-2.1.1 vs spec/punchblock/translator/asterisk/call_spec.rb in punchblock-2.2.0

- old
+ new

@@ -67,18 +67,10 @@ its(:translator) { should be translator } its(:agi_env) { should be == agi_env } before { translator.stub :handle_pb_event } - describe '#shutdown' do - it 'should terminate the actor' do - subject.shutdown - sleep 0.5 - subject.should_not be_alive - end - end - describe '#register_component' do it 'should make the component accessible by ID' do component_id = 'abc123' component = double 'Translator::Asterisk::Component', :id => component_id subject.register_component component @@ -121,19 +113,19 @@ end describe '#send_progress' do context "with a call that is already answered" do it 'should not send the EXEC Progress command' do - subject.wrapped_object.should_receive(:'answered?').and_return true - subject.wrapped_object.should_receive(:execute_agi_command).with("EXEC Progress").never + subject.should_receive(:'answered?').and_return true + subject.should_receive(:execute_agi_command).with("EXEC Progress").never subject.send_progress end end context "with an unanswered call" do before do - subject.wrapped_object.should_receive(:'answered?').at_least(:once).and_return(false) + subject.should_receive(:'answered?').at_least(:once).and_return(false) end context "with a call that is outbound" do let(:dial_command) { Command::Dial.new } @@ -141,27 +133,27 @@ dial_command.request! subject.dial dial_command end it 'should not send the EXEC Progress command' do - subject.wrapped_object.should_receive(:execute_agi_command).with("EXEC Progress").never + subject.should_receive(:execute_agi_command).with("EXEC Progress").never subject.send_progress end end context "with a call that is inbound" do before do subject.send_offer end it 'should send the EXEC Progress command to a call that is inbound and not answered' do - subject.wrapped_object.should_receive(:execute_agi_command).with("EXEC Progress").and_return code: 200, result: 0 + subject.should_receive(:execute_agi_command).with("EXEC Progress").and_return code: 200, result: 0 subject.send_progress end it 'should send the EXEC Progress command only once if called twice' do - subject.wrapped_object.should_receive(:execute_agi_command).with("EXEC Progress").once.and_return code: 200, result: 0 + subject.should_receive(:execute_agi_command).with("EXEC Progress").once.and_return code: 200, result: 0 subject.send_progress subject.send_progress end end end @@ -274,11 +266,11 @@ it 'causes accepting the call to be a null operation' do subject.dial dial_command accept_command = Command::Accept.new accept_command.request! - subject.wrapped_object.should_receive(:execute_agi_command).never + subject.should_receive(:execute_agi_command).never subject.execute_command accept_command accept_command.response(0.5).should be true end end @@ -295,17 +287,10 @@ end let(:cause) { '16' } let(:cause_txt) { 'Normal Clearing' } - it "should cause the actor to be terminated" do - translator.should_receive(:handle_pb_event).twice - subject.process_ami_event ami_event - Celluloid::Actor.join(subject, 1) - subject.should_not be_alive - end - it "de-registers the call from the translator" do translator.stub :handle_pb_event translator.should_receive(:deregister_call).once.with(subject.id, subject.channel) subject.process_ami_event ami_event end @@ -332,11 +317,11 @@ comp_command = Punchblock::Component::Input.new :grammar => {:value => RubySpeech::GRXML.draw(root: 'foo') { rule id: 'foo' }}, :mode => :dtmf comp_command.request! component = subject.execute_command comp_command comp_command.response(0.1).should be_a Ref - subject.async.process_ami_event ami_event + subject.process_ami_event ami_event comp_command = Punchblock::Component::Input.new :grammar => {:value => '<grammar root="foo"><rule id="foo"/></grammar>'}, :mode => :dtmf comp_command.request! subject.execute_command comp_command comp_command.response(0.1).should == ProtocolError.new.setup(:item_not_found, "Could not find a call with ID #{call_id}", call_id) @@ -655,11 +640,11 @@ end before do translator.register_call other_call command.request! - subject.wrapped_object.should_receive(:execute_agi_command).and_return code: 200 + subject.should_receive(:execute_agi_command).and_return code: 200 subject.execute_command command end it 'retrieves and sets success on the correct Join' do subject.process_ami_event ami_event @@ -858,10 +843,19 @@ it 'sends the AMI event to the connection as a PB event' do translator.should_receive(:handle_pb_event).with expected_pb_event subject.process_ami_event ami_event end + context "when the event doesn't pass the filter" do + before { Asterisk.event_filter = ->(event) { false } } + after { Asterisk.event_filter = nil } + + it 'does not send the AMI event to the connection as a PB event' do + translator.should_receive(:handle_pb_event).never + subject.process_ami_event ami_event + end + end end describe '#execute_command' do before do command.request! @@ -869,20 +863,20 @@ context 'with an accept command' do let(:command) { Command::Accept.new } it "should send an EXEC RINGING AGI command and set the command's response" do - subject.wrapped_object.should_receive(:execute_agi_command).with('EXEC RINGING').and_return code: 200 + subject.should_receive(:execute_agi_command).with('EXEC RINGING').and_return code: 200 subject.execute_command command command.response(0.5).should be true end context "when the AMI commannd raises an error" do let(:message) { 'Some error' } let(:error) { RubyAMI::Error.new.tap { |e| e.message = message } } - before { subject.wrapped_object.should_receive(:execute_agi_command).and_raise error } + before { subject.should_receive(:execute_agi_command).and_raise error } it "should return an error with the message" do subject.execute_command command command.response(0.5).should be == ProtocolError.new.setup('error', message, subject.id) end @@ -901,11 +895,11 @@ context 'with a reject command' do let(:command) { Command::Reject.new } it "with a :busy reason should send an EXEC Busy AGI command and set the command's response" do command.reason = :busy - subject.wrapped_object.should_receive(:execute_agi_command).with('EXEC Busy').and_return code: 200 + subject.should_receive(:execute_agi_command).with('EXEC Busy').and_return code: 200 subject.execute_command command command.response(0.5).should be true end it "with a :decline reason should send a Hangup AMI command (cause 21) and set the command's response" do @@ -915,20 +909,20 @@ command.response(0.5).should be true end it "with an :error reason should send an EXEC Congestion AGI command and set the command's response" do command.reason = :error - subject.wrapped_object.should_receive(:execute_agi_command).with('EXEC Congestion').and_return code: 200 + subject.should_receive(:execute_agi_command).with('EXEC Congestion').and_return code: 200 subject.execute_command command command.response(0.5).should be true end context "when the AMI commannd raises an error" do let(:message) { 'Some error' } let(:error) { RubyAMI::Error.new.tap { |e| e.message = message } } - before { subject.wrapped_object.should_receive(:execute_agi_command).and_raise error } + before { subject.should_receive(:execute_agi_command).and_raise error } it "should return an error with the message" do subject.execute_command command command.response(0.5).should be == ProtocolError.new.setup('error', message, subject.id) end @@ -946,26 +940,26 @@ context 'with an answer command' do let(:command) { Command::Answer.new } it "should send an ANSWER AGI command and set the command's response" do - subject.wrapped_object.should_receive(:execute_agi_command).with('ANSWER').and_return code: 200 + subject.should_receive(:execute_agi_command).with('ANSWER').and_return code: 200 subject.execute_command command command.response(0.5).should be true end it "should be answered" do - subject.wrapped_object.should_receive(:execute_agi_command) + subject.should_receive(:execute_agi_command) subject.execute_command command subject.should be_answered end context "when the AMI command raises an error" do let(:message) { 'Some error' } let(:error) { RubyAMI::Error.new.tap { |e| e.message = message } } - before { subject.wrapped_object.should_receive(:execute_agi_command).and_raise error } + before { subject.should_receive(:execute_agi_command).and_raise error } it "should return an error with the message" do subject.execute_command command command.response(0.5).should be == ProtocolError.new.setup('error', message, subject.id) end @@ -1040,19 +1034,19 @@ end before { translator.should_receive(:call_with_id).with(other_call_id).and_return(other_call) } it "executes the proper dialplan Bridge application" do - subject.wrapped_object.should_receive(:execute_agi_command).with('EXEC Bridge', "#{other_channel},F(#{REDIRECT_CONTEXT},#{REDIRECT_EXTENSION},#{REDIRECT_PRIORITY})").and_return code: 200 + subject.should_receive(:execute_agi_command).with('EXEC Bridge', "#{other_channel},F(#{REDIRECT_CONTEXT},#{REDIRECT_EXTENSION},#{REDIRECT_PRIORITY})").and_return code: 200 subject.execute_command command end context "when the AMI command raises an error" do let(:message) { 'Some error' } let(:error) { RubyAMI::Error.new.tap { |e| e.message = message } } - before { subject.wrapped_object.should_receive(:execute_agi_command).and_raise error } + before { subject.should_receive(:execute_agi_command).and_raise error } it "should return an error with the message" do subject.execute_command command command.response(0.5).should be == ProtocolError.new.setup('error', message, subject.id) end @@ -1154,43 +1148,40 @@ context 'with an AGI command component' do let :command do Punchblock::Component::Asterisk::AGI::Command.new :name => 'Answer' end - let(:mock_action) { Translator::Asterisk::Component::Asterisk::AGICommand.new(command, subject) } - it 'should create an AGI command component actor and execute it asynchronously' do - Component::Asterisk::AGICommand.should_receive(:new_link).once.with(command, subject).and_return mock_action - mock_action.async.should_receive(:execute).once + mock_action = Translator::Asterisk::Component::Asterisk::AGICommand.new(command, subject) + Component::Asterisk::AGICommand.should_receive(:new).once.with(command, subject).and_return mock_action + mock_action.should_receive(:execute).once subject.execute_command command end end context 'with an Output component' do let :command do Punchblock::Component::Output.new end - let(:mock_action) { Translator::Asterisk::Component::Output.new(command, subject) } - it 'should create an Output component and execute it asynchronously' do - Component::Output.should_receive(:new_link).once.with(command, subject).and_return mock_action - mock_action.async.should_receive(:execute).once + mock_action = Translator::Asterisk::Component::Output.new(command, subject) + Component::Output.should_receive(:new).once.with(command, subject).and_return mock_action + mock_action.should_receive(:execute).once subject.execute_command command end end context 'with an Input component' do let :command do Punchblock::Component::Input.new end - let(:mock_action) { Translator::Asterisk::Component::Input.new(command, subject) } - it 'should create an Input component and execute it asynchronously' do - Component::Input.should_receive(:new_link).once.with(command, subject).and_return mock_action - mock_action.async.should_receive(:execute).once + mock_action = Translator::Asterisk::Component::Input.new(command, subject) + Component::Input.should_receive(:new).once.with(command, subject).and_return mock_action + mock_action.should_receive(:execute).once subject.execute_command command end end context 'with a Prompt component' do @@ -1222,28 +1213,30 @@ }) end let(:mock_action) { Translator::Asterisk::Component::MRCPPrompt.new(command, subject) } + before { mock_action} + context "when the recognizer is unimrcp and the renderer is unimrcp" do let(:recognizer) { :unimrcp } let(:renderer) { :unimrcp } it 'should create an MRCPPrompt component and execute it asynchronously' do - Component::MRCPPrompt.should_receive(:new_link).once.with(command, subject).and_return mock_action - mock_action.async.should_receive(:execute).once + Component::MRCPPrompt.should_receive(:new).once.with(command, subject).and_return mock_action + mock_action.should_receive(:execute).once subject.execute_command command end end context "when the recognizer is unimrcp and the renderer is asterisk" do let(:recognizer) { :unimrcp } let(:renderer) { :asterisk } it 'should create an MRCPPrompt component and execute it asynchronously' do - Component::MRCPNativePrompt.should_receive(:new_link).once.with(command, subject).and_return mock_action - mock_action.async.should_receive(:execute).once + Component::MRCPNativePrompt.should_receive(:new).once.with(command, subject).and_return mock_action + mock_action.should_receive(:execute).once subject.execute_command command end end context "when the recognizer is unimrcp and the renderer is something we can't compose with unimrcp" do @@ -1259,27 +1252,26 @@ context "when the recognizer is something other than unimrcp" do let(:recognizer) { :asterisk } let(:renderer) { :unimrcp } it 'should create a ComposedPrompt component and execute it asynchronously' do - Component::ComposedPrompt.should_receive(:new_link).once.with(command, subject).and_return mock_action - mock_action.async.should_receive(:execute).once + Component::ComposedPrompt.should_receive(:new).once.with(command, subject).and_return mock_action + mock_action.should_receive(:execute).once subject.execute_command command end end end context 'with a Record component' do let :command do Punchblock::Component::Record.new end - let(:mock_action) { Translator::Asterisk::Component::Record.new(command, subject) } - it 'should create a Record component and execute it asynchronously' do - Component::Record.should_receive(:new_link).once.with(command, subject).and_return mock_action - mock_action.async.should_receive(:execute).once + mock_action = Translator::Asterisk::Component::Record.new(command, subject) + Component::Record.should_receive(:new).once.with(command, subject).and_return mock_action + mock_action.should_receive(:execute).once subject.execute_command command end end context 'with a component command' do @@ -1325,41 +1317,21 @@ context "normally" do it 'sends an error in response to the command' do component = subject.component_with_id comp_id - component.terminate - sleep 0.1 - component.should_not be_alive + component.send_complete_event Punchblock::Component::Asterisk::AGI::Command::Complete.new + subject.component_with_id(comp_id).should be_nil subsequent_command.request! subject.execute_command subsequent_command subsequent_command.response.should be == ProtocolError.new.setup(:item_not_found, "Could not find a component with ID #{comp_id} for call #{subject.id}", subject.id, comp_id) end end context "by crashing" do - it 'sends an error in response to the command' do - component = subject.component_with_id comp_id - - component.wrapped_object.define_singleton_method(:oops) do - raise 'Woops, I died' - end - - translator.should_receive(:handle_pb_event).once.with expected_event - - lambda { component.oops }.should raise_error(/Woops, I died/) - sleep 0.1 - component.should_not be_alive - subject.component_with_id(comp_id).should be_nil - - subsequent_command.request! - subject.execute_command subsequent_command - subsequent_command.response.should be == ProtocolError.new.setup(:item_not_found, "Could not find a component with ID #{comp_id} for call #{subject.id}", subject.id, comp_id) - end - context "when we dispatch the command to it" do it 'sends an error in response to the command' do component = subject.component_with_id comp_id component.should_receive(:execute_command).and_raise(Celluloid::DeadActorError) @@ -1457,10 +1429,12 @@ "Command" => "EXEC ANSWER", "Result" => "200%20result=123%20(timeout)%0A" end it 'should return the result' do - fut = subject.future.execute_agi_command 'EXEC ANSWER' + fut = Celluloid::Future.new { subject.execute_agi_command 'EXEC ANSWER' } + + sleep 0.25 subject.process_ami_event ami_event fut.value.should == {code: 200, result: 123, data: 'timeout'} end