punchblock 0.9.2 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/CHANGELOG.md +34 -21
- data/Rakefile +20 -0
- data/lib/punchblock/client/component_registry.rb +2 -0
- data/lib/punchblock/client.rb +2 -2
- data/lib/punchblock/command/accept.rb +2 -0
- data/lib/punchblock/command/answer.rb +2 -0
- data/lib/punchblock/command/dial.rb +2 -0
- data/lib/punchblock/command/hangup.rb +2 -0
- data/lib/punchblock/command/join.rb +2 -0
- data/lib/punchblock/command/mute.rb +2 -0
- data/lib/punchblock/command/redirect.rb +2 -0
- data/lib/punchblock/command/reject.rb +3 -1
- data/lib/punchblock/command/unjoin.rb +2 -0
- data/lib/punchblock/command/unmute.rb +2 -0
- data/lib/punchblock/command.rb +2 -0
- data/lib/punchblock/command_node.rb +2 -0
- data/lib/punchblock/component/asterisk/agi/command.rb +4 -2
- data/lib/punchblock/component/asterisk/agi.rb +2 -0
- data/lib/punchblock/component/asterisk/ami/action.rb +4 -2
- data/lib/punchblock/component/asterisk/ami.rb +2 -0
- data/lib/punchblock/component/asterisk.rb +2 -0
- data/lib/punchblock/component/component_node.rb +2 -0
- data/lib/punchblock/component/input.rb +2 -0
- data/lib/punchblock/component/output.rb +2 -0
- data/lib/punchblock/component/record.rb +2 -0
- data/lib/punchblock/component/stop.rb +2 -0
- data/lib/punchblock/component.rb +2 -0
- data/lib/punchblock/connection/asterisk.rb +4 -1
- data/lib/punchblock/connection/connected.rb +2 -0
- data/lib/punchblock/connection/generic_connection.rb +5 -0
- data/lib/punchblock/connection/xmpp.rb +5 -6
- data/lib/punchblock/connection.rb +2 -0
- data/lib/punchblock/core_ext/blather/stanza/presence.rb +2 -0
- data/lib/punchblock/core_ext/blather/stanza.rb +2 -0
- data/lib/punchblock/core_ext/ruby.rb +1 -12
- data/lib/punchblock/disconnected_error.rb +2 -0
- data/lib/punchblock/event/answered.rb +2 -0
- data/lib/punchblock/event/asterisk/ami/event.rb +3 -1
- data/lib/punchblock/event/asterisk/ami.rb +2 -0
- data/lib/punchblock/event/asterisk.rb +2 -0
- data/lib/punchblock/event/complete.rb +3 -1
- data/lib/punchblock/event/dtmf.rb +2 -0
- data/lib/punchblock/event/end.rb +2 -0
- data/lib/punchblock/event/joined.rb +2 -0
- data/lib/punchblock/event/offer.rb +6 -0
- data/lib/punchblock/event/ringing.rb +2 -0
- data/lib/punchblock/event/unjoined.rb +2 -0
- data/lib/punchblock/event.rb +2 -0
- data/lib/punchblock/has_headers.rb +3 -1
- data/lib/punchblock/header.rb +2 -0
- data/lib/punchblock/key_value_pair_node.rb +2 -0
- data/lib/punchblock/media_container.rb +2 -0
- data/lib/punchblock/media_node.rb +2 -0
- data/lib/punchblock/protocol_error.rb +2 -0
- data/lib/punchblock/rayo_node.rb +4 -3
- data/lib/punchblock/ref.rb +2 -0
- data/lib/punchblock/translator/asterisk/call.rb +80 -26
- data/lib/punchblock/translator/asterisk/component/asterisk/agi_command.rb +3 -1
- data/lib/punchblock/translator/asterisk/component/asterisk/ami_action.rb +3 -1
- data/lib/punchblock/translator/asterisk/component/asterisk.rb +2 -0
- data/lib/punchblock/translator/asterisk/component/input.rb +4 -2
- data/lib/punchblock/translator/asterisk/component/output.rb +21 -3
- data/lib/punchblock/translator/asterisk/component.rb +2 -0
- data/lib/punchblock/translator/asterisk.rb +50 -20
- data/lib/punchblock/translator.rb +2 -0
- data/lib/punchblock/version.rb +3 -1
- data/lib/punchblock.rb +2 -0
- data/punchblock.gemspec +2 -2
- data/spec/capture_warnings.rb +32 -0
- data/spec/punchblock/client/component_registry_spec.rb +2 -0
- data/spec/punchblock/client_spec.rb +3 -1
- data/spec/punchblock/command/accept_spec.rb +3 -1
- data/spec/punchblock/command/answer_spec.rb +3 -1
- data/spec/punchblock/command/dial_spec.rb +12 -10
- data/spec/punchblock/command/hangup_spec.rb +3 -1
- data/spec/punchblock/command/join_spec.rb +11 -9
- data/spec/punchblock/command/mute_spec.rb +3 -1
- data/spec/punchblock/command/redirect_spec.rb +5 -3
- data/spec/punchblock/command/reject_spec.rb +7 -5
- data/spec/punchblock/command/unjoin_spec.rb +7 -5
- data/spec/punchblock/command/unmute_spec.rb +3 -1
- data/spec/punchblock/command_node_spec.rb +9 -7
- data/spec/punchblock/component/asterisk/agi/command_spec.rb +21 -19
- data/spec/punchblock/component/asterisk/ami/action_spec.rb +19 -17
- data/spec/punchblock/component/component_node_spec.rb +5 -3
- data/spec/punchblock/component/input_spec.rb +51 -49
- data/spec/punchblock/component/output_spec.rb +60 -58
- data/spec/punchblock/component/record_spec.rb +36 -34
- data/spec/punchblock/connection/asterisk_spec.rb +9 -4
- data/spec/punchblock/connection/xmpp_spec.rb +40 -39
- data/spec/punchblock/event/answered_spec.rb +4 -2
- data/spec/punchblock/event/asterisk/ami/event_spec.rb +9 -7
- data/spec/punchblock/event/complete_spec.rb +12 -10
- data/spec/punchblock/event/dtmf_spec.rb +6 -4
- data/spec/punchblock/event/end_spec.rb +6 -4
- data/spec/punchblock/event/joined_spec.rb +8 -6
- data/spec/punchblock/event/offer_spec.rb +7 -5
- data/spec/punchblock/event/ringing_spec.rb +4 -2
- data/spec/punchblock/event/unjoined_spec.rb +8 -6
- data/spec/punchblock/header_spec.rb +13 -11
- data/spec/punchblock/protocol_error_spec.rb +8 -6
- data/spec/punchblock/ref_spec.rb +5 -3
- data/spec/punchblock/translator/asterisk/call_spec.rb +261 -14
- data/spec/punchblock/translator/asterisk/component/asterisk/agi_command_spec.rb +13 -11
- data/spec/punchblock/translator/asterisk/component/asterisk/ami_action_spec.rb +4 -2
- data/spec/punchblock/translator/asterisk/component/input_spec.rb +10 -8
- data/spec/punchblock/translator/asterisk/component/output_spec.rb +111 -20
- data/spec/punchblock/translator/asterisk/component_spec.rb +3 -1
- data/spec/punchblock/translator/asterisk_spec.rb +107 -10
- data/spec/spec_helper.rb +23 -17
- data/spec/support/mock_connection_with_event_handler.rb +2 -0
- metadata +43 -41
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
|
3
5
|
module Punchblock
|
@@ -40,6 +42,97 @@ module Punchblock
|
|
40
42
|
|
41
43
|
before { mock_call.stubs :answer_if_not_answered }
|
42
44
|
|
45
|
+
context 'with a media engine of :swift' do
|
46
|
+
let(:media_engine) { :swift }
|
47
|
+
|
48
|
+
let(:audio_filename) { 'http://foo.com/bar.mp3' }
|
49
|
+
|
50
|
+
let :ssml_doc do
|
51
|
+
RubySpeech::SSML.draw do
|
52
|
+
audio :src => audio_filename
|
53
|
+
say_as(:interpret_as => :cardinal) { 'FOO' }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
let(:command_opts) { {} }
|
58
|
+
|
59
|
+
let :command_options do
|
60
|
+
{ :ssml => ssml_doc }.merge(command_opts)
|
61
|
+
end
|
62
|
+
|
63
|
+
def ssml_with_options(prefix = '', postfix = '')
|
64
|
+
base_doc = ssml_doc.to_s.squish.gsub(/["\\]/) { |m| "\\#{m}" }
|
65
|
+
prefix + base_doc + postfix
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should execute Swift" do
|
69
|
+
mock_call.expects(:send_agi_action!).once.with 'EXEC Swift', ssml_with_options
|
70
|
+
subject.execute
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'should send a complete event when Swift completes' do
|
74
|
+
def mock_call.send_agi_action!(*args, &block)
|
75
|
+
block.call Punchblock::Component::Asterisk::AGI::Command::Complete::Success.new(:code => 200, :result => 1)
|
76
|
+
end
|
77
|
+
subject.execute
|
78
|
+
command.complete_event(0.1).reason.should be_a Punchblock::Component::Output::Complete::Success
|
79
|
+
end
|
80
|
+
|
81
|
+
describe 'interrupt_on' do
|
82
|
+
context "set to nil" do
|
83
|
+
let(:command_opts) { { :interrupt_on => nil } }
|
84
|
+
it "should not add interrupt arguments" do
|
85
|
+
mock_call.expects(:send_agi_action!).once.with 'EXEC Swift', ssml_with_options
|
86
|
+
subject.execute
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context "set to :any" do
|
91
|
+
let(:command_opts) { { :interrupt_on => :any } }
|
92
|
+
it "should add the interrupt options to the argument" do
|
93
|
+
mock_call.expects(:send_agi_action!).once.with 'EXEC Swift', ssml_with_options('', '|1|1')
|
94
|
+
subject.execute
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context "set to :dtmf" do
|
99
|
+
let(:command_opts) { { :interrupt_on => :dtmf } }
|
100
|
+
it "should add the interrupt options to the argument" do
|
101
|
+
mock_call.expects(:send_agi_action!).once.with 'EXEC Swift', ssml_with_options('', '|1|1')
|
102
|
+
subject.execute
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
context "set to :speech" do
|
107
|
+
let(:command_opts) { { :interrupt_on => :speech } }
|
108
|
+
it "should return an error and not execute any actions" do
|
109
|
+
subject.execute
|
110
|
+
error = ProtocolError.new 'option error', 'An interrupt-on value of speech is unsupported.'
|
111
|
+
command.response(0.1).should be == error
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe 'voice' do
|
117
|
+
context "set to nil" do
|
118
|
+
let(:command_opts) { { :voice => nil } }
|
119
|
+
it "should not add a voice at the beginning of the argument" do
|
120
|
+
mock_call.expects(:send_agi_action!).once.with 'EXEC Swift', ssml_with_options
|
121
|
+
subject.execute
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
context "set to Leonard" do
|
126
|
+
let(:command_opts) { { :voice => "Leonard" } }
|
127
|
+
it "should add a voice at the beginning of the argument" do
|
128
|
+
mock_call.expects(:send_agi_action!).once.with 'EXEC Swift', ssml_with_options('Leonard^', '')
|
129
|
+
subject.execute
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
43
136
|
context 'with a media engine of :unimrcp' do
|
44
137
|
let(:media_engine) { :unimrcp }
|
45
138
|
|
@@ -60,7 +153,7 @@ module Punchblock
|
|
60
153
|
|
61
154
|
def expect_mrcpsynth_with_options(options)
|
62
155
|
mock_call.expects(:send_agi_action!).once.with do |*args|
|
63
|
-
args[0].should == 'EXEC MRCPSynth'
|
156
|
+
args[0].should be == 'EXEC MRCPSynth'
|
64
157
|
args[2].should match options
|
65
158
|
end
|
66
159
|
end
|
@@ -84,7 +177,7 @@ module Punchblock
|
|
84
177
|
it "should return an error and not execute any actions" do
|
85
178
|
subject.execute
|
86
179
|
error = ProtocolError.new 'option error', 'An SSML document is required.'
|
87
|
-
command.response(0.1).should == error
|
180
|
+
command.response(0.1).should be == error
|
88
181
|
end
|
89
182
|
end
|
90
183
|
end
|
@@ -103,7 +196,7 @@ module Punchblock
|
|
103
196
|
it "should return an error and not execute any actions" do
|
104
197
|
subject.execute
|
105
198
|
error = ProtocolError.new 'option error', 'A start_offset value is unsupported on Asterisk.'
|
106
|
-
command.response(0.1).should == error
|
199
|
+
command.response(0.1).should be == error
|
107
200
|
end
|
108
201
|
end
|
109
202
|
end
|
@@ -122,7 +215,7 @@ module Punchblock
|
|
122
215
|
it "should return an error and not execute any actions" do
|
123
216
|
subject.execute
|
124
217
|
error = ProtocolError.new 'option error', 'A start_paused value is unsupported on Asterisk.'
|
125
|
-
command.response(0.1).should == error
|
218
|
+
command.response(0.1).should be == error
|
126
219
|
end
|
127
220
|
end
|
128
221
|
end
|
@@ -141,7 +234,7 @@ module Punchblock
|
|
141
234
|
it "should return an error and not execute any actions" do
|
142
235
|
subject.execute
|
143
236
|
error = ProtocolError.new 'option error', 'A repeat_interval value is unsupported on Asterisk.'
|
144
|
-
command.response(0.1).should == error
|
237
|
+
command.response(0.1).should be == error
|
145
238
|
end
|
146
239
|
end
|
147
240
|
end
|
@@ -160,7 +253,7 @@ module Punchblock
|
|
160
253
|
it "should return an error and not execute any actions" do
|
161
254
|
subject.execute
|
162
255
|
error = ProtocolError.new 'option error', 'A repeat_times value is unsupported on Asterisk.'
|
163
|
-
command.response(0.1).should == error
|
256
|
+
command.response(0.1).should be == error
|
164
257
|
end
|
165
258
|
end
|
166
259
|
end
|
@@ -179,7 +272,7 @@ module Punchblock
|
|
179
272
|
it "should return an error and not execute any actions" do
|
180
273
|
subject.execute
|
181
274
|
error = ProtocolError.new 'option error', 'A max_time value is unsupported on Asterisk.'
|
182
|
-
command.response(0.1).should == error
|
275
|
+
command.response(0.1).should be == error
|
183
276
|
end
|
184
277
|
end
|
185
278
|
end
|
@@ -232,7 +325,7 @@ module Punchblock
|
|
232
325
|
it "should return an error and not execute any actions" do
|
233
326
|
subject.execute
|
234
327
|
error = ProtocolError.new 'option error', 'An interrupt-on value of speech is unsupported.'
|
235
|
-
command.response(0.1).should == error
|
328
|
+
command.response(0.1).should be == error
|
236
329
|
end
|
237
330
|
end
|
238
331
|
end
|
@@ -243,7 +336,7 @@ module Punchblock
|
|
243
336
|
|
244
337
|
def expect_stream_file_with_options(options = nil)
|
245
338
|
mock_call.expects(:send_agi_action!).once.with 'STREAM FILE', audio_filename, options do |*args|
|
246
|
-
args[2].should == options
|
339
|
+
args[2].should be == options
|
247
340
|
subject.continue!
|
248
341
|
true
|
249
342
|
end
|
@@ -273,7 +366,7 @@ module Punchblock
|
|
273
366
|
it "should return an error and not execute any actions" do
|
274
367
|
subject.execute
|
275
368
|
error = ProtocolError.new 'option error', 'An SSML document is required.'
|
276
|
-
command.response(0.1).should == error
|
369
|
+
command.response(0.1).should be == error
|
277
370
|
end
|
278
371
|
end
|
279
372
|
|
@@ -315,12 +408,10 @@ module Punchblock
|
|
315
408
|
latch = CountDownLatch.new 2
|
316
409
|
mock_call.expects(:send_agi_action!).once.with 'STREAM FILE', audio_filename1, nil do
|
317
410
|
subject.continue
|
318
|
-
true
|
319
411
|
latch.countdown!
|
320
412
|
end
|
321
413
|
mock_call.expects(:send_agi_action!).once.with 'STREAM FILE', audio_filename2, nil do
|
322
414
|
subject.continue
|
323
|
-
true
|
324
415
|
latch.countdown!
|
325
416
|
end
|
326
417
|
subject.execute
|
@@ -351,7 +442,7 @@ module Punchblock
|
|
351
442
|
it "should return an unrenderable document error" do
|
352
443
|
subject.execute
|
353
444
|
error = ProtocolError.new 'unrenderable document error', 'The provided document could not be rendered.'
|
354
|
-
command.response(0.1).should == error
|
445
|
+
command.response(0.1).should be == error
|
355
446
|
end
|
356
447
|
end
|
357
448
|
end
|
@@ -370,7 +461,7 @@ module Punchblock
|
|
370
461
|
it "should return an error and not execute any actions" do
|
371
462
|
subject.execute
|
372
463
|
error = ProtocolError.new 'option error', 'A start_offset value is unsupported on Asterisk.'
|
373
|
-
command.response(0.1).should == error
|
464
|
+
command.response(0.1).should be == error
|
374
465
|
end
|
375
466
|
end
|
376
467
|
end
|
@@ -389,7 +480,7 @@ module Punchblock
|
|
389
480
|
it "should return an error and not execute any actions" do
|
390
481
|
subject.execute
|
391
482
|
error = ProtocolError.new 'option error', 'A start_paused value is unsupported on Asterisk.'
|
392
|
-
command.response(0.1).should == error
|
483
|
+
command.response(0.1).should be == error
|
393
484
|
end
|
394
485
|
end
|
395
486
|
end
|
@@ -408,7 +499,7 @@ module Punchblock
|
|
408
499
|
it "should return an error and not execute any actions" do
|
409
500
|
subject.execute
|
410
501
|
error = ProtocolError.new 'option error', 'A repeat_interval value is unsupported on Asterisk.'
|
411
|
-
command.response(0.1).should == error
|
502
|
+
command.response(0.1).should be == error
|
412
503
|
end
|
413
504
|
end
|
414
505
|
end
|
@@ -427,7 +518,7 @@ module Punchblock
|
|
427
518
|
it "should return an error and not execute any actions" do
|
428
519
|
subject.execute
|
429
520
|
error = ProtocolError.new 'option error', 'A repeat_times value is unsupported on Asterisk.'
|
430
|
-
command.response(0.1).should == error
|
521
|
+
command.response(0.1).should be == error
|
431
522
|
end
|
432
523
|
end
|
433
524
|
end
|
@@ -446,7 +537,7 @@ module Punchblock
|
|
446
537
|
it "should return an error and not execute any actions" do
|
447
538
|
subject.execute
|
448
539
|
error = ProtocolError.new 'option error', 'A max_time value is unsupported on Asterisk.'
|
449
|
-
command.response(0.1).should == error
|
540
|
+
command.response(0.1).should be == error
|
450
541
|
end
|
451
542
|
end
|
452
543
|
end
|
@@ -465,7 +556,7 @@ module Punchblock
|
|
465
556
|
it "should return an error and not execute any actions" do
|
466
557
|
subject.execute
|
467
558
|
error = ProtocolError.new 'option error', 'A voice value is unsupported on Asterisk.'
|
468
|
-
command.response(0.1).should == error
|
559
|
+
command.response(0.1).should be == error
|
469
560
|
end
|
470
561
|
end
|
471
562
|
end
|
@@ -500,7 +591,7 @@ module Punchblock
|
|
500
591
|
it "should return an error and not execute any actions" do
|
501
592
|
subject.execute
|
502
593
|
error = ProtocolError.new 'option error', 'An interrupt-on value of speech is unsupported.'
|
503
|
-
command.response(0.1).should == error
|
594
|
+
command.response(0.1).should be == error
|
504
595
|
end
|
505
596
|
end
|
506
597
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
|
3
5
|
module Punchblock
|
@@ -81,7 +83,7 @@ module Punchblock
|
|
81
83
|
|
82
84
|
it 'sends an error in response to the command' do
|
83
85
|
subject.execute_command component_command
|
84
|
-
component_command.response.should == ProtocolError.new('command-not-acceptable', "Did not understand command for component #{subject.id}", call.id, subject.id)
|
86
|
+
component_command.response.should be == ProtocolError.new('command-not-acceptable', "Did not understand command for component #{subject.id}", call.id, subject.id)
|
85
87
|
end
|
86
88
|
end
|
87
89
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
|
3
5
|
module Punchblock
|
@@ -18,12 +20,12 @@ module Punchblock
|
|
18
20
|
|
19
21
|
context 'with a configured media engine of :asterisk' do
|
20
22
|
let(:media_engine) { :asterisk }
|
21
|
-
its(:media_engine) { should == :asterisk }
|
23
|
+
its(:media_engine) { should be == :asterisk }
|
22
24
|
end
|
23
25
|
|
24
26
|
context 'with a configured media engine of :unimrcp' do
|
25
27
|
let(:media_engine) { :unimrcp }
|
26
|
-
its(:media_engine) { should == :unimrcp }
|
28
|
+
its(:media_engine) { should be == :unimrcp }
|
27
29
|
end
|
28
30
|
|
29
31
|
describe '#shutdown' do
|
@@ -48,7 +50,7 @@ module Punchblock
|
|
48
50
|
it 'executes the call command' do
|
49
51
|
subject.wrapped_object.expects(:execute_call_command).with do |c|
|
50
52
|
c.should be command
|
51
|
-
c.call_id.should == call_id
|
53
|
+
c.call_id.should be == call_id
|
52
54
|
end
|
53
55
|
subject.execute_command command, :call_id => call_id
|
54
56
|
end
|
@@ -61,7 +63,7 @@ module Punchblock
|
|
61
63
|
it 'executes the component command' do
|
62
64
|
subject.wrapped_object.expects(:execute_component_command).with do |c|
|
63
65
|
c.should be command
|
64
|
-
c.component_id.should == component_id
|
66
|
+
c.component_id.should be == component_id
|
65
67
|
end
|
66
68
|
subject.execute_command command, :component_id => component_id
|
67
69
|
end
|
@@ -130,7 +132,7 @@ module Punchblock
|
|
130
132
|
context "with an unknown call ID" do
|
131
133
|
it 'sends an error in response to the command' do
|
132
134
|
subject.execute_call_command command
|
133
|
-
command.response.should == ProtocolError.new('call-not-found', "Could not find a call with ID #{call_id}", call_id, nil)
|
135
|
+
command.response.should be == ProtocolError.new('call-not-found', "Could not find a call with ID #{call_id}", call_id, nil)
|
134
136
|
end
|
135
137
|
end
|
136
138
|
end
|
@@ -159,7 +161,7 @@ module Punchblock
|
|
159
161
|
context "with an unknown component ID" do
|
160
162
|
it 'sends an error in response to the command' do
|
161
163
|
subject.execute_component_command command
|
162
|
-
command.response.should == ProtocolError.new('component-not-found', "Could not find a component with ID #{component_id}", nil, component_id)
|
164
|
+
command.response.should be == ProtocolError.new('component-not-found', "Could not find a component with ID #{component_id}", nil, component_id)
|
163
165
|
end
|
164
166
|
end
|
165
167
|
end
|
@@ -216,7 +218,7 @@ module Punchblock
|
|
216
218
|
|
217
219
|
it 'sends an error in response to the command' do
|
218
220
|
subject.execute_command command
|
219
|
-
command.response.should == ProtocolError.new('command-not-acceptable', "Did not understand command")
|
221
|
+
command.response.should be == ProtocolError.new('command-not-acceptable', "Did not understand command")
|
220
222
|
end
|
221
223
|
end
|
222
224
|
end
|
@@ -272,6 +274,7 @@ module Punchblock
|
|
272
274
|
context 'twice' do
|
273
275
|
it 'sends a connected event to the event handler' do
|
274
276
|
subject.connection.expects(:handle_event).once.with Connection::Connected.new
|
277
|
+
subject.wrapped_object.expects(:run_at_fully_booted).once
|
275
278
|
subject.handle_ami_event ami_event
|
276
279
|
subject.handle_ami_event ami_event
|
277
280
|
end
|
@@ -294,7 +297,28 @@ module Punchblock
|
|
294
297
|
call_actor = subject.call_for_channel('SIP/1234-00000000')
|
295
298
|
call_actor.wrapped_object.should be_a Asterisk::Call
|
296
299
|
call_actor.agi_env.should be_a Hash
|
297
|
-
call_actor.agi_env
|
300
|
+
call_actor.agi_env.should be == {
|
301
|
+
:agi_request => 'async',
|
302
|
+
:agi_channel => 'SIP/1234-00000000',
|
303
|
+
:agi_language => 'en',
|
304
|
+
:agi_type => 'SIP',
|
305
|
+
:agi_uniqueid => '1320835995.0',
|
306
|
+
:agi_version => '1.8.4.1',
|
307
|
+
:agi_callerid => '5678',
|
308
|
+
:agi_calleridname => 'Jane Smith',
|
309
|
+
:agi_callingpres => '0',
|
310
|
+
:agi_callingani2 => '0',
|
311
|
+
:agi_callington => '0',
|
312
|
+
:agi_callingtns => '0',
|
313
|
+
:agi_dnid => '1000',
|
314
|
+
:agi_rdnis => 'unknown',
|
315
|
+
:agi_context => 'default',
|
316
|
+
:agi_extension => '1000',
|
317
|
+
:agi_priority => '1',
|
318
|
+
:agi_enhanced => '0.0',
|
319
|
+
:agi_accountcode => '',
|
320
|
+
:agi_threadid => '4366221312'
|
321
|
+
}
|
298
322
|
end
|
299
323
|
|
300
324
|
it 'should instruct the call to send an offer' do
|
@@ -316,6 +340,46 @@ module Punchblock
|
|
316
340
|
subject.handle_ami_event ami_event
|
317
341
|
end
|
318
342
|
end
|
343
|
+
|
344
|
+
context "for a 'h' extension" do
|
345
|
+
let :ami_event do
|
346
|
+
RubyAMI::Event.new('AsyncAGI').tap do |e|
|
347
|
+
e['SubEvent'] = "Start"
|
348
|
+
e['Channel'] = "SIP/1234-00000000"
|
349
|
+
e['Env'] = "agi_extension%3A%20h%0A%0A"
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
it "should not create a new call" do
|
354
|
+
Asterisk::Call.expects(:new).never
|
355
|
+
subject.handle_ami_event ami_event
|
356
|
+
end
|
357
|
+
|
358
|
+
it 'should not be able to look up the call by channel ID' do
|
359
|
+
subject.handle_ami_event ami_event
|
360
|
+
subject.call_for_channel('SIP/1234-00000000').should be nil
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
context "for a 'Kill' type" do
|
365
|
+
let :ami_event do
|
366
|
+
RubyAMI::Event.new('AsyncAGI').tap do |e|
|
367
|
+
e['SubEvent'] = "Start"
|
368
|
+
e['Channel'] = "SIP/1234-00000000"
|
369
|
+
e['Env'] = "agi_type%3A%20Kill%0A%0A"
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
it "should not create a new call" do
|
374
|
+
Asterisk::Call.expects(:new).never
|
375
|
+
subject.handle_ami_event ami_event
|
376
|
+
end
|
377
|
+
|
378
|
+
it 'should not be able to look up the call by channel ID' do
|
379
|
+
subject.handle_ami_event ami_event
|
380
|
+
subject.call_for_channel('SIP/1234-00000000').should be nil
|
381
|
+
end
|
382
|
+
end
|
319
383
|
end
|
320
384
|
|
321
385
|
describe 'with a VarSet event including a punchblock_call_id' do
|
@@ -348,7 +412,7 @@ module Punchblock
|
|
348
412
|
|
349
413
|
it "should set the correct channel on the call" do
|
350
414
|
subject.handle_ami_event ami_event
|
351
|
-
call.channel.should == 'SIP/1234-00000000'
|
415
|
+
call.channel.should be == 'SIP/1234-00000000'
|
352
416
|
end
|
353
417
|
|
354
418
|
it "should make it possible to look up the call by the full channel name" do
|
@@ -397,8 +461,34 @@ module Punchblock
|
|
397
461
|
call.expects(:process_ami_event!).once.with ami_event
|
398
462
|
subject.handle_ami_event ami_event
|
399
463
|
end
|
464
|
+
|
465
|
+
context 'with a Channel1 and Channel2 specified on the event' do
|
466
|
+
let :ami_event do
|
467
|
+
RubyAMI::Event.new('BridgeAction').tap do |e|
|
468
|
+
e['Privilege'] = "call,all"
|
469
|
+
e['Response'] = "Success"
|
470
|
+
e['Channel1'] = "SIP/1234-00000000"
|
471
|
+
e['Channel2'] = "SIP/5678-00000000"
|
472
|
+
end
|
473
|
+
end
|
474
|
+
|
475
|
+
context 'with calls for those channels' do
|
476
|
+
let(:call2) do
|
477
|
+
Asterisk::Call.new "SIP/5678-00000000", subject, "agi_request%3A%20async%0Aagi_channel%3A%20SIP%2F1234-00000000%0Aagi_language%3A%20en%0Aagi_type%3A%20SIP%0Aagi_uniqueid%3A%201320835995.0%0Aagi_version%3A%201.8.4.1%0Aagi_callerid%3A%205678%0Aagi_calleridname%3A%20Jane%20Smith%0Aagi_callingpres%3A%200%0Aagi_callingani2%3A%200%0Aagi_callington%3A%200%0Aagi_callingtns%3A%200%0Aagi_dnid%3A%201000%0Aagi_rdnis%3A%20unknown%0Aagi_context%3A%20default%0Aagi_extension%3A%201000%0Aagi_priority%3A%201%0Aagi_enhanced%3A%200.0%0Aagi_accountcode%3A%20%0Aagi_threadid%3A%204366221312%0A%0A"
|
478
|
+
end
|
479
|
+
|
480
|
+
before { subject.register_call call2 }
|
481
|
+
|
482
|
+
it 'should send the event to both calls and to the connection once as a PB event' do
|
483
|
+
subject.wrapped_object.expects(:handle_pb_event).once
|
484
|
+
call.expects(:process_ami_event!).once.with ami_event
|
485
|
+
call2.expects(:process_ami_event!).once.with ami_event
|
486
|
+
subject.handle_ami_event ami_event
|
487
|
+
end
|
488
|
+
end
|
489
|
+
end
|
400
490
|
end
|
401
|
-
end
|
491
|
+
end#handle_ami_event
|
402
492
|
|
403
493
|
describe '#send_ami_action' do
|
404
494
|
it 'should send the action to the AMI client' do
|
@@ -406,6 +496,13 @@ module Punchblock
|
|
406
496
|
subject.send_ami_action 'foo', :foo => :bar
|
407
497
|
end
|
408
498
|
end
|
499
|
+
|
500
|
+
describe '#run_at_fully_booted' do
|
501
|
+
it 'should send the redirect extension Command to the AMI client' do
|
502
|
+
ami_client.expects(:send_action).once.with 'Command', 'Command' => "dialplan add extension #{Asterisk::REDIRECT_EXTENSION},#{Asterisk::REDIRECT_PRIORITY},AGI,agi:async into #{Asterisk::REDIRECT_CONTEXT}"
|
503
|
+
subject.run_at_fully_booted
|
504
|
+
end
|
505
|
+
end
|
409
506
|
end
|
410
507
|
end
|
411
508
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
3
|
require 'punchblock'
|
4
4
|
require 'mocha'
|
5
5
|
require 'countdownlatch'
|
@@ -7,6 +7,8 @@ require 'logger'
|
|
7
7
|
|
8
8
|
Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each {|f| require f}
|
9
9
|
|
10
|
+
Thread.abort_on_exception = true
|
11
|
+
|
10
12
|
RSpec.configure do |config|
|
11
13
|
config.mock_with :mocha
|
12
14
|
config.filter_run :focus => true
|
@@ -15,6 +17,10 @@ RSpec.configure do |config|
|
|
15
17
|
config.before :suite do |variable|
|
16
18
|
Punchblock.logger = Logger.new(STDOUT)
|
17
19
|
end
|
20
|
+
|
21
|
+
config.after :each do
|
22
|
+
Object.const_defined?(:Celluloid) && Celluloid.shutdown
|
23
|
+
end
|
18
24
|
end
|
19
25
|
|
20
26
|
def parse_stanza(xml)
|
@@ -27,8 +33,8 @@ end
|
|
27
33
|
|
28
34
|
# FIXME: change this to rayo_event? It can be ambigous
|
29
35
|
shared_examples_for 'event' do
|
30
|
-
its(:call_id) { should == '9f00061' }
|
31
|
-
its(:component_id) { should == '1' }
|
36
|
+
its(:call_id) { should be == '9f00061' }
|
37
|
+
its(:component_id) { should be == '1' }
|
32
38
|
end
|
33
39
|
|
34
40
|
shared_examples_for 'command_headers' do
|
@@ -44,47 +50,47 @@ shared_examples_for 'command_headers' do
|
|
44
50
|
end
|
45
51
|
|
46
52
|
shared_examples_for 'event_headers' do
|
47
|
-
its(:headers) { should == [Punchblock::Header.new(:x_skill, 'agent'), Punchblock::Header.new(:x_customer_id, '8877')]}
|
48
|
-
its(:headers_hash) { should == {:x_skill => 'agent', :x_customer_id => '8877'} }
|
53
|
+
its(:headers) { should be == [Punchblock::Header.new(:x_skill, 'agent'), Punchblock::Header.new(:x_customer_id, '8877')]}
|
54
|
+
its(:headers_hash) { should be == {:x_skill => 'agent', :x_customer_id => '8877'} }
|
49
55
|
end
|
50
56
|
|
51
57
|
shared_examples_for 'key_value_pairs' do
|
52
58
|
it 'will auto-inherit nodes' do
|
53
59
|
n = parse_stanza "<#{element_name} name='boo' value='bah' />"
|
54
60
|
h = class_name.new n.root
|
55
|
-
h.name.should == :boo
|
56
|
-
h.value.should == 'bah'
|
61
|
+
h.name.should be == :boo
|
62
|
+
h.value.should be == 'bah'
|
57
63
|
end
|
58
64
|
|
59
65
|
it 'has a name attribute' do
|
60
66
|
n = class_name.new :boo, 'bah'
|
61
|
-
n.name.should == :boo
|
67
|
+
n.name.should be == :boo
|
62
68
|
n.name = :foo
|
63
|
-
n.name.should == :foo
|
69
|
+
n.name.should be == :foo
|
64
70
|
end
|
65
71
|
|
66
72
|
it "substitutes - for _ on the name attribute when reading" do
|
67
73
|
n = parse_stanza "<#{element_name} name='boo-bah' value='foo' />"
|
68
74
|
h = class_name.new n.root
|
69
|
-
h.name.should == :boo_bah
|
75
|
+
h.name.should be == :boo_bah
|
70
76
|
end
|
71
77
|
|
72
78
|
it "substitutes _ for - on the name attribute when writing" do
|
73
79
|
h = class_name.new :boo_bah, 'foo'
|
74
|
-
h.to_xml.should == "<#{element_name} name=\"boo-bah\" value=\"foo\"/>"
|
80
|
+
h.to_xml.should be == "<#{element_name} name=\"boo-bah\" value=\"foo\"/>"
|
75
81
|
end
|
76
82
|
|
77
83
|
it 'has a value param' do
|
78
84
|
n = class_name.new :boo, 'en'
|
79
|
-
n.value.should == 'en'
|
85
|
+
n.value.should be == 'en'
|
80
86
|
n.value = 'de'
|
81
|
-
n.value.should == 'de'
|
87
|
+
n.value.should be == 'de'
|
82
88
|
end
|
83
89
|
|
84
90
|
it 'can determine equality' do
|
85
91
|
a = class_name.new :boo, 'bah'
|
86
|
-
a.should == class_name.new(:boo, 'bah')
|
87
|
-
a.should_not == class_name.new(:bah, 'bah')
|
88
|
-
a.should_not == class_name.new(:boo, 'boo')
|
92
|
+
a.should be == class_name.new(:boo, 'bah')
|
93
|
+
a.should_not be == class_name.new(:bah, 'bah')
|
94
|
+
a.should_not be == class_name.new(:boo, 'boo')
|
89
95
|
end
|
90
96
|
end
|