punchblock 2.1.1 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
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