punchblock 1.2.0 → 1.3.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/.travis.yml +3 -3
- data/CHANGELOG.md +23 -0
- data/lib/punchblock.rb +24 -0
- data/lib/punchblock/command/reject.rb +10 -2
- data/lib/punchblock/component/record.rb +16 -0
- data/lib/punchblock/core_ext/blather/stanza.rb +3 -1
- data/lib/punchblock/dead_actor_safety.rb +9 -0
- data/lib/punchblock/event/complete.rb +9 -11
- data/lib/punchblock/rayo_node.rb +4 -0
- data/lib/punchblock/translator/asterisk.rb +65 -22
- data/lib/punchblock/translator/asterisk/call.rb +49 -30
- data/lib/punchblock/translator/asterisk/component.rb +6 -8
- data/lib/punchblock/translator/asterisk/component/asterisk/agi_command.rb +13 -20
- data/lib/punchblock/translator/asterisk/component/asterisk/ami_action.rb +1 -1
- data/lib/punchblock/translator/asterisk/component/input.rb +3 -6
- data/lib/punchblock/translator/asterisk/component/output.rb +40 -45
- data/lib/punchblock/translator/asterisk/component/record.rb +1 -1
- data/lib/punchblock/translator/asterisk/component/stop_by_redirect.rb +5 -2
- data/lib/punchblock/version.rb +1 -1
- data/punchblock.gemspec +5 -5
- data/spec/punchblock/command/reject_spec.rb +7 -1
- data/spec/punchblock/command_node_spec.rb +5 -2
- data/spec/punchblock/component/component_node_spec.rb +4 -0
- data/spec/punchblock/component/output_spec.rb +1 -1
- data/spec/punchblock/component/record_spec.rb +30 -0
- data/spec/punchblock/event/complete_spec.rb +10 -0
- data/spec/punchblock/translator/asterisk/call_spec.rb +191 -48
- data/spec/punchblock/translator/asterisk/component/asterisk/agi_command_spec.rb +6 -39
- data/spec/punchblock/translator/asterisk/component/asterisk/ami_action_spec.rb +3 -3
- data/spec/punchblock/translator/asterisk/component/input_spec.rb +8 -3
- data/spec/punchblock/translator/asterisk/component/output_spec.rb +153 -46
- data/spec/punchblock/translator/asterisk/component/record_spec.rb +6 -5
- data/spec/punchblock/translator/asterisk/component/stop_by_redirect_spec.rb +1 -2
- data/spec/punchblock/translator/asterisk/component_spec.rb +1 -0
- data/spec/punchblock/translator/asterisk_spec.rb +147 -12
- data/spec/punchblock_spec.rb +34 -0
- data/spec/spec_helper.rb +5 -1
- metadata +30 -20
|
@@ -16,9 +16,9 @@ module Punchblock
|
|
|
16
16
|
end
|
|
17
17
|
let(:translator) { Punchblock::Translator::Asterisk.new mock('AMI'), connection }
|
|
18
18
|
let(:mock_call) { Punchblock::Translator::Asterisk::Call.new channel, translator }
|
|
19
|
-
let(:component_id) {
|
|
19
|
+
let(:component_id) { Punchblock.new_uuid }
|
|
20
20
|
|
|
21
|
-
before {
|
|
21
|
+
before { stub_uuids component_id }
|
|
22
22
|
|
|
23
23
|
let :command do
|
|
24
24
|
Punchblock::Component::Asterisk::AGI::Command.new :name => 'EXEC ANSWER'
|
|
@@ -31,8 +31,10 @@ module Punchblock
|
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
context 'initial execution' do
|
|
34
|
+
before { command.request! }
|
|
35
|
+
|
|
34
36
|
it 'should send the appropriate RubyAMI::Action' do
|
|
35
|
-
mock_call.expects(:send_ami_action
|
|
37
|
+
mock_call.expects(:send_ami_action).once.with(expected_action).returns(expected_action)
|
|
36
38
|
subject.execute
|
|
37
39
|
end
|
|
38
40
|
|
|
@@ -48,7 +50,7 @@ module Punchblock
|
|
|
48
50
|
end
|
|
49
51
|
|
|
50
52
|
it 'should send the appropriate RubyAMI::Action' do
|
|
51
|
-
mock_call.expects(:send_ami_action
|
|
53
|
+
mock_call.expects(:send_ami_action).once.with(expected_action).returns(expected_action)
|
|
52
54
|
subject.execute
|
|
53
55
|
end
|
|
54
56
|
end
|
|
@@ -125,41 +127,6 @@ module Punchblock
|
|
|
125
127
|
end
|
|
126
128
|
end
|
|
127
129
|
end
|
|
128
|
-
|
|
129
|
-
describe '#parse_agi_result' do
|
|
130
|
-
context 'with a simple result with no data' do
|
|
131
|
-
let(:result_string) { "200%20result=123%0A" }
|
|
132
|
-
|
|
133
|
-
it 'should provide the code and result' do
|
|
134
|
-
code, result, data = subject.parse_agi_result result_string
|
|
135
|
-
code.should be == 200
|
|
136
|
-
result.should be == 123
|
|
137
|
-
data.should be == ''
|
|
138
|
-
end
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
context 'with a result and data in parens' do
|
|
142
|
-
let(:result_string) { "200%20result=-123%20(timeout)%0A" }
|
|
143
|
-
|
|
144
|
-
it 'should provide the code and result' do
|
|
145
|
-
code, result, data = subject.parse_agi_result result_string
|
|
146
|
-
code.should be == 200
|
|
147
|
-
result.should be == -123
|
|
148
|
-
data.should be == 'timeout'
|
|
149
|
-
end
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
context 'with a result and key-value data' do
|
|
153
|
-
let(:result_string) { "200%20result=123%20foo=bar%0A" }
|
|
154
|
-
|
|
155
|
-
it 'should provide the code and result' do
|
|
156
|
-
code, result, data = subject.parse_agi_result result_string
|
|
157
|
-
code.should be == 200
|
|
158
|
-
result.should be == 123
|
|
159
|
-
data.should be == 'foo=bar'
|
|
160
|
-
end
|
|
161
|
-
end
|
|
162
|
-
end
|
|
163
130
|
end
|
|
164
131
|
end
|
|
165
132
|
end
|
|
@@ -26,16 +26,16 @@ module Punchblock
|
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
context 'initial execution' do
|
|
29
|
-
let(:component_id) {
|
|
29
|
+
let(:component_id) { Punchblock.new_uuid }
|
|
30
30
|
|
|
31
31
|
let :expected_response do
|
|
32
32
|
Ref.new :id => component_id
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
-
before {
|
|
35
|
+
before { stub_uuids component_id }
|
|
36
36
|
|
|
37
37
|
it 'should send the appropriate RubyAMI::Action and send the component node a ref with the action ID' do
|
|
38
|
-
mock_translator.expects(:send_ami_action
|
|
38
|
+
mock_translator.expects(:send_ami_action).once.with(expected_action).returns(expected_action)
|
|
39
39
|
command.expects(:response=).once.with(expected_response)
|
|
40
40
|
subject.execute
|
|
41
41
|
end
|
|
@@ -42,12 +42,12 @@ module Punchblock
|
|
|
42
42
|
describe '#execute' do
|
|
43
43
|
before { original_command.request! }
|
|
44
44
|
|
|
45
|
-
it "calls
|
|
46
|
-
call.expects
|
|
45
|
+
it "calls send_progress on the call" do
|
|
46
|
+
call.expects(:send_progress)
|
|
47
47
|
subject.execute
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
-
before { call.stubs :
|
|
50
|
+
before { call.stubs :send_progress }
|
|
51
51
|
|
|
52
52
|
let(:original_command_opts) { {} }
|
|
53
53
|
|
|
@@ -94,6 +94,11 @@ module Punchblock
|
|
|
94
94
|
it "should send a success complete event with the relevant data" do
|
|
95
95
|
reason.should be == expected_event
|
|
96
96
|
end
|
|
97
|
+
|
|
98
|
+
it "should not process further dtmf events" do
|
|
99
|
+
subject.expects(:process_dtmf!).never
|
|
100
|
+
send_ami_events_for_dtmf 3
|
|
101
|
+
end
|
|
97
102
|
end
|
|
98
103
|
|
|
99
104
|
context "when the match is invalid" do
|
|
@@ -32,16 +32,13 @@ module Punchblock
|
|
|
32
32
|
|
|
33
33
|
subject { Output.new original_command, mock_call }
|
|
34
34
|
|
|
35
|
+
def expect_answered(value = true)
|
|
36
|
+
mock_call.expects(:answered?).returns(value).at_least_once
|
|
37
|
+
end
|
|
38
|
+
|
|
35
39
|
describe '#execute' do
|
|
36
40
|
before { original_command.request! }
|
|
37
41
|
|
|
38
|
-
it "calls answer_if_not_answered on the call" do
|
|
39
|
-
mock_call.expects :answer_if_not_answered
|
|
40
|
-
subject.execute
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
before { mock_call.stubs :answer_if_not_answered }
|
|
44
|
-
|
|
45
42
|
context 'with a media engine of :swift' do
|
|
46
43
|
let(:media_engine) { :swift }
|
|
47
44
|
|
|
@@ -90,6 +87,7 @@ module Punchblock
|
|
|
90
87
|
context "set to :any" do
|
|
91
88
|
let(:command_opts) { { :interrupt_on => :any } }
|
|
92
89
|
it "should add the interrupt options to the argument" do
|
|
90
|
+
expect_answered
|
|
93
91
|
mock_call.expects(:send_agi_action!).once.with 'EXEC Swift', ssml_with_options('', '|1|1')
|
|
94
92
|
subject.execute
|
|
95
93
|
end
|
|
@@ -98,6 +96,7 @@ module Punchblock
|
|
|
98
96
|
context "set to :dtmf" do
|
|
99
97
|
let(:command_opts) { { :interrupt_on => :dtmf } }
|
|
100
98
|
it "should add the interrupt options to the argument" do
|
|
99
|
+
expect_answered
|
|
101
100
|
mock_call.expects(:send_agi_action!).once.with 'EXEC Swift', ssml_with_options('', '|1|1')
|
|
102
101
|
subject.execute
|
|
103
102
|
end
|
|
@@ -307,6 +306,7 @@ module Punchblock
|
|
|
307
306
|
context "set to :any" do
|
|
308
307
|
let(:command_opts) { { :interrupt_on => :any } }
|
|
309
308
|
it "should pass the i option to MRCPSynth" do
|
|
309
|
+
expect_answered
|
|
310
310
|
expect_mrcpsynth_with_options(/i=any/)
|
|
311
311
|
subject.execute
|
|
312
312
|
end
|
|
@@ -315,6 +315,7 @@ module Punchblock
|
|
|
315
315
|
context "set to :dtmf" do
|
|
316
316
|
let(:command_opts) { { :interrupt_on => :dtmf } }
|
|
317
317
|
it "should pass the i option to MRCPSynth" do
|
|
318
|
+
expect_answered
|
|
318
319
|
expect_mrcpsynth_with_options(/i=any/)
|
|
319
320
|
subject.execute
|
|
320
321
|
end
|
|
@@ -334,12 +335,12 @@ module Punchblock
|
|
|
334
335
|
context 'with a media engine of :asterisk' do
|
|
335
336
|
let(:media_engine) { :asterisk }
|
|
336
337
|
|
|
337
|
-
def
|
|
338
|
-
mock_call.expects(:send_agi_action!).once.with '
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
338
|
+
def expect_playback(filename = audio_filename)
|
|
339
|
+
mock_call.expects(:send_agi_action!).once.with 'EXEC Playback', filename
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
def expect_playback_noanswer
|
|
343
|
+
mock_call.expects(:send_agi_action!).once.with 'EXEC Playback', audio_filename + ',noanswer'
|
|
343
344
|
end
|
|
344
345
|
|
|
345
346
|
let(:audio_filename) { 'http://foo.com/bar.mp3' }
|
|
@@ -378,12 +379,16 @@ module Punchblock
|
|
|
378
379
|
}
|
|
379
380
|
end
|
|
380
381
|
|
|
381
|
-
it 'should playback the audio file using
|
|
382
|
-
|
|
382
|
+
it 'should playback the audio file using Playback' do
|
|
383
|
+
expect_answered
|
|
384
|
+
expect_playback
|
|
383
385
|
subject.execute
|
|
384
386
|
end
|
|
385
387
|
|
|
386
388
|
it 'should send a complete event when the file finishes playback' do
|
|
389
|
+
def mock_call.answered?
|
|
390
|
+
true
|
|
391
|
+
end
|
|
387
392
|
def mock_call.send_agi_action!(*args, &block)
|
|
388
393
|
block.call Punchblock::Component::Asterisk::AGI::Command::Complete::Success.new(:code => 200, :result => 1)
|
|
389
394
|
end
|
|
@@ -400,18 +405,45 @@ module Punchblock
|
|
|
400
405
|
}
|
|
401
406
|
end
|
|
402
407
|
|
|
403
|
-
it 'should playback the audio file using
|
|
404
|
-
|
|
408
|
+
it 'should playback the audio file using Playback' do
|
|
409
|
+
expect_answered
|
|
410
|
+
expect_playback
|
|
405
411
|
subject.execute
|
|
406
412
|
end
|
|
407
413
|
|
|
408
414
|
it 'should send a complete event when the file finishes playback' do
|
|
415
|
+
expect_answered
|
|
409
416
|
def mock_call.send_agi_action!(*args, &block)
|
|
410
417
|
block.call Punchblock::Component::Asterisk::AGI::Command::Complete::Success.new(:code => 200, :result => 1)
|
|
411
418
|
end
|
|
412
419
|
subject.execute
|
|
413
420
|
original_command.complete_event(0.1).reason.should be_a Punchblock::Component::Output::Complete::Success
|
|
414
421
|
end
|
|
422
|
+
|
|
423
|
+
context "with early media playback" do
|
|
424
|
+
it "should play the file with Playback" do
|
|
425
|
+
expect_answered false
|
|
426
|
+
expect_playback_noanswer
|
|
427
|
+
mock_call.expects(:send_progress)
|
|
428
|
+
subject.execute
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
context "with interrupt_on set to something that is not nil" do
|
|
432
|
+
let(:audio_filename) { 'tt-monkeys' }
|
|
433
|
+
let :command_options do
|
|
434
|
+
{
|
|
435
|
+
:ssml => RubySpeech::SSML.draw { string audio_filename },
|
|
436
|
+
:interrupt_on => :any
|
|
437
|
+
}
|
|
438
|
+
end
|
|
439
|
+
it "should return an error when the output is interruptible and it is early media" do
|
|
440
|
+
expect_answered false
|
|
441
|
+
error = ProtocolError.new.setup 'option error', 'Interrupt digits are not allowed with early media.'
|
|
442
|
+
subject.execute
|
|
443
|
+
original_command.response(0.1).should be == error
|
|
444
|
+
end
|
|
445
|
+
end
|
|
446
|
+
end
|
|
415
447
|
end
|
|
416
448
|
|
|
417
449
|
context 'with a string (not SSML)' do
|
|
@@ -438,29 +470,27 @@ module Punchblock
|
|
|
438
470
|
}
|
|
439
471
|
end
|
|
440
472
|
|
|
441
|
-
it 'should playback
|
|
473
|
+
it 'should playback all audio files using Playback' do
|
|
442
474
|
latch = CountDownLatch.new 2
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
latch.countdown!
|
|
446
|
-
end
|
|
447
|
-
mock_call.expects(:send_agi_action!).once.with 'STREAM FILE', audio_filename2, nil do
|
|
448
|
-
subject.continue
|
|
449
|
-
latch.countdown!
|
|
450
|
-
end
|
|
475
|
+
expect_playback [audio_filename1, audio_filename2].join('&')
|
|
476
|
+
expect_answered
|
|
451
477
|
subject.execute
|
|
452
478
|
latch.wait 2
|
|
453
479
|
sleep 2
|
|
454
480
|
end
|
|
455
481
|
|
|
456
482
|
it 'should send a complete event after the final file has finished playback' do
|
|
483
|
+
expect_answered
|
|
457
484
|
def mock_call.send_agi_action!(*args, &block)
|
|
458
485
|
block.call Punchblock::Component::Asterisk::AGI::Command::Complete::Success.new(:code => 200, :result => 1)
|
|
459
486
|
end
|
|
487
|
+
latch = CountDownLatch.new 1
|
|
460
488
|
original_command.expects(:add_event).once.with do |e|
|
|
461
489
|
e.reason.should be_a Punchblock::Component::Output::Complete::Success
|
|
490
|
+
latch.countdown!
|
|
462
491
|
end
|
|
463
492
|
subject.execute
|
|
493
|
+
latch.wait(2).should be_true
|
|
464
494
|
end
|
|
465
495
|
end
|
|
466
496
|
|
|
@@ -484,8 +514,9 @@ module Punchblock
|
|
|
484
514
|
describe 'start-offset' do
|
|
485
515
|
context 'unset' do
|
|
486
516
|
let(:command_opts) { { :start_offset => nil } }
|
|
487
|
-
it 'should not pass any options to
|
|
488
|
-
|
|
517
|
+
it 'should not pass any options to Playback' do
|
|
518
|
+
expect_answered
|
|
519
|
+
expect_playback
|
|
489
520
|
subject.execute
|
|
490
521
|
end
|
|
491
522
|
end
|
|
@@ -503,8 +534,9 @@ module Punchblock
|
|
|
503
534
|
describe 'start-paused' do
|
|
504
535
|
context 'false' do
|
|
505
536
|
let(:command_opts) { { :start_paused => false } }
|
|
506
|
-
it 'should not pass any options to
|
|
507
|
-
|
|
537
|
+
it 'should not pass any options to Playback' do
|
|
538
|
+
expect_answered
|
|
539
|
+
expect_playback
|
|
508
540
|
subject.execute
|
|
509
541
|
end
|
|
510
542
|
end
|
|
@@ -522,8 +554,9 @@ module Punchblock
|
|
|
522
554
|
describe 'repeat-interval' do
|
|
523
555
|
context 'unset' do
|
|
524
556
|
let(:command_opts) { { :repeat_interval => nil } }
|
|
525
|
-
it 'should not pass any options to
|
|
526
|
-
|
|
557
|
+
it 'should not pass any options to Playback' do
|
|
558
|
+
expect_answered
|
|
559
|
+
expect_playback
|
|
527
560
|
subject.execute
|
|
528
561
|
end
|
|
529
562
|
end
|
|
@@ -541,8 +574,9 @@ module Punchblock
|
|
|
541
574
|
describe 'repeat-times' do
|
|
542
575
|
context 'unset' do
|
|
543
576
|
let(:command_opts) { { :repeat_times => nil } }
|
|
544
|
-
it 'should not pass any options to
|
|
545
|
-
|
|
577
|
+
it 'should not pass any options to Playback' do
|
|
578
|
+
expect_answered
|
|
579
|
+
expect_playback
|
|
546
580
|
subject.execute
|
|
547
581
|
end
|
|
548
582
|
end
|
|
@@ -560,8 +594,9 @@ module Punchblock
|
|
|
560
594
|
describe 'max-time' do
|
|
561
595
|
context 'unset' do
|
|
562
596
|
let(:command_opts) { { :max_time => nil } }
|
|
563
|
-
it 'should not pass any options to
|
|
564
|
-
|
|
597
|
+
it 'should not pass any options to Playback' do
|
|
598
|
+
expect_answered
|
|
599
|
+
expect_playback
|
|
565
600
|
subject.execute
|
|
566
601
|
end
|
|
567
602
|
end
|
|
@@ -579,8 +614,9 @@ module Punchblock
|
|
|
579
614
|
describe 'voice' do
|
|
580
615
|
context 'unset' do
|
|
581
616
|
let(:command_opts) { { :voice => nil } }
|
|
582
|
-
it 'should not pass the v option to
|
|
583
|
-
|
|
617
|
+
it 'should not pass the v option to Playback' do
|
|
618
|
+
expect_answered
|
|
619
|
+
expect_playback
|
|
584
620
|
subject.execute
|
|
585
621
|
end
|
|
586
622
|
end
|
|
@@ -596,27 +632,98 @@ module Punchblock
|
|
|
596
632
|
end
|
|
597
633
|
|
|
598
634
|
describe 'interrupt_on' do
|
|
635
|
+
def ami_event_for_dtmf(digit, position)
|
|
636
|
+
RubyAMI::Event.new('DTMF').tap do |e|
|
|
637
|
+
e['Digit'] = digit.to_s
|
|
638
|
+
e['Start'] = position == :start ? 'Yes' : 'No'
|
|
639
|
+
e['End'] = position == :end ? 'Yes' : 'No'
|
|
640
|
+
end
|
|
641
|
+
end
|
|
642
|
+
|
|
643
|
+
def send_ami_events_for_dtmf(digit)
|
|
644
|
+
mock_call.process_ami_event ami_event_for_dtmf(digit, :start)
|
|
645
|
+
mock_call.process_ami_event ami_event_for_dtmf(digit, :end)
|
|
646
|
+
end
|
|
647
|
+
|
|
648
|
+
let(:reason) { original_command.complete_event(5).reason }
|
|
649
|
+
let(:channel) { "SIP/1234-00000000" }
|
|
650
|
+
let :ami_event do
|
|
651
|
+
RubyAMI::Event.new('AsyncAGI').tap do |e|
|
|
652
|
+
e['SubEvent'] = "Start"
|
|
653
|
+
e['Channel'] = channel
|
|
654
|
+
e['Env'] = "agi_request%3A%20async%0Aagi_channel%3A%20SIP%2F1234-00000000%0Aagi_language%3A%20en%0Aagi_type%3A%20SIP%0Aagi_uniqueid%3A%201320835995.0%0Aagi_version%3A%201.8.4.1%0Aagi_callerid%3A%205678%0Aagi_calleridname%3A%20Jane%20Smith%0Aagi_callingpres%3A%200%0Aagi_callingani2%3A%200%0Aagi_callington%3A%200%0Aagi_callingtns%3A%200%0Aagi_dnid%3A%201000%0Aagi_rdnis%3A%20unknown%0Aagi_context%3A%20default%0Aagi_extension%3A%201000%0Aagi_priority%3A%201%0Aagi_enhanced%3A%200.0%0Aagi_accountcode%3A%20%0Aagi_threadid%3A%204366221312%0A%0A"
|
|
655
|
+
end
|
|
656
|
+
end
|
|
657
|
+
|
|
599
658
|
context "set to nil" do
|
|
600
659
|
let(:command_opts) { { :interrupt_on => nil } }
|
|
601
|
-
it "
|
|
602
|
-
|
|
660
|
+
it "does not redirect the call" do
|
|
661
|
+
expect_answered
|
|
662
|
+
expect_playback
|
|
663
|
+
mock_call.expects(:redirect_back!).never
|
|
603
664
|
subject.execute
|
|
665
|
+
original_command.response(0.1).should be_a Ref
|
|
666
|
+
send_ami_events_for_dtmf 1
|
|
604
667
|
end
|
|
605
668
|
end
|
|
606
669
|
|
|
607
670
|
context "set to :any" do
|
|
608
671
|
let(:command_opts) { { :interrupt_on => :any } }
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
672
|
+
|
|
673
|
+
before do
|
|
674
|
+
expect_answered
|
|
675
|
+
expect_playback
|
|
676
|
+
end
|
|
677
|
+
|
|
678
|
+
context "when a DTMF digit is received" do
|
|
679
|
+
it "sends the correct complete event" do
|
|
680
|
+
mock_call.expects :redirect_back!
|
|
681
|
+
subject.execute
|
|
682
|
+
original_command.response(0.1).should be_a Ref
|
|
683
|
+
original_command.should_not be_complete
|
|
684
|
+
send_ami_events_for_dtmf 1
|
|
685
|
+
mock_call.process_ami_event! ami_event
|
|
686
|
+
sleep 0.2
|
|
687
|
+
original_command.should be_complete
|
|
688
|
+
reason.should be_a Punchblock::Component::Output::Complete::Success
|
|
689
|
+
end
|
|
690
|
+
|
|
691
|
+
it "redirects the call back to async AGI" do
|
|
692
|
+
mock_call.expects(:redirect_back!).with(nil).once
|
|
693
|
+
subject.execute
|
|
694
|
+
original_command.response(0.1).should be_a Ref
|
|
695
|
+
send_ami_events_for_dtmf 1
|
|
696
|
+
end
|
|
612
697
|
end
|
|
613
698
|
end
|
|
614
699
|
|
|
615
700
|
context "set to :dtmf" do
|
|
616
701
|
let(:command_opts) { { :interrupt_on => :dtmf } }
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
702
|
+
|
|
703
|
+
before do
|
|
704
|
+
expect_answered
|
|
705
|
+
expect_playback
|
|
706
|
+
end
|
|
707
|
+
|
|
708
|
+
context "when a DTMF digit is received" do
|
|
709
|
+
it "sends the correct complete event" do
|
|
710
|
+
mock_call.expects :redirect_back!
|
|
711
|
+
subject.execute
|
|
712
|
+
original_command.response(0.1).should be_a Ref
|
|
713
|
+
original_command.should_not be_complete
|
|
714
|
+
send_ami_events_for_dtmf 1
|
|
715
|
+
mock_call.process_ami_event! ami_event
|
|
716
|
+
sleep 0.2
|
|
717
|
+
original_command.should be_complete
|
|
718
|
+
reason.should be_a Punchblock::Component::Output::Complete::Success
|
|
719
|
+
end
|
|
720
|
+
|
|
721
|
+
it "redirects the call back to async AGI" do
|
|
722
|
+
mock_call.expects(:redirect_back!).with(nil).once
|
|
723
|
+
subject.execute
|
|
724
|
+
original_command.response(0.1).should be_a Ref
|
|
725
|
+
send_ami_events_for_dtmf 1
|
|
726
|
+
end
|
|
620
727
|
end
|
|
621
728
|
end
|
|
622
729
|
|