punchblock 0.8.1 → 0.8.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +4 -0
- data/lib/punchblock/component/asterisk/ami/action.rb +1 -1
- data/lib/punchblock/translator/asterisk.rb +24 -6
- data/lib/punchblock/translator/asterisk/call.rb +60 -3
- data/lib/punchblock/version.rb +1 -1
- data/spec/punchblock/component/asterisk/ami/action_spec.rb +20 -0
- data/spec/punchblock/translator/asterisk/call_spec.rb +203 -7
- data/spec/punchblock/translator/asterisk_spec.rb +86 -1
- data/spec/spec_helper.rb +1 -0
- metadata +41 -41
data/CHANGELOG.md
CHANGED
@@ -30,7 +30,9 @@ module Punchblock
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def call_for_channel(channel)
|
33
|
-
call_with_id @channel_to_call_id[channel]
|
33
|
+
call = call_with_id @channel_to_call_id[channel]
|
34
|
+
pb_logger.trace "Looking up call for channel #{channel} from #{@channel_to_call_id}. Found: #{call || 'none'}"
|
35
|
+
call
|
34
36
|
end
|
35
37
|
|
36
38
|
def register_component(component)
|
@@ -53,13 +55,22 @@ module Punchblock
|
|
53
55
|
end
|
54
56
|
return
|
55
57
|
end
|
56
|
-
|
57
|
-
|
58
|
+
|
59
|
+
if event.name == 'VarSet' && event['Variable'] == 'punchblock_call_id' && (call = call_with_id event['Value'])
|
60
|
+
pb_logger.trace "Received a VarSet event indicating the full channel for call #{call}"
|
61
|
+
@channel_to_call_id.delete call.channel
|
62
|
+
pb_logger.trace "Removed call with old channel from channel map: #{@channel_to_call_id}"
|
63
|
+
call.channel = event['Channel']
|
64
|
+
register_call call
|
58
65
|
end
|
66
|
+
|
59
67
|
if call = call_for_channel(event['Channel'])
|
60
68
|
pb_logger.trace "Found call by channel matching this event. Sending to call #{call.id}"
|
61
69
|
call.process_ami_event! event
|
70
|
+
elsif event.name.downcase == "asyncagi" && event['SubEvent'] == "Start"
|
71
|
+
handle_async_agi_start_event event
|
62
72
|
end
|
73
|
+
|
63
74
|
handle_pb_event Event::Asterisk::AMI::Event.new(:name => event.name, :attributes => event.headers)
|
64
75
|
end
|
65
76
|
|
@@ -92,9 +103,16 @@ module Punchblock
|
|
92
103
|
end
|
93
104
|
|
94
105
|
def execute_global_command(command)
|
95
|
-
|
96
|
-
|
97
|
-
|
106
|
+
case command
|
107
|
+
when Punchblock::Component::Asterisk::AMI::Action
|
108
|
+
component = Component::Asterisk::AMIAction.new command, current_actor
|
109
|
+
register_component component
|
110
|
+
component.execute!
|
111
|
+
when Punchblock::Command::Dial
|
112
|
+
call = Call.new command.to, current_actor
|
113
|
+
register_call call
|
114
|
+
call.dial! command
|
115
|
+
end
|
98
116
|
end
|
99
117
|
|
100
118
|
def send_ami_action(name, headers = {}, &block)
|
@@ -7,7 +7,16 @@ module Punchblock
|
|
7
7
|
include HasGuardedHandlers
|
8
8
|
include Celluloid
|
9
9
|
|
10
|
-
attr_reader :id, :channel, :translator, :agi_env
|
10
|
+
attr_reader :id, :channel, :translator, :agi_env, :direction
|
11
|
+
|
12
|
+
HANGUP_CAUSE_TO_END_REASON = Hash.new { :error }
|
13
|
+
HANGUP_CAUSE_TO_END_REASON[16] = :hangup
|
14
|
+
HANGUP_CAUSE_TO_END_REASON[17] = :busy
|
15
|
+
HANGUP_CAUSE_TO_END_REASON[18] = :timeout
|
16
|
+
HANGUP_CAUSE_TO_END_REASON[19] = :reject
|
17
|
+
HANGUP_CAUSE_TO_END_REASON[21] = :reject
|
18
|
+
HANGUP_CAUSE_TO_END_REASON[22] = :reject
|
19
|
+
HANGUP_CAUSE_TO_END_REASON[102] = :timeout
|
11
20
|
|
12
21
|
def initialize(channel, translator, agi_env = '')
|
13
22
|
@channel, @translator = channel, translator
|
@@ -25,15 +34,49 @@ module Punchblock
|
|
25
34
|
end
|
26
35
|
|
27
36
|
def send_offer
|
37
|
+
@direction = :inbound
|
28
38
|
send_pb_event offer_event
|
29
39
|
end
|
30
40
|
|
41
|
+
def to_s
|
42
|
+
"#<#{self.class}:#{id} Channel: #{channel.inspect}>"
|
43
|
+
end
|
44
|
+
|
45
|
+
def dial(dial_command)
|
46
|
+
@direction = :outbound
|
47
|
+
originate_action = Punchblock::Component::Asterisk::AMI::Action.new :name => 'Originate',
|
48
|
+
:params => {
|
49
|
+
:async => true,
|
50
|
+
:application => 'AGI',
|
51
|
+
:data => 'agi:async',
|
52
|
+
:channel => dial_command.to,
|
53
|
+
:callerid => dial_command.from,
|
54
|
+
:variable => "punchblock_call_id=#{id}"
|
55
|
+
}
|
56
|
+
originate_action.request!
|
57
|
+
translator.execute_global_command! originate_action
|
58
|
+
dial_command.response = Ref.new :id => id
|
59
|
+
end
|
60
|
+
|
61
|
+
def outbound?
|
62
|
+
direction == :outbound
|
63
|
+
end
|
64
|
+
|
65
|
+
def inbound?
|
66
|
+
direction == :inbound
|
67
|
+
end
|
68
|
+
|
69
|
+
def channel=(other)
|
70
|
+
pb_logger.info "Channel is changing from #{channel} to #{other}."
|
71
|
+
@channel = other
|
72
|
+
end
|
73
|
+
|
31
74
|
def process_ami_event(ami_event)
|
32
75
|
pb_logger.trace "Processing AMI event #{ami_event.inspect}"
|
33
76
|
case ami_event.name
|
34
77
|
when 'Hangup'
|
35
78
|
pb_logger.debug "Received a Hangup AMI event. Sending End event."
|
36
|
-
send_pb_event Event::End.new(:reason =>
|
79
|
+
send_pb_event Event::End.new(:reason => HANGUP_CAUSE_TO_END_REASON[ami_event['Cause'].to_i])
|
37
80
|
when 'AsyncAGI'
|
38
81
|
pb_logger.debug "Received an AsyncAGI event. Looking for matching AGICommand component."
|
39
82
|
if component = component_with_id(ami_event['CommandID'])
|
@@ -42,6 +85,14 @@ module Punchblock
|
|
42
85
|
else
|
43
86
|
pb_logger.debug "Could not find component for AMI event: #{ami_event}"
|
44
87
|
end
|
88
|
+
when 'Newstate'
|
89
|
+
pb_logger.debug "Received a Newstate AMI event with state #{ami_event['ChannelState']}: #{ami_event['ChannelStateDesc']}"
|
90
|
+
case ami_event['ChannelState']
|
91
|
+
when '5'
|
92
|
+
send_pb_event Event::Ringing.new
|
93
|
+
when '6'
|
94
|
+
send_pb_event Event::Answered.new
|
95
|
+
end
|
45
96
|
end
|
46
97
|
trigger_handler :ami, ami_event
|
47
98
|
end
|
@@ -53,8 +104,14 @@ module Punchblock
|
|
53
104
|
end
|
54
105
|
case command
|
55
106
|
when Command::Accept
|
56
|
-
|
107
|
+
if outbound?
|
108
|
+
pb_logger.trace "Attempting to accept an outbound call. Skipping RINGING."
|
57
109
|
command.response = true
|
110
|
+
else
|
111
|
+
pb_logger.trace "Attempting to accept an inbound call. Executing RINGING."
|
112
|
+
send_agi_action 'EXEC RINGING' do |response|
|
113
|
+
command.response = true
|
114
|
+
end
|
58
115
|
end
|
59
116
|
when Command::Answer
|
60
117
|
send_agi_action 'EXEC ANSWER' do |response|
|
data/lib/punchblock/version.rb
CHANGED
@@ -52,6 +52,26 @@ module Punchblock
|
|
52
52
|
:async => '1'} }
|
53
53
|
end
|
54
54
|
|
55
|
+
describe "testing equality" do
|
56
|
+
context "with the same name and params" do
|
57
|
+
it "should be equal" do
|
58
|
+
Action.new(:name => 'Originate', :params => { :channel => 'SIP/101test' }).should == Action.new(:name => 'Originate', :params => { :channel => 'SIP/101test' })
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context "with the same name and different params" do
|
63
|
+
it "should be equal" do
|
64
|
+
Action.new(:name => 'Originate', :params => { :channel => 'SIP/101' }).should_not == Action.new(:name => 'Originate', :params => { :channel => 'SIP/101test' })
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context "with a different name and the same params" do
|
69
|
+
it "should be equal" do
|
70
|
+
Action.new(:name => 'Hangup', :params => { :channel => 'SIP/101test' }).should_not == Action.new(:name => 'Originate', :params => { :channel => 'SIP/101test' })
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
55
75
|
describe "when setting options in initializer" do
|
56
76
|
subject do
|
57
77
|
Action.new :name => 'Originate',
|
@@ -82,6 +82,58 @@ module Punchblock
|
|
82
82
|
translator.expects(:handle_pb_event!).with expected_offer
|
83
83
|
subject.send_offer
|
84
84
|
end
|
85
|
+
|
86
|
+
it 'should make the call identify as inbound' do
|
87
|
+
subject.send_offer
|
88
|
+
subject.direction.should == :inbound
|
89
|
+
subject.inbound?.should be true
|
90
|
+
subject.outbound?.should be false
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe '#dial' do
|
95
|
+
let :dial_command do
|
96
|
+
Punchblock::Command::Dial.new :to => 'SIP/1234', :from => 'sip:foo@bar.com'
|
97
|
+
end
|
98
|
+
|
99
|
+
before { dial_command.request! }
|
100
|
+
|
101
|
+
it 'sends an Originate AMI action' do
|
102
|
+
expected_action = Punchblock::Component::Asterisk::AMI::Action.new :name => 'Originate',
|
103
|
+
:params => {
|
104
|
+
:async => true,
|
105
|
+
:application => 'AGI',
|
106
|
+
:data => 'agi:async',
|
107
|
+
:channel => 'SIP/1234',
|
108
|
+
:callerid => 'sip:foo@bar.com',
|
109
|
+
:variable => "punchblock_call_id=#{subject.id}"
|
110
|
+
}
|
111
|
+
|
112
|
+
translator.expects(:execute_global_command!).once.with expected_action
|
113
|
+
subject.dial dial_command
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'sends the call ID as a response to the Dial' do
|
117
|
+
subject.dial dial_command
|
118
|
+
dial_command.response
|
119
|
+
dial_command.call_id.should == subject.id
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'should make the call identify as outbound' do
|
123
|
+
subject.dial dial_command
|
124
|
+
subject.direction.should == :outbound
|
125
|
+
subject.outbound?.should be true
|
126
|
+
subject.inbound?.should be false
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'causes accepting the call to be a null operation' do
|
130
|
+
subject.dial dial_command
|
131
|
+
accept_command = Command::Accept.new
|
132
|
+
accept_command.request!
|
133
|
+
subject.wrapped_object.expects(:send_agi_action).never
|
134
|
+
subject.execute_command accept_command
|
135
|
+
accept_command.response(0.5).should be true
|
136
|
+
end
|
85
137
|
end
|
86
138
|
|
87
139
|
describe '#process_ami_event' do
|
@@ -91,17 +143,121 @@ module Punchblock
|
|
91
143
|
e['Uniqueid'] = "1320842458.8"
|
92
144
|
e['Calleridnum'] = "5678"
|
93
145
|
e['Calleridname'] = "Jane Smith"
|
94
|
-
e['Cause'] =
|
95
|
-
e['Cause-txt'] =
|
146
|
+
e['Cause'] = cause
|
147
|
+
e['Cause-txt'] = cause_txt
|
96
148
|
e['Channel'] = "SIP/1234-00000000"
|
97
149
|
end
|
98
150
|
end
|
99
151
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
152
|
+
context "with a normal clearing cause" do
|
153
|
+
let(:cause) { '16' }
|
154
|
+
let(:cause_txt) { 'Normal Clearing' }
|
155
|
+
|
156
|
+
it 'should send an end (hangup) event to the translator' do
|
157
|
+
expected_end_event = Punchblock::Event::End.new :reason => :hangup,
|
158
|
+
:call_id => subject.id
|
159
|
+
translator.expects(:handle_pb_event!).with expected_end_event
|
160
|
+
subject.process_ami_event ami_event
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
context "with a user busy cause" do
|
165
|
+
let(:cause) { '17' }
|
166
|
+
let(:cause_txt) { 'User Busy' }
|
167
|
+
|
168
|
+
it 'should send an end (busy) event to the translator' do
|
169
|
+
expected_end_event = Punchblock::Event::End.new :reason => :busy,
|
170
|
+
:call_id => subject.id
|
171
|
+
translator.expects(:handle_pb_event!).with expected_end_event
|
172
|
+
subject.process_ami_event ami_event
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
{
|
177
|
+
18 => 'No user response',
|
178
|
+
102 => 'Recovery on timer expire'
|
179
|
+
}.each_pair do |cause, cause_txt|
|
180
|
+
context "with a #{cause_txt} cause" do
|
181
|
+
let(:cause) { cause.to_s }
|
182
|
+
let(:cause_txt) { cause_txt }
|
183
|
+
|
184
|
+
it 'should send an end (timeout) event to the translator' do
|
185
|
+
expected_end_event = Punchblock::Event::End.new :reason => :timeout,
|
186
|
+
:call_id => subject.id
|
187
|
+
translator.expects(:handle_pb_event!).with expected_end_event
|
188
|
+
subject.process_ami_event ami_event
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
{
|
194
|
+
19 => 'No Answer',
|
195
|
+
21 => 'Call Rejected',
|
196
|
+
22 => 'Number Changed'
|
197
|
+
}.each_pair do |cause, cause_txt|
|
198
|
+
context "with a #{cause_txt} cause" do
|
199
|
+
let(:cause) { cause.to_s }
|
200
|
+
let(:cause_txt) { cause_txt }
|
201
|
+
|
202
|
+
it 'should send an end (reject) event to the translator' do
|
203
|
+
expected_end_event = Punchblock::Event::End.new :reason => :reject,
|
204
|
+
:call_id => subject.id
|
205
|
+
translator.expects(:handle_pb_event!).with expected_end_event
|
206
|
+
subject.process_ami_event ami_event
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
{
|
212
|
+
1 => 'AST_CAUSE_UNALLOCATED',
|
213
|
+
2 => 'NO_ROUTE_TRANSIT_NET',
|
214
|
+
3 => 'NO_ROUTE_DESTINATION',
|
215
|
+
6 => 'CHANNEL_UNACCEPTABLE',
|
216
|
+
7 => 'CALL_AWARDED_DELIVERED',
|
217
|
+
27 => 'DESTINATION_OUT_OF_ORDER',
|
218
|
+
28 => 'INVALID_NUMBER_FORMAT',
|
219
|
+
29 => 'FACILITY_REJECTED',
|
220
|
+
30 => 'RESPONSE_TO_STATUS_ENQUIRY',
|
221
|
+
31 => 'NORMAL_UNSPECIFIED',
|
222
|
+
34 => 'NORMAL_CIRCUIT_CONGESTION',
|
223
|
+
38 => 'NETWORK_OUT_OF_ORDER',
|
224
|
+
41 => 'NORMAL_TEMPORARY_FAILURE',
|
225
|
+
42 => 'SWITCH_CONGESTION',
|
226
|
+
43 => 'ACCESS_INFO_DISCARDED',
|
227
|
+
44 => 'REQUESTED_CHAN_UNAVAIL',
|
228
|
+
45 => 'PRE_EMPTED',
|
229
|
+
50 => 'FACILITY_NOT_SUBSCRIBED',
|
230
|
+
52 => 'OUTGOING_CALL_BARRED',
|
231
|
+
54 => 'INCOMING_CALL_BARRED',
|
232
|
+
57 => 'BEARERCAPABILITY_NOTAUTH',
|
233
|
+
58 => 'BEARERCAPABILITY_NOTAVAIL',
|
234
|
+
65 => 'BEARERCAPABILITY_NOTIMPL',
|
235
|
+
66 => 'CHAN_NOT_IMPLEMENTED',
|
236
|
+
69 => 'FACILITY_NOT_IMPLEMENTED',
|
237
|
+
81 => 'INVALID_CALL_REFERENCE',
|
238
|
+
88 => 'INCOMPATIBLE_DESTINATION',
|
239
|
+
95 => 'INVALID_MSG_UNSPECIFIED',
|
240
|
+
96 => 'MANDATORY_IE_MISSING',
|
241
|
+
97 => 'MESSAGE_TYPE_NONEXIST',
|
242
|
+
98 => 'WRONG_MESSAGE',
|
243
|
+
99 => 'IE_NONEXIST',
|
244
|
+
100 => 'INVALID_IE_CONTENTS',
|
245
|
+
101 => 'WRONG_CALL_STATE',
|
246
|
+
103 => 'MANDATORY_IE_LENGTH_ERROR',
|
247
|
+
111 => 'PROTOCOL_ERROR',
|
248
|
+
127 => 'INTERWORKING'
|
249
|
+
}.each_pair do |cause, cause_txt|
|
250
|
+
context "with a #{cause_txt} cause" do
|
251
|
+
let(:cause) { cause.to_s }
|
252
|
+
let(:cause_txt) { cause_txt }
|
253
|
+
|
254
|
+
it 'should send an end (error) event to the translator' do
|
255
|
+
expected_end_event = Punchblock::Event::End.new :reason => :error,
|
256
|
+
:call_id => subject.id
|
257
|
+
translator.expects(:handle_pb_event!).with expected_end_event
|
258
|
+
subject.process_ami_event ami_event
|
259
|
+
end
|
260
|
+
end
|
105
261
|
end
|
106
262
|
end
|
107
263
|
|
@@ -131,6 +287,46 @@ module Punchblock
|
|
131
287
|
end
|
132
288
|
end
|
133
289
|
|
290
|
+
context 'with a Newstate event' do
|
291
|
+
let :ami_event do
|
292
|
+
RubyAMI::Event.new('Newstate').tap do |e|
|
293
|
+
e['Privilege'] = 'call,all'
|
294
|
+
e['Channel'] = 'SIP/1234-00000000'
|
295
|
+
e['ChannelState'] = channel_state
|
296
|
+
e['ChannelStateDesc'] = channel_state_desc
|
297
|
+
e['CallerIDNum'] = ''
|
298
|
+
e['CallerIDName'] = ''
|
299
|
+
e['ConnectedLineNum'] = ''
|
300
|
+
e['ConnectedLineName'] = ''
|
301
|
+
e['Uniqueid'] = '1326194671.0'
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
context 'ringing' do
|
306
|
+
let(:channel_state) { '5' }
|
307
|
+
let(:channel_state_desc) { 'Ringing' }
|
308
|
+
|
309
|
+
it 'should send a ringing event' do
|
310
|
+
expected_ringing = Punchblock::Event::Ringing.new
|
311
|
+
expected_ringing.call_id = subject.id
|
312
|
+
translator.expects(:handle_pb_event!).with expected_ringing
|
313
|
+
subject.process_ami_event ami_event
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
context 'up' do
|
318
|
+
let(:channel_state) { '6' }
|
319
|
+
let(:channel_state_desc) { 'Up' }
|
320
|
+
|
321
|
+
it 'should send a ringing event' do
|
322
|
+
expected_answered = Punchblock::Event::Answered.new
|
323
|
+
expected_answered.call_id = subject.id
|
324
|
+
translator.expects(:handle_pb_event!).with expected_answered
|
325
|
+
subject.process_ami_event ami_event
|
326
|
+
end
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
134
330
|
context 'with a handler registered for a matching event' do
|
135
331
|
let :ami_event do
|
136
332
|
RubyAMI::Event.new('DTMF').tap do |e|
|
@@ -126,7 +126,26 @@ module Punchblock
|
|
126
126
|
|
127
127
|
describe '#execute_global_command' do
|
128
128
|
context 'with a Dial' do
|
129
|
-
|
129
|
+
let :command do
|
130
|
+
Command::Dial.new :to => 'SIP/1234', :from => 'abc123'
|
131
|
+
end
|
132
|
+
|
133
|
+
before { command.request! }
|
134
|
+
|
135
|
+
let(:mock_action) { stub_everything 'Asterisk::Component::Asterisk::AMIAction' }
|
136
|
+
|
137
|
+
it 'should be able to look up the call by channel ID' do
|
138
|
+
subject.execute_global_command command
|
139
|
+
call_actor = subject.call_for_channel('SIP/1234')
|
140
|
+
call_actor.wrapped_object.should be_a Asterisk::Call
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'should instruct the call to send a dial' do
|
144
|
+
mock_call = stub_everything 'Asterisk::Call'
|
145
|
+
Asterisk::Call.expects(:new).once.returns mock_call
|
146
|
+
mock_call.expects(:dial!).once.with command
|
147
|
+
subject.execute_global_command command
|
148
|
+
end
|
130
149
|
end
|
131
150
|
|
132
151
|
context 'with an AMI action' do
|
@@ -232,6 +251,72 @@ module Punchblock
|
|
232
251
|
mock_call.expects(:send_offer!).once
|
233
252
|
subject.handle_ami_event ami_event
|
234
253
|
end
|
254
|
+
|
255
|
+
context 'if a call already exists for a matching channel' do
|
256
|
+
let(:call) { Asterisk::Call.new "SIP/1234-00000000", subject }
|
257
|
+
|
258
|
+
before do
|
259
|
+
subject.register_call call
|
260
|
+
end
|
261
|
+
|
262
|
+
it "should not create a new call" do
|
263
|
+
Asterisk::Call.expects(:new).never
|
264
|
+
subject.handle_ami_event ami_event
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
describe 'with a VarSet event including a punchblock_call_id' do
|
270
|
+
let :ami_event do
|
271
|
+
RubyAMI::Event.new('VarSet').tap do |e|
|
272
|
+
e["Privilege"] = "dialplan,all"
|
273
|
+
e["Channel"] = "SIP/1234-00000000"
|
274
|
+
e["Variable"] = "punchblock_call_id"
|
275
|
+
e["Value"] = call_id
|
276
|
+
e["Uniqueid"] = "1326210224.0"
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
before do
|
281
|
+
ami_client.stub_everything
|
282
|
+
subject.wrapped_object.stubs :handle_pb_event
|
283
|
+
end
|
284
|
+
|
285
|
+
context "matching a call that was created by a Dial command" do
|
286
|
+
let(:dial_command) { Punchblock::Command::Dial.new :to => 'SIP/1234', :from => 'abc123' }
|
287
|
+
|
288
|
+
before do
|
289
|
+
dial_command.request!
|
290
|
+
subject.execute_global_command dial_command
|
291
|
+
call
|
292
|
+
end
|
293
|
+
|
294
|
+
let(:call) { subject.call_for_channel 'SIP/1234' }
|
295
|
+
let(:call_id) { call.id }
|
296
|
+
|
297
|
+
it "should set the correct channel on the call" do
|
298
|
+
subject.handle_ami_event ami_event
|
299
|
+
call.channel.should == 'SIP/1234-00000000'
|
300
|
+
end
|
301
|
+
|
302
|
+
it "should make it possible to look up the call by the full channel name" do
|
303
|
+
subject.handle_ami_event ami_event
|
304
|
+
subject.call_for_channel("SIP/1234-00000000").should be call
|
305
|
+
end
|
306
|
+
|
307
|
+
it "should make looking up the channel by the requested channel name impossible" do
|
308
|
+
subject.handle_ami_event ami_event
|
309
|
+
subject.call_for_channel('SIP/1234').should be_nil
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
context "for a call that doesn't exist" do
|
314
|
+
let(:call_id) { 'foobarbaz' }
|
315
|
+
|
316
|
+
it "should not raise" do
|
317
|
+
lambda { subject.handle_ami_event ami_event }.should_not raise_error
|
318
|
+
end
|
319
|
+
end
|
235
320
|
end
|
236
321
|
|
237
322
|
describe 'with an AMI event for a known channel' do
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: punchblock
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -11,11 +11,11 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2012-01-
|
14
|
+
date: 2012-01-10 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: niceogiri
|
18
|
-
requirement: &
|
18
|
+
requirement: &2168470140 !ruby/object:Gem::Requirement
|
19
19
|
none: false
|
20
20
|
requirements:
|
21
21
|
- - ! '>='
|
@@ -23,10 +23,10 @@ dependencies:
|
|
23
23
|
version: 0.0.4
|
24
24
|
type: :runtime
|
25
25
|
prerelease: false
|
26
|
-
version_requirements: *
|
26
|
+
version_requirements: *2168470140
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: blather
|
29
|
-
requirement: &
|
29
|
+
requirement: &2168468720 !ruby/object:Gem::Requirement
|
30
30
|
none: false
|
31
31
|
requirements:
|
32
32
|
- - ! '>='
|
@@ -34,10 +34,10 @@ dependencies:
|
|
34
34
|
version: 0.5.12
|
35
35
|
type: :runtime
|
36
36
|
prerelease: false
|
37
|
-
version_requirements: *
|
37
|
+
version_requirements: *2168468720
|
38
38
|
- !ruby/object:Gem::Dependency
|
39
39
|
name: activesupport
|
40
|
-
requirement: &
|
40
|
+
requirement: &2168467360 !ruby/object:Gem::Requirement
|
41
41
|
none: false
|
42
42
|
requirements:
|
43
43
|
- - ! '>='
|
@@ -45,10 +45,10 @@ dependencies:
|
|
45
45
|
version: 2.1.0
|
46
46
|
type: :runtime
|
47
47
|
prerelease: false
|
48
|
-
version_requirements: *
|
48
|
+
version_requirements: *2168467360
|
49
49
|
- !ruby/object:Gem::Dependency
|
50
50
|
name: state_machine
|
51
|
-
requirement: &
|
51
|
+
requirement: &2168466140 !ruby/object:Gem::Requirement
|
52
52
|
none: false
|
53
53
|
requirements:
|
54
54
|
- - ! '>='
|
@@ -56,10 +56,10 @@ dependencies:
|
|
56
56
|
version: 1.0.1
|
57
57
|
type: :runtime
|
58
58
|
prerelease: false
|
59
|
-
version_requirements: *
|
59
|
+
version_requirements: *2168466140
|
60
60
|
- !ruby/object:Gem::Dependency
|
61
61
|
name: future-resource
|
62
|
-
requirement: &
|
62
|
+
requirement: &2168464520 !ruby/object:Gem::Requirement
|
63
63
|
none: false
|
64
64
|
requirements:
|
65
65
|
- - ! '>='
|
@@ -67,10 +67,10 @@ dependencies:
|
|
67
67
|
version: 0.0.2
|
68
68
|
type: :runtime
|
69
69
|
prerelease: false
|
70
|
-
version_requirements: *
|
70
|
+
version_requirements: *2168464520
|
71
71
|
- !ruby/object:Gem::Dependency
|
72
72
|
name: has-guarded-handlers
|
73
|
-
requirement: &
|
73
|
+
requirement: &2168508400 !ruby/object:Gem::Requirement
|
74
74
|
none: false
|
75
75
|
requirements:
|
76
76
|
- - ! '>='
|
@@ -78,10 +78,10 @@ dependencies:
|
|
78
78
|
version: 0.1.0
|
79
79
|
type: :runtime
|
80
80
|
prerelease: false
|
81
|
-
version_requirements: *
|
81
|
+
version_requirements: *2168508400
|
82
82
|
- !ruby/object:Gem::Dependency
|
83
83
|
name: celluloid
|
84
|
-
requirement: &
|
84
|
+
requirement: &2168506560 !ruby/object:Gem::Requirement
|
85
85
|
none: false
|
86
86
|
requirements:
|
87
87
|
- - ! '>='
|
@@ -89,10 +89,10 @@ dependencies:
|
|
89
89
|
version: 0.6.0
|
90
90
|
type: :runtime
|
91
91
|
prerelease: false
|
92
|
-
version_requirements: *
|
92
|
+
version_requirements: *2168506560
|
93
93
|
- !ruby/object:Gem::Dependency
|
94
94
|
name: ruby_ami
|
95
|
-
requirement: &
|
95
|
+
requirement: &2168504680 !ruby/object:Gem::Requirement
|
96
96
|
none: false
|
97
97
|
requirements:
|
98
98
|
- - ! '>='
|
@@ -100,10 +100,10 @@ dependencies:
|
|
100
100
|
version: 0.1.3
|
101
101
|
type: :runtime
|
102
102
|
prerelease: false
|
103
|
-
version_requirements: *
|
103
|
+
version_requirements: *2168504680
|
104
104
|
- !ruby/object:Gem::Dependency
|
105
105
|
name: ruby_speech
|
106
|
-
requirement: &
|
106
|
+
requirement: &2168503400 !ruby/object:Gem::Requirement
|
107
107
|
none: false
|
108
108
|
requirements:
|
109
109
|
- - ! '>='
|
@@ -111,10 +111,10 @@ dependencies:
|
|
111
111
|
version: 0.5.1
|
112
112
|
type: :runtime
|
113
113
|
prerelease: false
|
114
|
-
version_requirements: *
|
114
|
+
version_requirements: *2168503400
|
115
115
|
- !ruby/object:Gem::Dependency
|
116
116
|
name: bundler
|
117
|
-
requirement: &
|
117
|
+
requirement: &2168500560 !ruby/object:Gem::Requirement
|
118
118
|
none: false
|
119
119
|
requirements:
|
120
120
|
- - ~>
|
@@ -122,10 +122,10 @@ dependencies:
|
|
122
122
|
version: 1.0.0
|
123
123
|
type: :development
|
124
124
|
prerelease: false
|
125
|
-
version_requirements: *
|
125
|
+
version_requirements: *2168500560
|
126
126
|
- !ruby/object:Gem::Dependency
|
127
127
|
name: rspec
|
128
|
-
requirement: &
|
128
|
+
requirement: &2168497720 !ruby/object:Gem::Requirement
|
129
129
|
none: false
|
130
130
|
requirements:
|
131
131
|
- - ~>
|
@@ -133,10 +133,10 @@ dependencies:
|
|
133
133
|
version: 2.7.0
|
134
134
|
type: :development
|
135
135
|
prerelease: false
|
136
|
-
version_requirements: *
|
136
|
+
version_requirements: *2168497720
|
137
137
|
- !ruby/object:Gem::Dependency
|
138
138
|
name: ci_reporter
|
139
|
-
requirement: &
|
139
|
+
requirement: &2152104200 !ruby/object:Gem::Requirement
|
140
140
|
none: false
|
141
141
|
requirements:
|
142
142
|
- - ! '>='
|
@@ -144,10 +144,10 @@ dependencies:
|
|
144
144
|
version: 1.6.3
|
145
145
|
type: :development
|
146
146
|
prerelease: false
|
147
|
-
version_requirements: *
|
147
|
+
version_requirements: *2152104200
|
148
148
|
- !ruby/object:Gem::Dependency
|
149
149
|
name: yard
|
150
|
-
requirement: &
|
150
|
+
requirement: &2152102500 !ruby/object:Gem::Requirement
|
151
151
|
none: false
|
152
152
|
requirements:
|
153
153
|
- - ~>
|
@@ -155,10 +155,10 @@ dependencies:
|
|
155
155
|
version: 0.6.0
|
156
156
|
type: :development
|
157
157
|
prerelease: false
|
158
|
-
version_requirements: *
|
158
|
+
version_requirements: *2152102500
|
159
159
|
- !ruby/object:Gem::Dependency
|
160
160
|
name: rcov
|
161
|
-
requirement: &
|
161
|
+
requirement: &2152101300 !ruby/object:Gem::Requirement
|
162
162
|
none: false
|
163
163
|
requirements:
|
164
164
|
- - ! '>='
|
@@ -166,10 +166,10 @@ dependencies:
|
|
166
166
|
version: '0'
|
167
167
|
type: :development
|
168
168
|
prerelease: false
|
169
|
-
version_requirements: *
|
169
|
+
version_requirements: *2152101300
|
170
170
|
- !ruby/object:Gem::Dependency
|
171
171
|
name: rake
|
172
|
-
requirement: &
|
172
|
+
requirement: &2152100160 !ruby/object:Gem::Requirement
|
173
173
|
none: false
|
174
174
|
requirements:
|
175
175
|
- - ! '>='
|
@@ -177,10 +177,10 @@ dependencies:
|
|
177
177
|
version: '0'
|
178
178
|
type: :development
|
179
179
|
prerelease: false
|
180
|
-
version_requirements: *
|
180
|
+
version_requirements: *2152100160
|
181
181
|
- !ruby/object:Gem::Dependency
|
182
182
|
name: mocha
|
183
|
-
requirement: &
|
183
|
+
requirement: &2152097280 !ruby/object:Gem::Requirement
|
184
184
|
none: false
|
185
185
|
requirements:
|
186
186
|
- - ! '>='
|
@@ -188,10 +188,10 @@ dependencies:
|
|
188
188
|
version: '0'
|
189
189
|
type: :development
|
190
190
|
prerelease: false
|
191
|
-
version_requirements: *
|
191
|
+
version_requirements: *2152097280
|
192
192
|
- !ruby/object:Gem::Dependency
|
193
193
|
name: i18n
|
194
|
-
requirement: &
|
194
|
+
requirement: &2152084420 !ruby/object:Gem::Requirement
|
195
195
|
none: false
|
196
196
|
requirements:
|
197
197
|
- - ! '>='
|
@@ -199,10 +199,10 @@ dependencies:
|
|
199
199
|
version: '0'
|
200
200
|
type: :development
|
201
201
|
prerelease: false
|
202
|
-
version_requirements: *
|
202
|
+
version_requirements: *2152084420
|
203
203
|
- !ruby/object:Gem::Dependency
|
204
204
|
name: countdownlatch
|
205
|
-
requirement: &
|
205
|
+
requirement: &2152079640 !ruby/object:Gem::Requirement
|
206
206
|
none: false
|
207
207
|
requirements:
|
208
208
|
- - ! '>='
|
@@ -210,10 +210,10 @@ dependencies:
|
|
210
210
|
version: '0'
|
211
211
|
type: :development
|
212
212
|
prerelease: false
|
213
|
-
version_requirements: *
|
213
|
+
version_requirements: *2152079640
|
214
214
|
- !ruby/object:Gem::Dependency
|
215
215
|
name: guard-rspec
|
216
|
-
requirement: &
|
216
|
+
requirement: &2152075260 !ruby/object:Gem::Requirement
|
217
217
|
none: false
|
218
218
|
requirements:
|
219
219
|
- - ! '>='
|
@@ -221,7 +221,7 @@ dependencies:
|
|
221
221
|
version: '0'
|
222
222
|
type: :development
|
223
223
|
prerelease: false
|
224
|
-
version_requirements: *
|
224
|
+
version_requirements: *2152075260
|
225
225
|
description: Like Rack is to Rails and Sinatra, Punchblock provides a consistent API
|
226
226
|
on top of several underlying third-party call control protocols.
|
227
227
|
email: punchblock@adhearsion.com
|
@@ -363,7 +363,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
363
363
|
version: '0'
|
364
364
|
segments:
|
365
365
|
- 0
|
366
|
-
hash: -
|
366
|
+
hash: -2044158183945900193
|
367
367
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
368
368
|
none: false
|
369
369
|
requirements:
|