spec/punchblock/translator/asterisk/component/output_spec.rb in punchblock-1.9.4 vs spec/punchblock/translator/asterisk/component/output_spec.rb in punchblock-2.0.0.beta1
- old
+ new
@@ -8,11 +8,11 @@
module Component
describe Output do
include HasMockCallbackConnection
let(:media_engine) { nil }
- let(:ami_client) { mock('AMI') }
+ let(:ami_client) { double('AMI') }
let(:translator) { Punchblock::Translator::Asterisk.new ami_client, connection, media_engine }
let(:mock_call) { Punchblock::Translator::Asterisk::Call.new 'foo', translator, ami_client, connection }
let :original_command do
Punchblock::Component::Output.new command_options
@@ -23,11 +23,11 @@
say_as(:interpret_as => :cardinal) { 'FOO' }
end
end
let :command_options do
- { :ssml => ssml_doc }
+ { :render_document => {:value => ssml_doc} }
end
subject { Output.new original_command, mock_call }
def expect_answered(value = true)
@@ -60,11 +60,11 @@
end
let(:command_opts) { {} }
let :command_options do
- { :ssml => ssml_doc }.merge(command_opts)
+ { :render_document => {:value => ssml_doc} }.merge(command_opts)
end
def ssml_with_options(prefix = '', postfix = '')
base_doc = ssml_doc.to_s.squish.gsub(/["\\]/) { |m| "\\#{m}" }
prefix + base_doc + postfix
@@ -78,11 +78,11 @@
end
it 'should send a complete event when Swift completes' do
mock_call.should_receive(:execute_agi_command).and_return code: 200, result: 1
subject.execute
- original_command.complete_event(0.1).reason.should be_a Punchblock::Component::Output::Complete::Success
+ original_command.complete_event(0.1).reason.should be_a Punchblock::Component::Output::Complete::Finish
end
context "when we get a RubyAMI Error" do
it "should send an error complete event" do
error = RubyAMI::Error.new.tap { |e| e.message = 'FooBar' }
@@ -92,10 +92,20 @@
complete_reason.should be_a Punchblock::Event::Complete::Error
complete_reason.details.should == "Terminated due to AMI error 'FooBar'"
end
end
+ context "when the channel is gone" do
+ it "should send an error complete event" do
+ error = ChannelGoneError.new 'FooBar'
+ mock_call.should_receive(:execute_agi_command).and_raise error
+ subject.execute
+ complete_reason = original_command.complete_event(0.1).reason
+ complete_reason.should be_a Punchblock::Event::Complete::Hangup
+ end
+ end
+
context "when the call is not answered" do
before { expect_answered false }
it "should send progress" do
mock_call.should_receive(:send_progress)
@@ -127,12 +137,12 @@
mock_call.should_receive(:execute_agi_command).once.with('EXEC Swift', ssml_with_options('', '|1|1')).and_return code: 200, result: 1
subject.execute
end
end
- context "set to :speech" do
- let(:command_opts) { { :interrupt_on => :speech } }
+ context "set to :voice" do
+ let(:command_opts) { { :interrupt_on => :voice } }
it "should return an error and not execute any actions" do
subject.execute
error = ProtocolError.new.setup 'option error', 'An interrupt-on value of speech is unsupported.'
original_command.response(0.1).should be == error
end
@@ -172,47 +182,34 @@
end
let(:command_opts) { {} }
let :command_options do
- { :ssml => ssml_doc }.merge(command_opts)
+ { :render_document => {:value => ssml_doc} }.merge(command_opts)
end
+ let(:synthstatus) { 'OK' }
+ before { mock_call.stub(:channel_var).with('SYNTHSTATUS').and_return synthstatus }
+
def expect_mrcpsynth_with_options(options)
mock_call.should_receive(:execute_agi_command).once.with do |*args|
args[0].should be == 'EXEC MRCPSynth'
- args[2].should match options
+ args[1].should match options
end.and_return code: 200, result: 1
end
before { expect_answered }
it "should execute MRCPSynth" do
- mock_call.should_receive(:execute_agi_command).once.with('EXEC MRCPSynth', ssml_doc.to_s.squish.gsub(/["\\]/) { |m| "\\#{m}" }, '').and_return code: 200, result: 1
+ mock_call.should_receive(:execute_agi_command).once.with('EXEC MRCPSynth', ["\"#{ssml_doc.to_s.squish.gsub('"', '\"')}\"", ''].join(',')).and_return code: 200, result: 1
subject.execute
end
- context "when the SSML document contains commas" do
- let :ssml_doc do
- RubySpeech::SSML.draw do
- string "this, here, is a test"
- end
- end
-
- it 'should escape TTS strings containing a comma' do
- mock_call.should_receive(:execute_agi_command).once.with do |*args|
- args[0].should be == 'EXEC MRCPSynth'
- args[1].should match(/this\\, here\\, is a test/)
- end.and_return code: 200, result: 1
- subject.execute
- end
- end
-
it 'should send a complete event when MRCPSynth completes' do
mock_call.should_receive(:execute_agi_command).and_return code: 200, result: 1
subject.execute
- original_command.complete_event(0.1).reason.should be_a Punchblock::Component::Output::Complete::Success
+ original_command.complete_event(0.1).reason.should be_a Punchblock::Component::Output::Complete::Finish
end
context "when we get a RubyAMI Error" do
it "should send an error complete event" do
error = RubyAMI::Error.new.tap { |e| e.message = 'FooBar' }
@@ -222,29 +219,60 @@
complete_reason.should be_a Punchblock::Event::Complete::Error
complete_reason.details.should == "Terminated due to AMI error 'FooBar'"
end
end
+ context "when the channel is gone" do
+ it "should send an error complete event" do
+ error = ChannelGoneError.new 'FooBar'
+ mock_call.should_receive(:execute_agi_command).and_raise error
+ subject.execute
+ complete_reason = original_command.complete_event(0.1).reason
+ complete_reason.should be_a Punchblock::Event::Complete::Hangup
+ end
+ end
+
context "when the call is not answered" do
before { expect_answered false }
it "should send progress" do
mock_call.should_receive(:send_progress)
mock_call.should_receive(:execute_agi_command).and_return code: 200, result: 1
subject.execute
end
end
- describe 'ssml' do
+ context "when the SYNTHSTATUS variable is set to 'ERROR'" do
+ let(:synthstatus) { 'ERROR' }
+
+ it "should send an error complete event" do
+ mock_call.should_receive(:execute_agi_command).and_return code: 200, result: 1
+ subject.execute
+ complete_reason = original_command.complete_event(0.1).reason
+ complete_reason.should be_a Punchblock::Event::Complete::Error
+ complete_reason.details.should == "Terminated due to UniMRCP error"
+ end
+ end
+
+ describe 'document' do
context 'unset' do
- let(:command_opts) { { :ssml => nil } }
+ let(:ssml_doc) { nil }
it "should return an error and not execute any actions" do
subject.execute
error = ProtocolError.new.setup 'option error', 'An SSML document is required.'
original_command.response(0.1).should be == error
end
end
+
+ context 'with multiple documents' do
+ let(:command_opts) { { :render_documents => [{:value => ssml_doc}, {:value => ssml_doc}] } }
+ it "should return an error and not execute any actions" do
+ subject.execute
+ error = ProtocolError.new.setup 'option error', 'Only a single document is supported.'
+ original_command.response(0.1).should be == error
+ end
+ end
end
describe 'start-offset' do
context 'unset' do
let(:command_opts) { { :start_offset => nil } }
@@ -381,12 +409,12 @@
expect_mrcpsynth_with_options(/i=any/)
subject.execute
end
end
- context "set to :speech" do
- let(:command_opts) { { :interrupt_on => :speech } }
+ context "set to :voice" do
+ let(:command_opts) { { :interrupt_on => :voice } }
it "should return an error and not execute any actions" do
subject.execute
error = ProtocolError.new.setup 'option error', 'An interrupt-on value of speech is unsupported.'
original_command.response(0.1).should be == error
end
@@ -413,33 +441,34 @@
end
let(:command_opts) { {} }
let :command_options do
- { :ssml => ssml_doc }.merge(command_opts)
+ { :render_document => {:value => ssml_doc} }.merge(command_opts)
end
let :original_command do
Punchblock::Component::Output.new command_options
end
+ let(:playbackstatus) { 'SUCCESS' }
+ before { mock_call.stub(:channel_var).with('PLAYBACKSTATUS').and_return playbackstatus }
+
describe 'ssml' do
context 'unset' do
- let(:command_opts) { { :ssml => nil } }
+ let(:ssml_doc) { nil }
it "should return an error and not execute any actions" do
subject.execute
error = ProtocolError.new.setup 'option error', 'An SSML document is required.'
original_command.response(0.1).should be == error
end
end
context 'with a single audio SSML node' do
- let(:audio_filename) { 'http://foo.com/bar.mp3' }
- let :command_options do
- {
- :ssml => RubySpeech::SSML.draw { audio :src => audio_filename }
- }
+ let(:audio_filename) { 'tt-monkeys' }
+ let :ssml_doc do
+ RubySpeech::SSML.draw { audio :src => audio_filename }
end
it 'should playback the audio file using Playback' do
expect_answered
expect_playback
@@ -450,13 +479,23 @@
def mock_call.answered?
true
end
expect_playback
subject.execute
- original_command.complete_event(0.1).reason.should be_a Punchblock::Component::Output::Complete::Success
+ original_command.complete_event(0.1).reason.should be_a Punchblock::Component::Output::Complete::Finish
end
+ context "when the audio filename is prefixed by file://" do
+ let(:audio_filename) { 'file://tt-monkeys' }
+
+ it 'should playback the audio file using Playback' do
+ expect_answered
+ expect_playback 'tt-monkeys'
+ subject.execute
+ end
+ end
+
context "when we get a RubyAMI Error" do
it "should send an error complete event" do
expect_answered
error = RubyAMI::Error.new.tap { |e| e.message = 'FooBar' }
mock_call.should_receive(:execute_agi_command).and_raise error
@@ -464,18 +503,40 @@
complete_reason = original_command.complete_event(0.1).reason
complete_reason.should be_a Punchblock::Event::Complete::Error
complete_reason.details.should == "Terminated due to AMI error 'FooBar'"
end
end
+
+ context "when the channel is gone" do
+ it "should send an error complete event" do
+ expect_answered
+ error = ChannelGoneError.new 'FooBar'
+ mock_call.should_receive(:execute_agi_command).and_raise error
+ subject.execute
+ complete_reason = original_command.complete_event(0.1).reason
+ complete_reason.should be_a Punchblock::Event::Complete::Hangup
+ end
+ end
+
+ context "when the PLAYBACKSTATUS variable is set to 'FAILED'" do
+ let(:playbackstatus) { 'FAILED' }
+
+ it "should send an error complete event" do
+ expect_answered
+ mock_call.should_receive(:execute_agi_command).and_return code: 200, result: 1
+ subject.execute
+ complete_reason = original_command.complete_event(0.1).reason
+ complete_reason.should be_a Punchblock::Event::Complete::Error
+ complete_reason.details.should == "Terminated due to playback error"
+ end
+ end
end
context 'with a single text node without spaces' do
let(:audio_filename) { 'tt-monkeys' }
- let :command_options do
- {
- :ssml => RubySpeech::SSML.draw { string audio_filename }
- }
+ let :ssml_doc do
+ RubySpeech::SSML.draw { string audio_filename }
end
it 'should playback the audio file using Playback' do
expect_answered
expect_playback
@@ -484,11 +545,11 @@
it 'should send a complete event when the file finishes playback' do
expect_answered
expect_playback
subject.execute
- original_command.complete_event(0.1).reason.should be_a Punchblock::Component::Output::Complete::Success
+ original_command.complete_event(0.1).reason.should be_a Punchblock::Component::Output::Complete::Finish
end
context "when we get a RubyAMI Error" do
it "should send an error complete event" do
expect_answered
@@ -511,11 +572,13 @@
context "with interrupt_on set to something that is not nil" do
let(:audio_filename) { 'tt-monkeys' }
let :command_options do
{
- :ssml => RubySpeech::SSML.draw { string audio_filename },
+ :render_document => {
+ :value => RubySpeech::SSML.draw { string audio_filename },
+ },
:interrupt_on => :any
}
end
it "should return an error when the output is interruptible and it is early media" do
expect_answered false
@@ -525,32 +588,18 @@
end
end
end
end
- context 'with a string (not SSML)' do
- let :command_options do
- { :text => 'Foo Bar' }
- end
-
- it "should return an unrenderable document error" do
- subject.execute
- error = ProtocolError.new.setup 'unrenderable document error', 'The provided document could not be rendered. See http://adhearsion.com/docs/common_problems#unrenderable-document-error for details.'
- original_command.response(0.1).should be == error
- end
- end
-
context 'with multiple audio SSML nodes' do
let(:audio_filename1) { 'http://foo.com/bar.mp3' }
let(:audio_filename2) { 'http://foo.com/baz.mp3' }
- let :command_options do
- {
- :ssml => RubySpeech::SSML.draw do
- audio :src => audio_filename1
- audio :src => audio_filename2
- end
- }
+ let :ssml_doc do
+ RubySpeech::SSML.draw do
+ audio :src => audio_filename1
+ audio :src => audio_filename2
+ end
end
it 'should playback all audio files using Playback' do
latch = CountDownLatch.new 2
expect_playback [audio_filename1, audio_filename2].join('&')
@@ -563,25 +612,23 @@
it 'should send a complete event after the final file has finished playback' do
expect_answered
expect_playback [audio_filename1, audio_filename2].join('&')
latch = CountDownLatch.new 1
original_command.should_receive(:add_event).once.with do |e|
- e.reason.should be_a Punchblock::Component::Output::Complete::Success
+ e.reason.should be_a Punchblock::Component::Output::Complete::Finish
latch.countdown!
end
subject.execute
latch.wait(2).should be_true
end
end
context "with an SSML document containing elements other than <audio/>" do
- let :command_options do
- {
- :ssml => RubySpeech::SSML.draw do
- string "Foo Bar"
- end
- }
+ let :ssml_doc do
+ RubySpeech::SSML.draw do
+ string "Foo Bar"
+ end
end
it "should return an unrenderable document error" do
subject.execute
error = ProtocolError.new.setup 'unrenderable document error', 'The provided document could not be rendered. See http://adhearsion.com/docs/common_problems#unrenderable-document-error for details.'
@@ -748,11 +795,11 @@
let(:command_opts) { { :interrupt_on => :any } }
before do
expect_answered
mock_call.should_receive(:execute_agi_command).once.with('EXEC Playback', audio_filename)
- subject.wrapped_object.should_receive(:send_success).and_return nil
+ subject.wrapped_object.should_receive(:send_finish).and_return nil
end
context "when a DTMF digit is received" do
it "sends the correct complete event" do
mock_call.async.should_receive :redirect_back
@@ -761,11 +808,11 @@
original_command.should_not be_complete
send_ami_events_for_dtmf 1
mock_call.async.process_ami_event ami_event
sleep 0.2
original_command.should be_complete
- reason.should be_a Punchblock::Component::Output::Complete::Success
+ reason.should be_a Punchblock::Component::Output::Complete::Finish
end
it "redirects the call back to async AGI" do
mock_call.async.should_receive(:redirect_back).once
subject.execute
@@ -779,11 +826,11 @@
let(:command_opts) { { :interrupt_on => :dtmf } }
before do
expect_answered
mock_call.should_receive(:execute_agi_command).once.with('EXEC Playback', audio_filename)
- subject.wrapped_object.should_receive(:send_success).and_return nil
+ subject.wrapped_object.should_receive(:send_finish).and_return nil
end
context "when a DTMF digit is received" do
it "sends the correct complete event" do
mock_call.async.should_receive :redirect_back
@@ -792,11 +839,11 @@
original_command.should_not be_complete
send_ami_events_for_dtmf 1
mock_call.async.process_ami_event ami_event
sleep 0.2
original_command.should be_complete
- reason.should be_a Punchblock::Component::Output::Complete::Success
+ reason.should be_a Punchblock::Component::Output::Complete::Finish
end
it "redirects the call back to async AGI" do
mock_call.async.should_receive(:redirect_back).once
subject.execute
@@ -804,12 +851,12 @@
send_ami_events_for_dtmf 1
end
end
end
- context "set to :speech" do
- let(:command_opts) { { :interrupt_on => :speech } }
+ context "set to :voice" do
+ let(:command_opts) { { :interrupt_on => :voice } }
it "should return an error and not execute any actions" do
subject.execute
error = ProtocolError.new.setup 'option error', 'An interrupt-on value of speech is unsupported.'
original_command.response(0.1).should be == error
end
@@ -828,15 +875,18 @@
end
let(:command_opts) { {:renderer => :asterisk} }
let :command_options do
- { :ssml => ssml_doc }.merge(command_opts)
+ { :render_document => {:value => ssml_doc} }.merge(command_opts)
end
let :original_command do
Punchblock::Component::Output.new command_options
end
+
+ let(:playbackstatus) { 'SUCCESS' }
+ before { mock_call.stub(:channel_var).with('PLAYBACKSTATUS').and_return playbackstatus }
it "should use the media renderer set and not the platform default" do
expect_answered
mock_call.should_receive(:execute_agi_command).once.with 'EXEC Playback', audio_filename
subject.execute