punchblock 0.9.2 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.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
|