punchblock 1.8.2 → 1.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -0
  3. data/CHANGELOG.md +8 -0
  4. data/lib/punchblock/component/asterisk/agi/command.rb +0 -11
  5. data/lib/punchblock/connection/asterisk.rb +3 -3
  6. data/lib/punchblock/translator/asterisk/agi_command.rb +40 -0
  7. data/lib/punchblock/translator/asterisk/call.rb +56 -47
  8. data/lib/punchblock/translator/asterisk/component/asterisk/agi_command.rb +13 -37
  9. data/lib/punchblock/translator/asterisk/component/asterisk/ami_action.rb +24 -41
  10. data/lib/punchblock/translator/asterisk/component/input.rb +2 -1
  11. data/lib/punchblock/translator/asterisk/component/output.rb +16 -21
  12. data/lib/punchblock/translator/asterisk/component/record.rb +11 -19
  13. data/lib/punchblock/translator/asterisk/component.rb +12 -9
  14. data/lib/punchblock/translator/asterisk.rb +16 -22
  15. data/lib/punchblock/translator/dtmf_recognizer.rb +4 -4
  16. data/lib/punchblock/translator/freeswitch/component/input.rb +2 -1
  17. data/lib/punchblock/translator/input_component.rb +2 -2
  18. data/lib/punchblock/version.rb +1 -1
  19. data/punchblock.gemspec +1 -1
  20. data/spec/punchblock/connection/asterisk_spec.rb +8 -7
  21. data/spec/punchblock/translator/asterisk/call_spec.rb +262 -229
  22. data/spec/punchblock/translator/asterisk/component/asterisk/agi_command_spec.rb +57 -29
  23. data/spec/punchblock/translator/asterisk/component/asterisk/ami_action_spec.rb +40 -46
  24. data/spec/punchblock/translator/asterisk/component/input_spec.rb +7 -7
  25. data/spec/punchblock/translator/asterisk/component/output_spec.rb +84 -53
  26. data/spec/punchblock/translator/asterisk/component/record_spec.rb +55 -83
  27. data/spec/punchblock/translator/asterisk/component/stop_by_redirect_spec.rb +5 -1
  28. data/spec/punchblock/translator/asterisk/component_spec.rb +2 -10
  29. data/spec/punchblock/translator/asterisk_spec.rb +73 -100
  30. metadata +5 -10
@@ -7,7 +7,9 @@ module Punchblock
7
7
  class Asterisk
8
8
  describe Call do
9
9
  let(:channel) { 'SIP/foo' }
10
- let(:translator) { Asterisk.new stub('AMI Client').as_null_object, stub('connection').as_null_object }
10
+ let(:ami_client) { stub('AMI Client').as_null_object }
11
+ let(:connection) { stub('connection').as_null_object }
12
+ let(:translator) { Asterisk.new ami_client, connection }
11
13
  let(:agi_env) do
12
14
  {
13
15
  :agi_request => 'async',
@@ -58,7 +60,7 @@ module Punchblock
58
60
  }
59
61
  end
60
62
 
61
- subject { Call.new channel, translator, agi_env }
63
+ subject { Call.new channel, translator, ami_client, connection, agi_env }
62
64
 
63
65
  its(:id) { should be_a String }
64
66
  its(:channel) { should be == channel }
@@ -84,6 +86,22 @@ module Punchblock
84
86
  end
85
87
  end
86
88
 
89
+ describe "getting channel vars" do
90
+ it "should do a GetVar when we don't have a cached value" do
91
+ response = RubyAMI::Response.new 'Value' => 'thevalue'
92
+ ami_client.should_receive(:send_action).once.with('GetVar', 'Channel' => channel, 'Variable' => 'somevariable').and_return response
93
+ subject.channel_var('somevariable').should == 'thevalue'
94
+ end
95
+
96
+ context "when the value comes back from GetVar as '(null)'" do
97
+ it "should return nil" do
98
+ response = RubyAMI::Response.new 'Value' => '(null)'
99
+ ami_client.should_receive(:send_action).once.with('GetVar', 'Channel' => channel, 'Variable' => 'somevariable').and_return response
100
+ subject.channel_var('somevariable').should be_nil
101
+ end
102
+ end
103
+ end
104
+
87
105
  describe '#send_offer' do
88
106
  it 'sends an offer to the translator' do
89
107
  expected_offer = Punchblock::Event::Offer.new :target_call_id => subject.id,
@@ -103,11 +121,10 @@ module Punchblock
103
121
  end
104
122
 
105
123
  describe '#send_progress' do
106
-
107
124
  context "with a call that is already answered" do
108
125
  it 'should not send the EXEC Progress command' do
109
126
  subject.wrapped_object.should_receive(:'answered?').and_return true
110
- subject.wrapped_object.should_receive(:send_agi_action).with("EXEC Progress").never
127
+ subject.wrapped_object.should_receive(:execute_agi_command).with("EXEC Progress").never
111
128
  subject.send_progress
112
129
  end
113
130
  end
@@ -126,7 +143,7 @@ module Punchblock
126
143
  end
127
144
 
128
145
  it 'should not send the EXEC Progress command' do
129
- subject.wrapped_object.should_receive(:send_agi_action).with("EXEC Progress").never
146
+ subject.wrapped_object.should_receive(:execute_agi_command).with("EXEC Progress").never
130
147
  subject.send_progress
131
148
  end
132
149
  end
@@ -137,12 +154,12 @@ module Punchblock
137
154
  end
138
155
 
139
156
  it 'should send the EXEC Progress command to a call that is inbound and not answered' do
140
- subject.wrapped_object.should_receive(:send_agi_action).with("EXEC Progress")
157
+ subject.wrapped_object.should_receive(:execute_agi_command).with("EXEC Progress").and_return code: 200, result: 0
141
158
  subject.send_progress
142
159
  end
143
160
 
144
161
  it 'should send the EXEC Progress command only once if called twice' do
145
- subject.wrapped_object.should_receive(:send_agi_action).with("EXEC Progress").once
162
+ subject.wrapped_object.should_receive(:execute_agi_command).with("EXEC Progress").once.and_return code: 200, result: 0
146
163
  subject.send_progress
147
164
  subject.send_progress
148
165
  end
@@ -255,7 +272,7 @@ module Punchblock
255
272
  subject.dial dial_command
256
273
  accept_command = Command::Accept.new
257
274
  accept_command.request!
258
- subject.wrapped_object.should_receive(:send_agi_action).never
275
+ subject.wrapped_object.should_receive(:execute_agi_command).never
259
276
  subject.execute_command accept_command
260
277
  accept_command.response(0.5).should be true
261
278
  end
@@ -264,14 +281,13 @@ module Punchblock
264
281
  describe '#process_ami_event' do
265
282
  context 'with a Hangup event' do
266
283
  let :ami_event do
267
- RubyAMI::Event.new('Hangup').tap do |e|
268
- e['Uniqueid'] = "1320842458.8"
269
- e['Calleridnum'] = "5678"
270
- e['Calleridname'] = "Jane Smith"
271
- e['Cause'] = cause
272
- e['Cause-txt'] = cause_txt
273
- e['Channel'] = "SIP/1234-00000000"
274
- end
284
+ RubyAMI::Event.new 'Hangup',
285
+ 'Uniqueid' => "1320842458.8",
286
+ 'Calleridnum' => "5678",
287
+ 'Calleridname' => "Jane Smith",
288
+ 'Cause' => cause,
289
+ 'Cause-txt' => cause_txt,
290
+ 'Channel' => "SIP/1234-00000000"
275
291
  end
276
292
 
277
293
  let(:cause) { '16' }
@@ -291,6 +307,7 @@ module Punchblock
291
307
  end
292
308
 
293
309
  it "should cause all components to send complete events before sending end event" do
310
+ subject.stub :send_progress
294
311
  comp_command = Punchblock::Component::Input.new :grammar => {:value => '<grammar/>'}, :mode => :dtmf
295
312
  comp_command.request!
296
313
  component = subject.execute_command comp_command
@@ -305,6 +322,7 @@ module Punchblock
305
322
  end
306
323
 
307
324
  it "should not allow commands to be executed while components are shutting down" do
325
+ subject.stub :send_progress
308
326
  comp_command = Punchblock::Component::Input.new :grammar => {:value => '<grammar/>'}, :mode => :dtmf
309
327
  comp_command.request!
310
328
  component = subject.execute_command comp_command
@@ -449,13 +467,12 @@ module Punchblock
449
467
  end
450
468
 
451
469
  let(:ami_event) do
452
- RubyAMI::Event.new("AsyncAGI").tap do |e|
453
- e["SubEvent"] = "End"
454
- e["Channel"] = "SIP/1234-00000000"
455
- e["CommandID"] = component.id
456
- e["Command"] = "EXEC ANSWER"
457
- e["Result"] = "200%20result=123%20(timeout)%0A"
458
- end
470
+ RubyAMI::Event.new "AsyncAGI",
471
+ "SubEvent" => "End",
472
+ "Channel" => "SIP/1234-00000000",
473
+ "CommandID" => component.id,
474
+ "Command" => "EXEC ANSWER",
475
+ "Result" => "200%20result=123%20(timeout)%0A"
459
476
  end
460
477
 
461
478
  before do
@@ -470,17 +487,16 @@ module Punchblock
470
487
 
471
488
  context 'with a Newstate event' do
472
489
  let :ami_event do
473
- RubyAMI::Event.new('Newstate').tap do |e|
474
- e['Privilege'] = 'call,all'
475
- e['Channel'] = 'SIP/1234-00000000'
476
- e['ChannelState'] = channel_state
477
- e['ChannelStateDesc'] = channel_state_desc
478
- e['CallerIDNum'] = ''
479
- e['CallerIDName'] = ''
480
- e['ConnectedLineNum'] = ''
481
- e['ConnectedLineName'] = ''
482
- e['Uniqueid'] = '1326194671.0'
483
- end
490
+ RubyAMI::Event.new 'Newstate',
491
+ 'Privilege' => 'call,all',
492
+ 'Channel' => 'SIP/1234-00000000',
493
+ 'ChannelState' => channel_state,
494
+ 'ChannelStateDesc' => channel_state_desc,
495
+ 'CallerIDNum' => '',
496
+ 'CallerIDName' => '',
497
+ 'ConnectedLineNum' => '',
498
+ 'ConnectedLineName' => '',
499
+ 'Uniqueid' => '1326194671.0'
484
500
  end
485
501
 
486
502
  context 'ringing' do
@@ -520,18 +536,17 @@ module Punchblock
520
536
 
521
537
  context 'with an OriginateResponse event' do
522
538
  let :ami_event do
523
- RubyAMI::Event.new('OriginateResponse').tap do |e|
524
- e['Privilege'] = 'call,all'
525
- e['ActionID'] = '9d0c1aa4-5e3b-4cae-8aef-76a6119e2909'
526
- e['Response'] = response
527
- e['Channel'] = 'SIP/15557654321'
528
- e['Context'] = ''
529
- e['Exten'] = ''
530
- e['Reason'] = '0'
531
- e['Uniqueid'] = uniqueid
532
- e['CallerIDNum'] = 'sip:5551234567'
533
- e['CallerIDName'] = 'Bryan 100'
534
- end
539
+ RubyAMI::Event.new 'OriginateResponse',
540
+ 'Privilege' => 'call,all',
541
+ 'ActionID' => '9d0c1aa4-5e3b-4cae-8aef-76a6119e2909',
542
+ 'Response' => response,
543
+ 'Channel' => 'SIP/15557654321',
544
+ 'Context' => '',
545
+ 'Exten' => '',
546
+ 'Reason' => '0',
547
+ 'Uniqueid' => uniqueid,
548
+ 'CallerIDNum' => 'sip:5551234567',
549
+ 'CallerIDName' => 'Bryan 100'
535
550
  end
536
551
 
537
552
  context 'sucessful' do
@@ -569,13 +584,12 @@ module Punchblock
569
584
 
570
585
  context 'with a handler registered for a matching event' do
571
586
  let :ami_event do
572
- RubyAMI::Event.new('DTMF').tap do |e|
573
- e['Digit'] = '4'
574
- e['Start'] = 'Yes'
575
- e['End'] = 'No'
576
- e['Uniqueid'] = "1320842458.8"
577
- e['Channel'] = "SIP/1234-00000000"
578
- end
587
+ RubyAMI::Event.new 'DTMF',
588
+ 'Digit' => '4',
589
+ 'Start' => 'Yes',
590
+ 'End' => 'No',
591
+ 'Uniqueid' => "1320842458.8",
592
+ 'Channel' => "SIP/1234-00000000"
579
593
  end
580
594
 
581
595
  let(:response) { mock 'Response' }
@@ -591,19 +605,18 @@ module Punchblock
591
605
 
592
606
  context 'with a BridgeExec event' do
593
607
  let :ami_event do
594
- RubyAMI::Event.new('BridgeExec').tap do |e|
595
- e['Privilege'] = "call,all"
596
- e['Response'] = "Success"
597
- e['Channel1'] = "SIP/foo"
598
- e['Channel2'] = other_channel
599
- end
608
+ RubyAMI::Event.new 'BridgeExec',
609
+ 'Privilege' => "call,all",
610
+ 'Response' => "Success",
611
+ 'Channel1' => "SIP/foo",
612
+ 'Channel2' => other_channel
600
613
  end
601
614
 
602
615
  let(:other_channel) { 'SIP/5678-00000000' }
603
616
 
604
617
  context "when a join has been executed against another call" do
605
618
  let :other_call do
606
- Call.new other_channel, translator
619
+ Call.new other_channel, translator, ami_client, connection
607
620
  end
608
621
 
609
622
  let(:other_call_id) { other_call.id }
@@ -614,6 +627,7 @@ module Punchblock
614
627
  before do
615
628
  translator.register_call other_call
616
629
  command.request!
630
+ subject.wrapped_object.should_receive(:execute_agi_command).and_return code: 200
617
631
  subject.execute_command command
618
632
  end
619
633
 
@@ -624,12 +638,11 @@ module Punchblock
624
638
 
625
639
  context "with the channel names reversed" do
626
640
  let :ami_event do
627
- RubyAMI::Event.new('BridgeExec').tap do |e|
628
- e['Privilege'] = "call,all"
629
- e['Response'] = "Success"
630
- e['Channel1'] = other_channel
631
- e['Channel2'] = "SIP/foo"
632
- end
641
+ RubyAMI::Event.new 'BridgeExec',
642
+ 'Privilege' => "call,all",
643
+ 'Response' => "Success",
644
+ 'Channel1' => other_channel,
645
+ 'Channel2' => "SIP/foo"
633
646
  end
634
647
 
635
648
  it 'retrieves and sets success on the correct Join' do
@@ -650,35 +663,33 @@ module Punchblock
650
663
  let(:other_channel) { 'SIP/5678-00000000' }
651
664
  let(:other_call_id) { 'def567' }
652
665
  let :other_call do
653
- Call.new other_channel, translator
666
+ Call.new other_channel, translator, ami_client, connection
654
667
  end
655
668
 
656
669
  let :ami_event do
657
- RubyAMI::Event.new('Bridge').tap do |e|
658
- e['Privilege'] = "call,all"
659
- e['Bridgestate'] = state
660
- e['Bridgetype'] = "core"
661
- e['Channel1'] = channel
662
- e['Channel2'] = other_channel
663
- e['Uniqueid1'] = "1319717537.11"
664
- e['Uniqueid2'] = "1319717537.10"
665
- e['CallerID1'] = "1234"
666
- e['CallerID2'] = "5678"
667
- end
670
+ RubyAMI::Event.new 'Bridge',
671
+ 'Privilege' => "call,all",
672
+ 'Bridgestate' => state,
673
+ 'Bridgetype' => "core",
674
+ 'Channel1' => channel,
675
+ 'Channel2' => other_channel,
676
+ 'Uniqueid1' => "1319717537.11",
677
+ 'Uniqueid2' => "1319717537.10",
678
+ 'CallerID1' => "1234",
679
+ 'CallerID2' => "5678"
668
680
  end
669
681
 
670
682
  let :switched_ami_event do
671
- RubyAMI::Event.new('Bridge').tap do |e|
672
- e['Privilege'] = "call,all"
673
- e['Bridgestate'] = state
674
- e['Bridgetype'] = "core"
675
- e['Channel1'] = other_channel
676
- e['Channel2'] = channel
677
- e['Uniqueid1'] = "1319717537.11"
678
- e['Uniqueid2'] = "1319717537.10"
679
- e['CallerID1'] = "1234"
680
- e['CallerID2'] = "5678"
681
- end
683
+ RubyAMI::Event.new 'Bridge',
684
+ 'Privilege' => "call,all",
685
+ 'Bridgestate' => state,
686
+ 'Bridgetype' => "core",
687
+ 'Channel1' => other_channel,
688
+ 'Channel2' => channel,
689
+ 'Uniqueid1' => "1319717537.11",
690
+ 'Uniqueid2' => "1319717537.10",
691
+ 'CallerID1' => "1234",
692
+ 'CallerID2' => "5678"
682
693
  end
683
694
 
684
695
  before do
@@ -734,31 +745,29 @@ module Punchblock
734
745
  let(:other_channel) { 'SIP/5678-00000000' }
735
746
  let(:other_call_id) { 'def567' }
736
747
  let :other_call do
737
- Call.new other_channel, translator
748
+ Call.new other_channel, translator, ami_client, connection
738
749
  end
739
750
 
740
751
  let :ami_event do
741
- RubyAMI::Event.new('Unlink').tap do |e|
742
- e['Privilege'] = "call,all"
743
- e['Channel1'] = channel
744
- e['Channel2'] = other_channel
745
- e['Uniqueid1'] = "1319717537.11"
746
- e['Uniqueid2'] = "1319717537.10"
747
- e['CallerID1'] = "1234"
748
- e['CallerID2'] = "5678"
749
- end
752
+ RubyAMI::Event.new 'Unlink',
753
+ 'Privilege' => "call,all",
754
+ 'Channel1' => channel,
755
+ 'Channel2' => other_channel,
756
+ 'Uniqueid1' => "1319717537.11",
757
+ 'Uniqueid2' => "1319717537.10",
758
+ 'CallerID1' => "1234",
759
+ 'CallerID2' => "5678"
750
760
  end
751
761
 
752
762
  let :switched_ami_event do
753
- RubyAMI::Event.new('Unlink').tap do |e|
754
- e['Privilege'] = "call,all"
755
- e['Channel1'] = other_channel
756
- e['Channel2'] = channel
757
- e['Uniqueid1'] = "1319717537.11"
758
- e['Uniqueid2'] = "1319717537.10"
759
- e['CallerID1'] = "1234"
760
- e['CallerID2'] = "5678"
761
- end
763
+ RubyAMI::Event.new 'Unlink',
764
+ 'Privilege' => "call,all",
765
+ 'Channel1' => other_channel,
766
+ 'Channel2' => channel,
767
+ 'Uniqueid1' => "1319717537.11",
768
+ 'Uniqueid2' => "1319717537.10",
769
+ 'CallerID1' => "1234",
770
+ 'CallerID2' => "5678"
762
771
  end
763
772
 
764
773
  before do
@@ -785,17 +794,32 @@ module Punchblock
785
794
  end
786
795
  end
787
796
 
788
- let :ami_event do
789
- RubyAMI::Event.new('Foo').tap do |e|
790
- e['Uniqueid'] = "1320842458.8"
791
- e['Calleridnum'] = "5678"
792
- e['Calleridname'] = "Jane Smith"
793
- e['Cause'] = "0"
794
- e['Cause-txt'] = "Unknown"
795
- e['Channel'] = channel
797
+ context 'with a VarSet event' do
798
+ let :ami_event do
799
+ RubyAMI::Event.new 'VarSet',
800
+ "Privilege" => "dialplan,all",
801
+ "Channel" => "SIP/1234-00000000",
802
+ "Variable" => "foobar",
803
+ "Value" => 'abc123',
804
+ "Uniqueid" => "1326210224.0"
805
+ end
806
+
807
+ it 'makes the variable accessible on the call' do
808
+ subject.process_ami_event ami_event
809
+ subject.channel_var('foobar').should == 'abc123'
796
810
  end
797
811
  end
798
812
 
813
+ let :ami_event do
814
+ RubyAMI::Event.new 'Foo',
815
+ 'Uniqueid' => "1320842458.8",
816
+ 'Calleridnum' => "5678",
817
+ 'Calleridname' => "Jane Smith",
818
+ 'Cause' => "0",
819
+ 'Cause-txt' => "Unknown",
820
+ 'Channel' => channel
821
+ end
822
+
799
823
  let :expected_pb_event do
800
824
  Event::Asterisk::AMI::Event.new :name => 'Foo',
801
825
  :attributes => { :channel => channel,
@@ -815,14 +839,6 @@ module Punchblock
815
839
  end
816
840
 
817
841
  describe '#execute_command' do
818
- let :expected_agi_complete_event do
819
- Punchblock::Event::Complete.new.tap do |c|
820
- c.reason = Punchblock::Component::Asterisk::AGI::Command::Complete::Success.new :code => 200,
821
- :result => 'Success',
822
- :data => 'FOO'
823
- end
824
- end
825
-
826
842
  before do
827
843
  command.request!
828
844
  end
@@ -831,11 +847,8 @@ module Punchblock
831
847
  let(:command) { Command::Accept.new }
832
848
 
833
849
  it "should send an EXEC RINGING AGI command and set the command's response" do
834
- component = subject.execute_command command
835
- component.internal.should be_true
836
- agi_command = subject.wrapped_object.instance_variable_get(:'@current_agi_command')
837
- agi_command.name.should be == "EXEC RINGING"
838
- agi_command.add_event expected_agi_complete_event
850
+ subject.wrapped_object.should_receive(:execute_agi_command).with('EXEC RINGING').and_return code: 200
851
+ subject.execute_command command
839
852
  command.response(0.5).should be true
840
853
  end
841
854
  end
@@ -845,31 +858,22 @@ module Punchblock
845
858
 
846
859
  it "with a :busy reason should send an EXEC Busy AGI command and set the command's response" do
847
860
  command.reason = :busy
848
- component = subject.execute_command command
849
- component.internal.should be_true
850
- agi_command = subject.wrapped_object.instance_variable_get(:'@current_agi_command')
851
- agi_command.name.should be == "EXEC Busy"
852
- agi_command.add_event expected_agi_complete_event
861
+ subject.wrapped_object.should_receive(:execute_agi_command).with('EXEC Busy').and_return code: 200
862
+ subject.execute_command command
853
863
  command.response(0.5).should be true
854
864
  end
855
865
 
856
866
  it "with a :decline reason should send an EXEC Busy AGI command and set the command's response" do
857
867
  command.reason = :decline
858
- component = subject.execute_command command
859
- component.internal.should be_true
860
- agi_command = subject.wrapped_object.instance_variable_get(:'@current_agi_command')
861
- agi_command.name.should be == "EXEC Busy"
862
- agi_command.add_event expected_agi_complete_event
868
+ subject.wrapped_object.should_receive(:execute_agi_command).with('EXEC Busy').and_return code: 200
869
+ subject.execute_command command
863
870
  command.response(0.5).should be true
864
871
  end
865
872
 
866
873
  it "with an :error reason should send an EXEC Congestion AGI command and set the command's response" do
867
874
  command.reason = :error
868
- component = subject.execute_command command
869
- component.internal.should be_true
870
- agi_command = subject.wrapped_object.instance_variable_get(:'@current_agi_command')
871
- agi_command.name.should be == "EXEC Congestion"
872
- agi_command.add_event expected_agi_complete_event
875
+ subject.wrapped_object.should_receive(:execute_agi_command).with('EXEC Congestion').and_return code: 200
876
+ subject.execute_command command
873
877
  command.response(0.5).should be true
874
878
  end
875
879
  end
@@ -878,11 +882,8 @@ module Punchblock
878
882
  let(:command) { Command::Answer.new }
879
883
 
880
884
  it "should send an ANSWER AGI command and set the command's response" do
881
- component = subject.execute_command command
882
- component.internal.should be_true
883
- agi_command = subject.wrapped_object.instance_variable_get(:'@current_agi_command')
884
- agi_command.name.should be == "ANSWER"
885
- agi_command.add_event expected_agi_complete_event
885
+ subject.wrapped_object.should_receive(:execute_agi_command).with('ANSWER').and_return code: 200
886
+ subject.execute_command command
886
887
  command.response(0.5).should be true
887
888
  end
888
889
  end
@@ -891,11 +892,8 @@ module Punchblock
891
892
  let(:command) { Command::Hangup.new }
892
893
 
893
894
  it "should send a Hangup AMI command and set the command's response" do
895
+ ami_client.should_receive(:send_action).once.with('Hangup', 'Channel' => channel, 'Cause' => 16).and_return RubyAMI::Response.new
894
896
  subject.execute_command command
895
- ami_action = subject.wrapped_object.instance_variable_get(:'@current_ami_action')
896
- ami_action.name.should be == "hangup"
897
- ami_action.headers['Cause'].should be == 16
898
- ami_action << RubyAMI::Response.new
899
897
  command.response(0.5).should be true
900
898
  end
901
899
  end
@@ -908,7 +906,6 @@ module Punchblock
908
906
  let(:mock_action) { Translator::Asterisk::Component::Asterisk::AGICommand.new(command, subject) }
909
907
 
910
908
  it 'should create an AGI command component actor and execute it asynchronously' do
911
- mock_action.should_receive(:internal=).never
912
909
  Component::Asterisk::AGICommand.should_receive(:new_link).once.with(command, subject).and_return mock_action
913
910
  mock_action.async.should_receive(:execute).once
914
911
  subject.execute_command command
@@ -924,7 +921,6 @@ module Punchblock
924
921
 
925
922
  it 'should create an Output component and execute it asynchronously' do
926
923
  Component::Output.should_receive(:new_link).once.with(command, subject).and_return mock_action
927
- mock_action.should_receive(:internal=).never
928
924
  mock_action.async.should_receive(:execute).once
929
925
  subject.execute_command command
930
926
  end
@@ -939,7 +935,6 @@ module Punchblock
939
935
 
940
936
  it 'should create an Input component and execute it asynchronously' do
941
937
  Component::Input.should_receive(:new_link).once.with(command, subject).and_return mock_action
942
- mock_action.should_receive(:internal=).never
943
938
  mock_action.async.should_receive(:execute).once
944
939
  subject.execute_command command
945
940
  end
@@ -954,7 +949,6 @@ module Punchblock
954
949
 
955
950
  it 'should create a Record component and execute it asynchronously' do
956
951
  Component::Record.should_receive(:new_link).once.with(command, subject).and_return mock_action
957
- mock_action.should_receive(:internal=).never
958
952
  mock_action.async.should_receive(:execute).once
959
953
  subject.execute_command command
960
954
  end
@@ -1059,7 +1053,7 @@ module Punchblock
1059
1053
  let(:other_translator) { stub('Translator::Asterisk').as_null_object }
1060
1054
 
1061
1055
  let :other_call do
1062
- Call.new other_channel, other_translator
1056
+ Call.new other_channel, other_translator, ami_client, connection
1063
1057
  end
1064
1058
 
1065
1059
  let :command do
@@ -1067,11 +1061,9 @@ module Punchblock
1067
1061
  end
1068
1062
 
1069
1063
  it "executes the proper dialplan Bridge application" do
1064
+ subject.wrapped_object.should_receive(:execute_agi_command).with('EXEC Bridge', other_channel).and_return code: 200
1070
1065
  translator.should_receive(:call_with_id).with(other_call_id).and_return(other_call)
1071
1066
  subject.execute_command command
1072
- agi_command = subject.wrapped_object.instance_variable_get(:'@current_agi_command')
1073
- agi_command.name.should be == "EXEC Bridge"
1074
- agi_command.params_array.should be == [other_channel]
1075
1067
  end
1076
1068
  end
1077
1069
 
@@ -1080,7 +1072,7 @@ module Punchblock
1080
1072
  let(:other_channel) { 'SIP/bar' }
1081
1073
 
1082
1074
  let :other_call do
1083
- Call.new other_channel, translator
1075
+ Call.new other_channel, translator, ami_client, connection
1084
1076
  end
1085
1077
 
1086
1078
  let :command do
@@ -1089,45 +1081,49 @@ module Punchblock
1089
1081
 
1090
1082
  it "executes the unjoin through redirection" do
1091
1083
  translator.should_receive(:call_with_id).with(other_call_id).and_return(nil)
1084
+
1085
+ ami_client.should_receive(:send_action).once.with("Redirect",
1086
+ 'Channel' => channel,
1087
+ 'Exten' => Punchblock::Translator::Asterisk::REDIRECT_EXTENSION,
1088
+ 'Priority' => Punchblock::Translator::Asterisk::REDIRECT_PRIORITY,
1089
+ 'Context' => Punchblock::Translator::Asterisk::REDIRECT_CONTEXT,
1090
+ ).and_return RubyAMI::Response.new
1091
+
1092
1092
  subject.execute_command command
1093
- ami_action = subject.wrapped_object.instance_variable_get(:'@current_ami_action')
1094
- ami_action.name.should be == "redirect"
1095
- ami_action.headers['Channel'].should be == channel
1096
- ami_action.headers['Exten'].should be == Punchblock::Translator::Asterisk::REDIRECT_EXTENSION
1097
- ami_action.headers['Priority'].should be == Punchblock::Translator::Asterisk::REDIRECT_PRIORITY
1098
- ami_action.headers['Context'].should be == Punchblock::Translator::Asterisk::REDIRECT_CONTEXT
1099
-
1100
- ami_action << RubyAMI::Response.new
1093
+
1101
1094
  command.response(1).should be_true
1102
1095
  end
1103
1096
 
1104
1097
  it "executes the unjoin through redirection, on the subject call and the other call" do
1105
1098
  translator.should_receive(:call_with_id).with(other_call_id).and_return(other_call)
1106
- subject.execute_command command
1107
- ami_action = subject.wrapped_object.instance_variable_get(:'@current_ami_action')
1108
- ami_action.name.should be == "redirect"
1109
- ami_action.headers['Channel'].should be == channel
1110
- ami_action.headers['Exten'].should be == Punchblock::Translator::Asterisk::REDIRECT_EXTENSION
1111
- ami_action.headers['Priority'].should be == Punchblock::Translator::Asterisk::REDIRECT_PRIORITY
1112
- ami_action.headers['Context'].should be == Punchblock::Translator::Asterisk::REDIRECT_CONTEXT
1113
1099
 
1114
- ami_action.headers['ExtraChannel'].should be == other_channel
1115
- ami_action.headers['ExtraExten'].should be == Punchblock::Translator::Asterisk::REDIRECT_EXTENSION
1116
- ami_action.headers['ExtraPriority'].should be == Punchblock::Translator::Asterisk::REDIRECT_PRIORITY
1117
- ami_action.headers['ExtraContext'].should be == Punchblock::Translator::Asterisk::REDIRECT_CONTEXT
1100
+ ami_client.should_receive(:send_action).once.with("Redirect",
1101
+ 'Channel' => channel,
1102
+ 'Exten' => Punchblock::Translator::Asterisk::REDIRECT_EXTENSION,
1103
+ 'Priority' => Punchblock::Translator::Asterisk::REDIRECT_PRIORITY,
1104
+ 'Context' => Punchblock::Translator::Asterisk::REDIRECT_CONTEXT,
1105
+ 'ExtraChannel' => other_channel,
1106
+ 'ExtraExten' => Punchblock::Translator::Asterisk::REDIRECT_EXTENSION,
1107
+ 'ExtraPriority' => Punchblock::Translator::Asterisk::REDIRECT_PRIORITY,
1108
+ 'ExtraContext' => Punchblock::Translator::Asterisk::REDIRECT_CONTEXT
1109
+ ).and_return RubyAMI::Response.new
1110
+
1111
+ subject.execute_command command
1118
1112
  end
1119
1113
 
1120
1114
  it "handles redirect errors" do
1121
1115
  translator.should_receive(:call_with_id).with(other_call_id).and_return(nil)
1116
+
1117
+ error = RubyAMI::Error.new.tap { |e| e.message = 'FooBar' }
1118
+
1119
+ ami_client.should_receive(:send_action).once.with("Redirect",
1120
+ 'Channel' => channel,
1121
+ 'Exten' => Punchblock::Translator::Asterisk::REDIRECT_EXTENSION,
1122
+ 'Priority' => Punchblock::Translator::Asterisk::REDIRECT_PRIORITY,
1123
+ 'Context' => Punchblock::Translator::Asterisk::REDIRECT_CONTEXT,
1124
+ ).and_raise error
1125
+
1122
1126
  subject.execute_command command
1123
- ami_action = subject.wrapped_object.instance_variable_get(:'@current_ami_action')
1124
- ami_action.name.should be == "redirect"
1125
- ami_action.headers['Channel'].should be == channel
1126
- ami_action.headers['Exten'].should be == Punchblock::Translator::Asterisk::REDIRECT_EXTENSION
1127
- ami_action.headers['Priority'].should be == Punchblock::Translator::Asterisk::REDIRECT_PRIORITY
1128
- ami_action.headers['Context'].should be == Punchblock::Translator::Asterisk::REDIRECT_CONTEXT
1129
-
1130
- ami_action << RubyAMI::Error.new.tap { |e| e.message = 'FooBar' }
1131
1127
  response = command.response(1)
1132
1128
  response.should be_a ProtocolError
1133
1129
  response.text.should == 'FooBar'
@@ -1135,54 +1131,91 @@ module Punchblock
1135
1131
  end
1136
1132
  end#execute_command
1137
1133
 
1138
- describe '#send_agi_action' do
1134
+ describe '#execute_agi_command' do
1135
+ before { stub_uuids Punchblock.new_uuid }
1136
+
1137
+ let :response do
1138
+ RubyAMI::Response.new 'ActionID' => "552a9d9f-46d7-45d8-a257-06fe95f48d99",
1139
+ 'Message' => 'Added AGI original_command to queue'
1140
+ end
1141
+
1139
1142
  it 'should send an appropriate AsyncAGI AMI action' do
1140
- pending
1141
- subject.wrapped_object.should_receive(:send_ami_action).once.with('AGI', 'Command' => 'FOO', 'Channel' => subject.channel)
1142
- subject.send_agi_action 'FOO'
1143
+ Celluloid::Condition.any_instance.should_receive(:wait).and_return nil
1144
+ ami_client.should_receive(:send_action).once.with('AGI', 'Channel' => channel, 'Command' => 'EXEC ANSWER', 'CommandID' => Punchblock.new_uuid).and_return(response)
1145
+ subject.execute_agi_command 'EXEC ANSWER'
1143
1146
  end
1144
- end
1145
1147
 
1146
- describe '#send_ami_action' do
1147
- let(:component_id) { Punchblock.new_uuid }
1148
- before { stub_uuids component_id }
1148
+ context 'with some parameters' do
1149
+ let(:params) { [1000, 'foo'] }
1150
+
1151
+ it 'should send the appropriate action' do
1152
+ Celluloid::Condition.any_instance.should_receive(:wait).and_return nil
1153
+ ami_client.should_receive(:send_action).once.with('AGI', 'Channel' => channel, 'Command' => 'WAIT FOR DIGIT "1000" "foo"', 'CommandID' => Punchblock.new_uuid).and_return(response)
1154
+ subject.execute_agi_command 'WAIT FOR DIGIT', *params
1155
+ end
1156
+ end
1157
+
1158
+ context 'with an error' do
1159
+ let :error do
1160
+ RubyAMI::Error.new.tap { |e| e.message = 'Action failed' }
1161
+ end
1162
+
1163
+ it 'should raise the error' do
1164
+ ami_client.should_receive(:send_action).once.and_raise error
1165
+ expect { subject.execute_agi_command 'EXEC ANSWER' }.to raise_error(RubyAMI::Error, 'Action failed')
1166
+ end
1167
+ end
1168
+
1169
+ describe 'when receiving an AsyncAGI event' do
1170
+ context 'of type Exec' do
1171
+ let(:ami_event) do
1172
+ RubyAMI::Event.new 'AsyncAGI',
1173
+ "SubEvent" => "Exec",
1174
+ "Channel" => channel,
1175
+ "CommandID" => Punchblock.new_uuid,
1176
+ "Command" => "EXEC ANSWER",
1177
+ "Result" => "200%20result=123%20(timeout)%0A"
1178
+ end
1179
+
1180
+ it 'should return the result' do
1181
+ fut = subject.future.execute_agi_command 'EXEC ANSWER'
1149
1182
 
1150
- it 'should send the action to the AMI client' do
1151
- action = RubyAMI::Action.new 'foo', :foo => :bar
1152
- translator.should_receive(:send_ami_action).once.with action
1153
- subject.send_ami_action 'foo', :foo => :bar
1183
+ subject.process_ami_event ami_event
1184
+
1185
+ fut.value.should == {code: 200, result: 123, data: 'timeout'}
1186
+ end
1187
+ end
1154
1188
  end
1155
1189
  end
1156
1190
 
1157
1191
  describe '#redirect_back' do
1158
- let(:other_channel) { 'SIP/bar' }
1159
- let :other_call do
1160
- Call.new other_channel, translator
1161
- end
1162
-
1163
- it "executes the proper AMI action with only the subject call" do
1164
- subject.redirect_back
1165
- ami_action = subject.wrapped_object.instance_variable_get(:'@current_ami_action')
1166
- ami_action.name.should be == "redirect"
1167
- ami_action.headers['Channel'].should be == channel
1168
- ami_action.headers['Exten'].should be == Punchblock::Translator::Asterisk::REDIRECT_EXTENSION
1169
- ami_action.headers['Priority'].should be == Punchblock::Translator::Asterisk::REDIRECT_PRIORITY
1170
- ami_action.headers['Context'].should be == Punchblock::Translator::Asterisk::REDIRECT_CONTEXT
1171
- end
1172
-
1173
- it "executes the proper AMI action with another call specified" do
1174
- subject.redirect_back other_call
1175
- ami_action = subject.wrapped_object.instance_variable_get(:'@current_ami_action')
1176
- ami_action.name.should be == "redirect"
1177
- ami_action.headers['Channel'].should be == channel
1178
- ami_action.headers['Exten'].should be == Punchblock::Translator::Asterisk::REDIRECT_EXTENSION
1179
- ami_action.headers['Priority'].should be == Punchblock::Translator::Asterisk::REDIRECT_PRIORITY
1180
- ami_action.headers['Context'].should be == Punchblock::Translator::Asterisk::REDIRECT_CONTEXT
1181
- ami_action.headers['ExtraChannel'].should be == other_channel
1182
- ami_action.headers['ExtraExten'].should be == Punchblock::Translator::Asterisk::REDIRECT_EXTENSION
1183
- ami_action.headers['ExtraPriority'].should be == Punchblock::Translator::Asterisk::REDIRECT_PRIORITY
1184
- ami_action.headers['ExtraContext'].should be == Punchblock::Translator::Asterisk::REDIRECT_CONTEXT
1185
- end
1192
+ let(:other_channel) { 'SIP/bar' }
1193
+
1194
+ let :other_call do
1195
+ Call.new other_channel, translator, ami_client, connection
1196
+ end
1197
+
1198
+ it "executes the proper AMI action with only the subject call" do
1199
+ ami_client.should_receive(:send_action).once.with 'Redirect',
1200
+ 'Exten' => Punchblock::Translator::Asterisk::REDIRECT_EXTENSION,
1201
+ 'Priority' => Punchblock::Translator::Asterisk::REDIRECT_PRIORITY,
1202
+ 'Context' => Punchblock::Translator::Asterisk::REDIRECT_CONTEXT,
1203
+ 'Channel' => channel
1204
+ subject.redirect_back
1205
+ end
1206
+
1207
+ it "executes the proper AMI action with another call specified" do
1208
+ ami_client.should_receive(:send_action).once.with 'Redirect',
1209
+ 'Channel' => channel,
1210
+ 'Exten' => Punchblock::Translator::Asterisk::REDIRECT_EXTENSION,
1211
+ 'Priority' => Punchblock::Translator::Asterisk::REDIRECT_PRIORITY,
1212
+ 'Context' => Punchblock::Translator::Asterisk::REDIRECT_CONTEXT,
1213
+ 'ExtraChannel' => other_channel,
1214
+ 'ExtraExten' => Punchblock::Translator::Asterisk::REDIRECT_EXTENSION,
1215
+ 'ExtraPriority' => Punchblock::Translator::Asterisk::REDIRECT_PRIORITY,
1216
+ 'ExtraContext' => Punchblock::Translator::Asterisk::REDIRECT_CONTEXT
1217
+ subject.redirect_back other_call
1218
+ end
1186
1219
  end
1187
1220
  end
1188
1221
  end