adhearsion 1.1.1 → 1.2.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.
- data/.gitignore +3 -0
- data/.rspec +3 -0
- data/CHANGELOG +12 -0
- data/README.markdown +1 -10
- data/Rakefile +6 -28
- data/adhearsion.gemspec +21 -38
- data/app_generators/ahn/ahn_generator.rb +3 -4
- data/app_generators/ahn/templates/config/environment.rb +4 -0
- data/app_generators/ahn/templates/config/startup.rb +11 -5
- data/app_generators/ahn/templates/script/ahn +8 -0
- data/lib/adhearsion/cli.rb +5 -298
- data/lib/adhearsion/commands.rb +308 -0
- data/lib/adhearsion/events_support.rb +0 -20
- data/lib/adhearsion/initializer/asterisk.rb +0 -1
- data/lib/adhearsion/initializer/configuration.rb +4 -1
- data/lib/adhearsion/logging.rb +18 -3
- data/lib/adhearsion/script_ahn_loader.rb +30 -0
- data/lib/adhearsion/tasks/testing.rb +39 -8
- data/lib/adhearsion/version.rb +2 -2
- data/lib/adhearsion/voip/asterisk/agi_server.rb +15 -8
- data/lib/adhearsion/voip/asterisk/commands.rb +340 -86
- data/lib/adhearsion/voip/asterisk/manager_interface.rb +0 -2
- data/lib/adhearsion/voip/call.rb +11 -3
- data/lib/adhearsion/voip/commands.rb +5 -1
- data/lib/adhearsion/voip/dial_plan.rb +4 -0
- data/lib/theatre/invocation.rb +3 -0
- data/spec/{ahn_command_spec.rb → adhearsion/cli_spec.rb} +11 -0
- data/spec/{component_manager_spec.rb → adhearsion/component_manager_spec.rb} +0 -0
- data/spec/{constants_spec.rb → adhearsion/constants_spec.rb} +0 -0
- data/spec/{drb_spec.rb → adhearsion/drb_spec.rb} +0 -0
- data/spec/{fixtures → adhearsion/fixtures}/dialplan.rb +0 -0
- data/spec/{foundation → adhearsion/foundation}/event_socket_spec.rb +0 -0
- data/spec/{host_definitions_spec.rb → adhearsion/host_definitions_spec.rb} +0 -0
- data/spec/{initializer → adhearsion/initializer}/configuration_spec.rb +21 -0
- data/spec/{initializer → adhearsion/initializer}/loading_spec.rb +0 -0
- data/spec/{initializer → adhearsion/initializer}/paths_spec.rb +0 -0
- data/spec/{initialization_spec.rb → adhearsion/initializer_spec.rb} +0 -0
- data/spec/{logging_spec.rb → adhearsion/logging_spec.rb} +6 -0
- data/spec/{relationship_properties_spec.rb → adhearsion/relationship_properties_spec.rb} +0 -0
- data/spec/{voip → adhearsion/voip}/asterisk/agi_server_spec.rb +0 -0
- data/spec/{voip → adhearsion/voip}/asterisk/ami/ami_spec.rb +1 -0
- data/spec/{voip → adhearsion/voip}/asterisk/ami/lexer/ami_fixtures.yml +0 -0
- data/spec/{voip → adhearsion/voip}/asterisk/ami/lexer/lexer_story +0 -0
- data/spec/{voip → adhearsion/voip}/asterisk/ami/lexer/lexer_story.rb +0 -0
- data/spec/{voip → adhearsion/voip}/asterisk/ami/lexer/story_helper.rb +0 -0
- data/spec/{voip → adhearsion/voip}/asterisk/commands_spec.rb +549 -47
- data/spec/{voip → adhearsion/voip}/asterisk/config_file_generators/agents_spec.rb +0 -0
- data/spec/{voip → adhearsion/voip}/asterisk/config_file_generators/queues_spec.rb +0 -0
- data/spec/{voip → adhearsion/voip}/asterisk/config_file_generators/voicemail_spec.rb +0 -0
- data/spec/{voip → adhearsion/voip}/asterisk/config_manager_spec.rb +0 -0
- data/spec/{voip → adhearsion/voip}/asterisk/menu_command/calculated_match_spec.rb +0 -0
- data/spec/{voip → adhearsion/voip}/asterisk/menu_command/matchers_spec.rb +0 -0
- data/spec/{voip → adhearsion/voip}/call_routing_spec.rb +0 -0
- data/spec/{voip → adhearsion/voip}/dialplan_manager_spec.rb +0 -0
- data/spec/{voip → adhearsion/voip}/dsl/dialing_dsl_spec.rb +1 -1
- data/spec/{voip → adhearsion/voip}/dsl/dispatcher_spec.rb +0 -0
- data/spec/{voip → adhearsion/voip}/dsl/dispatcher_spec_helper.rb +0 -0
- data/spec/{voip → adhearsion/voip}/dsl/parser_spec.rb +0 -0
- data/spec/{voip → adhearsion/voip}/freeswitch/basic_connection_manager_spec.rb +0 -0
- data/spec/{voip → adhearsion/voip}/freeswitch/inbound_connection_manager_spec.rb +0 -0
- data/spec/{voip → adhearsion/voip}/freeswitch/oes_server_spec.rb +0 -0
- data/spec/{voip → adhearsion/voip}/numerical_string_spec.rb +0 -0
- data/spec/{voip → adhearsion/voip}/phone_number_spec.rb +0 -0
- data/spec/spec_helper.rb +36 -89
- data/spec/support/initializer_stubs.rb +47 -0
- data/spec/support/the_following_code.rb +3 -0
- data/{theatre-spec → spec/theatre}/dsl_examples/simple_before_call.rb +0 -0
- data/{theatre-spec → spec/theatre}/dsl_spec.rb +26 -0
- data/{theatre-spec → spec/theatre}/invocation_spec.rb +6 -10
- data/{theatre-spec → spec/theatre}/namespace_spec.rb +0 -0
- data/{theatre-spec → spec/theatre}/spec_helper_spec.rb +0 -0
- data/{theatre-spec → spec/theatre}/theatre_class_spec.rb +2 -5
- metadata +254 -271
- data/app_generators/ahn/templates/components/disabled/sandbox/sandbox.rb +0 -104
- data/app_generators/ahn/templates/components/disabled/sandbox/sandbox.yml +0 -2
- data/lib/adhearsion/voip/asterisk/super_manager.rb +0 -19
- data/spec/silence.rb +0 -10
- data/spec/voip/asterisk/ami/old_tests.rb +0 -204
- data/spec/voip/asterisk/ami/super_manager/super_manager_story +0 -25
- data/spec/voip/asterisk/ami/super_manager/super_manager_story.rb +0 -15
- data/spec/voip/asterisk/ami/super_manager/super_manager_story_helper.rb +0 -5
- data/theatre-spec/dsl_examples/dynamic_stomp.rb +0 -7
- data/theatre-spec/spec_helper.rb +0 -37
|
@@ -25,8 +25,6 @@ module Adhearsion
|
|
|
25
25
|
# ManagerInterfaceResponse, ManagerInterfaceError, etc.) are relatively user-friendly, they're designed to be a
|
|
26
26
|
# building block on which to build higher-level abstractions of the Asterisk Manager Interface.
|
|
27
27
|
#
|
|
28
|
-
# For a higher-level abstraction of the Asterisk Manager Interface, see the SuperManager class.
|
|
29
|
-
#
|
|
30
28
|
class ManagerInterface
|
|
31
29
|
|
|
32
30
|
CAUSAL_EVENT_NAMES = %w[queuestatus sippeers iaxpeers parkedcalls
|
data/lib/adhearsion/voip/call.rb
CHANGED
|
@@ -55,7 +55,7 @@ module Adhearsion
|
|
|
55
55
|
end
|
|
56
56
|
end
|
|
57
57
|
|
|
58
|
-
# Searches all active calls by their unique_identifier. See Call#unique_identifier.
|
|
58
|
+
# Searches all active calls by their unique_identifier. See Call#unique_identifier.
|
|
59
59
|
# Is this actually by channel?
|
|
60
60
|
def find(id)
|
|
61
61
|
atomically do
|
|
@@ -90,6 +90,12 @@ module Adhearsion
|
|
|
90
90
|
calls
|
|
91
91
|
end
|
|
92
92
|
|
|
93
|
+
def method_missing(m, *args)
|
|
94
|
+
atomically do
|
|
95
|
+
calls.send(m.to_sym, *args)
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
93
99
|
private
|
|
94
100
|
|
|
95
101
|
def atomically(&block)
|
|
@@ -146,8 +152,6 @@ module Adhearsion
|
|
|
146
152
|
raise Adhearsion::Call::CallMessageQueue::InboxClosedException, "The message queue for this call has aleady been disabled." if !@open
|
|
147
153
|
super
|
|
148
154
|
end
|
|
149
|
-
|
|
150
|
-
|
|
151
155
|
end
|
|
152
156
|
|
|
153
157
|
|
|
@@ -294,6 +298,10 @@ module Adhearsion
|
|
|
294
298
|
end
|
|
295
299
|
end
|
|
296
300
|
|
|
301
|
+
def ahn_log(*args)
|
|
302
|
+
Adhearsion::Logging::DefaultAdhearsionLogger.send Adhearsion::Logging::AdhearsionLogger.sanitized_logger_name(unique_identifier), *args
|
|
303
|
+
end
|
|
304
|
+
|
|
297
305
|
def define_variable_accessors(recipient=self)
|
|
298
306
|
variables.each do |key, value|
|
|
299
307
|
define_singleton_accessor_with_pair(key, value, recipient)
|
|
@@ -9,5 +9,9 @@ module Adhearsion
|
|
|
9
9
|
class PlaybackError < StandardError
|
|
10
10
|
# Represents failure to play audio, such as when the sound file cannot be found
|
|
11
11
|
end
|
|
12
|
+
|
|
13
|
+
class RecordError < StandardError
|
|
14
|
+
# Represents failure to record such as when a file cannot be written.
|
|
15
|
+
end
|
|
12
16
|
end
|
|
13
|
-
end
|
|
17
|
+
end
|
data/lib/theatre/invocation.rb
CHANGED
|
@@ -66,6 +66,10 @@ describe "A simulated use of the 'ahn' command" do
|
|
|
66
66
|
Adhearsion::CLI::AhnCommand.const_defined?('USAGE').should be true
|
|
67
67
|
end
|
|
68
68
|
|
|
69
|
+
before do
|
|
70
|
+
flexmock Adhearsion::ScriptAhnLoader, :in_ahn_application? => true
|
|
71
|
+
end
|
|
72
|
+
|
|
69
73
|
it "arguments to 'create' are executed properly" do
|
|
70
74
|
some_path = "/path/somewhere"
|
|
71
75
|
simulate_args "create", some_path
|
|
@@ -113,6 +117,13 @@ describe "A simulated use of the 'ahn' command" do
|
|
|
113
117
|
Adhearsion::CLI::AhnCommand.parse_arguments(arguments).should == [:start, project_path, :daemon, pid_file_path]
|
|
114
118
|
end
|
|
115
119
|
|
|
120
|
+
it 'should recognize start without daemon and with pid file properly' do
|
|
121
|
+
project_path = '/second/star/on/the/right'
|
|
122
|
+
pid_file_path = '/straight/on/til/morning'
|
|
123
|
+
arguments = ["start", project_path, "--pid-file=#{pid_file_path}"]
|
|
124
|
+
Adhearsion::CLI::AhnCommand.parse_arguments(arguments).should == [:start, project_path, :foreground, pid_file_path]
|
|
125
|
+
end
|
|
126
|
+
|
|
116
127
|
it 'parse_arguments should recognize start without daemon properly' do
|
|
117
128
|
path = '/path/to/somewhere'
|
|
118
129
|
arguments = ['start', path]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -87,6 +87,8 @@ describe 'Logging configuration' do
|
|
|
87
87
|
|
|
88
88
|
after :each do
|
|
89
89
|
Adhearsion::Logging.logging_level = :fatal
|
|
90
|
+
Adhearsion::Logging::AdhearsionLogger.outputters = [Log4r::Outputter.stdout]
|
|
91
|
+
Adhearsion::Logging::AdhearsionLogger.formatters = [Log4r::DefaultFormatter]
|
|
90
92
|
end
|
|
91
93
|
|
|
92
94
|
it 'the logging level should translate from symbols into Log4r constants' do
|
|
@@ -95,6 +97,25 @@ describe 'Logging configuration' do
|
|
|
95
97
|
Adhearsion::Logging.logging_level.should be Log4r::WARN
|
|
96
98
|
end
|
|
97
99
|
|
|
100
|
+
it 'outputters should be settable' do
|
|
101
|
+
Adhearsion::Logging::AdhearsionLogger.outputters.should == [Log4r::Outputter.stdout]
|
|
102
|
+
config.logging :outputters => Log4r::Outputter.stderr
|
|
103
|
+
Adhearsion::Logging::AdhearsionLogger.outputters.should == [Log4r::Outputter.stderr]
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
it 'formatters should be settable' do
|
|
107
|
+
Adhearsion::Logging::AdhearsionLogger.formatters.map(&:class).should == [Log4r::DefaultFormatter]
|
|
108
|
+
config.logging :formatters => Log4r::ObjectFormatter
|
|
109
|
+
Adhearsion::Logging::AdhearsionLogger.formatters.map(&:class).should == [Log4r::ObjectFormatter]
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
it 'a global formatter should be settable' do
|
|
113
|
+
Adhearsion::Logging::AdhearsionLogger.outputters << Log4r::Outputter.stdout
|
|
114
|
+
Adhearsion::Logging::AdhearsionLogger.formatters.map(&:class).should == [Log4r::DefaultFormatter, Log4r::DefaultFormatter]
|
|
115
|
+
config.logging :formatter => Log4r::ObjectFormatter
|
|
116
|
+
Adhearsion::Logging::AdhearsionLogger.formatters.map(&:class).should == [Log4r::ObjectFormatter, Log4r::ObjectFormatter]
|
|
117
|
+
end
|
|
118
|
+
|
|
98
119
|
end
|
|
99
120
|
|
|
100
121
|
describe "AMI configuration defaults" do
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -41,6 +41,12 @@ describe 'The ahn_log command' do
|
|
|
41
41
|
ahn_log.qwerty.should be_a_kind_of Adhearsion::Logging::AdhearsionLogger
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
+
it "handles crazy logger names" do
|
|
45
|
+
ahn_log.send :'locals@DEMO_ca.ll&', "hey"
|
|
46
|
+
Log4r::Logger['locals@DEMO_ca.ll&'].should_not be nil
|
|
47
|
+
ahn_log.send(:'localsdemo_call').should == Log4r::Logger['locals@DEMO_ca.ll&']
|
|
48
|
+
end
|
|
49
|
+
|
|
44
50
|
end
|
|
45
51
|
|
|
46
52
|
# Essential for running the tests
|
|
File without changes
|
|
File without changes
|
|
@@ -252,6 +252,7 @@ describe "ManagerInterface" do
|
|
|
252
252
|
write_queue_mock = mocked_queue
|
|
253
253
|
|
|
254
254
|
manager = new_manager_with_events
|
|
255
|
+
flexmock(manager).should_receive(:start_actions_writer_loop).and_return true
|
|
255
256
|
manager.connect!
|
|
256
257
|
|
|
257
258
|
write_queue_mock.actions.first.name.should == "login"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -20,9 +20,19 @@ module DialplanCommandTestHelpers
|
|
|
20
20
|
call.should_receive(:to_pbx).and_return(output)
|
|
21
21
|
end
|
|
22
22
|
end
|
|
23
|
+
|
|
24
|
+
test_case.after do
|
|
25
|
+
pbx_output_should_be_empty
|
|
26
|
+
end
|
|
23
27
|
end
|
|
24
28
|
|
|
25
29
|
class MockCall
|
|
30
|
+
attr_accessor :variables
|
|
31
|
+
|
|
32
|
+
def initialize
|
|
33
|
+
@variables = {}
|
|
34
|
+
end
|
|
35
|
+
|
|
26
36
|
def with_command_lock
|
|
27
37
|
yield
|
|
28
38
|
end
|
|
@@ -30,6 +40,10 @@ module DialplanCommandTestHelpers
|
|
|
30
40
|
|
|
31
41
|
class MockSocket
|
|
32
42
|
|
|
43
|
+
def empty?
|
|
44
|
+
messages.empty?
|
|
45
|
+
end
|
|
46
|
+
|
|
33
47
|
def print(message)
|
|
34
48
|
messages << message
|
|
35
49
|
end
|
|
@@ -98,7 +112,7 @@ module DialplanCommandTestHelpers
|
|
|
98
112
|
end
|
|
99
113
|
|
|
100
114
|
def pbx_should_respond_with_value(value)
|
|
101
|
-
pbx_should_respond_with
|
|
115
|
+
pbx_should_respond_with pbx_value_response value
|
|
102
116
|
end
|
|
103
117
|
|
|
104
118
|
def pbx_should_respond_with_success(success_code = nil)
|
|
@@ -148,6 +162,14 @@ module DialplanCommandTestHelpers
|
|
|
148
162
|
"200 result=#{code || default_code} endpos=#{endpos || default_code}\n"
|
|
149
163
|
end
|
|
150
164
|
|
|
165
|
+
def pbx_value_response(value)
|
|
166
|
+
"200 result=1 (#{value})"
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def pbx_result_response(value)
|
|
170
|
+
"200 result=#{value.ord}"
|
|
171
|
+
end
|
|
172
|
+
|
|
151
173
|
def default_success_code
|
|
152
174
|
'1'
|
|
153
175
|
end
|
|
@@ -192,6 +214,10 @@ module DialplanCommandTestHelpers
|
|
|
192
214
|
def pbx_was_asked_to_execute(application, *options)
|
|
193
215
|
output_stream_matches(/exec saydigits "#{options.join('|')}"/i)
|
|
194
216
|
end
|
|
217
|
+
|
|
218
|
+
def pbx_output_should_be_empty
|
|
219
|
+
output.messages.should be_empty, output.messages.inspect
|
|
220
|
+
end
|
|
195
221
|
end
|
|
196
222
|
include OutputStreamMatchers
|
|
197
223
|
|
|
@@ -248,7 +274,17 @@ describe 'hangup command' do
|
|
|
248
274
|
end
|
|
249
275
|
end
|
|
250
276
|
|
|
251
|
-
describe
|
|
277
|
+
describe "writing a command" do
|
|
278
|
+
include DialplanCommandTestHelpers
|
|
279
|
+
|
|
280
|
+
it "should strip out excess whitespace" do
|
|
281
|
+
pbx_should_respond_with_success
|
|
282
|
+
mock_call.should_receive(:write).with "EXEC Ringing"
|
|
283
|
+
mock_call.raw_response "EXEC \nRinging\n\n"
|
|
284
|
+
end
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
describe 'The #interruptible_play method' do
|
|
252
288
|
|
|
253
289
|
include DialplanCommandTestHelpers
|
|
254
290
|
|
|
@@ -257,7 +293,7 @@ describe 'interruptible_play command' do
|
|
|
257
293
|
file = "file_doesnt_matter"
|
|
258
294
|
digits.each { |digit| pbx_should_respond_with_stream_file_success digit }
|
|
259
295
|
digits.map { |digit| mock_call.interruptible_play file }.should == digits.map(&:chr)
|
|
260
|
-
pbx_was_asked_to_stream file
|
|
296
|
+
digits.size.times { pbx_was_asked_to_stream file }
|
|
261
297
|
end
|
|
262
298
|
|
|
263
299
|
it "should return nil if no digit was pressed" do
|
|
@@ -297,10 +333,9 @@ describe 'interruptible_play command' do
|
|
|
297
333
|
mock_call.interruptible_play(*play_files).should == '9'
|
|
298
334
|
pbx_was_asked_to_stream played_files
|
|
299
335
|
end
|
|
300
|
-
|
|
301
336
|
end
|
|
302
337
|
|
|
303
|
-
describe 'interruptible_play!
|
|
338
|
+
describe 'The #interruptible_play! method' do
|
|
304
339
|
include DialplanCommandTestHelpers
|
|
305
340
|
|
|
306
341
|
it 'should return a string for the digit that was pressed' do
|
|
@@ -308,7 +343,7 @@ describe 'interruptible_play! command' do
|
|
|
308
343
|
file = "file_doesnt_matter"
|
|
309
344
|
digits.each { |digit| pbx_should_respond_with_stream_file_success digit }
|
|
310
345
|
digits.map { |digit| mock_call.interruptible_play! file }.should == digits.map(&:chr)
|
|
311
|
-
pbx_was_asked_to_stream file
|
|
346
|
+
digits.size.times { pbx_was_asked_to_stream file }
|
|
312
347
|
end
|
|
313
348
|
|
|
314
349
|
it "should return nil if no digit was pressed" do
|
|
@@ -372,7 +407,7 @@ describe 'interruptible_play! command' do
|
|
|
372
407
|
end
|
|
373
408
|
end
|
|
374
409
|
|
|
375
|
-
describe 'wait_for_digit
|
|
410
|
+
describe 'The #wait_for_digit method' do
|
|
376
411
|
|
|
377
412
|
include DialplanCommandTestHelpers
|
|
378
413
|
|
|
@@ -380,16 +415,17 @@ describe 'wait_for_digit command' do
|
|
|
380
415
|
digits = %w{0 1 # * 9}.map{|c| c.ord}
|
|
381
416
|
digits.each { |digit| pbx_should_respond_with_success digit }
|
|
382
417
|
digits.map { |digit| mock_call.send(:wait_for_digit) }.should == digits.map(&:chr)
|
|
418
|
+
digits.size.times { pbx_should_have_been_sent 'WAIT FOR DIGIT "-1"' }
|
|
383
419
|
end
|
|
384
420
|
|
|
385
421
|
it "the timeout given must be converted to milliseconds" do
|
|
386
422
|
pbx_should_respond_with_success 0
|
|
387
423
|
mock_call.send(:wait_for_digit, 1)
|
|
388
|
-
|
|
424
|
+
pbx_should_have_been_sent 'WAIT FOR DIGIT "1000"'
|
|
389
425
|
end
|
|
390
426
|
end
|
|
391
427
|
|
|
392
|
-
describe 'answer' do
|
|
428
|
+
describe 'The #answer method' do
|
|
393
429
|
include DialplanCommandTestHelpers
|
|
394
430
|
|
|
395
431
|
it 'should send ANSWER over the AGI socket' do
|
|
@@ -400,18 +436,19 @@ describe 'answer' do
|
|
|
400
436
|
|
|
401
437
|
end
|
|
402
438
|
|
|
403
|
-
describe 'execute' do
|
|
439
|
+
describe 'The #execute method' do
|
|
404
440
|
include DialplanCommandTestHelpers
|
|
405
441
|
|
|
406
442
|
it 'execute writes exec and app name to the PBX' do
|
|
407
443
|
pbx_should_respond_with_success
|
|
408
444
|
assert_success mock_call.execute(:foo)
|
|
409
|
-
pbx_should_have_been_sent 'EXEC foo
|
|
445
|
+
pbx_should_have_been_sent 'EXEC foo'
|
|
410
446
|
end
|
|
411
447
|
|
|
412
448
|
it 'execute returns false if the command was not executed successfully by the PBX' do
|
|
413
449
|
pbx_should_respond_with_failure
|
|
414
450
|
mock_call.execute(:foo).should_not be true
|
|
451
|
+
pbx_should_have_been_sent 'EXEC foo'
|
|
415
452
|
end
|
|
416
453
|
|
|
417
454
|
it 'execute can accept arguments after the app name which get translated into pipe-delimited arguments to the PBX' do
|
|
@@ -425,6 +462,7 @@ describe 'execute' do
|
|
|
425
462
|
the_following_code {
|
|
426
463
|
mock_call.execute :foo, "bar"
|
|
427
464
|
}.should raise_error Adhearsion::Hangup
|
|
465
|
+
pbx_should_have_been_sent 'EXEC foo "bar"'
|
|
428
466
|
end
|
|
429
467
|
|
|
430
468
|
it "should raise a ArgumentError if given a null byte in the arguments" do
|
|
@@ -432,10 +470,121 @@ describe 'execute' do
|
|
|
432
470
|
mock_call.execute :foo, "bar\0"
|
|
433
471
|
}.should raise_error ArgumentError
|
|
434
472
|
end
|
|
473
|
+
end
|
|
474
|
+
|
|
475
|
+
describe 'The #inline_return_value method' do
|
|
476
|
+
include DialplanCommandTestHelpers
|
|
435
477
|
|
|
478
|
+
it 'should return nil when given false or nil' do
|
|
479
|
+
mock_call.inline_return_value(false).should be nil
|
|
480
|
+
mock_call.inline_return_value(nil).should be nil
|
|
481
|
+
end
|
|
482
|
+
|
|
483
|
+
it 'should return nil when given an empty AGI value (0)' do
|
|
484
|
+
mock_call.inline_return_value(pbx_result_response(0)).should be nil
|
|
485
|
+
end
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
it 'should raise AGIProtocolError with an invalid response' do
|
|
489
|
+
expect {
|
|
490
|
+
mock_call.inline_return_value("500 result=foo\n")
|
|
491
|
+
}.to raise_error Adhearsion::VoIP::Asterisk::AGIProtocolError
|
|
492
|
+
|
|
493
|
+
expect {
|
|
494
|
+
mock_call.inline_return_value('Hey man, not so loud!')
|
|
495
|
+
}.to raise_error Adhearsion::VoIP::Asterisk::AGIProtocolError
|
|
496
|
+
end
|
|
497
|
+
|
|
498
|
+
it 'should parse the return value' do
|
|
499
|
+
mock_call.inline_return_value(pbx_result_response(5)).should == '5'
|
|
500
|
+
end
|
|
501
|
+
end
|
|
502
|
+
|
|
503
|
+
describe 'The #inline_result_with_return_value method' do
|
|
504
|
+
include DialplanCommandTestHelpers
|
|
505
|
+
|
|
506
|
+
it 'should return nil when given false or nil' do
|
|
507
|
+
mock_call.inline_result_with_return_value(false).should be nil
|
|
508
|
+
mock_call.inline_result_with_return_value(nil).should be nil
|
|
509
|
+
end
|
|
510
|
+
|
|
511
|
+
it 'should return nil when given an empty AGI value (0)' do
|
|
512
|
+
mock_call.inline_result_with_return_value(pbx_result_response(0)).should be nil
|
|
513
|
+
end
|
|
514
|
+
|
|
515
|
+
it 'should raise AGIProtocolError with an invalid response' do
|
|
516
|
+
expect {
|
|
517
|
+
mock_call.inline_result_with_return_value("500 result=1 (foo)\n")
|
|
518
|
+
}.to raise_error Adhearsion::VoIP::Asterisk::AGIProtocolError
|
|
519
|
+
|
|
520
|
+
expect {
|
|
521
|
+
mock_call.inline_result_with_return_value('Hey man, not so loud!')
|
|
522
|
+
}.to raise_error Adhearsion::VoIP::Asterisk::AGIProtocolError
|
|
523
|
+
end
|
|
524
|
+
|
|
525
|
+
it 'should parse the return value' do
|
|
526
|
+
mock_call.inline_result_with_return_value(pbx_value_response(5)).should == '5'
|
|
527
|
+
end
|
|
436
528
|
end
|
|
437
529
|
|
|
438
|
-
describe '
|
|
530
|
+
describe 'The #play_or_speak method' do
|
|
531
|
+
include DialplanCommandTestHelpers
|
|
532
|
+
|
|
533
|
+
it 'should play a sound file if one exists' do
|
|
534
|
+
pbx_should_respond_with_playback_success
|
|
535
|
+
audio_file = "cents-per-minute"
|
|
536
|
+
mock_call.play_or_speak({audio_file => {}}).should be nil
|
|
537
|
+
pbx_was_asked_to_play audio_file
|
|
538
|
+
end
|
|
539
|
+
|
|
540
|
+
it 'should play a sound file via interruptible_play if file exists and interrupbible set and return key pressed and return the key press value' do
|
|
541
|
+
audio_file = "cents-per-minute"
|
|
542
|
+
mock_call.should_receive(:interruptible_play!).with(audio_file).once.and_return '#'
|
|
543
|
+
mock_call.play_or_speak({audio_file => {:interruptible => true}}).should == '#'
|
|
544
|
+
end
|
|
545
|
+
|
|
546
|
+
it 'should play a sound file via interruptible_play if file exists and interrupbible set' do
|
|
547
|
+
audio_file = "cents-per-minute"
|
|
548
|
+
mock_call.should_receive(:interruptible_play!).with(audio_file).once.and_return nil
|
|
549
|
+
mock_call.play_or_speak({audio_file => {:interruptible => true}}).should == nil
|
|
550
|
+
end
|
|
551
|
+
|
|
552
|
+
it 'should raise and error if a sound file does not exist and there is not text specified to fall back to' do
|
|
553
|
+
audio_file = "nixon tapes"
|
|
554
|
+
mock_call.should_receive(:play!).with(audio_file).and_raise Adhearsion::VoIP::PlaybackError
|
|
555
|
+
the_following_code {
|
|
556
|
+
mock_call.play_or_speak({audio_file => { :engine => :unimrcp}})
|
|
557
|
+
}.should raise_error ArgumentError
|
|
558
|
+
end
|
|
559
|
+
|
|
560
|
+
it 'should not send the command to play if the audio file is blank' do
|
|
561
|
+
mock_call.should_receive(:speak).with('hello', {:engine=>:unimrcp}).once.and_return nil
|
|
562
|
+
mock_call.play_or_speak({'' => { :text => 'hello', :engine => :unimrcp }}).should be nil
|
|
563
|
+
end
|
|
564
|
+
|
|
565
|
+
it 'should not send the command to play if the audio file is nil' do
|
|
566
|
+
mock_call.should_receive(:speak).with('hello', {:engine=>:unimrcp}).once.and_return nil
|
|
567
|
+
mock_call.play_or_speak({nil => { :text => 'hello', :engine => :unimrcp }}).should be nil
|
|
568
|
+
end
|
|
569
|
+
|
|
570
|
+
it 'should speak the text if a sound file does not exist' do
|
|
571
|
+
audio_file = "nixon tapes"
|
|
572
|
+
mock_call.should_receive(:play!).with(audio_file).and_raise Adhearsion::VoIP::PlaybackError
|
|
573
|
+
mock_call.should_receive(:speak).with('hello', {:engine=>:unimrcp}).once.and_return nil
|
|
574
|
+
mock_call.play_or_speak({audio_file => { :text => 'hello', :engine => :unimrcp }}).should be nil
|
|
575
|
+
end
|
|
576
|
+
|
|
577
|
+
it 'should speak the text if a sound file does not exist and pass back the entered text if a key is pressed' do
|
|
578
|
+
audio_file = "nixon tapes"
|
|
579
|
+
mock_call.should_receive(:interruptible_play!).with(audio_file).and_raise Adhearsion::VoIP::PlaybackError
|
|
580
|
+
mock_call.should_receive(:speak).with('hello', {:engine=>:unimrcp, :interruptible => true}).once.and_return '5'
|
|
581
|
+
mock_call.play_or_speak({audio_file => { :text => 'hello', :engine => :unimrcp, :interruptible => true
|
|
582
|
+
}}).should == '5'
|
|
583
|
+
end
|
|
584
|
+
|
|
585
|
+
end
|
|
586
|
+
|
|
587
|
+
describe 'The #play method' do
|
|
439
588
|
include DialplanCommandTestHelpers
|
|
440
589
|
|
|
441
590
|
it 'passing a single string to play results in the playback application being executed with that file name on the PBX' do
|
|
@@ -537,7 +686,7 @@ describe 'play command' do
|
|
|
537
686
|
end
|
|
538
687
|
end
|
|
539
688
|
|
|
540
|
-
describe 'play!
|
|
689
|
+
describe 'The #play! method' do
|
|
541
690
|
include DialplanCommandTestHelpers
|
|
542
691
|
|
|
543
692
|
it 'should accept multiple strings to play, causing multiple playback commands to be issued' do
|
|
@@ -570,12 +719,149 @@ describe 'play! command' do
|
|
|
570
719
|
end
|
|
571
720
|
end
|
|
572
721
|
|
|
573
|
-
describe '
|
|
722
|
+
describe 'the #record method' do
|
|
723
|
+
include DialplanCommandTestHelpers
|
|
724
|
+
|
|
725
|
+
it 'should return the recorded file name if the user hangs up during the recording' do
|
|
726
|
+
mock_call.should_receive(:response).once.with('RECORD FILE', 'foo', 'gsm', '#', -1, 0, 'BEEP').and_return("200 result=-1 (hangup) endpos=167840\n")
|
|
727
|
+
mock_call.record('foo').should == 'foo.gsm'
|
|
728
|
+
end
|
|
729
|
+
|
|
730
|
+
it 'create a default filename if no file is specifed and icrement it on subsequent calls' do
|
|
731
|
+
mock_call.call.variables.delete :recording_counter
|
|
732
|
+
mock_call.should_receive(:response).once.with('RECORD FILE', '/tmp/recording_0', 'gsm', '26', -1, 0).and_return("200 result=0 (timeout) endpos=21600\n")
|
|
733
|
+
mock_call.should_receive(:response).once.with('RECORD FILE', '/tmp/recording_1', 'gsm', '26', -1, 0).and_return("200 result=0 (timeout) endpos=21600\n")
|
|
734
|
+
mock_call.record(:beep => nil, :escapedigits => '26').should == '/tmp/recording_0.gsm'
|
|
735
|
+
mock_call.record(:beep => nil, :escapedigits => '26').should == '/tmp/recording_1.gsm'
|
|
736
|
+
end
|
|
737
|
+
|
|
738
|
+
it 'determine the format from the filename' do
|
|
739
|
+
mock_call.should_receive(:response).once.with('RECORD FILE', 'foo', 'wav', '26', -1, 0).and_return("200 result=0 (timeout) endpos=21600\n")
|
|
740
|
+
mock_call.record('foo.wav', :beep => nil, :escapedigits => '26').should == 'foo.wav'
|
|
741
|
+
end
|
|
742
|
+
|
|
743
|
+
it 'set the format of a file via the :format option' do
|
|
744
|
+
mock_call.should_receive(:response).once.with("RECORD FILE", "foo", "wav", "#", 2000, 0).and_return("200 result=0 (timeout) endpos=21600\n")
|
|
745
|
+
mock_call.record('foo', :beep => nil, :maxduration => 2, :format => 'wav').should == 'foo.wav'
|
|
746
|
+
end
|
|
747
|
+
|
|
748
|
+
it 'set the format of a file via the :format option over-riding a implicit format' do
|
|
749
|
+
mock_call.should_receive(:response).once.with("RECORD FILE", "foo.wav", "mpeg", "#", 2000, 0).and_return("200 result=0 (timeout) endpos=21600\n")
|
|
750
|
+
mock_call.record('foo.wav', :beep => nil, :maxduration => 2, :format => 'mpeg').should == 'foo.wav.mpeg'
|
|
751
|
+
end
|
|
752
|
+
end
|
|
753
|
+
|
|
754
|
+
describe 'the #record_to_file method' do
|
|
755
|
+
include DialplanCommandTestHelpers
|
|
756
|
+
|
|
757
|
+
it 'should return :hangup if the user hangs up during the recording' do
|
|
758
|
+
mock_call.should_receive(:response).once.with("RECORD FILE", "foo", "gsm", "#", -1, 0, "BEEP").and_return("200 result=-1 (hangup) endpos=167840\n")
|
|
759
|
+
mock_call.record_to_file('foo').should == :hangup
|
|
760
|
+
end
|
|
761
|
+
|
|
762
|
+
it 'should return :write error if the recording had a problem writing the file' do
|
|
763
|
+
mock_call.should_receive(:response).once.with("RECORD FILE", "foo", "gsm", "#", -1, 0, "BEEP").and_return("200 result=-1 (writefile) endpos=167840\n")
|
|
764
|
+
mock_call.record_to_file('foo').should == :write_error
|
|
765
|
+
end
|
|
766
|
+
|
|
767
|
+
it 'should return :success_dtmf if the recording was completed successfully with a dtmf tone to end' do
|
|
768
|
+
mock_call.should_receive(:response).once.with("RECORD FILE", "foo", "gsm", "#", -1, 0, "BEEP").and_return("200 result=35 (dtmf) endpos=29120\n")
|
|
769
|
+
mock_call.record_to_file('foo').should == :success_dtmf
|
|
770
|
+
end
|
|
771
|
+
|
|
772
|
+
it 'should return :success_timeout if the recording was completed successfully by timing out with silence' do
|
|
773
|
+
mock_call.should_receive(:response).once.with("RECORD FILE", "foo", "gsm", "#", -1, 0, "BEEP").and_return("200 result=0 (timeout) endpos=21600\n")
|
|
774
|
+
mock_call.record_to_file('foo').should == :success_timeout
|
|
775
|
+
end
|
|
776
|
+
|
|
777
|
+
it 'not send a beep if a :beep=>nil is passed in' do
|
|
778
|
+
mock_call.should_receive(:response).once.with("RECORD FILE", "foo", "gsm", "#", -1, 0).and_return("200 result=0 (timeout) endpos=21600\n")
|
|
779
|
+
mock_call.record_to_file('foo', :beep => nil).should == :success_timeout
|
|
780
|
+
end
|
|
781
|
+
|
|
782
|
+
it 'set the silence if it is passed in' do
|
|
783
|
+
mock_call.should_receive(:response).once.with("RECORD FILE", "foo", "gsm", "#", -1, 0, 's=2').and_return("200 result=0 (timeout) endpos=21600\n")
|
|
784
|
+
mock_call.record_to_file('foo', :beep => nil, :silence => 2).should == :success_timeout
|
|
785
|
+
end
|
|
786
|
+
|
|
787
|
+
it 'set the maxduration if it is passed in' do
|
|
788
|
+
mock_call.should_receive(:response).once.with("RECORD FILE", "foo", "gsm", "#", 2000, 0).and_return("200 result=0 (timeout) endpos=21600\n")
|
|
789
|
+
mock_call.record_to_file('foo', :beep => nil, :maxduration => 2).should == :success_timeout
|
|
790
|
+
end
|
|
791
|
+
|
|
792
|
+
it 'set the format of a file via the :format option' do
|
|
793
|
+
mock_call.should_receive(:response).once.with("RECORD FILE", "foo", "wav", "#", 2000, 0).and_return("200 result=0 (timeout) endpos=21600\n")
|
|
794
|
+
mock_call.record_to_file('foo', :beep => nil, :maxduration => 2, :format => 'wav').should == :success_timeout
|
|
795
|
+
end
|
|
796
|
+
|
|
797
|
+
it 'set the format of a file via the :format option over-riding a implicit format' do
|
|
798
|
+
mock_call.should_receive(:response).once.with("RECORD FILE", "foo.wav", "mpeg", "#", 2000, 0).and_return("200 result=0 (timeout) endpos=21600\n")
|
|
799
|
+
mock_call.record_to_file('foo.wav', :beep => nil, :maxduration => 2, :format => 'mpeg').should == :success_timeout
|
|
800
|
+
end
|
|
801
|
+
|
|
802
|
+
it 'set the escapedigits if it is passed in' do
|
|
803
|
+
mock_call.should_receive(:response).once.with("RECORD FILE", "foo", "gsm", "26", -1, 0).and_return("200 result=0 (timeout) endpos=21600\n")
|
|
804
|
+
mock_call.record_to_file('foo', :beep => nil, :escapedigits => '26').should == :success_timeout
|
|
805
|
+
end
|
|
806
|
+
|
|
807
|
+
it 'play a passed in beep file if it is passed in' do
|
|
808
|
+
mock_call.should_receive(:execute).once.with(:playback, 'my_awesome_beep.wav').and_return(true)
|
|
809
|
+
pbx_should_respond_with_playback_success
|
|
810
|
+
pbx_should_respond_with_playback_success
|
|
811
|
+
mock_call.should_receive(:response).once.with("RECORD FILE", "foo", "gsm", "26", -1, 0).and_return("200 result=0 (timeout) endpos=21600\n")
|
|
812
|
+
mock_call.record_to_file('foo', :beep => 'my_awesome_beep.wav', :escapedigits => '26').should == :success_timeout
|
|
813
|
+
end
|
|
814
|
+
|
|
815
|
+
it "should silently fail if the beep file passed in can't be played" do
|
|
816
|
+
mock_call.should_receive(:execute).once.with(:playback, 'my_awesome_beep.wav').and_return(true)
|
|
817
|
+
pbx_should_respond_with_playback_failure
|
|
818
|
+
pbx_should_respond_with_playback_failure
|
|
819
|
+
mock_call.should_receive(:response).once.with("RECORD FILE", "foo", "gsm", "26", -1, 0).and_return("200 result=0 (timeout) endpos=21600\n")
|
|
820
|
+
mock_call.record_to_file('foo', :beep => 'my_awesome_beep.wav', :escapedigits => '26').should == :success_timeout
|
|
821
|
+
end
|
|
822
|
+
|
|
823
|
+
it 'determine the format from the filename' do
|
|
824
|
+
mock_call.should_receive(:response).once.with("RECORD FILE", "foo", "wav", "26", -1, 0).and_return("200 result=0 (timeout) endpos=21600\n")
|
|
825
|
+
mock_call.record_to_file('foo.wav', :beep => nil, :escapedigits => '26').should == :success_timeout
|
|
826
|
+
end
|
|
827
|
+
|
|
828
|
+
it 'create a default filename if no file is specifed and icrement it on subsequent calls' do
|
|
829
|
+
mock_call.should_receive(:response).once.with("RECORD FILE", "/tmp/recording_0", "gsm", "26", -1, 0).and_return("200 result=0 (timeout) endpos=21600\n")
|
|
830
|
+
mock_call.should_receive(:response).once.with("RECORD FILE", "/tmp/recording_1", "gsm", "26", -1, 0).and_return("200 result=0 (timeout) endpos=21600\n")
|
|
831
|
+
mock_call.record_to_file(:beep => nil, :escapedigits => '26').should == :success_timeout
|
|
832
|
+
mock_call.record_to_file(:beep => nil, :escapedigits => '26').should == :success_timeout
|
|
833
|
+
end
|
|
834
|
+
end
|
|
574
835
|
|
|
836
|
+
describe 'The #record_to_file! method' do
|
|
575
837
|
include DialplanCommandTestHelpers
|
|
576
838
|
|
|
577
|
-
|
|
578
|
-
|
|
839
|
+
it "should throw an exception the beep file passed in can't be played" do
|
|
840
|
+
mock_call.should_receive(:execute).once.with(:playback, 'my_awesome_beep.wav').and_return(false)
|
|
841
|
+
pbx_should_respond_with_playback_failure
|
|
842
|
+
pbx_should_respond_with_playback_failure
|
|
843
|
+
mock_call.should_receive(:response).once.with("RECORD FILE", "foo", "gsm", "26", -1, 0).and_return("200 result=0 (timeout) endpos=21600\n")
|
|
844
|
+
the_following_code {
|
|
845
|
+
mock_call.record_to_file!('foo', :beep => 'my_awesome_beep.wav', :escapedigits => '26').should == :success_timeout
|
|
846
|
+
}.should raise_error Adhearsion::VoIP::PlaybackError
|
|
847
|
+
end
|
|
848
|
+
|
|
849
|
+
it 'should throw RecordError if the recording had a problem writing the file' do
|
|
850
|
+
mock_call.should_receive(:response).once.with("RECORD FILE", "foo", "gsm", "#", -1, 0, "BEEP").and_return("200 result=-1 (writefile) endpos=167840\n")
|
|
851
|
+
the_following_code {
|
|
852
|
+
mock_call.record_to_file!('foo').should == :write_error
|
|
853
|
+
}.should raise_error Adhearsion::VoIP::RecordError
|
|
854
|
+
end
|
|
855
|
+
|
|
856
|
+
it 'should be able get a response from a successfull call' do
|
|
857
|
+
mock_call.should_receive(:response).once.with("RECORD FILE", "foo", "wav", "26", -1, 0).and_return("200 result=0 (timeout) endpos=21600\n")
|
|
858
|
+
mock_call.record_to_file!('foo.wav', :beep => nil, :escapedigits => '26').should == :success_timeout
|
|
859
|
+
end
|
|
860
|
+
end
|
|
861
|
+
|
|
862
|
+
describe 'The #input method' do
|
|
863
|
+
|
|
864
|
+
include DialplanCommandTestHelpers
|
|
579
865
|
|
|
580
866
|
it 'should raise an error when the number of digits expected is -1 (this is deprecated behavior)' do
|
|
581
867
|
the_following_code {
|
|
@@ -608,6 +894,7 @@ describe 'input command' do
|
|
|
608
894
|
the_following_code {
|
|
609
895
|
mock_call.input(:accept_key => false)
|
|
610
896
|
}.should raise_error ArgumentError
|
|
897
|
+
pbx_should_have_been_sent 'WAIT FOR DIGIT "-1"'
|
|
611
898
|
end
|
|
612
899
|
|
|
613
900
|
it 'when :accept_key is false and input() is collecting a finite number of digits, it should allow all DTMFs' do
|
|
@@ -618,6 +905,18 @@ describe 'input command' do
|
|
|
618
905
|
}.should_not raise_error ArgumentError
|
|
619
906
|
end
|
|
620
907
|
|
|
908
|
+
it 'should terminate early when the passed block returns something truthy' do
|
|
909
|
+
three_digits = %w[9 3 0]
|
|
910
|
+
mock_call.should_receive(:wait_for_digit).times(2).and_return(*three_digits)
|
|
911
|
+
mock_call.input(3, :accept_key => false) { |buffer| buffer.size == 2 }.should == '93'
|
|
912
|
+
end
|
|
913
|
+
|
|
914
|
+
it "Input timing out when digits are pressed returns only the collected digits" do
|
|
915
|
+
timeout = 1.day
|
|
916
|
+
mock_call.should_receive(:wait_for_digit).twice.with(timeout).and_return '5', nil
|
|
917
|
+
mock_call.input(9, :timeout => timeout).should == '5'
|
|
918
|
+
end
|
|
919
|
+
|
|
621
920
|
it 'passes wait_for_digit the :timeout option when one is given' do
|
|
622
921
|
mock_call.should_receive(:interruptible_play!).never
|
|
623
922
|
mock_call.should_receive(:wait_for_digit).twice.and_return '1', '2'
|
|
@@ -633,6 +932,15 @@ describe 'input command' do
|
|
|
633
932
|
mock_call.input(2, :play => sound_files).should == '#*'
|
|
634
933
|
end
|
|
635
934
|
|
|
935
|
+
it 'executes #play! when :interruptible is set to false' do
|
|
936
|
+
sound_files = %w[foo bar qaz]
|
|
937
|
+
mock_call.should_receive(:play!).once.with('foo').and_return true
|
|
938
|
+
mock_call.should_receive(:play!).once.with('bar').and_return true
|
|
939
|
+
mock_call.should_receive(:play!).once.with('qaz').and_return true
|
|
940
|
+
mock_call.should_receive(:wait_for_digit).once.and_return '*'
|
|
941
|
+
mock_call.input(1, :play => sound_files, :interruptible => false).should == '*'
|
|
942
|
+
end
|
|
943
|
+
|
|
636
944
|
it 'pressing the terminating key before any other digits returns an empty string' do
|
|
637
945
|
mock_call.should_receive(:wait_for_digit).once.and_return '*'
|
|
638
946
|
mock_call.input(:accept_key => '*').should == ''
|
|
@@ -650,7 +958,7 @@ describe 'input command' do
|
|
|
650
958
|
mock_call.input(9, :timeout => timeout).should == '5'
|
|
651
959
|
end
|
|
652
960
|
|
|
653
|
-
it 'should execute wait_for_digit, even if some sound files are not found' do
|
|
961
|
+
it 'should execute wait_for_digit, even if some interruptible sound files are not found' do
|
|
654
962
|
pbx_should_respond_with_stream_file_failure_on_open
|
|
655
963
|
file = 'foobar'
|
|
656
964
|
timeout = 1.hour
|
|
@@ -659,6 +967,15 @@ describe 'input command' do
|
|
|
659
967
|
pbx_was_asked_to_stream file
|
|
660
968
|
end
|
|
661
969
|
|
|
970
|
+
it 'should execute wait_for_digit with, even if some uninterruptible sound files are not found' do
|
|
971
|
+
pbx_should_respond_with_playback_failure
|
|
972
|
+
file = 'foobar'
|
|
973
|
+
timeout = 1.hour
|
|
974
|
+
mock_call.should_receive(:wait_for_digit).twice.with(timeout).and_return '8', '9'
|
|
975
|
+
mock_call.input(2, :timeout => timeout, :play => file, :interruptible => false).should == '89'
|
|
976
|
+
pbx_was_asked_to_play file
|
|
977
|
+
end
|
|
978
|
+
|
|
662
979
|
it 'should return an empty string if no keys are pressed, even if the sound file is not found' do
|
|
663
980
|
pbx_should_respond_with_stream_file_failure_on_open
|
|
664
981
|
file = 'foobar'
|
|
@@ -682,7 +999,7 @@ describe 'input command' do
|
|
|
682
999
|
pbx_was_asked_to_stream played_files
|
|
683
1000
|
end
|
|
684
1001
|
|
|
685
|
-
it 'should play a series of 4
|
|
1002
|
+
it 'should play a series of 4 interruptible sounds, collecting digits even if some of the sound files cannot be found' do
|
|
686
1003
|
pbx_should_respond_with_stream_file_success 0
|
|
687
1004
|
pbx_should_respond_with_stream_file_success 0
|
|
688
1005
|
pbx_should_respond_with_stream_file_failure_on_open
|
|
@@ -697,9 +1014,57 @@ describe 'input command' do
|
|
|
697
1014
|
pbx_was_asked_to_stream played_files
|
|
698
1015
|
end
|
|
699
1016
|
|
|
1017
|
+
it 'should not raise an exception if the sound file is unplayable' do
|
|
1018
|
+
pbx_should_respond_with_stream_file_failure_on_open
|
|
1019
|
+
file = 'foobar'
|
|
1020
|
+
mock_call.should_receive(:wait_for_digit).once
|
|
1021
|
+
the_following_code {
|
|
1022
|
+
mock_call.input 1, :play => file
|
|
1023
|
+
}.should_not raise_error
|
|
1024
|
+
pbx_was_asked_to_stream file
|
|
1025
|
+
end
|
|
1026
|
+
|
|
1027
|
+
it 'should default to playing interruptible prompts' do
|
|
1028
|
+
mock_call.should_receive(:interruptible_play!).once.with('does_not_matter')
|
|
1029
|
+
mock_call.should_receive(:wait_for_digit).once
|
|
1030
|
+
mock_call.input(1, :play => 'does_not_matter')
|
|
1031
|
+
end
|
|
1032
|
+
|
|
1033
|
+
it 'should render uninterruptible prompts' do
|
|
1034
|
+
mock_call.should_receive(:play!).once.with('does_not_matter')
|
|
1035
|
+
mock_call.should_receive(:wait_for_digit).once
|
|
1036
|
+
mock_call.input(1, :play => 'does_not_matter', :interruptible => false)
|
|
1037
|
+
end
|
|
1038
|
+
|
|
1039
|
+
it 'should fall back to speaking TTS if sound file is unplayable' do
|
|
1040
|
+
pbx_should_respond_with_stream_file_failure_on_open
|
|
1041
|
+
mock_call.should_receive(:speak).once.with("The sound file was not available", :interruptible => true)
|
|
1042
|
+
mock_call.should_receive(:wait_for_digit).once
|
|
1043
|
+
mock_call.input(1, :play => 'unavailable sound file', :speak => {:text => "The sound file was not available"})
|
|
1044
|
+
@output.read.should == "STREAM FILE \"unavailable sound file\" \"1234567890*#\"\n"
|
|
1045
|
+
end
|
|
1046
|
+
|
|
1047
|
+
it 'should allow uninterruptible TTS prompts' do
|
|
1048
|
+
mock_call.should_receive(:speak).once.with("The sound file was not available", :interruptible => false)
|
|
1049
|
+
mock_call.should_receive(:wait_for_digit).once
|
|
1050
|
+
mock_call.input(1, :speak => {:text => "The sound file was not available"}, :interruptible => false)
|
|
1051
|
+
end
|
|
1052
|
+
|
|
1053
|
+
it 'should play a series of 4 uninterruptible sounds, collecting digits even if some of the sound files cannot be found' do
|
|
1054
|
+
pbx_should_respond_with_playback_success
|
|
1055
|
+
pbx_should_respond_with_playback_failure
|
|
1056
|
+
pbx_should_respond_with_playback_success
|
|
1057
|
+
|
|
1058
|
+
files = ('sound1'..'sound3').map &:to_s
|
|
1059
|
+
timeout = 1.second
|
|
1060
|
+
mock_call.should_receive(:wait_for_digit).twice.with(timeout).and_return '6', '7'
|
|
1061
|
+
mock_call.input(2, :timeout => timeout, :play => files, :interruptible => false).should == '67'
|
|
1062
|
+
pbx_was_asked_to_play files
|
|
1063
|
+
end
|
|
1064
|
+
|
|
700
1065
|
end
|
|
701
1066
|
|
|
702
|
-
describe 'input!
|
|
1067
|
+
describe 'The #input! method' do
|
|
703
1068
|
|
|
704
1069
|
include DialplanCommandTestHelpers
|
|
705
1070
|
|
|
@@ -727,6 +1092,15 @@ describe 'input! command' do
|
|
|
727
1092
|
mock_call.input!(2, :play => sound_files).should == '#*'
|
|
728
1093
|
end
|
|
729
1094
|
|
|
1095
|
+
it 'executes play!() with all of the files given to :play' do
|
|
1096
|
+
sound_files = %w[foo bar qaz]
|
|
1097
|
+
mock_call.should_receive(:play!).once.with('foo').and_return true
|
|
1098
|
+
mock_call.should_receive(:play!).once.with('bar').and_return true
|
|
1099
|
+
mock_call.should_receive(:play!).once.with('qaz').and_return true
|
|
1100
|
+
mock_call.should_receive(:wait_for_digit).once.and_return '*'
|
|
1101
|
+
mock_call.input!(1, :play => sound_files, :interruptible => false).should == '*'
|
|
1102
|
+
end
|
|
1103
|
+
|
|
730
1104
|
it 'should execute wait_for_digit first if no sound files are given' do
|
|
731
1105
|
mock_call.should_receive(:interruptible_play!).never
|
|
732
1106
|
mock_call.should_receive(:wait_for_digit).once.and_throw :digit_request
|
|
@@ -743,7 +1117,7 @@ describe 'input! command' do
|
|
|
743
1117
|
pbx_was_asked_to_stream file
|
|
744
1118
|
end
|
|
745
1119
|
|
|
746
|
-
it 'should play a series of files, raising an error if a sound file cannot be found' do
|
|
1120
|
+
it 'should play a series of interruptible files, raising an error if a sound file cannot be found' do
|
|
747
1121
|
pbx_should_respond_with_stream_file_success 0
|
|
748
1122
|
pbx_should_respond_with_stream_file_failure_on_open
|
|
749
1123
|
mock_call.should_receive(:wait_for_digit).never
|
|
@@ -756,9 +1130,21 @@ describe 'input! command' do
|
|
|
756
1130
|
pbx_was_asked_to_stream played_files
|
|
757
1131
|
end
|
|
758
1132
|
|
|
1133
|
+
it 'should play a series of uninterruptible files, raising an error if a sound file cannot be found' do
|
|
1134
|
+
pbx_should_respond_with_playback_success
|
|
1135
|
+
pbx_should_respond_with_playback_failure
|
|
1136
|
+
|
|
1137
|
+
play_files = ('sound1'..'sound6').map &:to_s
|
|
1138
|
+
played_files = ('sound1'..'sound2').map &:to_s
|
|
1139
|
+
the_following_code {
|
|
1140
|
+
mock_call.input! 10, :play => play_files, :timeout => 5.seconds, :interruptible => false
|
|
1141
|
+
}.should raise_error Adhearsion::VoIP::PlaybackError
|
|
1142
|
+
pbx_was_asked_to_play played_files
|
|
1143
|
+
end
|
|
1144
|
+
|
|
759
1145
|
end
|
|
760
1146
|
|
|
761
|
-
describe "The variable
|
|
1147
|
+
describe "The #variable method" do
|
|
762
1148
|
|
|
763
1149
|
include DialplanCommandTestHelpers
|
|
764
1150
|
|
|
@@ -795,7 +1181,7 @@ describe "The variable() command" do
|
|
|
795
1181
|
|
|
796
1182
|
end
|
|
797
1183
|
|
|
798
|
-
describe "
|
|
1184
|
+
describe "The #set_variable method" do
|
|
799
1185
|
|
|
800
1186
|
include DialplanCommandTestHelpers
|
|
801
1187
|
|
|
@@ -811,7 +1197,7 @@ describe "the set_variable method" do
|
|
|
811
1197
|
|
|
812
1198
|
end
|
|
813
1199
|
|
|
814
|
-
describe "
|
|
1200
|
+
describe "The #sip_add_header method" do
|
|
815
1201
|
include DialplanCommandTestHelpers
|
|
816
1202
|
|
|
817
1203
|
it "values are properly quoted" do
|
|
@@ -820,21 +1206,23 @@ describe "the sip_add_header method" do
|
|
|
820
1206
|
end
|
|
821
1207
|
end
|
|
822
1208
|
|
|
823
|
-
describe "
|
|
1209
|
+
describe "The #sip_get_header method" do
|
|
824
1210
|
include DialplanCommandTestHelpers
|
|
825
1211
|
|
|
826
|
-
it "
|
|
827
|
-
|
|
828
|
-
mock_call.
|
|
1212
|
+
it "properly formats the AGI request" do
|
|
1213
|
+
value = 'jason-was-here'
|
|
1214
|
+
mock_call.should_receive(:raw_response).once.with('GET VARIABLE "SIP_HEADER(x-ahn-header)"').and_return "200 result=1 (#{value})"
|
|
1215
|
+
mock_call.sip_get_header("x-ahn-header").should == value
|
|
829
1216
|
end
|
|
830
1217
|
|
|
831
|
-
it "
|
|
832
|
-
|
|
833
|
-
mock_call.
|
|
1218
|
+
it "properly formats the AGI request using the method alias" do
|
|
1219
|
+
value = 'jason-was-here'
|
|
1220
|
+
mock_call.should_receive(:raw_response).once.with('GET VARIABLE "SIP_HEADER(x-ahn-header)"').and_return "200 result=1 (#{value})"
|
|
1221
|
+
mock_call.sip_header("x-ahn-header").should == value
|
|
834
1222
|
end
|
|
835
1223
|
end
|
|
836
1224
|
|
|
837
|
-
describe '
|
|
1225
|
+
describe 'The #voicemail command' do
|
|
838
1226
|
|
|
839
1227
|
include DialplanCommandTestHelpers
|
|
840
1228
|
|
|
@@ -857,12 +1245,13 @@ describe 'the voicemail command' do
|
|
|
857
1245
|
end
|
|
858
1246
|
|
|
859
1247
|
it 'should combine mailbox numbers with the context name given when both are given' do
|
|
860
|
-
|
|
1248
|
+
pbx_should_respond_with_value 'SUCCESS'
|
|
861
1249
|
context = "lolcats"
|
|
862
1250
|
mailboxes = [1,2,3,4,5]
|
|
863
1251
|
mailboxes_with_context = mailboxes.map { |mailbox| "#{mailbox}@#{context}"}
|
|
864
1252
|
mock_call.should_receive(:execute).once.with('voicemail', mailboxes_with_context.join('&'), '')
|
|
865
1253
|
mock_call.voicemail context => mailboxes
|
|
1254
|
+
pbx_should_have_been_sent 'GET VARIABLE "VMSTATUS"'
|
|
866
1255
|
end
|
|
867
1256
|
|
|
868
1257
|
it 'should raise an argument error if the mailbox number is not numerical' do
|
|
@@ -1047,12 +1436,14 @@ describe "The queue management abstractions" do
|
|
|
1047
1436
|
does_not_read_data_back
|
|
1048
1437
|
mock_call.should_receive(:get_variable).once.with("QUEUESTATUS").and_return "TIMEOUT"
|
|
1049
1438
|
mock_call.queue('monkey').join!.should be :timeout
|
|
1439
|
+
pbx_should_have_been_sent 'EXEC queue "monkey"|""|""|""|""|""'
|
|
1050
1440
|
end
|
|
1051
1441
|
|
|
1052
1442
|
it 'should return :completed after joining the queue and being connected' do
|
|
1053
1443
|
does_not_read_data_back
|
|
1054
1444
|
mock_call.should_receive(:get_variable).once.with("QUEUESTATUS").and_return nil
|
|
1055
1445
|
mock_call.queue('monkey').join!.should be :completed
|
|
1446
|
+
pbx_should_have_been_sent 'EXEC queue "monkey"|""|""|""|""|""'
|
|
1056
1447
|
end
|
|
1057
1448
|
|
|
1058
1449
|
it 'should join a queue with a timeout properly' do
|
|
@@ -1204,6 +1595,7 @@ describe "The queue management abstractions" do
|
|
|
1204
1595
|
the_following_code {
|
|
1205
1596
|
mock_call.queue('this_should_not_exist').agents.new 'Agent/911'
|
|
1206
1597
|
}.should raise_error Adhearsion::VoIP::Asterisk::Commands::QueueProxy::QueueDoesNotExistError
|
|
1598
|
+
pbx_should_have_been_sent 'EXEC AddQueueMember "this_should_not_exist"|"Agent/911"|""|""|""|""'
|
|
1207
1599
|
end
|
|
1208
1600
|
|
|
1209
1601
|
it 'when a queue agent is dynamiaclly added and the adding was successful, an AgentProxy should be returned' do
|
|
@@ -1284,6 +1676,7 @@ describe "The queue management abstractions" do
|
|
|
1284
1676
|
|
|
1285
1677
|
agents = mock_call.queue('lolcats').agents :cache => true
|
|
1286
1678
|
agents.last.pause!.should be true
|
|
1679
|
+
pbx_should_have_been_sent 'EXEC PauseQueueMember "lolcats"|"Agent/008"'
|
|
1287
1680
|
end
|
|
1288
1681
|
|
|
1289
1682
|
it 'should pause an agent properly from a certain queue and return false when the agent did not exist' do
|
|
@@ -1442,6 +1835,7 @@ describe 'the menu() method' do
|
|
|
1442
1835
|
link.other 543
|
|
1443
1836
|
end
|
|
1444
1837
|
end
|
|
1838
|
+
3.times { pbx_should_have_been_sent 'WAIT FOR DIGIT "5000"' }
|
|
1445
1839
|
end
|
|
1446
1840
|
|
|
1447
1841
|
it "when the 'extension' variable is changed, it should be an instance of PhoneNumber" do
|
|
@@ -1455,6 +1849,7 @@ describe 'the menu() method' do
|
|
|
1455
1849
|
end
|
|
1456
1850
|
5.should === mock_call.extension
|
|
1457
1851
|
mock_call.extension.__real_string.should == "5"
|
|
1852
|
+
pbx_should_have_been_sent 'WAIT FOR DIGIT "5000"'
|
|
1458
1853
|
end
|
|
1459
1854
|
|
|
1460
1855
|
end
|
|
@@ -1511,9 +1906,6 @@ describe 'the Menu class' do
|
|
|
1511
1906
|
end
|
|
1512
1907
|
|
|
1513
1908
|
it "should default the timeout to five seconds" do
|
|
1514
|
-
pbx_should_respond_with_successful_background_response ?2.ord
|
|
1515
|
-
pbx_should_respond_with_a_wait_for_digit_timeout
|
|
1516
|
-
|
|
1517
1909
|
mock_call.should_receive(:wait_for_digit).once.with(5).and_return nil
|
|
1518
1910
|
mock_call.menu { |link| link.foobar 22 }
|
|
1519
1911
|
end
|
|
@@ -1536,6 +1928,7 @@ describe 'the Menu class' do
|
|
|
1536
1928
|
end
|
|
1537
1929
|
end
|
|
1538
1930
|
times_timed_out.should be tries
|
|
1931
|
+
30.times { pbx_should_have_been_sent 'WAIT FOR DIGIT "5000"' }
|
|
1539
1932
|
end
|
|
1540
1933
|
|
|
1541
1934
|
it "when matches fail due to invalid input, the menu should repeat :tries times" do
|
|
@@ -1555,6 +1948,7 @@ describe 'the Menu class' do
|
|
|
1555
1948
|
end
|
|
1556
1949
|
end
|
|
1557
1950
|
times_invalid.should be tries
|
|
1951
|
+
10.times { pbx_should_have_been_sent 'WAIT FOR DIGIT "5000"' }
|
|
1558
1952
|
end
|
|
1559
1953
|
|
|
1560
1954
|
it "invoke on_invalid callback when an invalid extension was entered" do
|
|
@@ -1567,6 +1961,7 @@ describe 'the Menu class' do
|
|
|
1567
1961
|
link.on_invalid { throw :inside_invalid_callback }
|
|
1568
1962
|
end
|
|
1569
1963
|
end
|
|
1964
|
+
pbx_should_have_been_sent 'WAIT FOR DIGIT "5000"'
|
|
1570
1965
|
end
|
|
1571
1966
|
|
|
1572
1967
|
it "invoke on_premature_timeout when a timeout is encountered" do
|
|
@@ -1579,6 +1974,7 @@ describe 'the Menu class' do
|
|
|
1579
1974
|
link.on_premature_timeout { throw :inside_timeout }
|
|
1580
1975
|
end
|
|
1581
1976
|
end
|
|
1977
|
+
2.times { pbx_should_have_been_sent 'WAIT FOR DIGIT "1000"' }
|
|
1582
1978
|
end
|
|
1583
1979
|
|
|
1584
1980
|
end
|
|
@@ -1603,6 +1999,7 @@ describe "the Menu class's high-level judgment" do
|
|
|
1603
1999
|
end
|
|
1604
2000
|
end
|
|
1605
2001
|
111.should === mock_call.extension
|
|
2002
|
+
4.times { pbx_should_have_been_sent 'WAIT FOR DIGIT "5000"' }
|
|
1606
2003
|
end
|
|
1607
2004
|
|
|
1608
2005
|
it 'should match things in a range when there are many other non-matching patterns' do
|
|
@@ -1621,6 +2018,7 @@ describe "the Menu class's high-level judgment" do
|
|
|
1621
2018
|
link.conferences 900..999
|
|
1622
2019
|
end
|
|
1623
2020
|
end
|
|
2021
|
+
3.times { pbx_should_have_been_sent 'WAIT FOR DIGIT "5000"' }
|
|
1624
2022
|
end
|
|
1625
2023
|
|
|
1626
2024
|
end
|
|
@@ -1938,11 +2336,13 @@ describe "get variable command" do
|
|
|
1938
2336
|
it "Getting a variable that isn't set returns nothing" do
|
|
1939
2337
|
pbx_should_respond_with "200 result=0"
|
|
1940
2338
|
mock_call.get_variable('OMGURFACE').should be nil
|
|
2339
|
+
pbx_should_have_been_sent 'GET VARIABLE "OMGURFACE"'
|
|
1941
2340
|
end
|
|
1942
2341
|
|
|
1943
2342
|
it 'An empty variable should return an empty String' do
|
|
1944
2343
|
pbx_should_respond_with_value ""
|
|
1945
2344
|
mock_call.get_variable('kablamm').should == ""
|
|
2345
|
+
pbx_should_have_been_sent 'GET VARIABLE "kablamm"'
|
|
1946
2346
|
end
|
|
1947
2347
|
|
|
1948
2348
|
it "Getting a variable that is set returns its value" do
|
|
@@ -1950,6 +2350,7 @@ describe "get variable command" do
|
|
|
1950
2350
|
pbx_should_respond_with_value unique_id
|
|
1951
2351
|
variable_value_returned = mock_call.get_variable('UNIQUEID')
|
|
1952
2352
|
variable_value_returned.should == unique_id
|
|
2353
|
+
pbx_should_have_been_sent 'GET VARIABLE "UNIQUEID"'
|
|
1953
2354
|
end
|
|
1954
2355
|
end
|
|
1955
2356
|
|
|
@@ -1991,6 +2392,7 @@ describe "Dial command" do
|
|
|
1991
2392
|
does_not_read_data_back
|
|
1992
2393
|
mock_call.should_receive(:set_caller_id_number).once
|
|
1993
2394
|
mock_call.dial 123, :caller_id => "1234678901"
|
|
2395
|
+
pbx_should_have_been_sent 'EXEC Dial "123"|""|""'
|
|
1994
2396
|
end
|
|
1995
2397
|
|
|
1996
2398
|
it 'should raise an exception when unknown hash key arguments are given to it' do
|
|
@@ -2004,6 +2406,7 @@ describe "Dial command" do
|
|
|
2004
2406
|
name = "Jay Phillips"
|
|
2005
2407
|
mock_call.should_receive(:set_caller_id_name).once.with(name)
|
|
2006
2408
|
mock_call.dial "BlahBlahBlah", :name => name
|
|
2409
|
+
pbx_should_have_been_sent 'EXEC Dial "BlahBlahBlah"|""|""'
|
|
2007
2410
|
end
|
|
2008
2411
|
|
|
2009
2412
|
it "should raise an exception when a non-numerical caller_id is specified" do
|
|
@@ -2012,11 +2415,19 @@ describe "Dial command" do
|
|
|
2012
2415
|
}.should raise_error ArgumentError
|
|
2013
2416
|
end
|
|
2014
2417
|
|
|
2418
|
+
it "should not raise an exception when a caller_id is specified in E.164 format (with '+' sign)" do
|
|
2419
|
+
the_following_code {
|
|
2420
|
+
mock_call.dial 911, :caller_id => "+123456789"
|
|
2421
|
+
}.should_not raise_error ArgumentError
|
|
2422
|
+
pbx_should_have_been_sent 'SET VARIABLE "CALLERID(num)" "+123456789"'
|
|
2423
|
+
end
|
|
2424
|
+
|
|
2015
2425
|
it 'should pass the value of the :confirm key to dial_macro_option_compiler()' do
|
|
2016
2426
|
does_not_read_data_back
|
|
2017
2427
|
value_of_confirm_key = {:play => "ohai", :timeout => 30}
|
|
2018
2428
|
mock_call.should_receive(:dial_macro_option_compiler).once.with value_of_confirm_key
|
|
2019
2429
|
mock_call.dial 123, :confirm => value_of_confirm_key
|
|
2430
|
+
pbx_should_have_been_sent 'EXEC Dial "123"|""|""'
|
|
2020
2431
|
end
|
|
2021
2432
|
|
|
2022
2433
|
it "should add the return value of dial_macro_option_compiler to the :options key's value given to the dial command" do
|
|
@@ -2248,33 +2659,124 @@ describe 'set_caller_id_name command' do
|
|
|
2248
2659
|
end
|
|
2249
2660
|
end
|
|
2250
2661
|
|
|
2251
|
-
describe "
|
|
2662
|
+
describe "speak command" do
|
|
2252
2663
|
include DialplanCommandTestHelpers
|
|
2253
2664
|
|
|
2665
|
+
before :all do
|
|
2666
|
+
@speech_engines = Adhearsion::VoIP::Asterisk::Commands::SpeechEngines
|
|
2667
|
+
end
|
|
2668
|
+
|
|
2254
2669
|
it "executes the command SpeechEngine gives it based on the engine name" do
|
|
2255
|
-
|
|
2256
|
-
flexmock(
|
|
2257
|
-
|
|
2258
|
-
mock_call.should_receive(:execute).once.with(mock_speak_command)
|
|
2259
|
-
mock_call.speak "Spoken text doesn't matter", :cepstral
|
|
2670
|
+
pbx_should_respond_with_success
|
|
2671
|
+
flexmock(@speech_engines).should_receive(:cepstral).once
|
|
2672
|
+
mock_call.speak "Spoken text doesn't matter", :engine => :cepstral
|
|
2260
2673
|
end
|
|
2261
2674
|
|
|
2262
2675
|
it "raises an InvalidSpeechEngine exception when the engine is 'none'" do
|
|
2263
2676
|
the_following_code {
|
|
2264
|
-
mock_call.speak("o hai!", :none)
|
|
2265
|
-
}.should raise_error
|
|
2677
|
+
mock_call.speak("o hai!", :engine => :none)
|
|
2678
|
+
}.should raise_error @speech_engines::InvalidSpeechEngine
|
|
2266
2679
|
end
|
|
2267
2680
|
|
|
2268
2681
|
it "should default its engine to :none" do
|
|
2269
2682
|
the_following_code {
|
|
2270
|
-
flexmock(
|
|
2271
|
-
and_raise(
|
|
2683
|
+
flexmock(@speech_engines).should_receive(:none).once.
|
|
2684
|
+
and_raise(@speech_engines::InvalidSpeechEngine)
|
|
2272
2685
|
mock_call.speak "ruby ruby ruby ruby!"
|
|
2273
|
-
}.should raise_error
|
|
2686
|
+
}.should raise_error @speech_engines::InvalidSpeechEngine
|
|
2687
|
+
end
|
|
2688
|
+
|
|
2689
|
+
it 'should default to a configured TTS engine' do
|
|
2690
|
+
Adhearsion::Configuration.configure {|c| c.asterisk.speech_engine = :unimrcp }
|
|
2691
|
+
flexmock(@speech_engines).should_receive(:unimrcp).once
|
|
2692
|
+
mock_call.speak 'What say you, sir?'
|
|
2693
|
+
end
|
|
2694
|
+
|
|
2695
|
+
it 'should allow the caller to override the default configured TTS engine' do
|
|
2696
|
+
Adhearsion::Configuration.configure {|c| c.asterisk.speech_engine = :unimrcp }
|
|
2697
|
+
flexmock(@speech_engines).should_receive(:cepstral).once
|
|
2698
|
+
mock_call.speak 'What say you now, sir?', :engine => :cepstral
|
|
2699
|
+
end
|
|
2700
|
+
|
|
2701
|
+
it 'should default to uninterruptible TTS rendering' do
|
|
2702
|
+
flexmock(@speech_engines).should_receive(:cepstral).once.with(mock_call, 'hello', {:interruptible => false})
|
|
2703
|
+
mock_call.speak 'hello', :engine => :cepstral
|
|
2704
|
+
end
|
|
2705
|
+
|
|
2706
|
+
it 'should allow setting TTS rendering interruptible' do
|
|
2707
|
+
flexmock(@speech_engines).should_receive(:cepstral).once.with(mock_call, 'hello', {:interruptible => true})
|
|
2708
|
+
mock_call.speak 'hello', :engine => :cepstral, :interruptible => true
|
|
2274
2709
|
end
|
|
2275
2710
|
|
|
2276
|
-
|
|
2711
|
+
it "should stringify the text" do
|
|
2712
|
+
flexmock(@speech_engines).should_receive(:cepstral).once.with(mock_call, 'hello', {:interruptible => false})
|
|
2713
|
+
mock_call.speak :hello, :engine => :cepstral
|
|
2714
|
+
end
|
|
2715
|
+
|
|
2716
|
+
context "with the engine :cepstral" do
|
|
2717
|
+
it "should execute Swift"do
|
|
2718
|
+
pbx_should_respond_with_value 0
|
|
2719
|
+
mock_call.should_receive(:execute).with('Swift', 'hello')
|
|
2720
|
+
@speech_engines.cepstral(mock_call, 'hello')
|
|
2721
|
+
@output.read.should == "GET VARIABLE \"SWIFT_DTMF\"\n"
|
|
2722
|
+
end
|
|
2723
|
+
|
|
2724
|
+
it "should properly escape commas in the TTS string" do
|
|
2725
|
+
pbx_should_respond_with_value 0
|
|
2726
|
+
mock_call.should_receive(:execute).with('Swift', 'Once\\\\, a long\\\\, long time ago\\\\, ...')
|
|
2727
|
+
@speech_engines.cepstral(mock_call, 'Once, a long, long time ago, ...')
|
|
2728
|
+
@output.read.should == "GET VARIABLE \"SWIFT_DTMF\"\n"
|
|
2729
|
+
end
|
|
2730
|
+
|
|
2731
|
+
it "should properly escape double-quotes (for XML) in the TTS string" do
|
|
2732
|
+
mock_call.should_receive(:raw_response).once.with('EXEC MRCPSynth "<speak xmlns=\\\\\"http://www.w3.org/2001/10/synthesis\\\\\" version=\\\\\"1.0\\\\\" xml:lang=\\\\\"en-US\\\\\"> <voice name=\\\\\"Paul\\\\\"> <prosody rate=\\\\\"1.0\\\\\">Howdy, stranger. How are you today?</prosody> </voice> </speak>"').and_return pbx_success_response
|
|
2733
|
+
@speech_engines.unimrcp(mock_call, '<speak xmlns="http://www.w3.org/2001/10/synthesis" version="1.0" xml:lang="en-US"> <voice name="Paul"> <prosody rate="1.0">Howdy, stranger. How are you today?</prosody> </voice> </speak>')
|
|
2734
|
+
end
|
|
2735
|
+
|
|
2736
|
+
context "with barge in digits set" do
|
|
2737
|
+
it "should return the digit when :interruptible = true" do
|
|
2738
|
+
mock_call.should_receive(:execute).once.with('Swift', 'hello', 1, 1).and_return pbx_success_response
|
|
2739
|
+
mock_call.should_receive(:get_variable).once.with('SWIFT_DTMF').and_return ?1
|
|
2740
|
+
@speech_engines.cepstral(mock_call, 'hello', :interruptible => true).should == ?1
|
|
2741
|
+
end
|
|
2742
|
+
end
|
|
2743
|
+
end
|
|
2744
|
+
|
|
2745
|
+
context "with the engine :unimrcp" do
|
|
2746
|
+
it "should execute MRCPSynth" do
|
|
2747
|
+
pbx_should_respond_with_success
|
|
2748
|
+
mock_call.should_receive(:execute).with('MRCPSynth', 'hello').once.and_return pbx_success_response
|
|
2749
|
+
@speech_engines.unimrcp(mock_call, 'hello')
|
|
2750
|
+
end
|
|
2751
|
+
|
|
2752
|
+
context "with barge in digits set" do
|
|
2753
|
+
it "should pass the i option for MRCPSynth" do
|
|
2754
|
+
mock_call.should_receive(:execute).with('MRCPSynth', 'hello', 'i=any').once.and_return pbx_result_response 0
|
|
2755
|
+
@speech_engines.unimrcp(mock_call, 'hello', :interrupt_digits => 'any')
|
|
2756
|
+
end
|
|
2757
|
+
end
|
|
2758
|
+
end
|
|
2759
|
+
|
|
2760
|
+
context "with the engine :tropo" do
|
|
2761
|
+
it "should execute tropo" do
|
|
2762
|
+
pbx_should_respond_with_success
|
|
2763
|
+
response = '200 result=' + {:interpretation => '1'}.to_json
|
|
2764
|
+
mock_call.should_receive(:raw_response).with(/Ask/i, 'hello').once.and_return response
|
|
2765
|
+
@speech_engines.tropo(mock_call, 'hello').should == "1"
|
|
2766
|
+
end
|
|
2767
|
+
|
|
2768
|
+
context "with :interruptible set to false"do
|
|
2769
|
+
it "should pass the :bargein => false option for Tropo Ask" do
|
|
2770
|
+
response = '200 result=' + {:interpretation => '1'}.to_json
|
|
2771
|
+
mock_call.should_receive(:raw_response).with(/Ask/i, 'hello', {:bargein => false}.to_json).once.and_return response
|
|
2772
|
+
@speech_engines.tropo(mock_call, 'hello', :interruptible => false)
|
|
2773
|
+
end
|
|
2774
|
+
end
|
|
2775
|
+
end
|
|
2277
2776
|
|
|
2777
|
+
it "properly escapes spoken text" do
|
|
2778
|
+
pending 'What are the escaping needs?'
|
|
2779
|
+
end
|
|
2278
2780
|
end
|
|
2279
2781
|
|
|
2280
2782
|
describe 'The join command' do
|