punchblock 1.7.0 → 1.7.1

Sign up to get free protection for your applications and to get access to all the features.
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: