punchblock 2.1.1 → 2.2.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.
- checksums.yaml +4 -4
- data/.travis.yml +2 -1
- data/CHANGELOG.md +7 -0
- data/lib/punchblock.rb +1 -1
- data/lib/punchblock/component.rb +2 -0
- data/lib/punchblock/component/input.rb +9 -1
- data/lib/punchblock/component/output.rb +1 -1
- data/lib/punchblock/component/receive_fax.rb +24 -0
- data/lib/punchblock/component/send_fax.rb +62 -0
- data/lib/punchblock/connection/asterisk.rb +1 -1
- data/lib/punchblock/event/complete.rb +15 -1
- data/lib/punchblock/translator/asterisk.rb +30 -15
- data/lib/punchblock/translator/asterisk/call.rb +13 -27
- data/lib/punchblock/translator/asterisk/component.rb +4 -7
- data/lib/punchblock/translator/asterisk/component/asterisk/agi_command.rb +1 -5
- data/lib/punchblock/translator/asterisk/component/composed_prompt.rb +8 -9
- data/lib/punchblock/translator/asterisk/component/input.rb +2 -3
- data/lib/punchblock/translator/asterisk/component/mrcp_prompt.rb +9 -9
- data/lib/punchblock/translator/asterisk/component/output.rb +134 -39
- data/lib/punchblock/translator/asterisk/component/record.rb +2 -3
- data/lib/punchblock/translator/asterisk/component/stop_by_redirect.rb +2 -3
- data/lib/punchblock/translator/dtmf_recognizer.rb +2 -4
- data/lib/punchblock/translator/freeswitch/component/abstract_output.rb +6 -1
- data/lib/punchblock/translator/freeswitch/component/flite_output.rb +1 -1
- data/lib/punchblock/translator/freeswitch/component/output.rb +12 -10
- data/lib/punchblock/translator/freeswitch/component/tts_output.rb +1 -1
- data/lib/punchblock/version.rb +1 -1
- data/spec/punchblock/component/input_spec.rb +91 -0
- data/spec/punchblock/component/output_spec.rb +1 -2
- data/spec/punchblock/component/receive_fax_spec.rb +111 -0
- data/spec/punchblock/component/send_fax_spec.rb +110 -0
- data/spec/punchblock/connection/asterisk_spec.rb +1 -1
- data/spec/punchblock/translator/asterisk/call_spec.rb +53 -79
- data/spec/punchblock/translator/asterisk/component/asterisk/agi_command_spec.rb +0 -3
- data/spec/punchblock/translator/asterisk/component/asterisk/ami_action_spec.rb +1 -1
- data/spec/punchblock/translator/asterisk/component/composed_prompt_spec.rb +2 -2
- data/spec/punchblock/translator/asterisk/component/input_spec.rb +6 -6
- data/spec/punchblock/translator/asterisk/component/mrcp_native_prompt_spec.rb +3 -3
- data/spec/punchblock/translator/asterisk/component/mrcp_prompt_spec.rb +9 -11
- data/spec/punchblock/translator/asterisk/component/output_spec.rb +902 -28
- data/spec/punchblock/translator/asterisk/component/stop_by_redirect_spec.rb +1 -1
- data/spec/punchblock/translator/asterisk/component_spec.rb +2 -9
- data/spec/punchblock/translator/asterisk_spec.rb +42 -94
- data/spec/punchblock/translator/freeswitch/component/flite_output_spec.rb +5 -5
- data/spec/punchblock/translator/freeswitch/component/output_spec.rb +7 -3
- data/spec/punchblock/translator/freeswitch/component/tts_output_spec.rb +17 -5
- metadata +67 -61
data/lib/punchblock/version.rb
CHANGED
|
@@ -166,6 +166,10 @@ module Punchblock
|
|
|
166
166
|
it { should be == grammar2 }
|
|
167
167
|
it { should_not be == grammar3 }
|
|
168
168
|
end
|
|
169
|
+
|
|
170
|
+
it "has children nested inside" do
|
|
171
|
+
subject.to_rayo.children.first.should be_a Nokogiri::XML::CDATA
|
|
172
|
+
end
|
|
169
173
|
end
|
|
170
174
|
|
|
171
175
|
describe 'with a grammar reference by URL' do
|
|
@@ -186,6 +190,14 @@ module Punchblock
|
|
|
186
190
|
end
|
|
187
191
|
end
|
|
188
192
|
end
|
|
193
|
+
|
|
194
|
+
describe "with a CPA grammar" do
|
|
195
|
+
subject { Input::Grammar.new url: "urn:xmpp:rayo:cpa:beep:1" }
|
|
196
|
+
|
|
197
|
+
it "has no children" do
|
|
198
|
+
subject.to_rayo.children.count.should == 0
|
|
199
|
+
end
|
|
200
|
+
end
|
|
189
201
|
end
|
|
190
202
|
|
|
191
203
|
describe "actions" do
|
|
@@ -378,6 +390,85 @@ module Punchblock
|
|
|
378
390
|
|
|
379
391
|
its(:name) { should be == :noinput }
|
|
380
392
|
end
|
|
393
|
+
|
|
394
|
+
describe Input::Signal do
|
|
395
|
+
let :stanza do
|
|
396
|
+
<<-MESSAGE
|
|
397
|
+
<signal xmlns="urn:xmpp:rayo:cpa:1" type="urn:xmpp:rayo:cpa:beep:1" duration="1000" value="8000"/>
|
|
398
|
+
MESSAGE
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
subject { RayoNode.from_xml(parse_stanza(stanza).root) }
|
|
402
|
+
|
|
403
|
+
it { should be_instance_of Input::Signal }
|
|
404
|
+
|
|
405
|
+
its(:name) { should be == :signal }
|
|
406
|
+
its(:type) { should be == 'urn:xmpp:rayo:cpa:beep:1' }
|
|
407
|
+
its(:duration) { should be == 1000 }
|
|
408
|
+
its(:value) { should be == '8000' }
|
|
409
|
+
|
|
410
|
+
describe "when creating from options" do
|
|
411
|
+
subject do
|
|
412
|
+
Input::Signal.new type: 'urn:xmpp:rayo:cpa:beep:1', duration: 1000, value: '8000'
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
its(:name) { should be == :signal }
|
|
416
|
+
its(:type) { should be == 'urn:xmpp:rayo:cpa:beep:1' }
|
|
417
|
+
its(:duration) { should be == 1000 }
|
|
418
|
+
its(:value) { should be == '8000' }
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
context "when in a complete event" do
|
|
422
|
+
let :stanza do
|
|
423
|
+
<<-MESSAGE
|
|
424
|
+
<complete xmlns='urn:xmpp:rayo:ext:1'>
|
|
425
|
+
<signal xmlns="urn:xmpp:rayo:cpa:1" type="urn:xmpp:rayo:cpa:beep:1" duration="1000" value="8000"/>
|
|
426
|
+
</complete>
|
|
427
|
+
MESSAGE
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
subject { RayoNode.from_xml(parse_stanza(stanza).root).reason }
|
|
431
|
+
|
|
432
|
+
it { should be_instance_of Input::Signal }
|
|
433
|
+
|
|
434
|
+
its(:name) { should be == :signal }
|
|
435
|
+
its(:type) { should be == 'urn:xmpp:rayo:cpa:beep:1' }
|
|
436
|
+
its(:duration) { should be == 1000 }
|
|
437
|
+
its(:value) { should be == '8000' }
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
describe "comparison" do
|
|
441
|
+
context "with the same options" do
|
|
442
|
+
it "should be equal" do
|
|
443
|
+
subject.should == RayoNode.from_xml(parse_stanza(stanza).root)
|
|
444
|
+
end
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
context "with different type" do
|
|
448
|
+
let(:other_stanza) { '<signal xmlns="urn:xmpp:rayo:cpa:1" type="urn:xmpp:rayo:cpa:ring:1" duration="1000" value="8000"/>' }
|
|
449
|
+
|
|
450
|
+
it "should not be equal" do
|
|
451
|
+
subject.should_not == RayoNode.from_xml(parse_stanza(other_stanza).root)
|
|
452
|
+
end
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
context "with different duration" do
|
|
456
|
+
let(:other_stanza) { '<signal xmlns="urn:xmpp:rayo:cpa:1" type="urn:xmpp:rayo:cpa:beep:1" duration="100" value="8000"/>' }
|
|
457
|
+
|
|
458
|
+
it "should not be equal" do
|
|
459
|
+
subject.should_not == RayoNode.from_xml(parse_stanza(other_stanza).root)
|
|
460
|
+
end
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
context "with different value" do
|
|
464
|
+
let(:other_stanza) { '<signal xmlns="urn:xmpp:rayo:cpa:1" type="urn:xmpp:rayo:cpa:beep:1" duration="1000" value="7000"/>' }
|
|
465
|
+
|
|
466
|
+
it "should not be equal" do
|
|
467
|
+
subject.should_not == RayoNode.from_xml(parse_stanza(other_stanza).root)
|
|
468
|
+
end
|
|
469
|
+
end
|
|
470
|
+
end
|
|
471
|
+
end
|
|
381
472
|
end
|
|
382
473
|
end
|
|
383
474
|
end # Punchblock
|
|
@@ -12,7 +12,7 @@ module Punchblock
|
|
|
12
12
|
describe 'default values' do
|
|
13
13
|
its(:interrupt_on) { should be nil }
|
|
14
14
|
its(:start_offset) { should be nil }
|
|
15
|
-
its(:start_paused) { should be
|
|
15
|
+
its(:start_paused) { should be nil }
|
|
16
16
|
its(:repeat_interval) { should be nil }
|
|
17
17
|
its(:repeat_times) { should be nil }
|
|
18
18
|
its(:max_time) { should be nil }
|
|
@@ -84,7 +84,6 @@ module Punchblock
|
|
|
84
84
|
|
|
85
85
|
describe "exporting to Rayo" do
|
|
86
86
|
it "should export to XML that can be understood by its parser" do
|
|
87
|
-
puts subject.to_rayo.to_xml
|
|
88
87
|
new_instance = RayoNode.from_xml Nokogiri::XML(subject.to_rayo.to_xml, nil, nil, Nokogiri::XML::ParseOptions::NOBLANKS).root
|
|
89
88
|
new_instance.render_documents.should be == [Output::Document.new(content_type: 'text/uri-list', value: ['http://example.com/hello.mp3'])]
|
|
90
89
|
end
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
module Punchblock
|
|
6
|
+
module Component
|
|
7
|
+
describe ReceiveFax do
|
|
8
|
+
it 'registers itself' do
|
|
9
|
+
RayoNode.class_from_registration(:receivefax, 'urn:xmpp:rayo:fax:1').should be == described_class
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
describe "exporting to Rayo" do
|
|
13
|
+
it "should export to XML that can be understood by its parser" do
|
|
14
|
+
new_instance = RayoNode.from_xml subject.to_rayo
|
|
15
|
+
new_instance.should be_instance_of described_class
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "should render to a parent node if supplied" do
|
|
19
|
+
doc = Nokogiri::XML::Document.new
|
|
20
|
+
parent = Nokogiri::XML::Node.new 'foo', doc
|
|
21
|
+
doc.root = parent
|
|
22
|
+
rayo_doc = subject.to_rayo(parent)
|
|
23
|
+
rayo_doc.should == parent
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
describe "from a stanza" do
|
|
28
|
+
let :stanza do
|
|
29
|
+
<<-MESSAGE
|
|
30
|
+
<receivefax xmlns="urn:xmpp:rayo:fax:1"/>
|
|
31
|
+
MESSAGE
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
subject { RayoNode.from_xml parse_stanza(stanza).root, '9f00061', '1' }
|
|
35
|
+
|
|
36
|
+
it { should be_instance_of described_class }
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
describe "actions" do
|
|
40
|
+
let(:mock_client) { double 'Client' }
|
|
41
|
+
let(:command) { described_class.new }
|
|
42
|
+
|
|
43
|
+
before do
|
|
44
|
+
command.component_id = 'abc123'
|
|
45
|
+
command.target_call_id = '123abc'
|
|
46
|
+
command.client = mock_client
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
describe '#stop_action' do
|
|
50
|
+
subject { command.stop_action }
|
|
51
|
+
|
|
52
|
+
its(:to_xml) { should be == '<stop xmlns="urn:xmpp:rayo:ext:1"/>' }
|
|
53
|
+
its(:component_id) { should be == 'abc123' }
|
|
54
|
+
its(:target_call_id) { should be == '123abc' }
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
describe '#stop!' do
|
|
58
|
+
describe "when the command is executing" do
|
|
59
|
+
before do
|
|
60
|
+
command.request!
|
|
61
|
+
command.execute!
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it "should send its command properly" do
|
|
65
|
+
mock_client.should_receive(:execute_command).with(command.stop_action, :target_call_id => '123abc', :component_id => 'abc123')
|
|
66
|
+
command.stop!
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
describe "when the command is not executing" do
|
|
71
|
+
it "should raise an error" do
|
|
72
|
+
lambda { command.stop! }.should raise_error(InvalidActionError, "Cannot stop a ReceiveFax that is new")
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
describe ReceiveFax::Complete::Finish do
|
|
79
|
+
let :stanza do
|
|
80
|
+
<<-MESSAGE
|
|
81
|
+
<complete xmlns='urn:xmpp:rayo:ext:1'>
|
|
82
|
+
<finish xmlns='urn:xmpp:rayo:fax:complete:1'/>
|
|
83
|
+
<fax xmlns='urn:xmpp:rayo:fax:complete:1' url='http://shakespere.lit/faxes/fax1.tiff' resolution='595x841' size='12287492817' pages='3'/>
|
|
84
|
+
<metadata xmlns='urn:xmpp:rayo:fax:complete:1' name="fax-transfer-rate" value="10000" />
|
|
85
|
+
<metadata xmlns='urn:xmpp:rayo:fax:complete:1' name="foo" value="true" />
|
|
86
|
+
</complete>
|
|
87
|
+
MESSAGE
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
subject(:complete_node) { RayoNode.from_xml(parse_stanza(stanza).root) }
|
|
91
|
+
|
|
92
|
+
it "should understand a finish reason" do
|
|
93
|
+
subject.reason.should be_instance_of ReceiveFax::Complete::Finish
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
describe "should make the fax data available" do
|
|
97
|
+
subject { complete_node.fax }
|
|
98
|
+
|
|
99
|
+
it { should be_instance_of ReceiveFax::Fax }
|
|
100
|
+
|
|
101
|
+
its(:url) { should be == 'http://shakespere.lit/faxes/fax1.tiff' }
|
|
102
|
+
its(:resolution) { should be == '595x841' }
|
|
103
|
+
its(:pages) { should be == 3 }
|
|
104
|
+
its(:size) { should be == 12287492817 }
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
its(:fax_metadata) { should == {'fax-transfer-rate' => '10000', 'foo' => 'true'} }
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
module Punchblock
|
|
6
|
+
module Component
|
|
7
|
+
describe SendFax do
|
|
8
|
+
it 'registers itself' do
|
|
9
|
+
RayoNode.class_from_registration(:sendfax, 'urn:xmpp:rayo:fax:1').should be == described_class
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
subject do
|
|
13
|
+
SendFax.new render_documents: [SendFax::FaxDocument.new(url: 'http://example.com/faxes/document.tiff', pages: [1..4,5,7..9])]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
its(:render_documents) { should be == [SendFax::FaxDocument.new(url: 'http://example.com/faxes/document.tiff', pages: [1..4,5,7..9])] }
|
|
17
|
+
|
|
18
|
+
describe "exporting to Rayo" do
|
|
19
|
+
it "should export to XML that can be understood by its parser" do
|
|
20
|
+
new_instance = RayoNode.from_xml Nokogiri::XML(subject.to_rayo.to_xml, nil, nil, Nokogiri::XML::ParseOptions::NOBLANKS).root
|
|
21
|
+
new_instance.render_documents.should be == [SendFax::FaxDocument.new(url: 'http://example.com/faxes/document.tiff', pages: [1..4,5,7..9])]
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
context "without optional attributes" do
|
|
26
|
+
subject do
|
|
27
|
+
SendFax.new render_documents: [SendFax::FaxDocument.new(url: 'http://example.com/faxes/document.tiff')]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
describe "exporting to Rayo" do
|
|
31
|
+
it "should export to XML that can be understood by its parser" do
|
|
32
|
+
new_instance = RayoNode.from_xml Nokogiri::XML(subject.to_rayo.to_xml, nil, nil, Nokogiri::XML::ParseOptions::NOBLANKS).root
|
|
33
|
+
new_instance.render_documents.should be == [SendFax::FaxDocument.new(url: 'http://example.com/faxes/document.tiff')]
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
context "from a rayo stanza" do
|
|
39
|
+
|
|
40
|
+
subject { RayoNode.from_xml parse_stanza(stanza).root, '9f00061', '1' }
|
|
41
|
+
|
|
42
|
+
let :stanza do
|
|
43
|
+
<<-MESSAGE
|
|
44
|
+
<sendfax xmlns='urn:xmpp:rayo:fax:1'>
|
|
45
|
+
<document xmlns='urn:xmpp:rayo:fax:1' url='http://shakespere.lit/my_fax.tiff' identity='+14045555555' header='Hello world' pages='1-4,5,7-9'/>
|
|
46
|
+
</sendfax>
|
|
47
|
+
MESSAGE
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
its(:render_documents) { should be == [SendFax::FaxDocument.new(url: 'http://shakespere.lit/my_fax.tiff', identity: '+14045555555', header: 'Hello world', pages: [1..4,5,7..9])] }
|
|
51
|
+
|
|
52
|
+
context "without optional attributes" do
|
|
53
|
+
let :stanza do
|
|
54
|
+
<<-MESSAGE
|
|
55
|
+
<sendfax xmlns='urn:xmpp:rayo:fax:1'>
|
|
56
|
+
<document xmlns='urn:xmpp:rayo:fax:1' url='http://shakespere.lit/my_fax.tiff'/>
|
|
57
|
+
</sendfax>
|
|
58
|
+
MESSAGE
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
its(:render_documents) { should be == [SendFax::FaxDocument.new(url: 'http://shakespere.lit/my_fax.tiff')] }
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
describe SendFax::FaxDocument do
|
|
67
|
+
it "registers itself" do
|
|
68
|
+
RayoNode.class_from_registration(:document, 'urn:xmpp:rayo:fax:1').should be == described_class
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
subject { SendFax::FaxDocument.new(url: 'http://shakespere.lit/my_fax.tiff', identity: '+14045555555', header: 'Hello world', pages: [1..4,5,7..9]) }
|
|
72
|
+
|
|
73
|
+
its(:url) { should == 'http://shakespere.lit/my_fax.tiff' }
|
|
74
|
+
its(:identity) { should == '+14045555555' }
|
|
75
|
+
its(:header) { should == 'Hello world' }
|
|
76
|
+
its(:pages) { should == [1..4,5,7..9] }
|
|
77
|
+
|
|
78
|
+
context "without optional attributes" do
|
|
79
|
+
subject { SendFax::FaxDocument.new(url: 'http://shakespere.lit/my_fax.tiff') }
|
|
80
|
+
|
|
81
|
+
its(:url) { should == 'http://shakespere.lit/my_fax.tiff' }
|
|
82
|
+
its(:identity) { should be_nil }
|
|
83
|
+
its(:header) { should be_nil }
|
|
84
|
+
its(:pages) { should be_nil }
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
describe "comparison" do
|
|
88
|
+
it "should be the same with the same attributes" do
|
|
89
|
+
should be == SendFax::FaxDocument.new(url: 'http://shakespere.lit/my_fax.tiff', identity: '+14045555555', header: 'Hello world', pages: [1..4,5,7..9])
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it "should be different with a different url" do
|
|
93
|
+
should_not be == SendFax::FaxDocument.new(url: 'http://shakespere.lit/my_other_fax.tiff', identity: '+14045555555', header: 'Hello world', pages: [1..4,5,7..9])
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it "should be different with a different identity" do
|
|
97
|
+
should_not be == SendFax::FaxDocument.new(url: 'http://shakespere.lit/my_fax.tiff', identity: '+14045555556', header: 'Hello world', pages: [1..4,5,7..9])
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
it "should be different with a different header" do
|
|
101
|
+
should_not be == SendFax::FaxDocument.new(url: 'http://shakespere.lit/my_fax.tiff', identity: '+14045555555', header: 'Hello Paul', pages: [1..4,5,7..9])
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
it "should be different with a different pages" do
|
|
105
|
+
should_not be == SendFax::FaxDocument.new(url: 'http://shakespere.lit/my_fax.tiff', identity: '+14045555555', header: 'Hello world', pages: [1..4,5,6..9])
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
@@ -69,14 +69,6 @@ module Punchblock
|
|
|
69
69
|
|
|
70
70
|
before { translator.stub :handle_pb_event }
|
|
71
71
|
|
|
72
|
-
describe '#shutdown' do
|
|
73
|
-
it 'should terminate the actor' do
|
|
74
|
-
subject.shutdown
|
|
75
|
-
sleep 0.5
|
|
76
|
-
subject.should_not be_alive
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
|
|
80
72
|
describe '#register_component' do
|
|
81
73
|
it 'should make the component accessible by ID' do
|
|
82
74
|
component_id = 'abc123'
|
|
@@ -123,15 +115,15 @@ module Punchblock
|
|
|
123
115
|
describe '#send_progress' do
|
|
124
116
|
context "with a call that is already answered" do
|
|
125
117
|
it 'should not send the EXEC Progress command' do
|
|
126
|
-
subject.
|
|
127
|
-
subject.
|
|
118
|
+
subject.should_receive(:'answered?').and_return true
|
|
119
|
+
subject.should_receive(:execute_agi_command).with("EXEC Progress").never
|
|
128
120
|
subject.send_progress
|
|
129
121
|
end
|
|
130
122
|
end
|
|
131
123
|
|
|
132
124
|
context "with an unanswered call" do
|
|
133
125
|
before do
|
|
134
|
-
subject.
|
|
126
|
+
subject.should_receive(:'answered?').at_least(:once).and_return(false)
|
|
135
127
|
end
|
|
136
128
|
|
|
137
129
|
context "with a call that is outbound" do
|
|
@@ -143,7 +135,7 @@ module Punchblock
|
|
|
143
135
|
end
|
|
144
136
|
|
|
145
137
|
it 'should not send the EXEC Progress command' do
|
|
146
|
-
subject.
|
|
138
|
+
subject.should_receive(:execute_agi_command).with("EXEC Progress").never
|
|
147
139
|
subject.send_progress
|
|
148
140
|
end
|
|
149
141
|
end
|
|
@@ -154,12 +146,12 @@ module Punchblock
|
|
|
154
146
|
end
|
|
155
147
|
|
|
156
148
|
it 'should send the EXEC Progress command to a call that is inbound and not answered' do
|
|
157
|
-
subject.
|
|
149
|
+
subject.should_receive(:execute_agi_command).with("EXEC Progress").and_return code: 200, result: 0
|
|
158
150
|
subject.send_progress
|
|
159
151
|
end
|
|
160
152
|
|
|
161
153
|
it 'should send the EXEC Progress command only once if called twice' do
|
|
162
|
-
subject.
|
|
154
|
+
subject.should_receive(:execute_agi_command).with("EXEC Progress").once.and_return code: 200, result: 0
|
|
163
155
|
subject.send_progress
|
|
164
156
|
subject.send_progress
|
|
165
157
|
end
|
|
@@ -276,7 +268,7 @@ module Punchblock
|
|
|
276
268
|
subject.dial dial_command
|
|
277
269
|
accept_command = Command::Accept.new
|
|
278
270
|
accept_command.request!
|
|
279
|
-
subject.
|
|
271
|
+
subject.should_receive(:execute_agi_command).never
|
|
280
272
|
subject.execute_command accept_command
|
|
281
273
|
accept_command.response(0.5).should be true
|
|
282
274
|
end
|
|
@@ -297,13 +289,6 @@ module Punchblock
|
|
|
297
289
|
let(:cause) { '16' }
|
|
298
290
|
let(:cause_txt) { 'Normal Clearing' }
|
|
299
291
|
|
|
300
|
-
it "should cause the actor to be terminated" do
|
|
301
|
-
translator.should_receive(:handle_pb_event).twice
|
|
302
|
-
subject.process_ami_event ami_event
|
|
303
|
-
Celluloid::Actor.join(subject, 1)
|
|
304
|
-
subject.should_not be_alive
|
|
305
|
-
end
|
|
306
|
-
|
|
307
292
|
it "de-registers the call from the translator" do
|
|
308
293
|
translator.stub :handle_pb_event
|
|
309
294
|
translator.should_receive(:deregister_call).once.with(subject.id, subject.channel)
|
|
@@ -334,7 +319,7 @@ module Punchblock
|
|
|
334
319
|
component = subject.execute_command comp_command
|
|
335
320
|
comp_command.response(0.1).should be_a Ref
|
|
336
321
|
|
|
337
|
-
subject.
|
|
322
|
+
subject.process_ami_event ami_event
|
|
338
323
|
|
|
339
324
|
comp_command = Punchblock::Component::Input.new :grammar => {:value => '<grammar root="foo"><rule id="foo"/></grammar>'}, :mode => :dtmf
|
|
340
325
|
comp_command.request!
|
|
@@ -657,7 +642,7 @@ module Punchblock
|
|
|
657
642
|
before do
|
|
658
643
|
translator.register_call other_call
|
|
659
644
|
command.request!
|
|
660
|
-
subject.
|
|
645
|
+
subject.should_receive(:execute_agi_command).and_return code: 200
|
|
661
646
|
subject.execute_command command
|
|
662
647
|
end
|
|
663
648
|
|
|
@@ -860,6 +845,15 @@ module Punchblock
|
|
|
860
845
|
subject.process_ami_event ami_event
|
|
861
846
|
end
|
|
862
847
|
|
|
848
|
+
context "when the event doesn't pass the filter" do
|
|
849
|
+
before { Asterisk.event_filter = ->(event) { false } }
|
|
850
|
+
after { Asterisk.event_filter = nil }
|
|
851
|
+
|
|
852
|
+
it 'does not send the AMI event to the connection as a PB event' do
|
|
853
|
+
translator.should_receive(:handle_pb_event).never
|
|
854
|
+
subject.process_ami_event ami_event
|
|
855
|
+
end
|
|
856
|
+
end
|
|
863
857
|
end
|
|
864
858
|
|
|
865
859
|
describe '#execute_command' do
|
|
@@ -871,7 +865,7 @@ module Punchblock
|
|
|
871
865
|
let(:command) { Command::Accept.new }
|
|
872
866
|
|
|
873
867
|
it "should send an EXEC RINGING AGI command and set the command's response" do
|
|
874
|
-
subject.
|
|
868
|
+
subject.should_receive(:execute_agi_command).with('EXEC RINGING').and_return code: 200
|
|
875
869
|
subject.execute_command command
|
|
876
870
|
command.response(0.5).should be true
|
|
877
871
|
end
|
|
@@ -880,7 +874,7 @@ module Punchblock
|
|
|
880
874
|
let(:message) { 'Some error' }
|
|
881
875
|
let(:error) { RubyAMI::Error.new.tap { |e| e.message = message } }
|
|
882
876
|
|
|
883
|
-
before { subject.
|
|
877
|
+
before { subject.should_receive(:execute_agi_command).and_raise error }
|
|
884
878
|
|
|
885
879
|
it "should return an error with the message" do
|
|
886
880
|
subject.execute_command command
|
|
@@ -903,7 +897,7 @@ module Punchblock
|
|
|
903
897
|
|
|
904
898
|
it "with a :busy reason should send an EXEC Busy AGI command and set the command's response" do
|
|
905
899
|
command.reason = :busy
|
|
906
|
-
subject.
|
|
900
|
+
subject.should_receive(:execute_agi_command).with('EXEC Busy').and_return code: 200
|
|
907
901
|
subject.execute_command command
|
|
908
902
|
command.response(0.5).should be true
|
|
909
903
|
end
|
|
@@ -917,7 +911,7 @@ module Punchblock
|
|
|
917
911
|
|
|
918
912
|
it "with an :error reason should send an EXEC Congestion AGI command and set the command's response" do
|
|
919
913
|
command.reason = :error
|
|
920
|
-
subject.
|
|
914
|
+
subject.should_receive(:execute_agi_command).with('EXEC Congestion').and_return code: 200
|
|
921
915
|
subject.execute_command command
|
|
922
916
|
command.response(0.5).should be true
|
|
923
917
|
end
|
|
@@ -926,7 +920,7 @@ module Punchblock
|
|
|
926
920
|
let(:message) { 'Some error' }
|
|
927
921
|
let(:error) { RubyAMI::Error.new.tap { |e| e.message = message } }
|
|
928
922
|
|
|
929
|
-
before { subject.
|
|
923
|
+
before { subject.should_receive(:execute_agi_command).and_raise error }
|
|
930
924
|
|
|
931
925
|
it "should return an error with the message" do
|
|
932
926
|
subject.execute_command command
|
|
@@ -948,13 +942,13 @@ module Punchblock
|
|
|
948
942
|
let(:command) { Command::Answer.new }
|
|
949
943
|
|
|
950
944
|
it "should send an ANSWER AGI command and set the command's response" do
|
|
951
|
-
subject.
|
|
945
|
+
subject.should_receive(:execute_agi_command).with('ANSWER').and_return code: 200
|
|
952
946
|
subject.execute_command command
|
|
953
947
|
command.response(0.5).should be true
|
|
954
948
|
end
|
|
955
949
|
|
|
956
950
|
it "should be answered" do
|
|
957
|
-
subject.
|
|
951
|
+
subject.should_receive(:execute_agi_command)
|
|
958
952
|
subject.execute_command command
|
|
959
953
|
subject.should be_answered
|
|
960
954
|
end
|
|
@@ -963,7 +957,7 @@ module Punchblock
|
|
|
963
957
|
let(:message) { 'Some error' }
|
|
964
958
|
let(:error) { RubyAMI::Error.new.tap { |e| e.message = message } }
|
|
965
959
|
|
|
966
|
-
before { subject.
|
|
960
|
+
before { subject.should_receive(:execute_agi_command).and_raise error }
|
|
967
961
|
|
|
968
962
|
it "should return an error with the message" do
|
|
969
963
|
subject.execute_command command
|
|
@@ -1042,7 +1036,7 @@ module Punchblock
|
|
|
1042
1036
|
before { translator.should_receive(:call_with_id).with(other_call_id).and_return(other_call) }
|
|
1043
1037
|
|
|
1044
1038
|
it "executes the proper dialplan Bridge application" do
|
|
1045
|
-
subject.
|
|
1039
|
+
subject.should_receive(:execute_agi_command).with('EXEC Bridge', "#{other_channel},F(#{REDIRECT_CONTEXT},#{REDIRECT_EXTENSION},#{REDIRECT_PRIORITY})").and_return code: 200
|
|
1046
1040
|
subject.execute_command command
|
|
1047
1041
|
end
|
|
1048
1042
|
|
|
@@ -1050,7 +1044,7 @@ module Punchblock
|
|
|
1050
1044
|
let(:message) { 'Some error' }
|
|
1051
1045
|
let(:error) { RubyAMI::Error.new.tap { |e| e.message = message } }
|
|
1052
1046
|
|
|
1053
|
-
before { subject.
|
|
1047
|
+
before { subject.should_receive(:execute_agi_command).and_raise error }
|
|
1054
1048
|
|
|
1055
1049
|
it "should return an error with the message" do
|
|
1056
1050
|
subject.execute_command command
|
|
@@ -1156,11 +1150,10 @@ module Punchblock
|
|
|
1156
1150
|
Punchblock::Component::Asterisk::AGI::Command.new :name => 'Answer'
|
|
1157
1151
|
end
|
|
1158
1152
|
|
|
1159
|
-
let(:mock_action) { Translator::Asterisk::Component::Asterisk::AGICommand.new(command, subject) }
|
|
1160
|
-
|
|
1161
1153
|
it 'should create an AGI command component actor and execute it asynchronously' do
|
|
1162
|
-
Component::Asterisk::AGICommand.
|
|
1163
|
-
|
|
1154
|
+
mock_action = Translator::Asterisk::Component::Asterisk::AGICommand.new(command, subject)
|
|
1155
|
+
Component::Asterisk::AGICommand.should_receive(:new).once.with(command, subject).and_return mock_action
|
|
1156
|
+
mock_action.should_receive(:execute).once
|
|
1164
1157
|
subject.execute_command command
|
|
1165
1158
|
end
|
|
1166
1159
|
end
|
|
@@ -1170,11 +1163,10 @@ module Punchblock
|
|
|
1170
1163
|
Punchblock::Component::Output.new
|
|
1171
1164
|
end
|
|
1172
1165
|
|
|
1173
|
-
let(:mock_action) { Translator::Asterisk::Component::Output.new(command, subject) }
|
|
1174
|
-
|
|
1175
1166
|
it 'should create an Output component and execute it asynchronously' do
|
|
1176
|
-
Component::Output.
|
|
1177
|
-
|
|
1167
|
+
mock_action = Translator::Asterisk::Component::Output.new(command, subject)
|
|
1168
|
+
Component::Output.should_receive(:new).once.with(command, subject).and_return mock_action
|
|
1169
|
+
mock_action.should_receive(:execute).once
|
|
1178
1170
|
subject.execute_command command
|
|
1179
1171
|
end
|
|
1180
1172
|
end
|
|
@@ -1184,11 +1176,10 @@ module Punchblock
|
|
|
1184
1176
|
Punchblock::Component::Input.new
|
|
1185
1177
|
end
|
|
1186
1178
|
|
|
1187
|
-
let(:mock_action) { Translator::Asterisk::Component::Input.new(command, subject) }
|
|
1188
|
-
|
|
1189
1179
|
it 'should create an Input component and execute it asynchronously' do
|
|
1190
|
-
Component::Input.
|
|
1191
|
-
|
|
1180
|
+
mock_action = Translator::Asterisk::Component::Input.new(command, subject)
|
|
1181
|
+
Component::Input.should_receive(:new).once.with(command, subject).and_return mock_action
|
|
1182
|
+
mock_action.should_receive(:execute).once
|
|
1192
1183
|
subject.execute_command command
|
|
1193
1184
|
end
|
|
1194
1185
|
end
|
|
@@ -1224,13 +1215,15 @@ module Punchblock
|
|
|
1224
1215
|
|
|
1225
1216
|
let(:mock_action) { Translator::Asterisk::Component::MRCPPrompt.new(command, subject) }
|
|
1226
1217
|
|
|
1218
|
+
before { mock_action}
|
|
1219
|
+
|
|
1227
1220
|
context "when the recognizer is unimrcp and the renderer is unimrcp" do
|
|
1228
1221
|
let(:recognizer) { :unimrcp }
|
|
1229
1222
|
let(:renderer) { :unimrcp }
|
|
1230
1223
|
|
|
1231
1224
|
it 'should create an MRCPPrompt component and execute it asynchronously' do
|
|
1232
|
-
Component::MRCPPrompt.should_receive(:
|
|
1233
|
-
mock_action.
|
|
1225
|
+
Component::MRCPPrompt.should_receive(:new).once.with(command, subject).and_return mock_action
|
|
1226
|
+
mock_action.should_receive(:execute).once
|
|
1234
1227
|
subject.execute_command command
|
|
1235
1228
|
end
|
|
1236
1229
|
end
|
|
@@ -1240,8 +1233,8 @@ module Punchblock
|
|
|
1240
1233
|
let(:renderer) { :asterisk }
|
|
1241
1234
|
|
|
1242
1235
|
it 'should create an MRCPPrompt component and execute it asynchronously' do
|
|
1243
|
-
Component::MRCPNativePrompt.should_receive(:
|
|
1244
|
-
mock_action.
|
|
1236
|
+
Component::MRCPNativePrompt.should_receive(:new).once.with(command, subject).and_return mock_action
|
|
1237
|
+
mock_action.should_receive(:execute).once
|
|
1245
1238
|
subject.execute_command command
|
|
1246
1239
|
end
|
|
1247
1240
|
end
|
|
@@ -1261,8 +1254,8 @@ module Punchblock
|
|
|
1261
1254
|
let(:renderer) { :unimrcp }
|
|
1262
1255
|
|
|
1263
1256
|
it 'should create a ComposedPrompt component and execute it asynchronously' do
|
|
1264
|
-
Component::ComposedPrompt.should_receive(:
|
|
1265
|
-
mock_action.
|
|
1257
|
+
Component::ComposedPrompt.should_receive(:new).once.with(command, subject).and_return mock_action
|
|
1258
|
+
mock_action.should_receive(:execute).once
|
|
1266
1259
|
subject.execute_command command
|
|
1267
1260
|
end
|
|
1268
1261
|
end
|
|
@@ -1273,11 +1266,10 @@ module Punchblock
|
|
|
1273
1266
|
Punchblock::Component::Record.new
|
|
1274
1267
|
end
|
|
1275
1268
|
|
|
1276
|
-
let(:mock_action) { Translator::Asterisk::Component::Record.new(command, subject) }
|
|
1277
|
-
|
|
1278
1269
|
it 'should create a Record component and execute it asynchronously' do
|
|
1279
|
-
Component::Record.
|
|
1280
|
-
|
|
1270
|
+
mock_action = Translator::Asterisk::Component::Record.new(command, subject)
|
|
1271
|
+
Component::Record.should_receive(:new).once.with(command, subject).and_return mock_action
|
|
1272
|
+
mock_action.should_receive(:execute).once
|
|
1281
1273
|
subject.execute_command command
|
|
1282
1274
|
end
|
|
1283
1275
|
end
|
|
@@ -1327,9 +1319,8 @@ module Punchblock
|
|
|
1327
1319
|
it 'sends an error in response to the command' do
|
|
1328
1320
|
component = subject.component_with_id comp_id
|
|
1329
1321
|
|
|
1330
|
-
component.
|
|
1331
|
-
|
|
1332
|
-
component.should_not be_alive
|
|
1322
|
+
component.send_complete_event Punchblock::Component::Asterisk::AGI::Command::Complete.new
|
|
1323
|
+
|
|
1333
1324
|
subject.component_with_id(comp_id).should be_nil
|
|
1334
1325
|
|
|
1335
1326
|
subsequent_command.request!
|
|
@@ -1339,25 +1330,6 @@ module Punchblock
|
|
|
1339
1330
|
end
|
|
1340
1331
|
|
|
1341
1332
|
context "by crashing" do
|
|
1342
|
-
it 'sends an error in response to the command' do
|
|
1343
|
-
component = subject.component_with_id comp_id
|
|
1344
|
-
|
|
1345
|
-
component.wrapped_object.define_singleton_method(:oops) do
|
|
1346
|
-
raise 'Woops, I died'
|
|
1347
|
-
end
|
|
1348
|
-
|
|
1349
|
-
translator.should_receive(:handle_pb_event).once.with expected_event
|
|
1350
|
-
|
|
1351
|
-
lambda { component.oops }.should raise_error(/Woops, I died/)
|
|
1352
|
-
sleep 0.1
|
|
1353
|
-
component.should_not be_alive
|
|
1354
|
-
subject.component_with_id(comp_id).should be_nil
|
|
1355
|
-
|
|
1356
|
-
subsequent_command.request!
|
|
1357
|
-
subject.execute_command subsequent_command
|
|
1358
|
-
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)
|
|
1359
|
-
end
|
|
1360
|
-
|
|
1361
1333
|
context "when we dispatch the command to it" do
|
|
1362
1334
|
it 'sends an error in response to the command' do
|
|
1363
1335
|
component = subject.component_with_id comp_id
|
|
@@ -1459,7 +1431,9 @@ module Punchblock
|
|
|
1459
1431
|
end
|
|
1460
1432
|
|
|
1461
1433
|
it 'should return the result' do
|
|
1462
|
-
fut = subject.
|
|
1434
|
+
fut = Celluloid::Future.new { subject.execute_agi_command 'EXEC ANSWER' }
|
|
1435
|
+
|
|
1436
|
+
sleep 0.25
|
|
1463
1437
|
|
|
1464
1438
|
subject.process_ami_event ami_event
|
|
1465
1439
|
|