punchblock 2.6.0 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/lib/punchblock/component/output.rb +12 -4
- data/lib/punchblock/translator/asterisk.rb +3 -4
- data/lib/punchblock/translator/asterisk/agi_command.rb +3 -0
- data/lib/punchblock/translator/asterisk/call.rb +53 -7
- data/lib/punchblock/translator/asterisk/component/asterisk/agi_command.rb +1 -1
- data/lib/punchblock/translator/asterisk/component/composed_prompt.rb +1 -1
- data/lib/punchblock/translator/asterisk/component/input.rb +1 -1
- data/lib/punchblock/translator/asterisk/component/mrcp_native_prompt.rb +14 -2
- data/lib/punchblock/translator/asterisk/component/mrcp_recog_prompt.rb +39 -0
- data/lib/punchblock/translator/asterisk/component/output.rb +1 -1
- data/lib/punchblock/translator/asterisk/component/stop_by_redirect.rb +1 -1
- data/lib/punchblock/version.rb +1 -1
- data/spec/punchblock/translator/asterisk/call_spec.rb +250 -35
- data/spec/punchblock/translator/asterisk/component/asterisk/agi_command_spec.rb +55 -2
- data/spec/punchblock/translator/asterisk/component/composed_prompt_spec.rb +24 -5
- data/spec/punchblock/translator/asterisk/component/input_spec.rb +26 -5
- data/spec/punchblock/translator/asterisk/component/mrcp_native_prompt_spec.rb +42 -2
- data/spec/punchblock/translator/asterisk/component/mrcp_prompt_spec.rb +479 -0
- data/spec/punchblock/translator/asterisk/component/output_spec.rb +40 -17
- data/spec/punchblock/translator/asterisk/component/stop_by_redirect_spec.rb +4 -3
- data/spec/punchblock/translator/asterisk_spec.rb +36 -9
- metadata +2 -2
|
@@ -112,22 +112,31 @@ module Punchblock
|
|
|
112
112
|
context 'of type start'
|
|
113
113
|
|
|
114
114
|
context 'of type Exec' do
|
|
115
|
+
let (:ami_event_result) { "200%20result=123%20(timeout)%0A" }
|
|
115
116
|
let(:ami_event) do
|
|
116
117
|
RubyAMI::Event.new 'AsyncAGI',
|
|
117
118
|
"SubEvent" => "Exec",
|
|
118
119
|
"Channel" => channel,
|
|
119
120
|
"CommandId" => component_id,
|
|
120
121
|
"Command" => "EXEC ANSWER",
|
|
121
|
-
"Result" =>
|
|
122
|
+
"Result" => ami_event_result
|
|
122
123
|
end
|
|
123
124
|
|
|
125
|
+
let(:ami_event_ast13) do
|
|
126
|
+
RubyAMI::Event.new 'AsyncAGIExec',
|
|
127
|
+
"Channel" => channel,
|
|
128
|
+
"CommandId" => component_id,
|
|
129
|
+
"Command" => "EXEC ANSWER",
|
|
130
|
+
"Result" => ami_event_result
|
|
131
|
+
end
|
|
132
|
+
|
|
124
133
|
let :expected_complete_reason do
|
|
125
134
|
Punchblock::Component::Asterisk::AGI::Command::Complete::Success.new :code => 200,
|
|
126
135
|
:result => 123,
|
|
127
136
|
:data => 'timeout'
|
|
128
137
|
end
|
|
129
138
|
|
|
130
|
-
|
|
139
|
+
def should_send_complete_event
|
|
131
140
|
subject.handle_ami_event ami_event
|
|
132
141
|
|
|
133
142
|
complete_event = original_command.complete_event 0.5
|
|
@@ -138,6 +147,50 @@ module Punchblock
|
|
|
138
147
|
expect(complete_event.reason).to eq(expected_complete_reason)
|
|
139
148
|
end
|
|
140
149
|
|
|
150
|
+
it 'should send a complete event' do
|
|
151
|
+
should_send_complete_event
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
context 'with an AsyncAGIExec event' do
|
|
155
|
+
let(:ami_event) { ami_event_ast13 }
|
|
156
|
+
|
|
157
|
+
it 'should send a complete event' do
|
|
158
|
+
should_send_complete_event
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
context 'when the result contains illegal characters in the AGI response' do
|
|
163
|
+
let (:ami_event_result) { '$' }
|
|
164
|
+
let :expected_complete_reason do
|
|
165
|
+
Punchblock::Component::Asterisk::AGI::Command::Complete::Success.new :code => -1,
|
|
166
|
+
:result => nil,
|
|
167
|
+
:data => nil
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def treat_as_failure
|
|
171
|
+
subject.handle_ami_event ami_event
|
|
172
|
+
|
|
173
|
+
complete_event = original_command.complete_event 0.5
|
|
174
|
+
|
|
175
|
+
expect(original_command).to be_complete
|
|
176
|
+
|
|
177
|
+
expect(complete_event.component_id).to eq(component_id.to_s)
|
|
178
|
+
expect(complete_event.reason).to eq(expected_complete_reason)
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
it 'treats it as a failure with code -1' do
|
|
182
|
+
treat_as_failure
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
context 'with an AsyncAGIExec event' do
|
|
186
|
+
let(:ami_event) { ami_event_ast13 }
|
|
187
|
+
|
|
188
|
+
it 'treats it as a failure with code -1' do
|
|
189
|
+
treat_as_failure
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
141
194
|
context "when the command was ASYNCAGI BREAK" do
|
|
142
195
|
let :original_command do
|
|
143
196
|
Punchblock::Component::Asterisk::AGI::Command.new :name => 'ASYNCAGI BREAK'
|
|
@@ -76,11 +76,18 @@ module Punchblock
|
|
|
76
76
|
original_command.request!
|
|
77
77
|
end
|
|
78
78
|
|
|
79
|
+
let (:ast13mode) { false }
|
|
80
|
+
|
|
79
81
|
def ami_event_for_dtmf(digit, position)
|
|
80
|
-
|
|
81
|
-
'
|
|
82
|
-
|
|
83
|
-
|
|
82
|
+
if ast13mode
|
|
83
|
+
RubyAMI::Event.new 'DTMF' + (position == :start ? 'Begin' : '') + (position == :end ? 'End' : ''),
|
|
84
|
+
'Digit' => digit.to_s
|
|
85
|
+
else
|
|
86
|
+
RubyAMI::Event.new 'DTMF',
|
|
87
|
+
'Digit' => digit.to_s,
|
|
88
|
+
'Start' => position == :start ? 'Yes' : 'No',
|
|
89
|
+
'End' => position == :end ? 'Yes' : 'No'
|
|
90
|
+
end
|
|
84
91
|
end
|
|
85
92
|
|
|
86
93
|
def send_ami_events_for_dtmf(digit)
|
|
@@ -163,7 +170,7 @@ module Punchblock
|
|
|
163
170
|
Punchblock::Component::Input::Complete::Match.new nlsml: expected_nlsml
|
|
164
171
|
end
|
|
165
172
|
|
|
166
|
-
|
|
173
|
+
def should_return_a_match_complete_event
|
|
167
174
|
expected_event
|
|
168
175
|
subject.execute
|
|
169
176
|
expect(original_command.response(0.1)).to be_a Ref
|
|
@@ -171,6 +178,18 @@ module Punchblock
|
|
|
171
178
|
|
|
172
179
|
expect(connection.events).to include(expected_event)
|
|
173
180
|
end
|
|
181
|
+
|
|
182
|
+
it "should return a match complete event" do
|
|
183
|
+
should_return_a_match_complete_event
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
context 'with Asterisk 13 DTMFEnd event' do
|
|
187
|
+
let (:ast13mode) { true }
|
|
188
|
+
|
|
189
|
+
it "should return a match complete event" do
|
|
190
|
+
should_return_a_match_complete_event
|
|
191
|
+
end
|
|
192
|
+
end
|
|
174
193
|
end
|
|
175
194
|
|
|
176
195
|
context "when not receiving any DTMF input at all" do
|
|
@@ -52,11 +52,18 @@ module Punchblock
|
|
|
52
52
|
{ :mode => :dtmf, :grammar => { :value => grammar } }.merge(original_command_opts)
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
+
let (:ast13mode) { false }
|
|
56
|
+
|
|
55
57
|
def ami_event_for_dtmf(digit, position)
|
|
56
|
-
|
|
57
|
-
'
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
if ast13mode
|
|
59
|
+
RubyAMI::Event.new 'DTMF' + (position == :start ? 'Begin' : '') + (position == :end ? 'End' : ''),
|
|
60
|
+
'Digit' => digit.to_s
|
|
61
|
+
else
|
|
62
|
+
RubyAMI::Event.new 'DTMF',
|
|
63
|
+
'Digit' => digit.to_s,
|
|
64
|
+
'Start' => position == :start ? 'Yes' : 'No',
|
|
65
|
+
'End' => position == :end ? 'Yes' : 'No'
|
|
66
|
+
end
|
|
60
67
|
end
|
|
61
68
|
|
|
62
69
|
def send_ami_events_for_dtmf(digit)
|
|
@@ -101,7 +108,14 @@ module Punchblock
|
|
|
101
108
|
end
|
|
102
109
|
|
|
103
110
|
it "should not leave the recognizer running" do
|
|
104
|
-
expect(Celluloid::Actor.all.
|
|
111
|
+
expect(Celluloid::Actor.all.any? { |a| a.class == Punchblock::Translator::DTMFRecognizer rescue false }).to eq(false)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
context 'with an Asterisk 13 DTMFEnd event' do
|
|
115
|
+
let(:ast13mode) { true }
|
|
116
|
+
it "should send a success complete event with the relevant data" do
|
|
117
|
+
expect(reason).to eq(expected_event)
|
|
118
|
+
end
|
|
105
119
|
end
|
|
106
120
|
end
|
|
107
121
|
|
|
@@ -118,6 +132,13 @@ module Punchblock
|
|
|
118
132
|
it "should send a nomatch complete event" do
|
|
119
133
|
expect(reason).to eq(expected_event)
|
|
120
134
|
end
|
|
135
|
+
|
|
136
|
+
context 'with an Asterisk 13 DTMFEnd event' do
|
|
137
|
+
let(:ast13mode) { true }
|
|
138
|
+
it "should send a nomatch complete event" do
|
|
139
|
+
expect(reason).to eq(expected_event)
|
|
140
|
+
end
|
|
141
|
+
end
|
|
121
142
|
end
|
|
122
143
|
|
|
123
144
|
context "dtmf event received after recognizer has terminated" do
|
|
@@ -51,10 +51,11 @@ module Punchblock
|
|
|
51
51
|
|
|
52
52
|
let(:output_command_opts) { {} }
|
|
53
53
|
|
|
54
|
-
let(:audio_filename) { '
|
|
54
|
+
let(:audio_filename) { '/var/foo' }
|
|
55
|
+
let(:audio_path) { "file://#{audio_filename}.wav" }
|
|
55
56
|
|
|
56
57
|
let :output_command_options do
|
|
57
|
-
{ render_document: {value: [
|
|
58
|
+
{ render_document: {value: [audio_path], content_type: 'text/uri-list'} }.merge(output_command_opts)
|
|
58
59
|
end
|
|
59
60
|
|
|
60
61
|
let(:input_command_opts) { {} }
|
|
@@ -158,6 +159,23 @@ module Punchblock
|
|
|
158
159
|
end
|
|
159
160
|
end
|
|
160
161
|
|
|
162
|
+
context 'with multiple audio tags in SSML' do
|
|
163
|
+
let :ssml_doc do
|
|
164
|
+
RubySpeech::SSML.draw do
|
|
165
|
+
audio(src: audio_path)
|
|
166
|
+
audio(src: audio_path)
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
let(:output_command_options) { { render_documents: [{value: ssml_doc}] } }
|
|
171
|
+
|
|
172
|
+
it "should return an error and not execute any actions" do
|
|
173
|
+
subject.execute
|
|
174
|
+
error = ProtocolError.new.setup 'option error', 'Only one audio file is allowed.'
|
|
175
|
+
expect(original_command.response(0.1)).to eq(error)
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
161
179
|
context 'unset' do
|
|
162
180
|
let(:output_command_options) { {} }
|
|
163
181
|
|
|
@@ -181,6 +199,28 @@ module Punchblock
|
|
|
181
199
|
expect(original_command.response(0.1)).to be_a Ref
|
|
182
200
|
end
|
|
183
201
|
|
|
202
|
+
context "when the render document is SSML" do
|
|
203
|
+
let :ssml_doc do
|
|
204
|
+
RubySpeech::SSML.draw do
|
|
205
|
+
audio(src: audio_path)
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
let(:output_command_opts) do
|
|
210
|
+
{
|
|
211
|
+
renderer: renderer,
|
|
212
|
+
render_document: {value: ssml_doc}
|
|
213
|
+
}
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
it "should return a ref and execute MRCPRecog" do
|
|
217
|
+
param = ["\"#{grammar.to_doc.to_s.squish.gsub('"', '\"')}\"", "uer=1&b=1&f=#{audio_filename}"].join(',')
|
|
218
|
+
expect(mock_call).to receive(:execute_agi_command).once.with('EXEC MRCPRecog', param).and_return code: 200, result: 1
|
|
219
|
+
subject.execute
|
|
220
|
+
expect(original_command.response(0.1)).to be_a Ref
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
184
224
|
context "when MRCPRecog completes" do
|
|
185
225
|
shared_context "with a match" do
|
|
186
226
|
let :expected_nlsml do
|
|
@@ -612,6 +612,485 @@ module Punchblock
|
|
|
612
612
|
end
|
|
613
613
|
end
|
|
614
614
|
|
|
615
|
+
describe 'Input#max-silence' do
|
|
616
|
+
context 'a positive number' do
|
|
617
|
+
let(:input_command_opts) { { max_silence: 1000 } }
|
|
618
|
+
|
|
619
|
+
it 'should pass the sint option to SynthAndRecog' do
|
|
620
|
+
expect_synthandrecog_with_options(/sint=1000/)
|
|
621
|
+
subject.execute
|
|
622
|
+
end
|
|
623
|
+
end
|
|
624
|
+
|
|
625
|
+
context '0' do
|
|
626
|
+
let(:input_command_opts) { { max_silence: 0 } }
|
|
627
|
+
|
|
628
|
+
it 'should pass the sint option to SynthAndRecog' do
|
|
629
|
+
expect_synthandrecog_with_options(/sint=0/)
|
|
630
|
+
subject.execute
|
|
631
|
+
end
|
|
632
|
+
end
|
|
633
|
+
|
|
634
|
+
context 'a negative number' do
|
|
635
|
+
let(:input_command_opts) { { max_silence: -1000 } }
|
|
636
|
+
|
|
637
|
+
it "should return an error and not execute any actions" do
|
|
638
|
+
subject.execute
|
|
639
|
+
error = ProtocolError.new.setup 'option error', 'A max-silence value must be -1, 0, or a positive integer.'
|
|
640
|
+
expect(original_command.response(0.1)).to eq(error)
|
|
641
|
+
end
|
|
642
|
+
end
|
|
643
|
+
|
|
644
|
+
context 'unset' do
|
|
645
|
+
let(:input_command_opts) { { max_silence: nil } }
|
|
646
|
+
|
|
647
|
+
it 'should not pass any options to SynthAndRecog' do
|
|
648
|
+
expect_synthandrecog_with_options(//)
|
|
649
|
+
subject.execute
|
|
650
|
+
end
|
|
651
|
+
end
|
|
652
|
+
end
|
|
653
|
+
|
|
654
|
+
describe 'Input#speech-complete-timeout' do
|
|
655
|
+
context 'a positive number' do
|
|
656
|
+
let(:input_command_opts) { { headers: {"Speech-Complete-Timeout" => 1000 } } }
|
|
657
|
+
|
|
658
|
+
it 'should pass the sct option to SynthAndRecog' do
|
|
659
|
+
expect_synthandrecog_with_options(/sct=1000/)
|
|
660
|
+
subject.execute
|
|
661
|
+
end
|
|
662
|
+
end
|
|
663
|
+
|
|
664
|
+
context '0' do
|
|
665
|
+
let(:input_command_opts) { { headers: {"Speech-Complete-Timeout" => 0 } } }
|
|
666
|
+
|
|
667
|
+
it 'should pass the sct option to SynthAndRecog' do
|
|
668
|
+
expect_synthandrecog_with_options(/sct=0/)
|
|
669
|
+
subject.execute
|
|
670
|
+
end
|
|
671
|
+
end
|
|
672
|
+
|
|
673
|
+
context 'a negative number' do
|
|
674
|
+
let(:input_command_opts) { { headers: {"Speech-Complete-Timeout" => -1000 } } }
|
|
675
|
+
|
|
676
|
+
it "should return an error and not execute any actions" do
|
|
677
|
+
subject.execute
|
|
678
|
+
error = ProtocolError.new.setup 'option error', 'A speech-complete-timeout value must be -1, 0, or a positive integer.'
|
|
679
|
+
expect(original_command.response(0.1)).to eq(error)
|
|
680
|
+
end
|
|
681
|
+
end
|
|
682
|
+
|
|
683
|
+
context 'unset' do
|
|
684
|
+
let(:input_command_opts) { { headers: {"Speech-Complete-Timeout" => nil } } }
|
|
685
|
+
|
|
686
|
+
it 'should not pass any options to SynthAndRecog' do
|
|
687
|
+
expect_synthandrecog_with_options(//)
|
|
688
|
+
subject.execute
|
|
689
|
+
end
|
|
690
|
+
end
|
|
691
|
+
end
|
|
692
|
+
|
|
693
|
+
describe 'Input#headers(Speed-Vs-Accuracy)' do
|
|
694
|
+
context 'a positive number' do
|
|
695
|
+
let(:input_command_opts) { { headers: {"Speed-Vs-Accuracy" => 1 } } }
|
|
696
|
+
|
|
697
|
+
it 'should pass the sva option to SynthAndRecog' do
|
|
698
|
+
expect_synthandrecog_with_options(/sva=1/)
|
|
699
|
+
subject.execute
|
|
700
|
+
end
|
|
701
|
+
end
|
|
702
|
+
|
|
703
|
+
context '0' do
|
|
704
|
+
let(:input_command_opts) { { headers: {"Speed-Vs-Accuracy" => 0 } } }
|
|
705
|
+
|
|
706
|
+
it 'should pass the sva option to SynthAndRecog' do
|
|
707
|
+
expect_synthandrecog_with_options(/sva=0/)
|
|
708
|
+
subject.execute
|
|
709
|
+
end
|
|
710
|
+
end
|
|
711
|
+
|
|
712
|
+
context 'a negative number' do
|
|
713
|
+
let(:input_command_opts) { { headers: {"Speed-Vs-Accuracy" => -1000 } } }
|
|
714
|
+
|
|
715
|
+
it "should return an error and not execute any actions" do
|
|
716
|
+
subject.execute
|
|
717
|
+
error = ProtocolError.new.setup 'option error', 'A speed-vs-accuracy value must be a positive integer.'
|
|
718
|
+
expect(original_command.response(0.1)).to eq(error)
|
|
719
|
+
end
|
|
720
|
+
end
|
|
721
|
+
|
|
722
|
+
context 'unset' do
|
|
723
|
+
let(:input_command_opts) { { headers: {"Speed-Vs-Accuracy" => nil } } }
|
|
724
|
+
|
|
725
|
+
it 'should not pass any options to SynthAndRecog' do
|
|
726
|
+
expect_synthandrecog_with_options(//)
|
|
727
|
+
subject.execute
|
|
728
|
+
end
|
|
729
|
+
end
|
|
730
|
+
end
|
|
731
|
+
|
|
732
|
+
describe 'Input#headers(N-Best-List-Length)' do
|
|
733
|
+
context 'a positive number' do
|
|
734
|
+
let(:input_command_opts) { { headers: {"N-Best-List-Length" => 5 } } }
|
|
735
|
+
|
|
736
|
+
it 'should pass the nb option to SynthAndRecog' do
|
|
737
|
+
expect_synthandrecog_with_options(/nb=5/)
|
|
738
|
+
subject.execute
|
|
739
|
+
end
|
|
740
|
+
end
|
|
741
|
+
|
|
742
|
+
context '0' do
|
|
743
|
+
let(:input_command_opts) { { headers: {"N-Best-List-Length" => 0 } } }
|
|
744
|
+
|
|
745
|
+
it "should return an error and not execute any actions" do
|
|
746
|
+
subject.execute
|
|
747
|
+
error = ProtocolError.new.setup 'option error', 'An n-best-list-length value must be a positive integer.'
|
|
748
|
+
expect(original_command.response(0.1)).to eq(error)
|
|
749
|
+
end
|
|
750
|
+
end
|
|
751
|
+
|
|
752
|
+
context 'a negative number' do
|
|
753
|
+
let(:input_command_opts) { { headers: {"N-Best-List-Length" => -1000 } } }
|
|
754
|
+
|
|
755
|
+
it "should return an error and not execute any actions" do
|
|
756
|
+
subject.execute
|
|
757
|
+
error = ProtocolError.new.setup 'option error', 'An n-best-list-length value must be a positive integer.'
|
|
758
|
+
expect(original_command.response(0.1)).to eq(error)
|
|
759
|
+
end
|
|
760
|
+
end
|
|
761
|
+
|
|
762
|
+
context 'unset' do
|
|
763
|
+
let(:input_command_opts) { { headers: {"N-Best-List-Length" => nil } } }
|
|
764
|
+
|
|
765
|
+
it 'should not pass any options to SynthAndRecog' do
|
|
766
|
+
expect_synthandrecog_with_options(//)
|
|
767
|
+
subject.execute
|
|
768
|
+
end
|
|
769
|
+
end
|
|
770
|
+
end
|
|
771
|
+
|
|
772
|
+
describe 'Input#headers(Start-Input-Timers)' do
|
|
773
|
+
context 'true' do
|
|
774
|
+
let(:input_command_opts) { { headers: {"Start-Input-Timers" => true } } }
|
|
775
|
+
|
|
776
|
+
it 'should pass the sit option to SynthAndRecog' do
|
|
777
|
+
expect_synthandrecog_with_options(/sit=true/)
|
|
778
|
+
subject.execute
|
|
779
|
+
end
|
|
780
|
+
end
|
|
781
|
+
|
|
782
|
+
context 'false' do
|
|
783
|
+
let(:input_command_opts) { { headers: {"Start-Input-Timers" => false } } }
|
|
784
|
+
|
|
785
|
+
it 'should pass the sit option to SynthAndRecog' do
|
|
786
|
+
expect_synthandrecog_with_options(/sit=false/)
|
|
787
|
+
subject.execute
|
|
788
|
+
end
|
|
789
|
+
end
|
|
790
|
+
|
|
791
|
+
context 'unset' do
|
|
792
|
+
let(:input_command_opts) { { headers: {"Start-Input-Timers" => nil } } }
|
|
793
|
+
|
|
794
|
+
it 'should not pass any options to SynthAndRecog' do
|
|
795
|
+
expect_synthandrecog_with_options(//)
|
|
796
|
+
subject.execute
|
|
797
|
+
end
|
|
798
|
+
end
|
|
799
|
+
end
|
|
800
|
+
|
|
801
|
+
describe 'Input#headers(DTMF-Terminate-Timeout)' do
|
|
802
|
+
context 'a positive number' do
|
|
803
|
+
let(:input_command_opts) { { headers: {"DTMF-Terminate-Timeout" => 1000 } } }
|
|
804
|
+
|
|
805
|
+
it 'should pass the dtt option to SynthAndRecog' do
|
|
806
|
+
expect_synthandrecog_with_options(/dtt=1000/)
|
|
807
|
+
subject.execute
|
|
808
|
+
end
|
|
809
|
+
end
|
|
810
|
+
|
|
811
|
+
context '0' do
|
|
812
|
+
let(:input_command_opts) { { headers: {"DTMF-Terminate-Timeout" => 0 } } }
|
|
813
|
+
|
|
814
|
+
it 'should pass the dtt option to SynthAndRecog' do
|
|
815
|
+
expect_synthandrecog_with_options(/dtt=0/)
|
|
816
|
+
subject.execute
|
|
817
|
+
end
|
|
818
|
+
end
|
|
819
|
+
|
|
820
|
+
context 'a negative number' do
|
|
821
|
+
let(:input_command_opts) { { headers: {"DTMF-Terminate-Timeout" => -1000 } } }
|
|
822
|
+
|
|
823
|
+
it "should return an error and not execute any actions" do
|
|
824
|
+
subject.execute
|
|
825
|
+
error = ProtocolError.new.setup 'option error', 'A dtmf-terminate-timeout value must be -1, 0, or a positive integer.'
|
|
826
|
+
expect(original_command.response(0.1)).to eq(error)
|
|
827
|
+
end
|
|
828
|
+
end
|
|
829
|
+
|
|
830
|
+
context 'unset' do
|
|
831
|
+
let(:input_command_opts) { { headers: {"DTMF-Terminate-Timeout" => nil } } }
|
|
832
|
+
|
|
833
|
+
it 'should not pass any options to SynthAndRecog' do
|
|
834
|
+
expect_synthandrecog_with_options(//)
|
|
835
|
+
subject.execute
|
|
836
|
+
end
|
|
837
|
+
end
|
|
838
|
+
end
|
|
839
|
+
|
|
840
|
+
describe 'Input#headers(Save-Waveform)' do
|
|
841
|
+
context 'true' do
|
|
842
|
+
let(:input_command_opts) { { headers: {"Save-Waveform" => true } } }
|
|
843
|
+
|
|
844
|
+
it 'should pass the sw option to SynthAndRecog' do
|
|
845
|
+
expect_synthandrecog_with_options(/sw=true/)
|
|
846
|
+
subject.execute
|
|
847
|
+
end
|
|
848
|
+
end
|
|
849
|
+
|
|
850
|
+
context 'false' do
|
|
851
|
+
let(:input_command_opts) { { headers: {"Save-Waveform" => false } } }
|
|
852
|
+
|
|
853
|
+
it 'should pass the sw option to SynthAndRecog' do
|
|
854
|
+
expect_synthandrecog_with_options(/sw=false/)
|
|
855
|
+
subject.execute
|
|
856
|
+
end
|
|
857
|
+
end
|
|
858
|
+
|
|
859
|
+
context 'unset' do
|
|
860
|
+
let(:input_command_opts) { { headers: {"Save-Waveform" => nil } } }
|
|
861
|
+
|
|
862
|
+
it 'should not pass any options to SynthAndRecog' do
|
|
863
|
+
expect_synthandrecog_with_options(//)
|
|
864
|
+
subject.execute
|
|
865
|
+
end
|
|
866
|
+
end
|
|
867
|
+
end
|
|
868
|
+
|
|
869
|
+
describe 'Input#headers(New-Audio-Channel)' do
|
|
870
|
+
context 'true' do
|
|
871
|
+
let(:input_command_opts) { { headers: {"New-Audio-Channel" => true } } }
|
|
872
|
+
|
|
873
|
+
it 'should pass the nac option to SynthAndRecog' do
|
|
874
|
+
expect_synthandrecog_with_options(/nac=true/)
|
|
875
|
+
subject.execute
|
|
876
|
+
end
|
|
877
|
+
end
|
|
878
|
+
|
|
879
|
+
context 'false' do
|
|
880
|
+
let(:input_command_opts) { { headers: {"New-Audio-Channel" => false } } }
|
|
881
|
+
|
|
882
|
+
it 'should pass the nac option to SynthAndRecog' do
|
|
883
|
+
expect_synthandrecog_with_options(/nac=false/)
|
|
884
|
+
subject.execute
|
|
885
|
+
end
|
|
886
|
+
end
|
|
887
|
+
|
|
888
|
+
context 'unset' do
|
|
889
|
+
let(:input_command_opts) { { headers: {"New-Audio-Channel" => nil } } }
|
|
890
|
+
|
|
891
|
+
it 'should not pass any options to SynthAndRecog' do
|
|
892
|
+
expect_synthandrecog_with_options(//)
|
|
893
|
+
subject.execute
|
|
894
|
+
end
|
|
895
|
+
end
|
|
896
|
+
end
|
|
897
|
+
|
|
898
|
+
describe 'Input#headers(Recognition-Mode)' do
|
|
899
|
+
context 'a string' do
|
|
900
|
+
let(:input_command_opts) { { headers: {"Recognition-Mode" => "hotword" } } }
|
|
901
|
+
|
|
902
|
+
it 'should pass the rm option to SynthAndRecog' do
|
|
903
|
+
expect_synthandrecog_with_options(/rm=hotword/)
|
|
904
|
+
subject.execute
|
|
905
|
+
end
|
|
906
|
+
end
|
|
907
|
+
|
|
908
|
+
context 'unset' do
|
|
909
|
+
let(:input_command_opts) { { headers: {"Recognition-Mode" => nil } } }
|
|
910
|
+
|
|
911
|
+
it 'should not pass any options to SynthAndRecog' do
|
|
912
|
+
expect_synthandrecog_with_options(//)
|
|
913
|
+
subject.execute
|
|
914
|
+
end
|
|
915
|
+
end
|
|
916
|
+
end
|
|
917
|
+
|
|
918
|
+
describe 'Input#headers(Hotword-Max-Duration)' do
|
|
919
|
+
context 'a positive number' do
|
|
920
|
+
let(:input_command_opts) { { headers: {"Hotword-Max-Duration" => 1000 } } }
|
|
921
|
+
|
|
922
|
+
it 'should pass the hmaxd option to SynthAndRecog' do
|
|
923
|
+
expect_synthandrecog_with_options(/hmaxd=1000/)
|
|
924
|
+
subject.execute
|
|
925
|
+
end
|
|
926
|
+
end
|
|
927
|
+
|
|
928
|
+
context '0' do
|
|
929
|
+
let(:input_command_opts) { { headers: {"Hotword-Max-Duration" => 0 } } }
|
|
930
|
+
|
|
931
|
+
it 'should pass the hmaxd option to SynthAndRecog' do
|
|
932
|
+
expect_synthandrecog_with_options(/hmaxd=0/)
|
|
933
|
+
subject.execute
|
|
934
|
+
end
|
|
935
|
+
end
|
|
936
|
+
|
|
937
|
+
context 'a negative number' do
|
|
938
|
+
let(:input_command_opts) { { headers: {"Hotword-Max-Duration" => -1000 } } }
|
|
939
|
+
|
|
940
|
+
it "should return an error and not execute any actions" do
|
|
941
|
+
subject.execute
|
|
942
|
+
error = ProtocolError.new.setup 'option error', 'A hotword-max-duration value must be -1, 0, or a positive integer.'
|
|
943
|
+
expect(original_command.response(0.1)).to eq(error)
|
|
944
|
+
end
|
|
945
|
+
end
|
|
946
|
+
|
|
947
|
+
context 'unset' do
|
|
948
|
+
let(:input_command_opts) { { headers: {"Hotword-Max-Duration" => nil } } }
|
|
949
|
+
|
|
950
|
+
it 'should not pass any options to SynthAndRecog' do
|
|
951
|
+
expect_synthandrecog_with_options(//)
|
|
952
|
+
subject.execute
|
|
953
|
+
end
|
|
954
|
+
end
|
|
955
|
+
end
|
|
956
|
+
|
|
957
|
+
describe 'Input#headers(Hotword-Min-Duration)' do
|
|
958
|
+
context 'a positive number' do
|
|
959
|
+
let(:input_command_opts) { { headers: {"Hotword-Min-Duration" => 1000 } } }
|
|
960
|
+
|
|
961
|
+
it 'should pass the hmind option to SynthAndRecog' do
|
|
962
|
+
expect_synthandrecog_with_options(/hmind=1000/)
|
|
963
|
+
subject.execute
|
|
964
|
+
end
|
|
965
|
+
end
|
|
966
|
+
|
|
967
|
+
context '0' do
|
|
968
|
+
let(:input_command_opts) { { headers: {"Hotword-Min-Duration" => 0 } } }
|
|
969
|
+
|
|
970
|
+
it 'should pass the hmind option to SynthAndRecog' do
|
|
971
|
+
expect_synthandrecog_with_options(/hmind=0/)
|
|
972
|
+
subject.execute
|
|
973
|
+
end
|
|
974
|
+
end
|
|
975
|
+
|
|
976
|
+
context 'a negative number' do
|
|
977
|
+
let(:input_command_opts) { { headers: {"Hotword-Min-Duration" => -1000 } } }
|
|
978
|
+
|
|
979
|
+
it "should return an error and not execute any actions" do
|
|
980
|
+
subject.execute
|
|
981
|
+
error = ProtocolError.new.setup 'option error', 'A hotword-min-duration value must be -1, 0, or a positive integer.'
|
|
982
|
+
expect(original_command.response(0.1)).to eq(error)
|
|
983
|
+
end
|
|
984
|
+
end
|
|
985
|
+
|
|
986
|
+
context 'unset' do
|
|
987
|
+
let(:input_command_opts) { { headers: {"Hotword-Min-Duration" => nil } } }
|
|
988
|
+
|
|
989
|
+
it 'should not pass any options to SynthAndRecog' do
|
|
990
|
+
expect_synthandrecog_with_options(//)
|
|
991
|
+
subject.execute
|
|
992
|
+
end
|
|
993
|
+
end
|
|
994
|
+
end
|
|
995
|
+
|
|
996
|
+
describe 'Input#headers(Clear-DTMF-Buffer)' do
|
|
997
|
+
context 'true' do
|
|
998
|
+
let(:input_command_opts) { { headers: {"Clear-DTMF-Buffer" => true } } }
|
|
999
|
+
|
|
1000
|
+
it 'should pass the cdb option to SynthAndRecog' do
|
|
1001
|
+
expect_synthandrecog_with_options(/cdb=true/)
|
|
1002
|
+
subject.execute
|
|
1003
|
+
end
|
|
1004
|
+
end
|
|
1005
|
+
|
|
1006
|
+
context 'false' do
|
|
1007
|
+
let(:input_command_opts) { { headers: {"Clear-DTMF-Buffer" => false } } }
|
|
1008
|
+
|
|
1009
|
+
it 'should pass the cdb option to SynthAndRecog' do
|
|
1010
|
+
expect_synthandrecog_with_options(/cdb=false/)
|
|
1011
|
+
subject.execute
|
|
1012
|
+
end
|
|
1013
|
+
end
|
|
1014
|
+
|
|
1015
|
+
context 'unset' do
|
|
1016
|
+
let(:input_command_opts) { { headers: {"Clear-DTMF-Buffer" => nil } } }
|
|
1017
|
+
|
|
1018
|
+
it 'should not pass any options to SynthAndRecog' do
|
|
1019
|
+
expect_synthandrecog_with_options(//)
|
|
1020
|
+
subject.execute
|
|
1021
|
+
end
|
|
1022
|
+
end
|
|
1023
|
+
end
|
|
1024
|
+
|
|
1025
|
+
describe 'Input#headers(Early-No-Match)' do
|
|
1026
|
+
context 'true' do
|
|
1027
|
+
let(:input_command_opts) { { headers: {"Early-No-Match" => true } } }
|
|
1028
|
+
|
|
1029
|
+
it 'should pass the enm option to SynthAndRecog' do
|
|
1030
|
+
expect_synthandrecog_with_options(/enm=true/)
|
|
1031
|
+
subject.execute
|
|
1032
|
+
end
|
|
1033
|
+
end
|
|
1034
|
+
|
|
1035
|
+
context 'a negative number' do
|
|
1036
|
+
let(:input_command_opts) { { headers: {"Early-No-Match" => false } } }
|
|
1037
|
+
|
|
1038
|
+
it "should return an error and not execute any actions" do
|
|
1039
|
+
expect_synthandrecog_with_options(/enm=false/)
|
|
1040
|
+
subject.execute
|
|
1041
|
+
end
|
|
1042
|
+
end
|
|
1043
|
+
|
|
1044
|
+
context 'unset' do
|
|
1045
|
+
let(:input_command_opts) { { headers: {"Early-No-Match" => nil } } }
|
|
1046
|
+
|
|
1047
|
+
it 'should not pass any options to SynthAndRecog' do
|
|
1048
|
+
expect_synthandrecog_with_options(//)
|
|
1049
|
+
subject.execute
|
|
1050
|
+
end
|
|
1051
|
+
end
|
|
1052
|
+
end
|
|
1053
|
+
|
|
1054
|
+
describe 'Input#headers(Input-Waveform-URI)' do
|
|
1055
|
+
context 'a positive number' do
|
|
1056
|
+
let(:input_command_opts) { { headers: {"Input-Waveform-URI" => 'http://wave.form.com' } } }
|
|
1057
|
+
|
|
1058
|
+
it 'should pass the iwu option to SynthAndRecog' do
|
|
1059
|
+
expect_synthandrecog_with_options(/iwu=http:\/\/wave\.form\.com/)
|
|
1060
|
+
subject.execute
|
|
1061
|
+
end
|
|
1062
|
+
end
|
|
1063
|
+
|
|
1064
|
+
context 'unset' do
|
|
1065
|
+
let(:input_command_opts) { { headers: {"Input-Waveform-URI" => nil } } }
|
|
1066
|
+
|
|
1067
|
+
it 'should not pass any options to SynthAndRecog' do
|
|
1068
|
+
expect_synthandrecog_with_options(//)
|
|
1069
|
+
subject.execute
|
|
1070
|
+
end
|
|
1071
|
+
end
|
|
1072
|
+
end
|
|
1073
|
+
|
|
1074
|
+
describe 'Input#headers(Media-Type)' do
|
|
1075
|
+
context 'a string' do
|
|
1076
|
+
let(:input_command_opts) { { headers: {"Media-Type" => "foo/type" } } }
|
|
1077
|
+
|
|
1078
|
+
it 'should pass the mt option to SynthAndRecog' do
|
|
1079
|
+
expect_synthandrecog_with_options(/mt=foo\/type/)
|
|
1080
|
+
subject.execute
|
|
1081
|
+
end
|
|
1082
|
+
end
|
|
1083
|
+
|
|
1084
|
+
context 'unset' do
|
|
1085
|
+
let(:input_command_opts) { { headers: {"Media-Type" => nil } } }
|
|
1086
|
+
|
|
1087
|
+
it 'should not pass any options to SynthAndRecog' do
|
|
1088
|
+
expect_synthandrecog_with_options(//)
|
|
1089
|
+
subject.execute
|
|
1090
|
+
end
|
|
1091
|
+
end
|
|
1092
|
+
end
|
|
1093
|
+
|
|
615
1094
|
describe 'Input#mode' do
|
|
616
1095
|
pending
|
|
617
1096
|
end
|