punchblock 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/.travis.yml +3 -3
  2. data/CHANGELOG.md +23 -0
  3. data/lib/punchblock.rb +24 -0
  4. data/lib/punchblock/command/reject.rb +10 -2
  5. data/lib/punchblock/component/record.rb +16 -0
  6. data/lib/punchblock/core_ext/blather/stanza.rb +3 -1
  7. data/lib/punchblock/dead_actor_safety.rb +9 -0
  8. data/lib/punchblock/event/complete.rb +9 -11
  9. data/lib/punchblock/rayo_node.rb +4 -0
  10. data/lib/punchblock/translator/asterisk.rb +65 -22
  11. data/lib/punchblock/translator/asterisk/call.rb +49 -30
  12. data/lib/punchblock/translator/asterisk/component.rb +6 -8
  13. data/lib/punchblock/translator/asterisk/component/asterisk/agi_command.rb +13 -20
  14. data/lib/punchblock/translator/asterisk/component/asterisk/ami_action.rb +1 -1
  15. data/lib/punchblock/translator/asterisk/component/input.rb +3 -6
  16. data/lib/punchblock/translator/asterisk/component/output.rb +40 -45
  17. data/lib/punchblock/translator/asterisk/component/record.rb +1 -1
  18. data/lib/punchblock/translator/asterisk/component/stop_by_redirect.rb +5 -2
  19. data/lib/punchblock/version.rb +1 -1
  20. data/punchblock.gemspec +5 -5
  21. data/spec/punchblock/command/reject_spec.rb +7 -1
  22. data/spec/punchblock/command_node_spec.rb +5 -2
  23. data/spec/punchblock/component/component_node_spec.rb +4 -0
  24. data/spec/punchblock/component/output_spec.rb +1 -1
  25. data/spec/punchblock/component/record_spec.rb +30 -0
  26. data/spec/punchblock/event/complete_spec.rb +10 -0
  27. data/spec/punchblock/translator/asterisk/call_spec.rb +191 -48
  28. data/spec/punchblock/translator/asterisk/component/asterisk/agi_command_spec.rb +6 -39
  29. data/spec/punchblock/translator/asterisk/component/asterisk/ami_action_spec.rb +3 -3
  30. data/spec/punchblock/translator/asterisk/component/input_spec.rb +8 -3
  31. data/spec/punchblock/translator/asterisk/component/output_spec.rb +153 -46
  32. data/spec/punchblock/translator/asterisk/component/record_spec.rb +6 -5
  33. data/spec/punchblock/translator/asterisk/component/stop_by_redirect_spec.rb +1 -2
  34. data/spec/punchblock/translator/asterisk/component_spec.rb +1 -0
  35. data/spec/punchblock/translator/asterisk_spec.rb +147 -12
  36. data/spec/punchblock_spec.rb +34 -0
  37. data/spec/spec_helper.rb +5 -1
  38. metadata +30 -20
@@ -9,6 +9,16 @@ module Punchblock
9
9
  RayoNode.class_from_registration(:complete, 'urn:xmpp:rayo:ext:1').should be == Complete
10
10
  end
11
11
 
12
+ describe "setting a reason" do
13
+ let(:reason) { Punchblock::Component::Asterisk::AGI::Command::Complete::Success.new }
14
+
15
+ subject { described_class.new }
16
+
17
+ before { subject.reason = reason }
18
+
19
+ its(:reason) { should == reason }
20
+ end
21
+
12
22
  describe "comparing for equality" do
13
23
  subject do
14
24
  Complete.new.tap do |c|
@@ -88,7 +88,7 @@ module Punchblock
88
88
  :to => '1000',
89
89
  :from => 'Jane Smith <sip:5678>',
90
90
  :headers => sip_headers
91
- translator.expects(:handle_pb_event!).with expected_offer
91
+ translator.expects(:handle_pb_event).with expected_offer
92
92
  subject.send_offer
93
93
  end
94
94
 
@@ -100,20 +100,19 @@ module Punchblock
100
100
  end
101
101
  end
102
102
 
103
- describe '#answer_if_not_answered' do
104
- let(:answer_command) { Command::Answer.new.tap { |a| a.request! } }
103
+ describe '#send_progress' do
105
104
 
106
105
  context "with a call that is already answered" do
107
- it 'should not answer the call' do
106
+ it 'should not send the EXEC Progress command' do
108
107
  subject.wrapped_object.expects(:'answered?').returns true
109
- subject.wrapped_object.expects(:execute_command).never
110
- subject.answer_if_not_answered
108
+ subject.wrapped_object.expects(:send_agi_action).with("EXEC Progress").never
109
+ subject.send_progress
111
110
  end
112
111
  end
113
112
 
114
113
  context "with an unanswered call" do
115
114
  before do
116
- subject.wrapped_object.expects(:'answered?').returns false
115
+ subject.wrapped_object.expects(:'answered?').returns(false).at_least_once
117
116
  end
118
117
 
119
118
  context "with a call that is outbound" do
@@ -124,9 +123,9 @@ module Punchblock
124
123
  subject.dial dial_command
125
124
  end
126
125
 
127
- it 'should not answer the call' do
128
- subject.wrapped_object.expects(:execute_command).never
129
- subject.answer_if_not_answered
126
+ it 'should not send the EXEC Progress command' do
127
+ subject.wrapped_object.expects(:send_agi_action).with("EXEC Progress").never
128
+ subject.send_progress
130
129
  end
131
130
  end
132
131
 
@@ -135,9 +134,15 @@ module Punchblock
135
134
  subject.send_offer
136
135
  end
137
136
 
138
- it 'should answer a call that is inbound and not answered' do
139
- subject.wrapped_object.expects(:execute_command).with(answer_command)
140
- subject.answer_if_not_answered
137
+ it 'should send the EXEC Progress command to a call that is inbound and not answered' do
138
+ subject.wrapped_object.expects(:send_agi_action).with("EXEC Progress")
139
+ subject.send_progress
140
+ end
141
+
142
+ it 'should send the EXEC Progress command only once if called twice' do
143
+ subject.wrapped_object.expects(:send_agi_action).with("EXEC Progress").once
144
+ subject.send_progress
145
+ subject.send_progress
141
146
  end
142
147
  end
143
148
  end
@@ -229,14 +234,19 @@ module Punchblock
229
234
  let(:cause_txt) { 'Normal Clearing' }
230
235
 
231
236
  it "should cause the actor to be terminated" do
232
- translator.expects(:handle_pb_event!).once
237
+ translator.expects(:handle_pb_event).twice
233
238
  subject.process_ami_event ami_event
234
239
  sleep 5.5
235
240
  subject.should_not be_alive
236
241
  end
237
242
 
243
+ it "de-registers the call from the translator" do
244
+ translator.stubs :handle_pb_event
245
+ translator.expects(:deregister_call).once.with(subject)
246
+ subject.process_ami_event ami_event
247
+ end
248
+
238
249
  it "should cause all components to send complete events before sending end event" do
239
- subject.expects :answer_if_not_answered
240
250
  comp_command = Punchblock::Component::Input.new :grammar => {:value => '<grammar/>'}, :mode => :dtmf
241
251
  comp_command.request!
242
252
  component = subject.execute_command comp_command
@@ -245,8 +255,8 @@ module Punchblock
245
255
  expected_complete_event.reason = Punchblock::Event::Complete::Hangup.new
246
256
  expected_end_event = Punchblock::Event::End.new :reason => :hangup, :target_call_id => subject.id
247
257
  end_sequence = sequence 'end events'
248
- translator.expects(:handle_pb_event!).with(expected_complete_event).once.in_sequence(end_sequence)
249
- translator.expects(:handle_pb_event!).with(expected_end_event).once.in_sequence(end_sequence)
258
+ translator.expects(:handle_pb_event).with(expected_complete_event).once.in_sequence(end_sequence)
259
+ translator.expects(:handle_pb_event).with(expected_end_event).once.in_sequence(end_sequence)
250
260
  subject.process_ami_event ami_event
251
261
  end
252
262
 
@@ -257,7 +267,7 @@ module Punchblock
257
267
  it 'should send an end (hangup) event to the translator' do
258
268
  expected_end_event = Punchblock::Event::End.new :reason => :hangup,
259
269
  :target_call_id => subject.id
260
- translator.expects(:handle_pb_event!).with expected_end_event
270
+ translator.expects(:handle_pb_event).with expected_end_event
261
271
  subject.process_ami_event ami_event
262
272
  end
263
273
  end
@@ -269,7 +279,7 @@ module Punchblock
269
279
  it 'should send an end (hangup) event to the translator' do
270
280
  expected_end_event = Punchblock::Event::End.new :reason => :hangup,
271
281
  :target_call_id => subject.id
272
- translator.expects(:handle_pb_event!).with expected_end_event
282
+ translator.expects(:handle_pb_event).with expected_end_event
273
283
  subject.process_ami_event ami_event
274
284
  end
275
285
  end
@@ -281,7 +291,7 @@ module Punchblock
281
291
  it 'should send an end (busy) event to the translator' do
282
292
  expected_end_event = Punchblock::Event::End.new :reason => :busy,
283
293
  :target_call_id => subject.id
284
- translator.expects(:handle_pb_event!).with expected_end_event
294
+ translator.expects(:handle_pb_event).with expected_end_event
285
295
  subject.process_ami_event ami_event
286
296
  end
287
297
  end
@@ -297,7 +307,7 @@ module Punchblock
297
307
  it 'should send an end (timeout) event to the translator' do
298
308
  expected_end_event = Punchblock::Event::End.new :reason => :timeout,
299
309
  :target_call_id => subject.id
300
- translator.expects(:handle_pb_event!).with expected_end_event
310
+ translator.expects(:handle_pb_event).with expected_end_event
301
311
  subject.process_ami_event ami_event
302
312
  end
303
313
  end
@@ -315,7 +325,7 @@ module Punchblock
315
325
  it 'should send an end (reject) event to the translator' do
316
326
  expected_end_event = Punchblock::Event::End.new :reason => :reject,
317
327
  :target_call_id => subject.id
318
- translator.expects(:handle_pb_event!).with expected_end_event
328
+ translator.expects(:handle_pb_event).with expected_end_event
319
329
  subject.process_ami_event ami_event
320
330
  end
321
331
  end
@@ -367,7 +377,7 @@ module Punchblock
367
377
  it 'should send an end (error) event to the translator' do
368
378
  expected_end_event = Punchblock::Event::End.new :reason => :error,
369
379
  :target_call_id => subject.id
370
- translator.expects(:handle_pb_event!).with expected_end_event
380
+ translator.expects(:handle_pb_event).with expected_end_event
371
381
  subject.process_ami_event ami_event
372
382
  end
373
383
  end
@@ -395,7 +405,7 @@ module Punchblock
395
405
  end
396
406
 
397
407
  it 'should send the event to the component' do
398
- component.expects(:handle_ami_event!).once.with ami_event
408
+ component.expects(:handle_ami_event).once.with ami_event
399
409
  subject.process_ami_event ami_event
400
410
  end
401
411
  end
@@ -422,7 +432,7 @@ module Punchblock
422
432
  it 'should send a ringing event' do
423
433
  expected_ringing = Punchblock::Event::Ringing.new
424
434
  expected_ringing.target_call_id = subject.id
425
- translator.expects(:handle_pb_event!).with expected_ringing
435
+ translator.expects(:handle_pb_event).with expected_ringing
426
436
  subject.process_ami_event ami_event
427
437
  end
428
438
 
@@ -439,7 +449,7 @@ module Punchblock
439
449
  it 'should send a ringing event' do
440
450
  expected_answered = Punchblock::Event::Answered.new
441
451
  expected_answered.target_call_id = subject.id
442
- translator.expects(:handle_pb_event!).with expected_answered
452
+ translator.expects(:handle_pb_event).with expected_answered
443
453
  subject.process_ami_event ami_event
444
454
  end
445
455
 
@@ -450,6 +460,55 @@ module Punchblock
450
460
  end
451
461
  end
452
462
 
463
+ context 'with an OriginateResponse event' do
464
+ let :ami_event do
465
+ RubyAMI::Event.new('OriginateResponse').tap do |e|
466
+ e['Privilege'] = 'call,all'
467
+ e['ActionID'] = '9d0c1aa4-5e3b-4cae-8aef-76a6119e2909'
468
+ e['Response'] = response
469
+ e['Channel'] = 'SIP/15557654321'
470
+ e['Context'] = ''
471
+ e['Exten'] = ''
472
+ e['Reason'] = '0'
473
+ e['Uniqueid'] = uniqueid
474
+ e['CallerIDNum'] = 'sip:5551234567'
475
+ e['CallerIDName'] = 'Bryan 100'
476
+ end
477
+ end
478
+
479
+ context 'sucessful' do
480
+ let(:response) { 'Success' }
481
+ let(:uniqueid) { '<null>' }
482
+
483
+ it 'should not send an end event' do
484
+ translator.expects(:handle_pb_event).once.with is_a(Punchblock::Event::Asterisk::AMI::Event)
485
+ subject.process_ami_event ami_event
486
+ end
487
+ end
488
+
489
+ context 'failed after being connected' do
490
+ let(:response) { 'Failure' }
491
+ let(:uniqueid) { '1235' }
492
+
493
+ it 'should not send an end event' do
494
+ translator.expects(:handle_pb_event).once.with is_a(Punchblock::Event::Asterisk::AMI::Event)
495
+ subject.process_ami_event ami_event
496
+ end
497
+ end
498
+
499
+ context 'failed without ever having connected' do
500
+ let(:response) { 'Failure' }
501
+ let(:uniqueid) { '<null>' }
502
+
503
+ it 'should send an error end event' do
504
+ expected_end_event = Punchblock::Event::End.new :reason => :error,
505
+ :target_call_id => subject.id
506
+ translator.expects(:handle_pb_event).with expected_end_event
507
+ subject.process_ami_event ami_event
508
+ end
509
+ end
510
+ end
511
+
453
512
  context 'with a handler registered for a matching event' do
454
513
  let :ami_event do
455
514
  RubyAMI::Event.new('DTMF').tap do |e|
@@ -551,12 +610,12 @@ module Punchblock
551
610
  end
552
611
 
553
612
  it 'sends the Joined event when the call is the first channel' do
554
- translator.expects(:handle_pb_event!).with expected_joined
613
+ translator.expects(:handle_pb_event).with expected_joined
555
614
  subject.process_ami_event ami_event
556
615
  end
557
616
 
558
617
  it 'sends the Joined event when the call is the second channel' do
559
- translator.expects(:handle_pb_event!).with expected_joined
618
+ translator.expects(:handle_pb_event).with expected_joined
560
619
  subject.process_ami_event switched_ami_event
561
620
  end
562
621
  end
@@ -572,12 +631,12 @@ module Punchblock
572
631
  end
573
632
 
574
633
  it 'sends the Unjoined event when the call is the first channel' do
575
- translator.expects(:handle_pb_event!).with expected_unjoined
634
+ translator.expects(:handle_pb_event).with expected_unjoined
576
635
  subject.process_ami_event ami_event
577
636
  end
578
637
 
579
638
  it 'sends the Unjoined event when the call is the second channel' do
580
- translator.expects(:handle_pb_event!).with expected_unjoined
639
+ translator.expects(:handle_pb_event).with expected_unjoined
581
640
  subject.process_ami_event switched_ami_event
582
641
  end
583
642
  end
@@ -628,15 +687,43 @@ module Punchblock
628
687
  end
629
688
 
630
689
  it 'sends the Unjoined event when the call is the first channel' do
631
- translator.expects(:handle_pb_event!).with expected_unjoined
690
+ translator.expects(:handle_pb_event).with expected_unjoined
632
691
  subject.process_ami_event ami_event
633
692
  end
634
693
 
635
694
  it 'sends the Unjoined event when the call is the second channel' do
636
- translator.expects(:handle_pb_event!).with expected_unjoined
695
+ translator.expects(:handle_pb_event).with expected_unjoined
637
696
  subject.process_ami_event switched_ami_event
638
697
  end
639
698
  end
699
+
700
+ let :ami_event do
701
+ RubyAMI::Event.new('Foo').tap do |e|
702
+ e['Uniqueid'] = "1320842458.8"
703
+ e['Calleridnum'] = "5678"
704
+ e['Calleridname'] = "Jane Smith"
705
+ e['Cause'] = "0"
706
+ e['Cause-txt'] = "Unknown"
707
+ e['Channel'] = channel
708
+ end
709
+ end
710
+
711
+ let :expected_pb_event do
712
+ Event::Asterisk::AMI::Event.new :name => 'Foo',
713
+ :attributes => { :channel => channel,
714
+ :uniqueid => "1320842458.8",
715
+ :calleridnum => "5678",
716
+ :calleridname => "Jane Smith",
717
+ :cause => "0",
718
+ :'cause-txt' => "Unknown"},
719
+ :target_call_id => subject.id
720
+ end
721
+
722
+ it 'sends the AMI event to the connection as a PB event' do
723
+ translator.expects(:handle_pb_event).with expected_pb_event
724
+ subject.process_ami_event ami_event
725
+ end
726
+
640
727
  end
641
728
 
642
729
  describe '#execute_command' do
@@ -660,7 +747,6 @@ module Punchblock
660
747
  component.internal.should be_true
661
748
  agi_command = subject.wrapped_object.instance_variable_get(:'@current_agi_command')
662
749
  agi_command.name.should be == "EXEC RINGING"
663
- agi_command.execute!
664
750
  agi_command.add_event expected_agi_complete_event
665
751
  command.response(0.5).should be true
666
752
  end
@@ -675,7 +761,6 @@ module Punchblock
675
761
  component.internal.should be_true
676
762
  agi_command = subject.wrapped_object.instance_variable_get(:'@current_agi_command')
677
763
  agi_command.name.should be == "EXEC Busy"
678
- agi_command.execute!
679
764
  agi_command.add_event expected_agi_complete_event
680
765
  command.response(0.5).should be true
681
766
  end
@@ -686,7 +771,6 @@ module Punchblock
686
771
  component.internal.should be_true
687
772
  agi_command = subject.wrapped_object.instance_variable_get(:'@current_agi_command')
688
773
  agi_command.name.should be == "EXEC Busy"
689
- agi_command.execute!
690
774
  agi_command.add_event expected_agi_complete_event
691
775
  command.response(0.5).should be true
692
776
  end
@@ -697,7 +781,6 @@ module Punchblock
697
781
  component.internal.should be_true
698
782
  agi_command = subject.wrapped_object.instance_variable_get(:'@current_agi_command')
699
783
  agi_command.name.should be == "EXEC Congestion"
700
- agi_command.execute!
701
784
  agi_command.add_event expected_agi_complete_event
702
785
  command.response(0.5).should be true
703
786
  end
@@ -706,12 +789,11 @@ module Punchblock
706
789
  context 'with an answer command' do
707
790
  let(:command) { Command::Answer.new }
708
791
 
709
- it "should send an EXEC ANSWER AGI command and set the command's response" do
792
+ it "should send an ANSWER AGI command and set the command's response" do
710
793
  component = subject.execute_command command
711
794
  component.internal.should be_true
712
795
  agi_command = subject.wrapped_object.instance_variable_get(:'@current_agi_command')
713
- agi_command.name.should be == "EXEC ANSWER"
714
- agi_command.execute!
796
+ agi_command.name.should be == "ANSWER"
715
797
  agi_command.add_event expected_agi_complete_event
716
798
  command.response(0.5).should be true
717
799
  end
@@ -738,7 +820,7 @@ module Punchblock
738
820
 
739
821
  it 'should create an AGI command component actor and execute it asynchronously' do
740
822
  mock_action.expects(:internal=).never
741
- Component::Asterisk::AGICommand.expects(:new).once.with(command, subject).returns mock_action
823
+ Component::Asterisk::AGICommand.expects(:new_link).once.with(command, subject).returns mock_action
742
824
  mock_action.expects(:execute!).once
743
825
  subject.execute_command command
744
826
  end
@@ -752,7 +834,7 @@ module Punchblock
752
834
  let(:mock_action) { mock 'Component::Asterisk::Output', :id => 'foo' }
753
835
 
754
836
  it 'should create an Output component and execute it asynchronously' do
755
- Component::Output.expects(:new).once.with(command, subject).returns mock_action
837
+ Component::Output.expects(:new_link).once.with(command, subject).returns mock_action
756
838
  mock_action.expects(:internal=).never
757
839
  mock_action.expects(:execute!).once
758
840
  subject.execute_command command
@@ -767,7 +849,7 @@ module Punchblock
767
849
  let(:mock_action) { mock 'Component::Asterisk::Input', :id => 'foo' }
768
850
 
769
851
  it 'should create an Input component and execute it asynchronously' do
770
- Component::Input.expects(:new).once.with(command, subject).returns mock_action
852
+ Component::Input.expects(:new_link).once.with(command, subject).returns mock_action
771
853
  mock_action.expects(:internal=).never
772
854
  mock_action.expects(:execute!).once
773
855
  subject.execute_command command
@@ -782,7 +864,7 @@ module Punchblock
782
864
  let(:mock_action) { mock 'Component::Asterisk::Record', :id => 'foo' }
783
865
 
784
866
  it 'should create a Record component and execute it asynchronously' do
785
- Component::Record.expects(:new).once.with(command, subject).returns mock_action
867
+ Component::Record.expects(:new_link).once.with(command, subject).returns mock_action
786
868
  mock_action.expects(:internal=).never
787
869
  mock_action.expects(:execute!).once
788
870
  subject.execute_command command
@@ -804,15 +886,57 @@ module Punchblock
804
886
  before { subject.register_component mock_component }
805
887
 
806
888
  it 'should send the command to the component for execution' do
807
- mock_component.expects(:execute_command!).once
889
+ mock_component.expects(:execute_command).once
808
890
  subject.execute_command command
809
891
  end
810
892
  end
811
893
 
894
+ context "for a component which began executing but crashed" do
895
+ let :component_command do
896
+ Punchblock::Component::Asterisk::AGI::Command.new :name => 'Wait'
897
+ end
898
+
899
+ let(:comp_id) { component_command.response.id }
900
+
901
+ let(:subsequent_command) { Punchblock::Component::Stop.new :component_id => comp_id }
902
+
903
+ let :expected_event do
904
+ Punchblock::Event::Complete.new.tap do |e|
905
+ e.target_call_id = subject.id
906
+ e.component_id = comp_id
907
+ e.reason = Punchblock::Event::Complete::Error.new
908
+ end
909
+ end
910
+
911
+ before do
912
+ component_command.request!
913
+ subject.execute_command component_command
914
+ end
915
+
916
+ it 'sends an error in response to the command' do
917
+ component = subject.component_with_id comp_id
918
+
919
+ component.wrapped_object.define_singleton_method(:oops) do
920
+ raise 'Woops, I died'
921
+ end
922
+
923
+ translator.expects(:handle_pb_event).once.with expected_event
924
+
925
+ lambda { component.oops }.should raise_error(/Woops, I died/)
926
+ sleep 0.1
927
+ component.should_not be_alive
928
+ subject.component_with_id(comp_id).should be_nil
929
+
930
+ subsequent_command.request!
931
+ subject.execute_command subsequent_command
932
+ subsequent_command.response.should be == ProtocolError.new.setup(:item_not_found, "Could not find a component with ID #{comp_id} for call #{subject.id}", subject.id, comp_id)
933
+ end
934
+ end
935
+
812
936
  context "for an unknown component ID" do
813
937
  it 'sends an error in response to the command' do
814
938
  subject.execute_command command
815
- command.response.should be == ProtocolError.new.setup('component-not-found', "Could not find a component with ID #{component_id} for call #{subject.id}", subject.id, component_id)
939
+ command.response.should be == ProtocolError.new.setup(:item_not_found, "Could not find a component with ID #{component_id} for call #{subject.id}", subject.id, component_id)
816
940
  end
817
941
  end
818
942
  end
@@ -877,6 +1001,9 @@ module Punchblock
877
1001
  ami_action.headers['Exten'].should be == Punchblock::Translator::Asterisk::REDIRECT_EXTENSION
878
1002
  ami_action.headers['Priority'].should be == Punchblock::Translator::Asterisk::REDIRECT_PRIORITY
879
1003
  ami_action.headers['Context'].should be == Punchblock::Translator::Asterisk::REDIRECT_CONTEXT
1004
+
1005
+ ami_action << RubyAMI::Response.new
1006
+ command.response(1).should be_true
880
1007
  end
881
1008
 
882
1009
  it "executes the unjoin through redirection, on the subject call and the other call" do
@@ -894,6 +1021,22 @@ module Punchblock
894
1021
  ami_action.headers['ExtraPriority'].should be == Punchblock::Translator::Asterisk::REDIRECT_PRIORITY
895
1022
  ami_action.headers['ExtraContext'].should be == Punchblock::Translator::Asterisk::REDIRECT_CONTEXT
896
1023
  end
1024
+
1025
+ it "handles redirect errors" do
1026
+ translator.expects(:call_with_id).with(other_call_id).returns(nil)
1027
+ subject.execute_command command
1028
+ ami_action = subject.wrapped_object.instance_variable_get(:'@current_ami_action')
1029
+ ami_action.name.should be == "redirect"
1030
+ ami_action.headers['Channel'].should be == channel
1031
+ ami_action.headers['Exten'].should be == Punchblock::Translator::Asterisk::REDIRECT_EXTENSION
1032
+ ami_action.headers['Priority'].should be == Punchblock::Translator::Asterisk::REDIRECT_PRIORITY
1033
+ ami_action.headers['Context'].should be == Punchblock::Translator::Asterisk::REDIRECT_CONTEXT
1034
+
1035
+ ami_action << RubyAMI::Error.new.tap { |e| e.message = 'FooBar' }
1036
+ response = command.response(1)
1037
+ response.should be_a ProtocolError
1038
+ response.text.should == 'FooBar'
1039
+ end
897
1040
  end
898
1041
  end#execute_command
899
1042
 
@@ -906,12 +1049,12 @@ module Punchblock
906
1049
  end
907
1050
 
908
1051
  describe '#send_ami_action' do
909
- let(:component_id) { UUIDTools::UUID.random_create }
910
- before { UUIDTools::UUID.stubs :random_create => component_id }
1052
+ let(:component_id) { Punchblock.new_uuid }
1053
+ before { stub_uuids component_id }
911
1054
 
912
1055
  it 'should send the action to the AMI client' do
913
1056
  action = RubyAMI::Action.new 'foo', :foo => :bar
914
- translator.expects(:send_ami_action!).once.with action
1057
+ translator.expects(:send_ami_action).once.with action
915
1058
  subject.send_ami_action 'foo', :foo => :bar
916
1059
  end
917
1060
  end