punchblock 1.7.0 → 1.7.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # [develop](https://github.com/adhearsion/punchblock)
2
2
 
3
+ # [v1.7.1](https://github.com/adhearsion/punchblock/compare/v1.7.0...v1.7.1) - [2012-12-17](https://rubygems.org/gems/punchblock/versions/1.7.1)
4
+ * Bugfix: Deal with nil media engines on FS/* properly
5
+
3
6
  # [v1.7.0](https://github.com/adhearsion/punchblock/compare/v1.6.1...v1.7.0) - [2012-12-13](https://rubygems.org/gems/punchblock/versions/1.7.0)
4
7
  * Feature: Support for the renderer attribute added to the Output component.
5
8
  * Feature: FreeSWITCH and Asterisk translators now use the :renderer attribute on Output
@@ -27,10 +27,10 @@ module Punchblock
27
27
 
28
28
  output_component = current_actor
29
29
 
30
- rendering_engine = @component_node.renderer ? @component_node.renderer : @media_engine
30
+ rendering_engine = @component_node.renderer || @media_engine || :asterisk
31
31
 
32
32
  case rendering_engine.to_sym
33
- when :asterisk, nil
33
+ when :asterisk
34
34
  raise OptionError, "A voice value is unsupported on Asterisk." if @component_node.voice
35
35
  raise OptionError, 'Interrupt digits are not allowed with early media.' if early && @component_node.interrupt_on
36
36
 
@@ -198,7 +198,7 @@ module Punchblock
198
198
  hangup REJECT_TO_HANGUP_REASON[command.reason]
199
199
  command.response = true
200
200
  when Punchblock::Component::Output
201
- media_renderer = command.renderer ? command.renderer : media_engine
201
+ media_renderer = command.renderer || media_engine || :freeswitch
202
202
  case media_renderer.to_sym
203
203
  when :freeswitch, :native, nil
204
204
  execute_component Component::Output, command
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Punchblock
4
- VERSION = "1.7.0"
4
+ VERSION = "1.7.1"
5
5
  end
@@ -355,407 +355,407 @@ module Punchblock
355
355
  end
356
356
  end
357
357
 
358
- context 'with a media engine of :asterisk' do
359
- let(:media_engine) { :asterisk }
360
-
361
- def expect_playback(filename = audio_filename)
362
- mock_call.should_receive(:send_agi_action!).once.with 'EXEC Playback', filename
363
- end
364
-
365
- def expect_playback_noanswer
366
- mock_call.should_receive(:send_agi_action!).once.with 'EXEC Playback', audio_filename + ',noanswer'
367
- end
368
-
369
- let(:audio_filename) { 'http://foo.com/bar.mp3' }
358
+ [:asterisk, nil].each do |media_engine|
359
+ context "with a media engine of #{media_engine.inspect}" do
360
+ def expect_playback(filename = audio_filename)
361
+ mock_call.should_receive(:send_agi_action!).once.with 'EXEC Playback', filename
362
+ end
370
363
 
371
- let :ssml_doc do
372
- RubySpeech::SSML.draw do
373
- audio :src => audio_filename
364
+ def expect_playback_noanswer
365
+ mock_call.should_receive(:send_agi_action!).once.with 'EXEC Playback', audio_filename + ',noanswer'
374
366
  end
375
- end
376
367
 
377
- let(:command_opts) { {} }
368
+ let(:audio_filename) { 'http://foo.com/bar.mp3' }
378
369
 
379
- let :command_options do
380
- { :ssml => ssml_doc }.merge(command_opts)
381
- end
370
+ let :ssml_doc do
371
+ RubySpeech::SSML.draw do
372
+ audio :src => audio_filename
373
+ end
374
+ end
382
375
 
383
- let :original_command do
384
- Punchblock::Component::Output.new command_options
385
- end
376
+ let(:command_opts) { {} }
386
377
 
387
- describe 'ssml' do
388
- context 'unset' do
389
- let(:command_opts) { { :ssml => nil } }
390
- it "should return an error and not execute any actions" do
391
- subject.execute
392
- error = ProtocolError.new.setup 'option error', 'An SSML document is required.'
393
- original_command.response(0.1).should be == error
394
- end
378
+ let :command_options do
379
+ { :ssml => ssml_doc }.merge(command_opts)
395
380
  end
396
381
 
397
- context 'with a single audio SSML node' do
398
- let(:audio_filename) { 'http://foo.com/bar.mp3' }
399
- let :command_options do
400
- {
401
- :ssml => RubySpeech::SSML.draw { audio :src => audio_filename }
402
- }
403
- end
382
+ let :original_command do
383
+ Punchblock::Component::Output.new command_options
384
+ end
404
385
 
405
- it 'should playback the audio file using Playback' do
406
- expect_answered
407
- expect_playback
408
- subject.execute
386
+ describe 'ssml' do
387
+ context 'unset' do
388
+ let(:command_opts) { { :ssml => nil } }
389
+ it "should return an error and not execute any actions" do
390
+ subject.execute
391
+ error = ProtocolError.new.setup 'option error', 'An SSML document is required.'
392
+ original_command.response(0.1).should be == error
393
+ end
409
394
  end
410
395
 
411
- it 'should send a complete event when the file finishes playback' do
412
- def mock_call.answered?
413
- true
414
- end
415
- def mock_call.send_agi_action!(*args, &block)
416
- block.call Punchblock::Component::Asterisk::AGI::Command::Complete::Success.new(:code => 200, :result => 1)
396
+ context 'with a single audio SSML node' do
397
+ let(:audio_filename) { 'http://foo.com/bar.mp3' }
398
+ let :command_options do
399
+ {
400
+ :ssml => RubySpeech::SSML.draw { audio :src => audio_filename }
401
+ }
417
402
  end
418
- subject.execute
419
- original_command.complete_event(0.1).reason.should be_a Punchblock::Component::Output::Complete::Success
420
- end
421
- end
422
403
 
423
- context 'with a single text node without spaces' do
424
- let(:audio_filename) { 'tt-monkeys' }
425
- let :command_options do
426
- {
427
- :ssml => RubySpeech::SSML.draw { string audio_filename }
428
- }
429
- end
404
+ it 'should playback the audio file using Playback' do
405
+ expect_answered
406
+ expect_playback
407
+ subject.execute
408
+ end
430
409
 
431
- it 'should playback the audio file using Playback' do
432
- expect_answered
433
- expect_playback
434
- subject.execute
410
+ it 'should send a complete event when the file finishes playback' do
411
+ def mock_call.answered?
412
+ true
413
+ end
414
+ def mock_call.send_agi_action!(*args, &block)
415
+ block.call Punchblock::Component::Asterisk::AGI::Command::Complete::Success.new(:code => 200, :result => 1)
416
+ end
417
+ subject.execute
418
+ original_command.complete_event(0.1).reason.should be_a Punchblock::Component::Output::Complete::Success
419
+ end
435
420
  end
436
421
 
437
- it 'should send a complete event when the file finishes playback' do
438
- expect_answered
439
- def mock_call.send_agi_action!(*args, &block)
440
- block.call Punchblock::Component::Asterisk::AGI::Command::Complete::Success.new(:code => 200, :result => 1)
422
+ context 'with a single text node without spaces' do
423
+ let(:audio_filename) { 'tt-monkeys' }
424
+ let :command_options do
425
+ {
426
+ :ssml => RubySpeech::SSML.draw { string audio_filename }
427
+ }
441
428
  end
442
- subject.execute
443
- original_command.complete_event(0.1).reason.should be_a Punchblock::Component::Output::Complete::Success
444
- end
445
429
 
446
- context "with early media playback" do
447
- it "should play the file with Playback" do
448
- expect_answered false
449
- expect_playback_noanswer
450
- mock_call.should_receive(:send_progress)
430
+ it 'should playback the audio file using Playback' do
431
+ expect_answered
432
+ expect_playback
451
433
  subject.execute
452
434
  end
453
435
 
454
- context "with interrupt_on set to something that is not nil" do
455
- let(:audio_filename) { 'tt-monkeys' }
456
- let :command_options do
457
- {
458
- :ssml => RubySpeech::SSML.draw { string audio_filename },
459
- :interrupt_on => :any
460
- }
436
+ it 'should send a complete event when the file finishes playback' do
437
+ expect_answered
438
+ def mock_call.send_agi_action!(*args, &block)
439
+ block.call Punchblock::Component::Asterisk::AGI::Command::Complete::Success.new(:code => 200, :result => 1)
461
440
  end
462
- it "should return an error when the output is interruptible and it is early media" do
441
+ subject.execute
442
+ original_command.complete_event(0.1).reason.should be_a Punchblock::Component::Output::Complete::Success
443
+ end
444
+
445
+ context "with early media playback" do
446
+ it "should play the file with Playback" do
463
447
  expect_answered false
464
- error = ProtocolError.new.setup 'option error', 'Interrupt digits are not allowed with early media.'
448
+ expect_playback_noanswer
449
+ mock_call.should_receive(:send_progress)
465
450
  subject.execute
466
- original_command.response(0.1).should be == error
467
451
  end
468
- end
469
- end
470
- end
471
452
 
472
- context 'with a string (not SSML)' do
473
- let :command_options do
474
- { :text => 'Foo Bar' }
475
- end
476
-
477
- it "should return an unrenderable document error" do
478
- subject.execute
479
- error = ProtocolError.new.setup 'unrenderable document error', 'The provided document could not be rendered. See http://adhearsion.com/docs/common_problems#unrenderable-document-error for details.'
480
- original_command.response(0.1).should be == error
481
- end
482
- end
483
-
484
- context 'with multiple audio SSML nodes' do
485
- let(:audio_filename1) { 'http://foo.com/bar.mp3' }
486
- let(:audio_filename2) { 'http://foo.com/baz.mp3' }
487
- let :command_options do
488
- {
489
- :ssml => RubySpeech::SSML.draw do
490
- audio :src => audio_filename1
491
- audio :src => audio_filename2
453
+ context "with interrupt_on set to something that is not nil" do
454
+ let(:audio_filename) { 'tt-monkeys' }
455
+ let :command_options do
456
+ {
457
+ :ssml => RubySpeech::SSML.draw { string audio_filename },
458
+ :interrupt_on => :any
459
+ }
460
+ end
461
+ it "should return an error when the output is interruptible and it is early media" do
462
+ expect_answered false
463
+ error = ProtocolError.new.setup 'option error', 'Interrupt digits are not allowed with early media.'
464
+ subject.execute
465
+ original_command.response(0.1).should be == error
466
+ end
492
467
  end
493
- }
468
+ end
494
469
  end
495
470
 
496
- it 'should playback all audio files using Playback' do
497
- latch = CountDownLatch.new 2
498
- expect_playback [audio_filename1, audio_filename2].join('&')
499
- expect_answered
500
- subject.execute
501
- latch.wait 2
502
- sleep 2
471
+ context 'with a string (not SSML)' do
472
+ let :command_options do
473
+ { :text => 'Foo Bar' }
474
+ end
475
+
476
+ it "should return an unrenderable document error" do
477
+ subject.execute
478
+ error = ProtocolError.new.setup 'unrenderable document error', 'The provided document could not be rendered. See http://adhearsion.com/docs/common_problems#unrenderable-document-error for details.'
479
+ original_command.response(0.1).should be == error
480
+ end
503
481
  end
504
482
 
505
- it 'should send a complete event after the final file has finished playback' do
506
- expect_answered
507
- def mock_call.send_agi_action!(*args, &block)
508
- block.call Punchblock::Component::Asterisk::AGI::Command::Complete::Success.new(:code => 200, :result => 1)
483
+ context 'with multiple audio SSML nodes' do
484
+ let(:audio_filename1) { 'http://foo.com/bar.mp3' }
485
+ let(:audio_filename2) { 'http://foo.com/baz.mp3' }
486
+ let :command_options do
487
+ {
488
+ :ssml => RubySpeech::SSML.draw do
489
+ audio :src => audio_filename1
490
+ audio :src => audio_filename2
491
+ end
492
+ }
509
493
  end
510
- latch = CountDownLatch.new 1
511
- original_command.should_receive(:add_event).once.with do |e|
512
- e.reason.should be_a Punchblock::Component::Output::Complete::Success
513
- latch.countdown!
494
+
495
+ it 'should playback all audio files using Playback' do
496
+ latch = CountDownLatch.new 2
497
+ expect_playback [audio_filename1, audio_filename2].join('&')
498
+ expect_answered
499
+ subject.execute
500
+ latch.wait 2
501
+ sleep 2
514
502
  end
515
- subject.execute
516
- latch.wait(2).should be_true
517
- end
518
- end
519
503
 
520
- context "with an SSML document containing elements other than <audio/>" do
521
- let :command_options do
522
- {
523
- :ssml => RubySpeech::SSML.draw do
524
- string "Foo Bar"
504
+ it 'should send a complete event after the final file has finished playback' do
505
+ expect_answered
506
+ def mock_call.send_agi_action!(*args, &block)
507
+ block.call Punchblock::Component::Asterisk::AGI::Command::Complete::Success.new(:code => 200, :result => 1)
525
508
  end
526
- }
509
+ latch = CountDownLatch.new 1
510
+ original_command.should_receive(:add_event).once.with do |e|
511
+ e.reason.should be_a Punchblock::Component::Output::Complete::Success
512
+ latch.countdown!
513
+ end
514
+ subject.execute
515
+ latch.wait(2).should be_true
516
+ end
527
517
  end
528
518
 
529
- it "should return an unrenderable document error" do
530
- subject.execute
531
- error = ProtocolError.new.setup 'unrenderable document error', 'The provided document could not be rendered. See http://adhearsion.com/docs/common_problems#unrenderable-document-error for details.'
532
- original_command.response(0.1).should be == error
533
- end
534
- end
535
- end
519
+ context "with an SSML document containing elements other than <audio/>" do
520
+ let :command_options do
521
+ {
522
+ :ssml => RubySpeech::SSML.draw do
523
+ string "Foo Bar"
524
+ end
525
+ }
526
+ end
536
527
 
537
- describe 'start-offset' do
538
- context 'unset' do
539
- let(:command_opts) { { :start_offset => nil } }
540
- it 'should not pass any options to Playback' do
541
- expect_answered
542
- expect_playback
543
- subject.execute
528
+ it "should return an unrenderable document error" do
529
+ subject.execute
530
+ error = ProtocolError.new.setup 'unrenderable document error', 'The provided document could not be rendered. See http://adhearsion.com/docs/common_problems#unrenderable-document-error for details.'
531
+ original_command.response(0.1).should be == error
532
+ end
544
533
  end
545
534
  end
546
535
 
547
- context 'set' do
548
- let(:command_opts) { { :start_offset => 10 } }
549
- it "should return an error and not execute any actions" do
550
- subject.execute
551
- error = ProtocolError.new.setup 'option error', 'A start_offset value is unsupported on Asterisk.'
552
- original_command.response(0.1).should be == error
536
+ describe 'start-offset' do
537
+ context 'unset' do
538
+ let(:command_opts) { { :start_offset => nil } }
539
+ it 'should not pass any options to Playback' do
540
+ expect_answered
541
+ expect_playback
542
+ subject.execute
543
+ end
553
544
  end
554
- end
555
- end
556
545
 
557
- describe 'start-paused' do
558
- context 'false' do
559
- let(:command_opts) { { :start_paused => false } }
560
- it 'should not pass any options to Playback' do
561
- expect_answered
562
- expect_playback
563
- subject.execute
546
+ context 'set' do
547
+ let(:command_opts) { { :start_offset => 10 } }
548
+ it "should return an error and not execute any actions" do
549
+ subject.execute
550
+ error = ProtocolError.new.setup 'option error', 'A start_offset value is unsupported on Asterisk.'
551
+ original_command.response(0.1).should be == error
552
+ end
564
553
  end
565
554
  end
566
555
 
567
- context 'true' do
568
- let(:command_opts) { { :start_paused => true } }
569
- it "should return an error and not execute any actions" do
570
- subject.execute
571
- error = ProtocolError.new.setup 'option error', 'A start_paused value is unsupported on Asterisk.'
572
- original_command.response(0.1).should be == error
556
+ describe 'start-paused' do
557
+ context 'false' do
558
+ let(:command_opts) { { :start_paused => false } }
559
+ it 'should not pass any options to Playback' do
560
+ expect_answered
561
+ expect_playback
562
+ subject.execute
563
+ end
573
564
  end
574
- end
575
- end
576
565
 
577
- describe 'repeat-interval' do
578
- context 'unset' do
579
- let(:command_opts) { { :repeat_interval => nil } }
580
- it 'should not pass any options to Playback' do
581
- expect_answered
582
- expect_playback
583
- subject.execute
566
+ context 'true' do
567
+ let(:command_opts) { { :start_paused => true } }
568
+ it "should return an error and not execute any actions" do
569
+ subject.execute
570
+ error = ProtocolError.new.setup 'option error', 'A start_paused value is unsupported on Asterisk.'
571
+ original_command.response(0.1).should be == error
572
+ end
584
573
  end
585
574
  end
586
575
 
587
- context 'set' do
588
- let(:command_opts) { { :repeat_interval => 10 } }
589
- it "should return an error and not execute any actions" do
590
- subject.execute
591
- error = ProtocolError.new.setup 'option error', 'A repeat_interval value is unsupported on Asterisk.'
592
- original_command.response(0.1).should be == error
576
+ describe 'repeat-interval' do
577
+ context 'unset' do
578
+ let(:command_opts) { { :repeat_interval => nil } }
579
+ it 'should not pass any options to Playback' do
580
+ expect_answered
581
+ expect_playback
582
+ subject.execute
583
+ end
593
584
  end
594
- end
595
- end
596
585
 
597
- describe 'repeat-times' do
598
- context 'unset' do
599
- let(:command_opts) { { :repeat_times => nil } }
600
- it 'should not pass any options to Playback' do
601
- expect_answered
602
- expect_playback
603
- subject.execute
586
+ context 'set' do
587
+ let(:command_opts) { { :repeat_interval => 10 } }
588
+ it "should return an error and not execute any actions" do
589
+ subject.execute
590
+ error = ProtocolError.new.setup 'option error', 'A repeat_interval value is unsupported on Asterisk.'
591
+ original_command.response(0.1).should be == error
592
+ end
604
593
  end
605
594
  end
606
595
 
607
- context 'set' do
608
- let(:command_opts) { { :repeat_times => 2 } }
609
- it "should return an error and not execute any actions" do
610
- subject.execute
611
- error = ProtocolError.new.setup 'option error', 'A repeat_times value is unsupported on Asterisk.'
612
- original_command.response(0.1).should be == error
596
+ describe 'repeat-times' do
597
+ context 'unset' do
598
+ let(:command_opts) { { :repeat_times => nil } }
599
+ it 'should not pass any options to Playback' do
600
+ expect_answered
601
+ expect_playback
602
+ subject.execute
603
+ end
613
604
  end
614
- end
615
- end
616
605
 
617
- describe 'max-time' do
618
- context 'unset' do
619
- let(:command_opts) { { :max_time => nil } }
620
- it 'should not pass any options to Playback' do
621
- expect_answered
622
- expect_playback
623
- subject.execute
606
+ context 'set' do
607
+ let(:command_opts) { { :repeat_times => 2 } }
608
+ it "should return an error and not execute any actions" do
609
+ subject.execute
610
+ error = ProtocolError.new.setup 'option error', 'A repeat_times value is unsupported on Asterisk.'
611
+ original_command.response(0.1).should be == error
612
+ end
624
613
  end
625
614
  end
626
615
 
627
- context 'set' do
628
- let(:command_opts) { { :max_time => 30 } }
629
- it "should return an error and not execute any actions" do
630
- subject.execute
631
- error = ProtocolError.new.setup 'option error', 'A max_time value is unsupported on Asterisk.'
632
- original_command.response(0.1).should be == error
616
+ describe 'max-time' do
617
+ context 'unset' do
618
+ let(:command_opts) { { :max_time => nil } }
619
+ it 'should not pass any options to Playback' do
620
+ expect_answered
621
+ expect_playback
622
+ subject.execute
623
+ end
633
624
  end
634
- end
635
- end
636
625
 
637
- describe 'voice' do
638
- context 'unset' do
639
- let(:command_opts) { { :voice => nil } }
640
- it 'should not pass the v option to Playback' do
641
- expect_answered
642
- expect_playback
643
- subject.execute
626
+ context 'set' do
627
+ let(:command_opts) { { :max_time => 30 } }
628
+ it "should return an error and not execute any actions" do
629
+ subject.execute
630
+ error = ProtocolError.new.setup 'option error', 'A max_time value is unsupported on Asterisk.'
631
+ original_command.response(0.1).should be == error
632
+ end
644
633
  end
645
634
  end
646
635
 
647
- context 'set' do
648
- let(:command_opts) { { :voice => 'alison' } }
649
- it "should return an error and not execute any actions" do
650
- subject.execute
651
- error = ProtocolError.new.setup 'option error', 'A voice value is unsupported on Asterisk.'
652
- original_command.response(0.1).should be == error
636
+ describe 'voice' do
637
+ context 'unset' do
638
+ let(:command_opts) { { :voice => nil } }
639
+ it 'should not pass the v option to Playback' do
640
+ expect_answered
641
+ expect_playback
642
+ subject.execute
643
+ end
653
644
  end
654
- end
655
- end
656
645
 
657
- describe 'interrupt_on' do
658
- def ami_event_for_dtmf(digit, position)
659
- RubyAMI::Event.new('DTMF').tap do |e|
660
- e['Digit'] = digit.to_s
661
- e['Start'] = position == :start ? 'Yes' : 'No'
662
- e['End'] = position == :end ? 'Yes' : 'No'
646
+ context 'set' do
647
+ let(:command_opts) { { :voice => 'alison' } }
648
+ it "should return an error and not execute any actions" do
649
+ subject.execute
650
+ error = ProtocolError.new.setup 'option error', 'A voice value is unsupported on Asterisk.'
651
+ original_command.response(0.1).should be == error
652
+ end
663
653
  end
664
654
  end
665
655
 
666
- def send_ami_events_for_dtmf(digit)
667
- mock_call.process_ami_event ami_event_for_dtmf(digit, :start)
668
- mock_call.process_ami_event ami_event_for_dtmf(digit, :end)
669
- end
670
-
671
- let(:reason) { original_command.complete_event(5).reason }
672
- let(:channel) { "SIP/1234-00000000" }
673
- let :ami_event do
674
- RubyAMI::Event.new('AsyncAGI').tap do |e|
675
- e['SubEvent'] = "Start"
676
- e['Channel'] = channel
677
- 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"
656
+ describe 'interrupt_on' do
657
+ def ami_event_for_dtmf(digit, position)
658
+ RubyAMI::Event.new('DTMF').tap do |e|
659
+ e['Digit'] = digit.to_s
660
+ e['Start'] = position == :start ? 'Yes' : 'No'
661
+ e['End'] = position == :end ? 'Yes' : 'No'
662
+ end
678
663
  end
679
- end
680
664
 
681
- context "set to nil" do
682
- let(:command_opts) { { :interrupt_on => nil } }
683
- it "does not redirect the call" do
684
- expect_answered
685
- expect_playback
686
- mock_call.should_receive(:redirect_back!).never
687
- subject.execute
688
- original_command.response(0.1).should be_a Ref
689
- send_ami_events_for_dtmf 1
665
+ def send_ami_events_for_dtmf(digit)
666
+ mock_call.process_ami_event ami_event_for_dtmf(digit, :start)
667
+ mock_call.process_ami_event ami_event_for_dtmf(digit, :end)
690
668
  end
691
- end
692
669
 
693
- context "set to :any" do
694
- let(:command_opts) { { :interrupt_on => :any } }
695
-
696
- before do
697
- expect_answered
698
- expect_playback
670
+ let(:reason) { original_command.complete_event(5).reason }
671
+ let(:channel) { "SIP/1234-00000000" }
672
+ let :ami_event do
673
+ RubyAMI::Event.new('AsyncAGI').tap do |e|
674
+ e['SubEvent'] = "Start"
675
+ e['Channel'] = channel
676
+ 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"
677
+ end
699
678
  end
700
679
 
701
- context "when a DTMF digit is received" do
702
- it "sends the correct complete event" do
703
- mock_call.should_receive :redirect_back!
680
+ context "set to nil" do
681
+ let(:command_opts) { { :interrupt_on => nil } }
682
+ it "does not redirect the call" do
683
+ expect_answered
684
+ expect_playback
685
+ mock_call.should_receive(:redirect_back!).never
704
686
  subject.execute
705
687
  original_command.response(0.1).should be_a Ref
706
- original_command.should_not be_complete
707
688
  send_ami_events_for_dtmf 1
708
- mock_call.process_ami_event! ami_event
709
- sleep 0.2
710
- original_command.should be_complete
711
- reason.should be_a Punchblock::Component::Output::Complete::Success
712
689
  end
690
+ end
713
691
 
714
- it "redirects the call back to async AGI" do
715
- mock_call.should_receive(:redirect_back!).once
716
- subject.execute
717
- original_command.response(0.1).should be_a Ref
718
- send_ami_events_for_dtmf 1
692
+ context "set to :any" do
693
+ let(:command_opts) { { :interrupt_on => :any } }
694
+
695
+ before do
696
+ expect_answered
697
+ expect_playback
719
698
  end
720
- end
721
- end
722
699
 
723
- context "set to :dtmf" do
724
- let(:command_opts) { { :interrupt_on => :dtmf } }
700
+ context "when a DTMF digit is received" do
701
+ it "sends the correct complete event" do
702
+ mock_call.should_receive :redirect_back!
703
+ subject.execute
704
+ original_command.response(0.1).should be_a Ref
705
+ original_command.should_not be_complete
706
+ send_ami_events_for_dtmf 1
707
+ mock_call.process_ami_event! ami_event
708
+ sleep 0.2
709
+ original_command.should be_complete
710
+ reason.should be_a Punchblock::Component::Output::Complete::Success
711
+ end
725
712
 
726
- before do
727
- expect_answered
728
- expect_playback
713
+ it "redirects the call back to async AGI" do
714
+ mock_call.should_receive(:redirect_back!).once
715
+ subject.execute
716
+ original_command.response(0.1).should be_a Ref
717
+ send_ami_events_for_dtmf 1
718
+ end
719
+ end
729
720
  end
730
721
 
731
- context "when a DTMF digit is received" do
732
- it "sends the correct complete event" do
733
- mock_call.should_receive :redirect_back!
734
- subject.execute
735
- original_command.response(0.1).should be_a Ref
736
- original_command.should_not be_complete
737
- send_ami_events_for_dtmf 1
738
- mock_call.process_ami_event! ami_event
739
- sleep 0.2
740
- original_command.should be_complete
741
- reason.should be_a Punchblock::Component::Output::Complete::Success
722
+ context "set to :dtmf" do
723
+ let(:command_opts) { { :interrupt_on => :dtmf } }
724
+
725
+ before do
726
+ expect_answered
727
+ expect_playback
742
728
  end
743
729
 
744
- it "redirects the call back to async AGI" do
745
- mock_call.should_receive(:redirect_back!).once
746
- subject.execute
747
- original_command.response(0.1).should be_a Ref
748
- send_ami_events_for_dtmf 1
730
+ context "when a DTMF digit is received" do
731
+ it "sends the correct complete event" do
732
+ mock_call.should_receive :redirect_back!
733
+ subject.execute
734
+ original_command.response(0.1).should be_a Ref
735
+ original_command.should_not be_complete
736
+ send_ami_events_for_dtmf 1
737
+ mock_call.process_ami_event! ami_event
738
+ sleep 0.2
739
+ original_command.should be_complete
740
+ reason.should be_a Punchblock::Component::Output::Complete::Success
741
+ end
742
+
743
+ it "redirects the call back to async AGI" do
744
+ mock_call.should_receive(:redirect_back!).once
745
+ subject.execute
746
+ original_command.response(0.1).should be_a Ref
747
+ send_ami_events_for_dtmf 1
748
+ end
749
749
  end
750
750
  end
751
- end
752
751
 
753
- context "set to :speech" do
754
- let(:command_opts) { { :interrupt_on => :speech } }
755
- it "should return an error and not execute any actions" do
756
- subject.execute
757
- error = ProtocolError.new.setup 'option error', 'An interrupt-on value of speech is unsupported.'
758
- original_command.response(0.1).should be == error
752
+ context "set to :speech" do
753
+ let(:command_opts) { { :interrupt_on => :speech } }
754
+ it "should return an error and not execute any actions" do
755
+ subject.execute
756
+ error = ProtocolError.new.setup 'option error', 'An interrupt-on value of speech is unsupported.'
757
+ original_command.response(0.1).should be == error
758
+ end
759
759
  end
760
760
  end
761
761
  end
@@ -754,11 +754,17 @@ module Punchblock
754
754
 
755
755
  let(:mock_component) { mock 'Freeswitch::Component::Output', :id => 'foo' }
756
756
 
757
- it 'should create an Output component and execute it asynchronously' do
758
- Component::Output.should_receive(:new_link).once.with(command, subject).and_return mock_component
759
- mock_component.should_receive(:execute!).once
760
- subject.execute_command command
761
- subject.component_with_id('foo').should be mock_component
757
+ ['freeswitch', nil].each do |media_engine|
758
+ let(:media_engine) { media_engine }
759
+
760
+ context "with a media engine of #{media_engine}" do
761
+ it 'should create an Output component and execute it asynchronously' do
762
+ Component::Output.should_receive(:new_link).once.with(command, subject).and_return mock_component
763
+ mock_component.should_receive(:execute!).once
764
+ subject.execute_command command
765
+ subject.component_with_id('foo').should be mock_component
766
+ end
767
+ end
762
768
  end
763
769
 
764
770
  context 'with the media engine of :flite' do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: punchblock
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.0
4
+ version: 1.7.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2012-12-13 00:00:00.000000000 Z
14
+ date: 2012-12-17 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: niceogiri
@@ -499,7 +499,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
499
499
  version: '0'
500
500
  segments:
501
501
  - 0
502
- hash: -475080832801704872
502
+ hash: -2704704399660670461
503
503
  required_rubygems_version: !ruby/object:Gem::Requirement
504
504
  none: false
505
505
  requirements: