punchblock 0.8.2 → 0.8.3
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +17 -0
- data/lib/punchblock/client.rb +1 -0
- data/lib/punchblock/connection/asterisk.rb +1 -0
- data/lib/punchblock/translator/asterisk.rb +18 -2
- data/lib/punchblock/translator/asterisk/call.rb +24 -7
- data/lib/punchblock/translator/asterisk/component.rb +38 -12
- data/lib/punchblock/translator/asterisk/component/asterisk/agi_command.rb +1 -1
- data/lib/punchblock/translator/asterisk/component/asterisk/ami_action.rb +15 -14
- data/lib/punchblock/translator/asterisk/component/asterisk/input.rb +1 -1
- data/lib/punchblock/translator/asterisk/component/asterisk/output.rb +2 -2
- data/lib/punchblock/version.rb +1 -1
- data/spec/punchblock/connection/asterisk_spec.rb +5 -0
- data/spec/punchblock/event/complete_spec.rb +58 -0
- data/spec/punchblock/translator/asterisk/call_spec.rb +46 -5
- data/spec/punchblock/translator/asterisk/component/asterisk/agi_command_spec.rb +8 -2
- data/spec/punchblock/translator/asterisk/component/asterisk/ami_action_spec.rb +16 -19
- data/spec/punchblock/translator/asterisk/component/asterisk/input_spec.rb +27 -11
- data/spec/punchblock/translator/asterisk/component/asterisk/output_spec.rb +9 -5
- data/spec/punchblock/translator/asterisk/component_spec.rb +81 -0
- data/spec/punchblock/translator/asterisk_spec.rb +66 -14
- data/spec/support/mock_connection_with_event_handler.rb +22 -0
- metadata +43 -41
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,22 @@
|
|
1
1
|
# develop
|
2
2
|
|
3
|
+
# v0.8.3 - 2012-01-17
|
4
|
+
* Feature: Return an error when trying to execute a command for unknown calls/components or when not understood
|
5
|
+
* Feature: Log calls/translator shutting down
|
6
|
+
* Feature: Calls and components should log their IDs
|
7
|
+
* Feature: Components marked as internal should send events directly to the component node
|
8
|
+
* Bugfix: Fix Asterisk Call and Component logger IDs
|
9
|
+
* Bugfix: Fix a stupidly high log level
|
10
|
+
* Bugfix: AGI commands executed by a call/component that are a translation of a Rayo command should be marked internal
|
11
|
+
* Bugfix: Asterisk components should sent events via the connection
|
12
|
+
* Bugfix: Shutting down an asterisk connection should do a cascading shutdown of the translator and all of its calls
|
13
|
+
* Bugfix: Component actors should be terminated once they've sent a complete event
|
14
|
+
* Bugfix: Component events should be sent with the call ID
|
15
|
+
* Bugfix: AMIAction components do not have a call
|
16
|
+
* Bugfix: Add test coverage for comparison of complete events
|
17
|
+
* Bugfix: A call being hung up should terminate the call actor
|
18
|
+
* Bugfix: Fix a mock expectation error in a test
|
19
|
+
|
3
20
|
# v0.8.2 - 2012-01-10
|
4
21
|
* Feature: Support outbound dial on Asterisk
|
5
22
|
* Bugfix: Asterisk hangup causes should map to correct Rayo End reason
|
data/lib/punchblock/client.rb
CHANGED
@@ -43,6 +43,12 @@ module Punchblock
|
|
43
43
|
@components[component_id]
|
44
44
|
end
|
45
45
|
|
46
|
+
def shutdown
|
47
|
+
pb_logger.debug "Shutting down"
|
48
|
+
@calls.values.each &:shutdown!
|
49
|
+
current_actor.terminate!
|
50
|
+
end
|
51
|
+
|
46
52
|
def handle_ami_event(event)
|
47
53
|
return unless event.is_a? RubyAMI::Event
|
48
54
|
pb_logger.trace "Handling AMI event #{event.inspect}"
|
@@ -95,11 +101,19 @@ module Punchblock
|
|
95
101
|
end
|
96
102
|
|
97
103
|
def execute_call_command(command)
|
98
|
-
call_with_id(command.call_id)
|
104
|
+
if call = call_with_id(command.call_id)
|
105
|
+
call.execute_command! command
|
106
|
+
else
|
107
|
+
command.response = ProtocolError.new 'call-not-found', "Could not find a call with ID #{command.call_id}", command.call_id
|
108
|
+
end
|
99
109
|
end
|
100
110
|
|
101
111
|
def execute_component_command(command)
|
102
|
-
component_with_id(command.component_id)
|
112
|
+
if (component = component_with_id(command.component_id))
|
113
|
+
component.execute_command! command
|
114
|
+
else
|
115
|
+
command.response = ProtocolError.new 'component-not-found', "Could not find a component with ID #{command.component_id}", command.call_id, command.component_id
|
116
|
+
end
|
103
117
|
end
|
104
118
|
|
105
119
|
def execute_global_command(command)
|
@@ -112,6 +126,8 @@ module Punchblock
|
|
112
126
|
call = Call.new command.to, current_actor
|
113
127
|
register_call call
|
114
128
|
call.dial! command
|
129
|
+
else
|
130
|
+
command.response = ProtocolError.new 'command-not-acceptable', "Did not understand command"
|
115
131
|
end
|
116
132
|
end
|
117
133
|
|
@@ -38,6 +38,11 @@ module Punchblock
|
|
38
38
|
send_pb_event offer_event
|
39
39
|
end
|
40
40
|
|
41
|
+
def shutdown
|
42
|
+
pb_logger.debug "Shutting down"
|
43
|
+
current_actor.terminate!
|
44
|
+
end
|
45
|
+
|
41
46
|
def to_s
|
42
47
|
"#<#{self.class}:#{id} Channel: #{channel.inspect}>"
|
43
48
|
end
|
@@ -76,7 +81,7 @@ module Punchblock
|
|
76
81
|
case ami_event.name
|
77
82
|
when 'Hangup'
|
78
83
|
pb_logger.debug "Received a Hangup AMI event. Sending End event."
|
79
|
-
|
84
|
+
send_end_event HANGUP_CAUSE_TO_END_REASON[ami_event['Cause'].to_i]
|
80
85
|
when 'AsyncAGI'
|
81
86
|
pb_logger.debug "Received an AsyncAGI event. Looking for matching AGICommand component."
|
82
87
|
if component = component_with_id(ami_event['CommandID'])
|
@@ -100,7 +105,11 @@ module Punchblock
|
|
100
105
|
def execute_command(command)
|
101
106
|
pb_logger.debug "Executing command: #{command.inspect}"
|
102
107
|
if command.component_id
|
103
|
-
component_with_id(command.component_id)
|
108
|
+
if component = component_with_id(command.component_id)
|
109
|
+
component.execute_command! command
|
110
|
+
else
|
111
|
+
command.response = ProtocolError.new 'component-not-found', "Could not find a component with ID #{command.component_id} for call #{id}", id, command.component_id
|
112
|
+
end
|
104
113
|
end
|
105
114
|
case command
|
106
115
|
when Command::Accept
|
@@ -122,11 +131,13 @@ module Punchblock
|
|
122
131
|
command.response = true
|
123
132
|
end
|
124
133
|
when Punchblock::Component::Asterisk::AGI::Command
|
125
|
-
|
134
|
+
execute_component Component::Asterisk::AGICommand, command
|
126
135
|
when Punchblock::Component::Output
|
127
136
|
execute_component Component::Asterisk::Output, command
|
128
137
|
when Punchblock::Component::Input
|
129
138
|
execute_component Component::Asterisk::Input, command
|
139
|
+
else
|
140
|
+
command.response = ProtocolError.new 'command-not-acceptable', "Did not understand command for call #{id}", id
|
130
141
|
end
|
131
142
|
end
|
132
143
|
|
@@ -138,7 +149,7 @@ module Punchblock
|
|
138
149
|
pb_logger.debug "AGI action received complete event #{e.inspect}"
|
139
150
|
block.call e
|
140
151
|
end
|
141
|
-
|
152
|
+
execute_component Component::Asterisk::AGICommand, @current_agi_command, :internal => true
|
142
153
|
end
|
143
154
|
|
144
155
|
def send_ami_action(name, headers = {}, &block)
|
@@ -149,15 +160,21 @@ module Punchblock
|
|
149
160
|
end
|
150
161
|
end
|
151
162
|
|
163
|
+
def logger_id
|
164
|
+
"#{self.class}: #{id}"
|
165
|
+
end
|
166
|
+
|
152
167
|
private
|
153
168
|
|
154
|
-
def
|
155
|
-
|
169
|
+
def send_end_event(reason)
|
170
|
+
send_pb_event Event::End.new(:reason => reason)
|
171
|
+
current_actor.terminate!
|
156
172
|
end
|
157
173
|
|
158
|
-
def execute_component(type, command)
|
174
|
+
def execute_component(type, command, options = {})
|
159
175
|
type.new(command, current_actor).tap do |component|
|
160
176
|
register_component component
|
177
|
+
component.internal = true if options[:internal]
|
161
178
|
component.execute!
|
162
179
|
end
|
163
180
|
end
|
@@ -10,6 +10,7 @@ module Punchblock
|
|
10
10
|
include Celluloid
|
11
11
|
|
12
12
|
attr_reader :id, :call
|
13
|
+
attr_accessor :internal
|
13
14
|
|
14
15
|
def initialize(component_node, call = nil)
|
15
16
|
@component_node, @call = component_node, call
|
@@ -21,6 +22,43 @@ module Punchblock
|
|
21
22
|
def setup
|
22
23
|
end
|
23
24
|
|
25
|
+
def execute_command(command)
|
26
|
+
command.response = ProtocolError.new 'command-not-acceptable', "Did not understand command for component #{id}", call_id, id
|
27
|
+
end
|
28
|
+
|
29
|
+
def send_complete_event(reason)
|
30
|
+
event = Punchblock::Event::Complete.new.tap do |c|
|
31
|
+
c.reason = reason
|
32
|
+
end
|
33
|
+
send_event event
|
34
|
+
current_actor.terminate!
|
35
|
+
end
|
36
|
+
|
37
|
+
def send_event(event)
|
38
|
+
event.component_id = id
|
39
|
+
event.call_id = call_id
|
40
|
+
pb_logger.debug "Sending event #{event}"
|
41
|
+
if internal
|
42
|
+
@component_node.add_event event
|
43
|
+
else
|
44
|
+
translator.connection.handle_event event
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def logger_id
|
49
|
+
"#{self.class}: #{call ? "Call ID: #{call.id}, Component ID: #{id}" : id}"
|
50
|
+
end
|
51
|
+
|
52
|
+
def call_id
|
53
|
+
call.id if call
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def translator
|
59
|
+
call.translator
|
60
|
+
end
|
61
|
+
|
24
62
|
def set_node_response(value)
|
25
63
|
pb_logger.debug "Setting response on component node to #{value}"
|
26
64
|
@component_node.response = value
|
@@ -33,18 +71,6 @@ module Punchblock
|
|
33
71
|
def with_error(name, text)
|
34
72
|
set_node_response ProtocolError.new(name, text)
|
35
73
|
end
|
36
|
-
|
37
|
-
def complete_event(reason)
|
38
|
-
Punchblock::Event::Complete.new.tap do |c|
|
39
|
-
c.reason = reason
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def send_event(event)
|
44
|
-
event.component_id = id
|
45
|
-
pb_logger.debug "Sending event #{event}"
|
46
|
-
@component_node.add_event event
|
47
|
-
end
|
48
74
|
end
|
49
75
|
end
|
50
76
|
end
|
@@ -22,7 +22,7 @@ module Punchblock
|
|
22
22
|
if event.name == 'AsyncAGI'
|
23
23
|
if event['SubEvent'] == 'Exec'
|
24
24
|
pb_logger.debug "Received AsyncAGI:Exec event, sending complete event."
|
25
|
-
|
25
|
+
send_complete_event success_reason(event)
|
26
26
|
end
|
27
27
|
end
|
28
28
|
end
|
@@ -4,10 +4,10 @@ module Punchblock
|
|
4
4
|
module Component
|
5
5
|
module Asterisk
|
6
6
|
class AMIAction < Component
|
7
|
-
attr_reader :action
|
7
|
+
attr_reader :action, :translator
|
8
8
|
|
9
9
|
def initialize(component_node, translator)
|
10
|
-
super
|
10
|
+
super component_node, nil
|
11
11
|
@translator = translator
|
12
12
|
end
|
13
13
|
|
@@ -21,6 +21,17 @@ module Punchblock
|
|
21
21
|
send_ref
|
22
22
|
end
|
23
23
|
|
24
|
+
def handle_response(response)
|
25
|
+
pb_logger.debug "Handling response #{response.inspect}"
|
26
|
+
case response
|
27
|
+
when RubyAMI::Error
|
28
|
+
send_complete_event error_reason(response)
|
29
|
+
when RubyAMI::Response
|
30
|
+
send_events
|
31
|
+
send_complete_event success_reason(response)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
24
35
|
private
|
25
36
|
|
26
37
|
def create_action
|
@@ -28,8 +39,9 @@ module Punchblock
|
|
28
39
|
@component_node.params_hash.each_pair do |key, value|
|
29
40
|
headers[key.to_s.capitalize] = value
|
30
41
|
end
|
42
|
+
component = current_actor
|
31
43
|
RubyAMI::Action.new @component_node.name, headers do |response|
|
32
|
-
handle_response response
|
44
|
+
component.handle_response! response
|
33
45
|
end
|
34
46
|
end
|
35
47
|
|
@@ -37,17 +49,6 @@ module Punchblock
|
|
37
49
|
@translator.send_ami_action! @action
|
38
50
|
end
|
39
51
|
|
40
|
-
def handle_response(response)
|
41
|
-
pb_logger.debug "Handling response #{response.inspect}"
|
42
|
-
case response
|
43
|
-
when RubyAMI::Error
|
44
|
-
send_event complete_event(error_reason(response))
|
45
|
-
when RubyAMI::Response
|
46
|
-
send_events
|
47
|
-
send_event complete_event(success_reason(response))
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
52
|
def error_reason(response)
|
52
53
|
Punchblock::Event::Complete::Error.new :details => response.message
|
53
54
|
end
|
@@ -47,7 +47,7 @@ module Punchblock
|
|
47
47
|
send_ref
|
48
48
|
@call.send_agi_action! 'EXEC MRCPSynth', doc, mrcpsynth_options do |complete_event|
|
49
49
|
pb_logger.debug "MRCPSynth completed with #{complete_event}."
|
50
|
-
|
50
|
+
send_complete_event success_reason
|
51
51
|
end
|
52
52
|
end
|
53
53
|
end
|
@@ -57,7 +57,7 @@ module Punchblock
|
|
57
57
|
pb_logger.debug "Received action completion. Now waiting on #{@pending_actions} actions."
|
58
58
|
if @pending_actions < 1
|
59
59
|
pb_logger.debug "Sending complete event"
|
60
|
-
|
60
|
+
send_complete_event success_reason
|
61
61
|
end
|
62
62
|
end
|
63
63
|
|
data/lib/punchblock/version.rb
CHANGED
@@ -42,6 +42,11 @@ module Punchblock
|
|
42
42
|
subject.ami_client.expects(:stop).once
|
43
43
|
subject.stop
|
44
44
|
end
|
45
|
+
|
46
|
+
it 'shuts down the translator' do
|
47
|
+
subject.translator.expects(:shutdown!).once
|
48
|
+
subject.stop
|
49
|
+
end
|
45
50
|
end
|
46
51
|
|
47
52
|
it 'sends events from RubyAMI to the translator' do
|
@@ -7,6 +7,64 @@ module Punchblock
|
|
7
7
|
RayoNode.class_from_registration(:complete, 'urn:xmpp:rayo:ext:1').should == Complete
|
8
8
|
end
|
9
9
|
|
10
|
+
describe "comparing for equality" do
|
11
|
+
subject do
|
12
|
+
Complete.new.tap do |c|
|
13
|
+
c.reason = Complete::Stop.new
|
14
|
+
c.call_id = '1234'
|
15
|
+
c.component_id = 'abcd'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
let :other_complete do
|
20
|
+
Complete.new.tap do |c|
|
21
|
+
c.reason = reason
|
22
|
+
c.call_id = call_id
|
23
|
+
c.component_id = component_id
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'with reason, call id and component id the same' do
|
28
|
+
let(:reason) { Complete::Stop.new }
|
29
|
+
let(:call_id) { '1234' }
|
30
|
+
let(:component_id) { 'abcd' }
|
31
|
+
|
32
|
+
it "should be equal" do
|
33
|
+
subject.should == other_complete
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'with a different reason' do
|
38
|
+
let(:reason) { Complete::Hangup.new }
|
39
|
+
let(:call_id) { '1234' }
|
40
|
+
let(:component_id) { 'abcd' }
|
41
|
+
|
42
|
+
it "should not be equal" do
|
43
|
+
subject.should_not == other_complete
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'with a different call id' do
|
48
|
+
let(:reason) { Complete::Stop.new }
|
49
|
+
let(:call_id) { '5678' }
|
50
|
+
let(:component_id) { 'abcd' }
|
51
|
+
|
52
|
+
it "should not be equal" do
|
53
|
+
subject.should_not == other_complete
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'with a different component id' do
|
58
|
+
let(:reason) { Complete::Stop.new }
|
59
|
+
let(:call_id) { '1234' }
|
60
|
+
let(:component_id) { 'efgh' }
|
61
|
+
|
62
|
+
it "should not be equal" do
|
63
|
+
subject.should_not == other_complete
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
10
68
|
describe "from a stanza" do
|
11
69
|
let :stanza do
|
12
70
|
<<-MESSAGE
|
@@ -64,6 +64,13 @@ module Punchblock
|
|
64
64
|
its(:translator) { should be translator }
|
65
65
|
its(:agi_env) { should == agi_env }
|
66
66
|
|
67
|
+
describe '#shutdown' do
|
68
|
+
it 'should terminate the actor' do
|
69
|
+
subject.shutdown
|
70
|
+
subject.should_not be_alive
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
67
74
|
describe '#register_component' do
|
68
75
|
it 'should make the component accessible by ID' do
|
69
76
|
component_id = 'abc123'
|
@@ -149,6 +156,15 @@ module Punchblock
|
|
149
156
|
end
|
150
157
|
end
|
151
158
|
|
159
|
+
let(:cause) { '16' }
|
160
|
+
let(:cause_txt) { 'Normal Clearing' }
|
161
|
+
|
162
|
+
it "should cause the actor to be terminated" do
|
163
|
+
translator.expects(:handle_pb_event!).once
|
164
|
+
subject.process_ami_event ami_event
|
165
|
+
subject.should_not be_alive
|
166
|
+
end
|
167
|
+
|
152
168
|
context "with a normal clearing cause" do
|
153
169
|
let(:cause) { '16' }
|
154
170
|
let(:cause_txt) { 'Normal Clearing' }
|
@@ -367,7 +383,8 @@ module Punchblock
|
|
367
383
|
let(:command) { Command::Accept.new }
|
368
384
|
|
369
385
|
it "should send an EXEC RINGING AGI command and set the command's response" do
|
370
|
-
subject.execute_command command
|
386
|
+
component = subject.execute_command command
|
387
|
+
component.internal.should be_true
|
371
388
|
agi_command = subject.wrapped_object.instance_variable_get(:'@current_agi_command')
|
372
389
|
agi_command.name.should == "EXEC RINGING"
|
373
390
|
agi_command.execute!
|
@@ -380,7 +397,8 @@ module Punchblock
|
|
380
397
|
let(:command) { Command::Answer.new }
|
381
398
|
|
382
399
|
it "should send an EXEC ANSWER AGI command and set the command's response" do
|
383
|
-
subject.execute_command command
|
400
|
+
component = subject.execute_command command
|
401
|
+
component.internal.should be_true
|
384
402
|
agi_command = subject.wrapped_object.instance_variable_get(:'@current_agi_command')
|
385
403
|
agi_command.name.should == "EXEC ANSWER"
|
386
404
|
agi_command.execute!
|
@@ -409,6 +427,7 @@ module Punchblock
|
|
409
427
|
let(:mock_action) { mock 'Component::Asterisk::AGI::Command', :id => 'foo' }
|
410
428
|
|
411
429
|
it 'should create an AGI command component actor and execute it asynchronously' do
|
430
|
+
mock_action.expects(:internal=).never
|
412
431
|
Component::Asterisk::AGICommand.expects(:new).once.with(command, subject).returns mock_action
|
413
432
|
mock_action.expects(:execute!).once
|
414
433
|
subject.execute_command command
|
@@ -424,6 +443,7 @@ module Punchblock
|
|
424
443
|
|
425
444
|
it 'should create an AGI command component actor and execute it asynchronously' do
|
426
445
|
Component::Asterisk::Output.expects(:new).once.with(command, subject).returns mock_action
|
446
|
+
mock_action.expects(:internal=).never
|
427
447
|
mock_action.expects(:execute!).once
|
428
448
|
subject.execute_command command
|
429
449
|
end
|
@@ -438,6 +458,7 @@ module Punchblock
|
|
438
458
|
|
439
459
|
it 'should create an AGI command component actor and execute it asynchronously' do
|
440
460
|
Component::Asterisk::Input.expects(:new).once.with(command, subject).returns mock_action
|
461
|
+
mock_action.expects(:internal=).never
|
441
462
|
mock_action.expects(:execute!).once
|
442
463
|
subject.execute_command command
|
443
464
|
end
|
@@ -454,11 +475,31 @@ module Punchblock
|
|
454
475
|
mock 'Component', :id => component_id
|
455
476
|
end
|
456
477
|
|
457
|
-
|
478
|
+
context "for a known component ID" do
|
479
|
+
before { subject.register_component mock_component }
|
480
|
+
|
481
|
+
it 'should send the command to the component for execution' do
|
482
|
+
mock_component.expects(:execute_command!).once
|
483
|
+
subject.execute_command command
|
484
|
+
end
|
485
|
+
end
|
486
|
+
|
487
|
+
context "for an unknown component ID" do
|
488
|
+
it 'sends an error in response to the command' do
|
489
|
+
subject.execute_command command
|
490
|
+
command.response.should == ProtocolError.new('component-not-found', "Could not find a component with ID #{component_id} for call #{subject.id}", subject.id, component_id)
|
491
|
+
end
|
492
|
+
end
|
493
|
+
end
|
494
|
+
|
495
|
+
context 'with a command we do not understand' do
|
496
|
+
let :command do
|
497
|
+
Punchblock::Component::Record.new
|
498
|
+
end
|
458
499
|
|
459
|
-
it '
|
460
|
-
mock_component.expects(:execute_command!).once
|
500
|
+
it 'sends an error in response to the command' do
|
461
501
|
subject.execute_command command
|
502
|
+
command.response.should == ProtocolError.new('command-not-acceptable', "Did not understand command for call #{subject.id}", subject.id)
|
462
503
|
end
|
463
504
|
end
|
464
505
|
end
|
@@ -7,7 +7,13 @@ module Punchblock
|
|
7
7
|
module Asterisk
|
8
8
|
describe AGICommand do
|
9
9
|
let(:channel) { 'SIP/foo' }
|
10
|
-
let(:
|
10
|
+
let(:connection) do
|
11
|
+
mock_connection_with_event_handler do |event|
|
12
|
+
command.add_event event
|
13
|
+
end
|
14
|
+
end
|
15
|
+
let(:translator) { Punchblock::Translator::Asterisk.new mock('AMI'), connection }
|
16
|
+
let(:mock_call) { Punchblock::Translator::Asterisk::Call.new channel, translator }
|
11
17
|
let(:component_id) { UUIDTools::UUID.random_create }
|
12
18
|
|
13
19
|
before { UUIDTools::UUID.stubs :random_create => component_id }
|
@@ -112,7 +118,7 @@ module Punchblock
|
|
112
118
|
|
113
119
|
complete_event = command.complete_event 0.5
|
114
120
|
|
115
|
-
complete_event.component_id.should ==
|
121
|
+
complete_event.component_id.should == component_id.to_s
|
116
122
|
complete_event.reason.should == expected_complete_reason
|
117
123
|
end
|
118
124
|
end
|
@@ -6,7 +6,12 @@ module Punchblock
|
|
6
6
|
module Component
|
7
7
|
module Asterisk
|
8
8
|
describe AMIAction do
|
9
|
-
let(:
|
9
|
+
let(:connection) do
|
10
|
+
mock_connection_with_event_handler do |event|
|
11
|
+
command.add_event event
|
12
|
+
end
|
13
|
+
end
|
14
|
+
let(:mock_translator) { Punchblock::Translator::Asterisk.new mock('AMI'), connection }
|
10
15
|
|
11
16
|
let :command do
|
12
17
|
Punchblock::Component::Asterisk::AMI::Action.new :name => 'ExtensionStatus', :params => { :context => 'default', :exten => 'idonno' }
|
@@ -57,14 +62,8 @@ module Punchblock
|
|
57
62
|
|
58
63
|
context 'for a non-causal action' do
|
59
64
|
it 'should send a complete event to the component node' do
|
60
|
-
subject.
|
61
|
-
|
62
|
-
command.should be_complete
|
63
|
-
|
64
|
-
complete_event = command.complete_event 0.5
|
65
|
-
|
66
|
-
complete_event.component_id.should == subject.id
|
67
|
-
complete_event.reason.should == expected_complete_reason
|
65
|
+
subject.wrapped_object.expects(:send_complete_event).once.with expected_complete_reason
|
66
|
+
subject.handle_response response
|
68
67
|
end
|
69
68
|
end
|
70
69
|
|
@@ -115,12 +114,14 @@ module Punchblock
|
|
115
114
|
end
|
116
115
|
|
117
116
|
it 'should send events to the component node' do
|
117
|
+
event_node
|
118
118
|
command.register_handler :internal, Punchblock::Event::Asterisk::AMI::Event do |event|
|
119
119
|
@event = event
|
120
120
|
end
|
121
|
-
subject.action
|
122
|
-
|
123
|
-
subject.
|
121
|
+
action = subject.action
|
122
|
+
action << event
|
123
|
+
subject.handle_response response
|
124
|
+
action << terminating_event
|
124
125
|
@event.should == event_node
|
125
126
|
end
|
126
127
|
|
@@ -138,16 +139,12 @@ module Punchblock
|
|
138
139
|
end
|
139
140
|
|
140
141
|
let :expected_complete_reason do
|
141
|
-
Punchblock::Event::Complete::Error.new :
|
142
|
+
Punchblock::Event::Complete::Error.new :details => 'Action failed'
|
142
143
|
end
|
143
144
|
|
144
145
|
it 'should send a complete event to the component node' do
|
145
|
-
subject.
|
146
|
-
|
147
|
-
complete_event = command.complete_event 0.5
|
148
|
-
|
149
|
-
complete_event.component_id.should == subject.id
|
150
|
-
complete_event.reason.should == expected_complete_reason
|
146
|
+
subject.wrapped_object.expects(:send_complete_event).once.with expected_complete_reason
|
147
|
+
subject.handle_response error
|
151
148
|
end
|
152
149
|
end
|
153
150
|
end
|
@@ -6,10 +6,15 @@ module Punchblock
|
|
6
6
|
module Component
|
7
7
|
module Asterisk
|
8
8
|
describe Input do
|
9
|
+
let(:connection) do
|
10
|
+
mock_connection_with_event_handler do |event|
|
11
|
+
command.add_event event
|
12
|
+
end
|
13
|
+
end
|
9
14
|
let(:media_engine) { nil }
|
10
|
-
let(:translator) { Punchblock::Translator::Asterisk.new mock('AMI'),
|
15
|
+
let(:translator) { Punchblock::Translator::Asterisk.new mock('AMI'), connection, media_engine }
|
11
16
|
let(:call) { Punchblock::Translator::Asterisk::Call.new 'foo', translator }
|
12
|
-
let(:command_options) {
|
17
|
+
let(:command_options) { {} }
|
13
18
|
|
14
19
|
let :command do
|
15
20
|
Punchblock::Component::Input.new command_options
|
@@ -31,12 +36,6 @@ module Punchblock
|
|
31
36
|
end
|
32
37
|
end
|
33
38
|
|
34
|
-
let :command_options do
|
35
|
-
{
|
36
|
-
|
37
|
-
}
|
38
|
-
end
|
39
|
-
|
40
39
|
subject { Input.new command, call }
|
41
40
|
|
42
41
|
describe '#execute' do
|
@@ -72,7 +71,10 @@ module Punchblock
|
|
72
71
|
let(:reason) { command.complete_event(5).reason }
|
73
72
|
|
74
73
|
describe "receiving DTMF events" do
|
75
|
-
before
|
74
|
+
before do
|
75
|
+
subject.execute
|
76
|
+
expected_event
|
77
|
+
end
|
76
78
|
|
77
79
|
context "when a match is found" do
|
78
80
|
before do
|
@@ -80,8 +82,17 @@ module Punchblock
|
|
80
82
|
send_ami_events_for_dtmf 2
|
81
83
|
end
|
82
84
|
|
85
|
+
let :expected_event do
|
86
|
+
Punchblock::Component::Input::Complete::Success.new :mode => :dtmf,
|
87
|
+
:confidence => 1,
|
88
|
+
:utterance => '12',
|
89
|
+
:interpretation => 'dtmf-1 dtmf-2',
|
90
|
+
:component_id => subject.id,
|
91
|
+
:call_id => call.id
|
92
|
+
end
|
93
|
+
|
83
94
|
it "should send a success complete event with the relevant data" do
|
84
|
-
reason.should ==
|
95
|
+
reason.should == expected_event
|
85
96
|
end
|
86
97
|
end
|
87
98
|
|
@@ -91,8 +102,13 @@ module Punchblock
|
|
91
102
|
send_ami_events_for_dtmf '#'
|
92
103
|
end
|
93
104
|
|
105
|
+
let :expected_event do
|
106
|
+
Punchblock::Component::Input::Complete::NoMatch.new :component_id => subject.id,
|
107
|
+
:call_id => call.id
|
108
|
+
end
|
109
|
+
|
94
110
|
it "should send a nomatch complete event" do
|
95
|
-
reason.should ==
|
111
|
+
reason.should == expected_event
|
96
112
|
end
|
97
113
|
end
|
98
114
|
end
|
@@ -6,10 +6,14 @@ module Punchblock
|
|
6
6
|
module Component
|
7
7
|
module Asterisk
|
8
8
|
describe Output do
|
9
|
-
let(:
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
let(:connection) do
|
10
|
+
mock_connection_with_event_handler do |event|
|
11
|
+
command.add_event event
|
12
|
+
end
|
13
|
+
end
|
14
|
+
let(:media_engine) { nil }
|
15
|
+
let(:translator) { Punchblock::Translator::Asterisk.new mock('AMI'), connection, media_engine }
|
16
|
+
let(:mock_call) { Punchblock::Translator::Asterisk::Call.new 'foo', translator }
|
13
17
|
|
14
18
|
let :command do
|
15
19
|
Punchblock::Component::Output.new command_options
|
@@ -316,7 +320,7 @@ module Punchblock
|
|
316
320
|
end
|
317
321
|
subject.execute
|
318
322
|
latch.wait 2
|
319
|
-
sleep
|
323
|
+
sleep 2
|
320
324
|
end
|
321
325
|
|
322
326
|
it 'should send a complete event after the final file has finished playback' do
|
@@ -6,6 +6,87 @@ module Punchblock
|
|
6
6
|
describe Component do
|
7
7
|
|
8
8
|
end
|
9
|
+
|
10
|
+
module Component
|
11
|
+
describe Component do
|
12
|
+
let(:connection) { Punchblock::Connection::Asterisk.new }
|
13
|
+
let(:translator) { connection.translator }
|
14
|
+
let(:call) { Punchblock::Translator::Asterisk::Call.new 'foo', translator }
|
15
|
+
let(:command) { Punchblock::Component::Input.new }
|
16
|
+
|
17
|
+
subject { Component.new command, call }
|
18
|
+
|
19
|
+
before { command.request! }
|
20
|
+
|
21
|
+
describe "#send_event" do
|
22
|
+
before { command.execute! }
|
23
|
+
|
24
|
+
let :event do
|
25
|
+
Punchblock::Event::Complete.new
|
26
|
+
end
|
27
|
+
|
28
|
+
let :expected_event do
|
29
|
+
Punchblock::Event::Complete.new.tap do |e|
|
30
|
+
e.call_id = call.id
|
31
|
+
e.component_id = subject.id
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should send the event to the connection" do
|
36
|
+
connection.expects(:handle_event).once.with expected_event
|
37
|
+
subject.send_event event
|
38
|
+
end
|
39
|
+
|
40
|
+
context "when marked internal" do
|
41
|
+
before { subject.internal = true }
|
42
|
+
|
43
|
+
it "should add the event to the command" do
|
44
|
+
command.expects(:add_event).once.with expected_event
|
45
|
+
subject.send_event event
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "#send_complete_event" do
|
51
|
+
before { command.execute! }
|
52
|
+
|
53
|
+
let(:reason) { Punchblock::Event::Complete::Stop.new }
|
54
|
+
let :expected_event do
|
55
|
+
Punchblock::Event::Complete.new.tap do |c|
|
56
|
+
c.reason = Punchblock::Event::Complete::Stop.new
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should send a complete event with the specified reason" do
|
61
|
+
subject.wrapped_object.expects(:send_event).once.with expected_event
|
62
|
+
subject.send_complete_event reason
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should cause the actor to be shut down" do
|
66
|
+
subject.wrapped_object.stubs(:send_event).returns true
|
67
|
+
subject.send_complete_event reason
|
68
|
+
subject.should_not be_alive
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe '#execute_command' do
|
73
|
+
before do
|
74
|
+
component_command.request!
|
75
|
+
end
|
76
|
+
|
77
|
+
context 'with a command we do not understand' do
|
78
|
+
let :component_command do
|
79
|
+
Punchblock::Component::Stop.new :component_id => subject.id
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'sends an error in response to the command' do
|
83
|
+
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)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
9
90
|
end
|
10
91
|
end
|
11
92
|
end
|
@@ -14,7 +14,7 @@ module Punchblock
|
|
14
14
|
its(:ami_client) { should be ami_client }
|
15
15
|
its(:connection) { should be connection }
|
16
16
|
|
17
|
-
after { translator.terminate }
|
17
|
+
after { translator.terminate if translator.alive? }
|
18
18
|
|
19
19
|
context 'with a configured media engine of :asterisk' do
|
20
20
|
let(:media_engine) { :asterisk }
|
@@ -26,6 +26,20 @@ module Punchblock
|
|
26
26
|
its(:media_engine) { should == :unimrcp }
|
27
27
|
end
|
28
28
|
|
29
|
+
describe '#shutdown' do
|
30
|
+
it "instructs all calls to shutdown" do
|
31
|
+
call = Asterisk::Call.new 'foo', subject
|
32
|
+
call.expects(:shutdown!).once
|
33
|
+
subject.register_call call
|
34
|
+
subject.shutdown
|
35
|
+
end
|
36
|
+
|
37
|
+
it "terminates the actor" do
|
38
|
+
subject.shutdown
|
39
|
+
subject.should_not be_alive
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
29
43
|
describe '#execute_command' do
|
30
44
|
describe 'with a call command' do
|
31
45
|
let(:command) { Command::Answer.new }
|
@@ -95,16 +109,29 @@ module Punchblock
|
|
95
109
|
describe '#execute_call_command' do
|
96
110
|
let(:call_id) { 'abc123' }
|
97
111
|
let(:call) { Translator::Asterisk::Call.new 'SIP/foo', subject }
|
98
|
-
let(:command) {
|
112
|
+
let(:command) { Command::Answer.new.tap { |c| c.call_id = call_id } }
|
99
113
|
|
100
114
|
before do
|
115
|
+
command.request!
|
101
116
|
call.stubs(:id).returns call_id
|
102
|
-
subject.register_call call
|
103
117
|
end
|
104
118
|
|
105
|
-
|
106
|
-
|
107
|
-
|
119
|
+
context "with a known call ID" do
|
120
|
+
before do
|
121
|
+
subject.register_call call
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'sends the command to the call for execution' do
|
125
|
+
call.expects(:execute_command!).once.with command
|
126
|
+
subject.execute_call_command command
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
context "with an unknown call ID" do
|
131
|
+
it 'sends an error in response to the command' do
|
132
|
+
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)
|
134
|
+
end
|
108
135
|
end
|
109
136
|
end
|
110
137
|
|
@@ -112,15 +139,28 @@ module Punchblock
|
|
112
139
|
let(:component_id) { '123abc' }
|
113
140
|
let(:component) { mock 'Translator::Asterisk::Component', :id => component_id }
|
114
141
|
|
115
|
-
let(:command) {
|
142
|
+
let(:command) { Component::Stop.new.tap { |c| c.component_id = component_id } }
|
116
143
|
|
117
144
|
before do
|
118
|
-
|
145
|
+
command.request!
|
119
146
|
end
|
120
147
|
|
121
|
-
|
122
|
-
|
123
|
-
|
148
|
+
context 'with a known component ID' do
|
149
|
+
before do
|
150
|
+
subject.register_component component
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'sends the command to the component for execution' do
|
154
|
+
component.expects(:execute_command!).once.with command
|
155
|
+
subject.execute_component_command command
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
context "with an unknown component ID" do
|
160
|
+
it 'sends an error in response to the command' do
|
161
|
+
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)
|
163
|
+
end
|
124
164
|
end
|
125
165
|
end
|
126
166
|
|
@@ -130,9 +170,10 @@ module Punchblock
|
|
130
170
|
Command::Dial.new :to => 'SIP/1234', :from => 'abc123'
|
131
171
|
end
|
132
172
|
|
133
|
-
before
|
134
|
-
|
135
|
-
|
173
|
+
before do
|
174
|
+
command.request!
|
175
|
+
ami_client.stub_everything
|
176
|
+
end
|
136
177
|
|
137
178
|
it 'should be able to look up the call by channel ID' do
|
138
179
|
subject.execute_global_command command
|
@@ -167,6 +208,17 @@ module Punchblock
|
|
167
208
|
subject.execute_global_command command
|
168
209
|
end
|
169
210
|
end
|
211
|
+
|
212
|
+
context "with a command we don't understand" do
|
213
|
+
let :command do
|
214
|
+
Command::Answer.new
|
215
|
+
end
|
216
|
+
|
217
|
+
it 'sends an error in response to the command' do
|
218
|
+
subject.execute_command command
|
219
|
+
command.response.should == ProtocolError.new('command-not-acceptable', "Did not understand command")
|
220
|
+
end
|
221
|
+
end
|
170
222
|
end
|
171
223
|
|
172
224
|
describe '#handle_pb_event' do
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# This is a nasty hack due to the fact that Mocha does not support expectations returning a value calculated by executing a block with the parameters passed.
|
2
|
+
# If it did, we could do this in our component tests:
|
3
|
+
# mc = mock 'Connection'
|
4
|
+
# mc.stubs(:handle_event).returns { |event| command.add_event event }
|
5
|
+
#
|
6
|
+
# Mocha does not support this feature because really, it's a smell in the tests
|
7
|
+
# We shouldn't really be mocking out behaviour like this if we actually need it to have side effects
|
8
|
+
# We only do this because of the difficulties in synchronising the tests with an asynchronous target in another thread.
|
9
|
+
#
|
10
|
+
def mock_connection_with_event_handler(&block)
|
11
|
+
mock('Connection').tap do |mc|
|
12
|
+
class << mc
|
13
|
+
attr_accessor :target
|
14
|
+
end
|
15
|
+
|
16
|
+
mc.target = block
|
17
|
+
|
18
|
+
def mc.handle_event(event)
|
19
|
+
target.call event
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
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.3
|
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-17 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: niceogiri
|
18
|
-
requirement: &
|
18
|
+
requirement: &2155905140 !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: *2155905140
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: blather
|
29
|
-
requirement: &
|
29
|
+
requirement: &2155903300 !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: *2155903300
|
38
38
|
- !ruby/object:Gem::Dependency
|
39
39
|
name: activesupport
|
40
|
-
requirement: &
|
40
|
+
requirement: &2155901420 !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: *2155901420
|
49
49
|
- !ruby/object:Gem::Dependency
|
50
50
|
name: state_machine
|
51
|
-
requirement: &
|
51
|
+
requirement: &2168536880 !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: *2168536880
|
60
60
|
- !ruby/object:Gem::Dependency
|
61
61
|
name: future-resource
|
62
|
-
requirement: &
|
62
|
+
requirement: &2168535180 !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: *2168535180
|
71
71
|
- !ruby/object:Gem::Dependency
|
72
72
|
name: has-guarded-handlers
|
73
|
-
requirement: &
|
73
|
+
requirement: &2168531860 !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: *2168531860
|
82
82
|
- !ruby/object:Gem::Dependency
|
83
83
|
name: celluloid
|
84
|
-
requirement: &
|
84
|
+
requirement: &2168527860 !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: *2168527860
|
93
93
|
- !ruby/object:Gem::Dependency
|
94
94
|
name: ruby_ami
|
95
|
-
requirement: &
|
95
|
+
requirement: &2168526320 !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: *2168526320
|
104
104
|
- !ruby/object:Gem::Dependency
|
105
105
|
name: ruby_speech
|
106
|
-
requirement: &
|
106
|
+
requirement: &2168524860 !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: *2168524860
|
115
115
|
- !ruby/object:Gem::Dependency
|
116
116
|
name: bundler
|
117
|
-
requirement: &
|
117
|
+
requirement: &2168523980 !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: *2168523980
|
126
126
|
- !ruby/object:Gem::Dependency
|
127
127
|
name: rspec
|
128
|
-
requirement: &
|
128
|
+
requirement: &2168522200 !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: *2168522200
|
137
137
|
- !ruby/object:Gem::Dependency
|
138
138
|
name: ci_reporter
|
139
|
-
requirement: &
|
139
|
+
requirement: &2168516560 !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: *2168516560
|
148
148
|
- !ruby/object:Gem::Dependency
|
149
149
|
name: yard
|
150
|
-
requirement: &
|
150
|
+
requirement: &2168515600 !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: *2168515600
|
159
159
|
- !ruby/object:Gem::Dependency
|
160
160
|
name: rcov
|
161
|
-
requirement: &
|
161
|
+
requirement: &2168475680 !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: *2168475680
|
170
170
|
- !ruby/object:Gem::Dependency
|
171
171
|
name: rake
|
172
|
-
requirement: &
|
172
|
+
requirement: &2168496000 !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: *2168496000
|
181
181
|
- !ruby/object:Gem::Dependency
|
182
182
|
name: mocha
|
183
|
-
requirement: &
|
183
|
+
requirement: &2152431080 !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: *2152431080
|
192
192
|
- !ruby/object:Gem::Dependency
|
193
193
|
name: i18n
|
194
|
-
requirement: &
|
194
|
+
requirement: &2152427440 !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: *2152427440
|
203
203
|
- !ruby/object:Gem::Dependency
|
204
204
|
name: countdownlatch
|
205
|
-
requirement: &
|
205
|
+
requirement: &2152370940 !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: *2152370940
|
214
214
|
- !ruby/object:Gem::Dependency
|
215
215
|
name: guard-rspec
|
216
|
-
requirement: &
|
216
|
+
requirement: &2152361220 !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: *2152361220
|
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
|
@@ -348,6 +348,7 @@ files:
|
|
348
348
|
- spec/punchblock/translator/asterisk/component_spec.rb
|
349
349
|
- spec/punchblock/translator/asterisk_spec.rb
|
350
350
|
- spec/spec_helper.rb
|
351
|
+
- spec/support/mock_connection_with_event_handler.rb
|
351
352
|
homepage: http://github.com/adhearsion/punchblock
|
352
353
|
licenses:
|
353
354
|
- MIT
|
@@ -363,7 +364,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
363
364
|
version: '0'
|
364
365
|
segments:
|
365
366
|
- 0
|
366
|
-
hash:
|
367
|
+
hash: 243839831400829248
|
367
368
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
368
369
|
none: false
|
369
370
|
requirements:
|
@@ -419,3 +420,4 @@ test_files:
|
|
419
420
|
- spec/punchblock/translator/asterisk/component_spec.rb
|
420
421
|
- spec/punchblock/translator/asterisk_spec.rb
|
421
422
|
- spec/spec_helper.rb
|
423
|
+
- spec/support/mock_connection_with_event_handler.rb
|