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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -1
  3. data/CHANGELOG.md +7 -0
  4. data/lib/punchblock.rb +1 -1
  5. data/lib/punchblock/component.rb +2 -0
  6. data/lib/punchblock/component/input.rb +9 -1
  7. data/lib/punchblock/component/output.rb +1 -1
  8. data/lib/punchblock/component/receive_fax.rb +24 -0
  9. data/lib/punchblock/component/send_fax.rb +62 -0
  10. data/lib/punchblock/connection/asterisk.rb +1 -1
  11. data/lib/punchblock/event/complete.rb +15 -1
  12. data/lib/punchblock/translator/asterisk.rb +30 -15
  13. data/lib/punchblock/translator/asterisk/call.rb +13 -27
  14. data/lib/punchblock/translator/asterisk/component.rb +4 -7
  15. data/lib/punchblock/translator/asterisk/component/asterisk/agi_command.rb +1 -5
  16. data/lib/punchblock/translator/asterisk/component/composed_prompt.rb +8 -9
  17. data/lib/punchblock/translator/asterisk/component/input.rb +2 -3
  18. data/lib/punchblock/translator/asterisk/component/mrcp_prompt.rb +9 -9
  19. data/lib/punchblock/translator/asterisk/component/output.rb +134 -39
  20. data/lib/punchblock/translator/asterisk/component/record.rb +2 -3
  21. data/lib/punchblock/translator/asterisk/component/stop_by_redirect.rb +2 -3
  22. data/lib/punchblock/translator/dtmf_recognizer.rb +2 -4
  23. data/lib/punchblock/translator/freeswitch/component/abstract_output.rb +6 -1
  24. data/lib/punchblock/translator/freeswitch/component/flite_output.rb +1 -1
  25. data/lib/punchblock/translator/freeswitch/component/output.rb +12 -10
  26. data/lib/punchblock/translator/freeswitch/component/tts_output.rb +1 -1
  27. data/lib/punchblock/version.rb +1 -1
  28. data/spec/punchblock/component/input_spec.rb +91 -0
  29. data/spec/punchblock/component/output_spec.rb +1 -2
  30. data/spec/punchblock/component/receive_fax_spec.rb +111 -0
  31. data/spec/punchblock/component/send_fax_spec.rb +110 -0
  32. data/spec/punchblock/connection/asterisk_spec.rb +1 -1
  33. data/spec/punchblock/translator/asterisk/call_spec.rb +53 -79
  34. data/spec/punchblock/translator/asterisk/component/asterisk/agi_command_spec.rb +0 -3
  35. data/spec/punchblock/translator/asterisk/component/asterisk/ami_action_spec.rb +1 -1
  36. data/spec/punchblock/translator/asterisk/component/composed_prompt_spec.rb +2 -2
  37. data/spec/punchblock/translator/asterisk/component/input_spec.rb +6 -6
  38. data/spec/punchblock/translator/asterisk/component/mrcp_native_prompt_spec.rb +3 -3
  39. data/spec/punchblock/translator/asterisk/component/mrcp_prompt_spec.rb +9 -11
  40. data/spec/punchblock/translator/asterisk/component/output_spec.rb +902 -28
  41. data/spec/punchblock/translator/asterisk/component/stop_by_redirect_spec.rb +1 -1
  42. data/spec/punchblock/translator/asterisk/component_spec.rb +2 -9
  43. data/spec/punchblock/translator/asterisk_spec.rb +42 -94
  44. data/spec/punchblock/translator/freeswitch/component/flite_output_spec.rb +5 -5
  45. data/spec/punchblock/translator/freeswitch/component/output_spec.rb +7 -3
  46. data/spec/punchblock/translator/freeswitch/component/tts_output_spec.rb +17 -5
  47. metadata +67 -61
@@ -20,7 +20,7 @@ module Punchblock
20
20
  end
21
21
 
22
22
  def document
23
- @component_node.render_documents.first.value.to_s
23
+ concatenated_render_doc.to_s
24
24
  end
25
25
  end
26
26
  end
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Punchblock
4
- VERSION = "2.1.1"
4
+ VERSION = "2.2.0"
5
5
  end
@@ -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 false }
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
@@ -60,7 +60,7 @@ module Punchblock
60
60
  end
61
61
 
62
62
  it 'shuts down the translator' do
63
- subject.translator.async.should_receive(:shutdown).once
63
+ subject.translator.should_receive(:terminate).once
64
64
  subject.stop
65
65
  end
66
66
  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.wrapped_object.should_receive(:'answered?').and_return true
127
- subject.wrapped_object.should_receive(:execute_agi_command).with("EXEC Progress").never
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.wrapped_object.should_receive(:'answered?').at_least(:once).and_return(false)
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.wrapped_object.should_receive(:execute_agi_command).with("EXEC Progress").never
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.wrapped_object.should_receive(:execute_agi_command).with("EXEC Progress").and_return code: 200, result: 0
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.wrapped_object.should_receive(:execute_agi_command).with("EXEC Progress").once.and_return code: 200, result: 0
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.wrapped_object.should_receive(:execute_agi_command).never
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.async.process_ami_event ami_event
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.wrapped_object.should_receive(:execute_agi_command).and_return code: 200
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.wrapped_object.should_receive(:execute_agi_command).with('EXEC RINGING').and_return code: 200
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.wrapped_object.should_receive(:execute_agi_command).and_raise error }
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.wrapped_object.should_receive(:execute_agi_command).with('EXEC Busy').and_return code: 200
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.wrapped_object.should_receive(:execute_agi_command).with('EXEC Congestion').and_return code: 200
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.wrapped_object.should_receive(:execute_agi_command).and_raise error }
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.wrapped_object.should_receive(:execute_agi_command).with('ANSWER').and_return code: 200
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.wrapped_object.should_receive(:execute_agi_command)
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.wrapped_object.should_receive(:execute_agi_command).and_raise error }
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.wrapped_object.should_receive(:execute_agi_command).with('EXEC Bridge', "#{other_channel},F(#{REDIRECT_CONTEXT},#{REDIRECT_EXTENSION},#{REDIRECT_PRIORITY})").and_return code: 200
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.wrapped_object.should_receive(:execute_agi_command).and_raise error }
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.should_receive(:new_link).once.with(command, subject).and_return mock_action
1163
- mock_action.async.should_receive(:execute).once
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.should_receive(:new_link).once.with(command, subject).and_return mock_action
1177
- mock_action.async.should_receive(:execute).once
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.should_receive(:new_link).once.with(command, subject).and_return mock_action
1191
- mock_action.async.should_receive(:execute).once
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(:new_link).once.with(command, subject).and_return mock_action
1233
- mock_action.async.should_receive(:execute).once
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(:new_link).once.with(command, subject).and_return mock_action
1244
- mock_action.async.should_receive(:execute).once
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(:new_link).once.with(command, subject).and_return mock_action
1265
- mock_action.async.should_receive(:execute).once
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.should_receive(:new_link).once.with(command, subject).and_return mock_action
1280
- mock_action.async.should_receive(:execute).once
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.terminate
1331
- sleep 0.1
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.future.execute_agi_command 'EXEC ANSWER'
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