punchblock 0.8.2 → 0.8.3
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/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
|