punchblock 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.travis.yml +3 -3
- data/CHANGELOG.md +23 -0
- data/lib/punchblock.rb +24 -0
- data/lib/punchblock/command/reject.rb +10 -2
- data/lib/punchblock/component/record.rb +16 -0
- data/lib/punchblock/core_ext/blather/stanza.rb +3 -1
- data/lib/punchblock/dead_actor_safety.rb +9 -0
- data/lib/punchblock/event/complete.rb +9 -11
- data/lib/punchblock/rayo_node.rb +4 -0
- data/lib/punchblock/translator/asterisk.rb +65 -22
- data/lib/punchblock/translator/asterisk/call.rb +49 -30
- data/lib/punchblock/translator/asterisk/component.rb +6 -8
- data/lib/punchblock/translator/asterisk/component/asterisk/agi_command.rb +13 -20
- data/lib/punchblock/translator/asterisk/component/asterisk/ami_action.rb +1 -1
- data/lib/punchblock/translator/asterisk/component/input.rb +3 -6
- data/lib/punchblock/translator/asterisk/component/output.rb +40 -45
- data/lib/punchblock/translator/asterisk/component/record.rb +1 -1
- data/lib/punchblock/translator/asterisk/component/stop_by_redirect.rb +5 -2
- data/lib/punchblock/version.rb +1 -1
- data/punchblock.gemspec +5 -5
- data/spec/punchblock/command/reject_spec.rb +7 -1
- data/spec/punchblock/command_node_spec.rb +5 -2
- data/spec/punchblock/component/component_node_spec.rb +4 -0
- data/spec/punchblock/component/output_spec.rb +1 -1
- data/spec/punchblock/component/record_spec.rb +30 -0
- data/spec/punchblock/event/complete_spec.rb +10 -0
- data/spec/punchblock/translator/asterisk/call_spec.rb +191 -48
- data/spec/punchblock/translator/asterisk/component/asterisk/agi_command_spec.rb +6 -39
- data/spec/punchblock/translator/asterisk/component/asterisk/ami_action_spec.rb +3 -3
- data/spec/punchblock/translator/asterisk/component/input_spec.rb +8 -3
- data/spec/punchblock/translator/asterisk/component/output_spec.rb +153 -46
- data/spec/punchblock/translator/asterisk/component/record_spec.rb +6 -5
- data/spec/punchblock/translator/asterisk/component/stop_by_redirect_spec.rb +1 -2
- data/spec/punchblock/translator/asterisk/component_spec.rb +1 -0
- data/spec/punchblock/translator/asterisk_spec.rb +147 -12
- data/spec/punchblock_spec.rb +34 -0
- data/spec/spec_helper.rb +5 -1
- metadata +30 -20
|
@@ -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
|
|
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 '#
|
|
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
|
|
106
|
+
it 'should not send the EXEC Progress command' do
|
|
108
107
|
subject.wrapped_object.expects(:'answered?').returns true
|
|
109
|
-
subject.wrapped_object.expects(:
|
|
110
|
-
subject.
|
|
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
|
|
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
|
|
128
|
-
subject.wrapped_object.expects(:
|
|
129
|
-
subject.
|
|
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
|
|
139
|
-
subject.wrapped_object.expects(:
|
|
140
|
-
subject.
|
|
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
|
|
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
|
|
249
|
-
translator.expects(:handle_pb_event
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 == "
|
|
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(:
|
|
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(:
|
|
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(:
|
|
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(:
|
|
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
|
|
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(
|
|
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) {
|
|
910
|
-
before {
|
|
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
|
|
1057
|
+
translator.expects(:send_ami_action).once.with action
|
|
915
1058
|
subject.send_ami_action 'foo', :foo => :bar
|
|
916
1059
|
end
|
|
917
1060
|
end
|