adhearsion 2.0.0.alpha3 → 2.0.0.beta1
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 +13 -1
- data/README.markdown +1 -1
- data/features/cli_daemon.feature +2 -3
- data/features/step_definitions/cli_steps.rb +0 -1
- data/lib/adhearsion/call.rb +50 -32
- data/lib/adhearsion/call_controller.rb +53 -4
- data/lib/adhearsion/call_controller/dial.rb +26 -6
- data/lib/adhearsion/call_controller/input.rb +1 -1
- data/lib/adhearsion/call_controller/menu.rb +2 -2
- data/lib/adhearsion/call_controller/output.rb +11 -11
- data/lib/adhearsion/call_controller/utility.rb +3 -3
- data/lib/adhearsion/calls.rb +0 -4
- data/lib/adhearsion/cli_commands.rb +2 -3
- data/lib/adhearsion/console.rb +42 -14
- data/lib/adhearsion/foundation/thread_safety.rb +8 -2
- data/lib/adhearsion/generators/app/templates/Rakefile +1 -4
- data/lib/adhearsion/initializer.rb +12 -5
- data/lib/adhearsion/logging.rb +23 -4
- data/lib/adhearsion/process.rb +11 -2
- data/lib/adhearsion/punchblock_plugin.rb +8 -0
- data/lib/adhearsion/punchblock_plugin/initializer.rb +11 -4
- data/lib/adhearsion/version.rb +1 -1
- data/spec/adhearsion/call_controller/dial_spec.rb +123 -85
- data/spec/adhearsion/call_controller/output_spec.rb +10 -0
- data/spec/adhearsion/call_controller_spec.rb +59 -52
- data/spec/adhearsion/call_spec.rb +47 -3
- data/spec/adhearsion/console_spec.rb +10 -1
- data/spec/adhearsion/initializer_spec.rb +5 -5
- data/spec/adhearsion/logging_spec.rb +17 -1
- data/spec/adhearsion/process_spec.rb +18 -0
- data/spec/adhearsion/punchblock_plugin/initializer_spec.rb +20 -8
- data/spec/adhearsion/punchblock_plugin_spec.rb +42 -0
- data/spec/spec_helper.rb +5 -1
- metadata +64 -64
@@ -7,7 +7,7 @@ module Adhearsion
|
|
7
7
|
# @param [Integer] Number of digits to accept in the grammar.
|
8
8
|
# @return [RubySpeech::GRXML::Grammar] A grammar suitable for use in SSML prompts
|
9
9
|
#
|
10
|
-
def grammar_digits(digits = 1)
|
10
|
+
def grammar_digits(digits = 1) # :nodoc:
|
11
11
|
RubySpeech::GRXML.draw :mode => 'dtmf', :root => 'inputdigits' do
|
12
12
|
rule id: 'inputdigits', scope: 'public' do
|
13
13
|
item repeat: digits.to_s do
|
@@ -24,7 +24,7 @@ module Adhearsion
|
|
24
24
|
# @param [String] String representing the digits to accept
|
25
25
|
# @return [RubySpeech::GRXML::Grammar] A grammar suitable for use in SSML prompts
|
26
26
|
#
|
27
|
-
def grammar_accept(digits = '0123456789#*')
|
27
|
+
def grammar_accept(digits = '0123456789#*') # :nodoc:
|
28
28
|
allowed_digits = '0123456789#*'
|
29
29
|
gram_digits = digits.chars.select { |x| allowed_digits.include? x }
|
30
30
|
|
@@ -43,7 +43,7 @@ module Adhearsion
|
|
43
43
|
# @param [String] the tone string to be parsed
|
44
44
|
# @return [String] the digit in case input was 0-9, * or # if star or pound respectively
|
45
45
|
#
|
46
|
-
def parse_single_dtmf(result)
|
46
|
+
def parse_single_dtmf(result) # :nodoc:
|
47
47
|
return if result.nil?
|
48
48
|
case tone = result.split('-')[1]
|
49
49
|
when 'star'
|
data/lib/adhearsion/calls.rb
CHANGED
@@ -68,13 +68,12 @@ module Adhearsion
|
|
68
68
|
def stop(path = nil)
|
69
69
|
execute_from_app_dir! path
|
70
70
|
|
71
|
-
path ||= '.'
|
72
|
-
|
73
71
|
pid_file = if options[:pidfile]
|
74
72
|
File.exists?(File.expand_path(options[:pidfile])) ?
|
75
73
|
options[:pidfile] :
|
76
74
|
File.join(path, options[:pidfile])
|
77
75
|
else
|
76
|
+
path = Dir.pwd
|
78
77
|
File.join path, Adhearsion::Initializer::DEFAULT_PID_FILE_NAME
|
79
78
|
end
|
80
79
|
pid_file = File.expand_path pid_file
|
@@ -118,7 +117,7 @@ module Adhearsion
|
|
118
117
|
def execute_from_app_dir!(path)
|
119
118
|
return if in_app? and running_script_ahn?
|
120
119
|
|
121
|
-
path ||=
|
120
|
+
path ||= Dir.pwd if in_app?
|
122
121
|
|
123
122
|
raise PathRequired, ARGV[0] if path.nil? or path.empty?
|
124
123
|
raise PathInvalid, path unless ScriptAhnLoader.in_ahn_application?(path)
|
data/lib/adhearsion/console.rb
CHANGED
@@ -28,23 +28,15 @@ module Adhearsion
|
|
28
28
|
# Start the Adhearsion console
|
29
29
|
#
|
30
30
|
def run
|
31
|
-
|
32
|
-
proc do |*args|
|
33
|
-
obj, nest_level, pry_instance = args
|
34
|
-
"AHN#{' ' * nest_level}> "
|
35
|
-
end,
|
36
|
-
proc do |*args|
|
37
|
-
obj, nest_level, pry_instance = args
|
38
|
-
"AHN#{' ' * nest_level}? "
|
39
|
-
end
|
40
|
-
]
|
31
|
+
set_prompt
|
41
32
|
Pry.config.command_prefix = "%"
|
42
33
|
if libedit?
|
43
34
|
logger.error "Cannot start. You are running Adhearsion on Ruby with libedit. You must use readline for the console to work."
|
44
35
|
else
|
45
36
|
logger.info "Starting up..."
|
46
37
|
@pry_thread = Thread.current
|
47
|
-
|
38
|
+
pry
|
39
|
+
logger.info "Console exiting"
|
48
40
|
end
|
49
41
|
end
|
50
42
|
|
@@ -82,7 +74,10 @@ module Adhearsion
|
|
82
74
|
logger.error "An active call with that ID does not exist"
|
83
75
|
end
|
84
76
|
when nil
|
85
|
-
|
77
|
+
case calls.size
|
78
|
+
when 0
|
79
|
+
logger.warn "No calls exist for control"
|
80
|
+
when 1
|
86
81
|
interact_with_call calls.values.first
|
87
82
|
else
|
88
83
|
puts "Please choose a call:"
|
@@ -97,6 +92,9 @@ module Adhearsion
|
|
97
92
|
else
|
98
93
|
raise ArgumentError
|
99
94
|
end
|
95
|
+
ensure
|
96
|
+
set_prompt
|
97
|
+
pry
|
100
98
|
end
|
101
99
|
|
102
100
|
def libedit?
|
@@ -111,16 +109,46 @@ module Adhearsion
|
|
111
109
|
|
112
110
|
private
|
113
111
|
|
112
|
+
def set_prompt
|
113
|
+
Pry.prompt = [
|
114
|
+
proc do |*args|
|
115
|
+
obj, nest_level, pry_instance = args
|
116
|
+
"AHN#{' ' * nest_level}> "
|
117
|
+
end,
|
118
|
+
proc do |*args|
|
119
|
+
obj, nest_level, pry_instance = args
|
120
|
+
"AHN#{' ' * nest_level}? "
|
121
|
+
end
|
122
|
+
]
|
123
|
+
end
|
124
|
+
|
114
125
|
def interact_with_call(call)
|
115
126
|
Pry.prompt = [ proc { "AHN<#{call.id}> " },
|
116
127
|
proc { "AHN<#{call.id}? " } ]
|
117
128
|
|
118
|
-
|
129
|
+
begin
|
130
|
+
call.pause_controllers
|
131
|
+
CallController.exec InteractiveController.new(call)
|
132
|
+
ensure
|
133
|
+
logger.debug "Resuming call's controllers"
|
134
|
+
call.resume_controllers
|
135
|
+
end
|
119
136
|
end
|
120
137
|
|
121
138
|
class InteractiveController < CallController
|
122
139
|
def run
|
123
|
-
|
140
|
+
logger.debug "Starting interactive controller."
|
141
|
+
begin
|
142
|
+
pry
|
143
|
+
rescue => e
|
144
|
+
logger.error e
|
145
|
+
end
|
146
|
+
logger.debug "Interactive controller finished."
|
147
|
+
end
|
148
|
+
|
149
|
+
def hangup(*args)
|
150
|
+
super
|
151
|
+
exit
|
124
152
|
end
|
125
153
|
end
|
126
154
|
end
|
@@ -8,8 +8,6 @@ class Object
|
|
8
8
|
end
|
9
9
|
|
10
10
|
class ThreadSafeArray
|
11
|
-
include Enumerable
|
12
|
-
|
13
11
|
def initialize
|
14
12
|
@mutex = Mutex.new
|
15
13
|
@array = []
|
@@ -20,4 +18,12 @@ class ThreadSafeArray
|
|
20
18
|
@array.send method, *args, &block
|
21
19
|
end
|
22
20
|
end
|
21
|
+
|
22
|
+
def inspect
|
23
|
+
@mutex.synchronize { @array.inspect }
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_s
|
27
|
+
@mutex.synchronize { @array.to_s }
|
28
|
+
end
|
23
29
|
end
|
@@ -111,14 +111,19 @@ module Adhearsion
|
|
111
111
|
def catch_termination_signal
|
112
112
|
%w'INT TERM'.each do |process_signal|
|
113
113
|
trap process_signal do
|
114
|
-
logger.info "Received #{process_signal}
|
114
|
+
logger.info "Received SIG#{process_signal}. Shutting down."
|
115
115
|
Adhearsion::Process.shutdown
|
116
116
|
end
|
117
117
|
end
|
118
118
|
|
119
|
-
trap '
|
120
|
-
logger.
|
121
|
-
Adhearsion::
|
119
|
+
trap 'HUP' do
|
120
|
+
logger.debug "Received SIGHUP. Reopening logfiles."
|
121
|
+
Adhearsion::Logging.reopen_logs
|
122
|
+
end
|
123
|
+
|
124
|
+
trap 'ALRM' do
|
125
|
+
logger.debug "Received SIGALRM. Toggling trace logging."
|
126
|
+
Adhearsion::Logging.toggle_trace!
|
122
127
|
end
|
123
128
|
|
124
129
|
trap 'ABRT' do
|
@@ -163,7 +168,9 @@ module Adhearsion
|
|
163
168
|
::Logging.appenders.file(f,
|
164
169
|
:layout => ::Logging.layouts.pattern(
|
165
170
|
:pattern => Adhearsion::Logging.adhearsion_pattern
|
166
|
-
)
|
171
|
+
),
|
172
|
+
:auto_flushing => 2,
|
173
|
+
:flush_period => 2
|
167
174
|
)
|
168
175
|
else
|
169
176
|
a
|
data/lib/adhearsion/logging.rb
CHANGED
@@ -24,16 +24,33 @@ module Adhearsion
|
|
24
24
|
'[%d] %-5l %c: %m\n'
|
25
25
|
end
|
26
26
|
|
27
|
+
# Silence Adhearsion's logging, printing only FATAL messages
|
27
28
|
def silence!
|
28
29
|
self.logging_level = :fatal
|
29
30
|
end
|
30
31
|
|
32
|
+
# Restore the default configured logging level
|
31
33
|
def unsilence!
|
32
|
-
self.logging_level =
|
34
|
+
self.logging_level = Adhearsion.config.platform.logging['level']
|
33
35
|
end
|
34
36
|
|
35
|
-
|
36
|
-
|
37
|
+
# Toggle between the configured log level and :trace
|
38
|
+
# Useful for debugging a live Adhearsion instance
|
39
|
+
def toggle_trace!
|
40
|
+
if level == ::Logging.level_num(Adhearsion.config.platform.logging['level'])
|
41
|
+
logger.warn "Turning TRACE logging ON."
|
42
|
+
self.level = :trace
|
43
|
+
else
|
44
|
+
logger.warn "Turning TRACE logging OFF."
|
45
|
+
self.level = Adhearsion.config.platform.logging['level']
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Close logfiles and reopen them. Useful for log rotation.
|
50
|
+
def reopen_logs
|
51
|
+
logger.info "Closing logfiles."
|
52
|
+
::Logging.reopen
|
53
|
+
logger.info "Logfiles reopened."
|
37
54
|
end
|
38
55
|
|
39
56
|
def init
|
@@ -58,7 +75,9 @@ module Adhearsion
|
|
58
75
|
:layout => ::Logging.layouts.pattern(
|
59
76
|
:pattern => adhearsion_pattern,
|
60
77
|
:color_scheme => 'bright'
|
61
|
-
)
|
78
|
+
),
|
79
|
+
:auto_flushing => 2,
|
80
|
+
:flush_period => 2
|
62
81
|
)]
|
63
82
|
end
|
64
83
|
|
data/lib/adhearsion/process.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'state_machine'
|
2
2
|
require 'singleton'
|
3
|
+
require 'socket'
|
3
4
|
|
4
5
|
module Adhearsion
|
5
6
|
class Process
|
@@ -9,7 +10,7 @@ module Adhearsion
|
|
9
10
|
before_transition :log_state_change
|
10
11
|
after_transition :on => :shutdown, :do => :request_stop
|
11
12
|
after_transition any => :stopped, :do => :final_shutdown
|
12
|
-
|
13
|
+
before_transition any => :force_stopped, :do => :die_now!
|
13
14
|
|
14
15
|
event :booted do
|
15
16
|
transition :booting => :running
|
@@ -27,8 +28,12 @@ module Adhearsion
|
|
27
28
|
# This corresponds to the admin pressing CTRL+C three times.
|
28
29
|
transition :rejecting => :stopped
|
29
30
|
|
31
|
+
# On the fourth shutdown request, we are probably hung.
|
32
|
+
# Attempt no more graceful shutdown and exit as quickly as possible.
|
33
|
+
transition :stopped => :force_stopped
|
34
|
+
|
30
35
|
# If we are still booting, transition directly to stopped
|
31
|
-
transition :booting => :
|
36
|
+
transition :booting => :force_stopped
|
32
37
|
end
|
33
38
|
|
34
39
|
event :hard_shutdown do
|
@@ -90,6 +95,10 @@ module Adhearsion
|
|
90
95
|
::Process.exit 1
|
91
96
|
end
|
92
97
|
|
98
|
+
def fqdn
|
99
|
+
Socket.gethostbyname(Socket.gethostname).first
|
100
|
+
end
|
101
|
+
|
93
102
|
def self.method_missing(method_name, *args, &block)
|
94
103
|
instance.send method_name, *args, &block
|
95
104
|
end
|
@@ -20,6 +20,7 @@ module Adhearsion
|
|
20
20
|
connection_timeout 60 , :transform => Proc.new { |v| PunchblockPlugin.validate_number v }, :desc => "The amount of time to wait for a connection"
|
21
21
|
reconnect_attempts 1.0/0.0 , :transform => Proc.new { |v| PunchblockPlugin.validate_number v }, :desc => "The number of times to (re)attempt connection to the server"
|
22
22
|
reconnect_timer 5 , :transform => Proc.new { |v| PunchblockPlugin.validate_number v }, :desc => "Delay between connection attempts"
|
23
|
+
media_engine nil , :transform => Proc.new { |v| v.to_sym }, :desc => "The media engine to use. Defaults to platform default."
|
23
24
|
end
|
24
25
|
|
25
26
|
init :punchblock do
|
@@ -38,6 +39,13 @@ module Adhearsion
|
|
38
39
|
return 1.0/0.0 if ["Infinity", 1.0/0.0].include? value
|
39
40
|
value.to_i
|
40
41
|
end
|
42
|
+
|
43
|
+
def execute_component(command, timeout = 60)
|
44
|
+
client.execute_command command
|
45
|
+
response = command.response timeout
|
46
|
+
raise response if response.is_a? Exception
|
47
|
+
command
|
48
|
+
end
|
41
49
|
end
|
42
50
|
end
|
43
51
|
end
|
@@ -10,19 +10,23 @@ module Adhearsion
|
|
10
10
|
self.config = Adhearsion.config[:punchblock]
|
11
11
|
connection_class = case (self.config.platform || :xmpp)
|
12
12
|
when :xmpp
|
13
|
+
username = [self.config.username, resource].join('/')
|
13
14
|
::Punchblock::Connection::XMPP
|
14
15
|
when :asterisk
|
16
|
+
username = self.config.username
|
15
17
|
::Punchblock::Connection::Asterisk
|
16
18
|
end
|
19
|
+
|
17
20
|
connection_options = {
|
18
|
-
:username =>
|
21
|
+
:username => username,
|
19
22
|
:password => self.config.password,
|
20
23
|
:connection_timeout => self.config.connection_timeout,
|
21
24
|
:host => self.config.host,
|
22
25
|
:port => self.config.port,
|
23
26
|
:root_domain => self.config.root_domain,
|
24
27
|
:calls_domain => self.config.calls_domain,
|
25
|
-
:mixers_domain => self.config.mixers_domain
|
28
|
+
:mixers_domain => self.config.mixers_domain,
|
29
|
+
:media_engine => self.config.media_engine
|
26
30
|
}
|
27
31
|
|
28
32
|
self.connection = connection_class.new connection_options
|
@@ -130,14 +134,17 @@ module Adhearsion
|
|
130
134
|
end
|
131
135
|
end
|
132
136
|
|
133
|
-
def dispatch_call_event(event
|
137
|
+
def dispatch_call_event(event)
|
134
138
|
if call = Adhearsion.active_calls.find(event.call_id)
|
135
139
|
call.deliver_message! event
|
136
|
-
latch.countdown! if latch
|
137
140
|
else
|
138
141
|
logger.error "Event received for inactive call #{event.call_id}: #{event.inspect}"
|
139
142
|
end
|
140
143
|
end
|
144
|
+
|
145
|
+
def resource
|
146
|
+
[Adhearsion::Process.fqdn, ::Process.pid].join '-'
|
147
|
+
end
|
141
148
|
end
|
142
149
|
end # Punchblock
|
143
150
|
end # Plugin
|
data/lib/adhearsion/version.rb
CHANGED
@@ -19,12 +19,15 @@ module Adhearsion
|
|
19
19
|
let(:latch) { CountDownLatch.new 1 }
|
20
20
|
|
21
21
|
describe "#dial" do
|
22
|
-
|
22
|
+
before do
|
23
23
|
other_mock_call
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should dial the call to the correct endpoint and return a dial status object" do
|
24
27
|
flexmock(OutboundCall).should_receive(:new).and_return other_mock_call
|
25
28
|
flexmock(other_mock_call).should_receive(:dial).with(to, :from => 'foo').once
|
26
29
|
dial_thread = Thread.new do
|
27
|
-
subject.dial(to, :from => 'foo').should be_a
|
30
|
+
subject.dial(to, :from => 'foo').should be_a Dial::DialStatus
|
28
31
|
end
|
29
32
|
sleep 0.1
|
30
33
|
other_mock_call << mock_end
|
@@ -32,7 +35,6 @@ module Adhearsion
|
|
32
35
|
end
|
33
36
|
|
34
37
|
it "should default the caller ID to that of the original call" do
|
35
|
-
other_mock_call
|
36
38
|
flexmock call, :from => 'sip:foo@bar.com'
|
37
39
|
flexmock(OutboundCall).should_receive(:new).and_return other_mock_call
|
38
40
|
flexmock(other_mock_call).should_receive(:dial).with(to, :from => 'sip:foo@bar.com').once
|
@@ -45,19 +47,22 @@ module Adhearsion
|
|
45
47
|
end
|
46
48
|
|
47
49
|
describe "without a block" do
|
48
|
-
|
49
|
-
other_mock_call
|
50
|
-
|
50
|
+
before do
|
51
51
|
flexmock(other_mock_call).should_receive(:dial).once
|
52
52
|
flexmock(other_mock_call).should_receive(:hangup).once
|
53
53
|
flexmock(OutboundCall).should_receive(:new).and_return other_mock_call
|
54
|
+
end
|
54
55
|
|
55
|
-
|
56
|
-
|
56
|
+
def dial_in_thread
|
57
57
|
Thread.new do
|
58
|
-
subject.dial to
|
58
|
+
status = subject.dial to
|
59
59
|
latch.countdown!
|
60
|
+
status
|
60
61
|
end
|
62
|
+
end
|
63
|
+
|
64
|
+
it "blocks the original controller until the new call ends" do
|
65
|
+
dial_in_thread
|
61
66
|
|
62
67
|
latch.wait(1).should be_false
|
63
68
|
|
@@ -67,18 +72,7 @@ module Adhearsion
|
|
67
72
|
end
|
68
73
|
|
69
74
|
it "unblocks the original controller if the original call ends" do
|
70
|
-
|
71
|
-
|
72
|
-
flexmock(other_mock_call).should_receive(:dial).once
|
73
|
-
flexmock(other_mock_call).should_receive(:hangup).once
|
74
|
-
flexmock(OutboundCall).should_receive(:new).and_return other_mock_call
|
75
|
-
|
76
|
-
latch = CountDownLatch.new 1
|
77
|
-
|
78
|
-
Thread.new do
|
79
|
-
subject.dial to
|
80
|
-
latch.countdown!
|
81
|
-
end
|
75
|
+
dial_in_thread
|
82
76
|
|
83
77
|
latch.wait(1).should be_false
|
84
78
|
|
@@ -88,19 +82,9 @@ module Adhearsion
|
|
88
82
|
end
|
89
83
|
|
90
84
|
it "joins the new call to the existing one on answer" do
|
91
|
-
other_mock_call
|
92
|
-
|
93
|
-
flexmock(other_mock_call).should_receive(:dial).once
|
94
85
|
flexmock(other_mock_call).should_receive(:join).once.with(call)
|
95
|
-
flexmock(other_mock_call).should_receive(:hangup).once
|
96
|
-
flexmock(OutboundCall).should_receive(:new).and_return other_mock_call
|
97
86
|
|
98
|
-
|
99
|
-
|
100
|
-
Thread.new do
|
101
|
-
subject.dial to
|
102
|
-
latch.countdown!
|
103
|
-
end
|
87
|
+
dial_in_thread
|
104
88
|
|
105
89
|
latch.wait(1).should be_false
|
106
90
|
|
@@ -111,19 +95,9 @@ module Adhearsion
|
|
111
95
|
end
|
112
96
|
|
113
97
|
it "hangs up the new call when the dial unblocks" do
|
114
|
-
other_mock_call
|
115
|
-
|
116
|
-
flexmock(other_mock_call).should_receive(:dial).once
|
117
98
|
flexmock(other_mock_call).should_receive(:join).once.with(call)
|
118
|
-
flexmock(other_mock_call).should_receive(:hangup).once
|
119
|
-
flexmock(OutboundCall).should_receive(:new).and_return other_mock_call
|
120
99
|
|
121
|
-
|
122
|
-
|
123
|
-
Thread.new do
|
124
|
-
subject.dial to
|
125
|
-
latch.countdown!
|
126
|
-
end
|
100
|
+
dial_in_thread
|
127
101
|
|
128
102
|
latch.wait(1).should be_false
|
129
103
|
|
@@ -132,29 +106,70 @@ module Adhearsion
|
|
132
106
|
|
133
107
|
latch.wait(1).should be_true
|
134
108
|
end
|
109
|
+
|
110
|
+
context "when the call is rejected" do
|
111
|
+
it "has an overall dial status of :no_answer" do
|
112
|
+
t = dial_in_thread
|
113
|
+
|
114
|
+
sleep 0.5
|
115
|
+
|
116
|
+
other_mock_call << mock_end
|
117
|
+
|
118
|
+
latch.wait(2).should be_true
|
119
|
+
|
120
|
+
t.join
|
121
|
+
status = t.value
|
122
|
+
status.result.should == :no_answer
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context "when the call is answered and joined" do
|
127
|
+
it "has an overall dial status of :answer" do
|
128
|
+
flexmock(other_mock_call).should_receive(:join).once.with(call)
|
129
|
+
|
130
|
+
t = dial_in_thread
|
131
|
+
|
132
|
+
sleep 0.5
|
133
|
+
|
134
|
+
other_mock_call << mock_answered
|
135
|
+
other_mock_call << mock_end
|
136
|
+
|
137
|
+
latch.wait(1).should be_true
|
138
|
+
|
139
|
+
t.join
|
140
|
+
status = t.value
|
141
|
+
status.result.should == :answer
|
142
|
+
end
|
143
|
+
end
|
135
144
|
end
|
136
145
|
|
137
146
|
describe "with multiple third parties specified" do
|
138
|
-
|
139
|
-
other_mock_call
|
147
|
+
before do
|
140
148
|
second_other_mock_call
|
141
149
|
|
150
|
+
flexmock(OutboundCall).should_receive(:new).and_return other_mock_call, second_other_mock_call
|
151
|
+
|
142
152
|
flexmock(other_mock_call).should_receive(:dial).once
|
143
|
-
flexmock(other_mock_call).should_receive(:join).once.with(call)
|
144
153
|
flexmock(other_mock_call).should_receive(:hangup).once
|
145
154
|
|
146
155
|
flexmock(second_other_mock_call).should_receive(:dial).once
|
147
156
|
flexmock(second_other_mock_call).should_receive(:join).never
|
148
|
-
flexmock(second_other_mock_call).should_receive(:hangup).
|
149
|
-
|
150
|
-
flexmock(OutboundCall).should_receive(:new).and_return other_mock_call, second_other_mock_call
|
151
|
-
latch = CountDownLatch.new 1
|
157
|
+
flexmock(second_other_mock_call).should_receive(:hangup).once
|
158
|
+
end
|
152
159
|
|
153
|
-
|
154
|
-
|
160
|
+
def dial_in_thread
|
161
|
+
Thread.new do
|
162
|
+
status = subject.dial [to, second_to]
|
155
163
|
latch.countdown!
|
156
|
-
|
164
|
+
status
|
157
165
|
end
|
166
|
+
end
|
167
|
+
|
168
|
+
it "dials all parties and joins the first one to answer, hanging up the rest" do
|
169
|
+
flexmock(other_mock_call).should_receive(:join).once.with(call)
|
170
|
+
flexmock(second_other_mock_call).should_receive(:hangup).once
|
171
|
+
|
172
|
+
t = dial_in_thread
|
158
173
|
|
159
174
|
latch.wait(1).should be_false
|
160
175
|
|
@@ -168,37 +183,22 @@ module Adhearsion
|
|
168
183
|
latch.wait(2).should be_true
|
169
184
|
|
170
185
|
t.join
|
171
|
-
|
172
|
-
|
173
|
-
|
186
|
+
status = t.value
|
187
|
+
status.should be_a Dial::DialStatus
|
188
|
+
status.should have(2).calls
|
189
|
+
status.calls.each { |c| c.should be_a OutboundCall }
|
174
190
|
end
|
175
191
|
|
176
192
|
it "unblocks when the joined call unjoins, allowing it to proceed further" do
|
177
|
-
other_mock_call
|
178
|
-
second_other_mock_call
|
179
|
-
|
180
|
-
flexmock(other_mock_call).should_receive(:dial).once
|
181
193
|
flexmock(other_mock_call).should_receive(:join).once.with(call)
|
182
|
-
flexmock(
|
194
|
+
flexmock(second_other_mock_call).should_receive(:hangup).once
|
183
195
|
|
184
|
-
|
185
|
-
flexmock(second_other_mock_call).should_receive(:join).never
|
186
|
-
flexmock(second_other_mock_call).should_receive(:hangup).twice
|
187
|
-
|
188
|
-
flexmock(OutboundCall).should_receive(:new).and_return other_mock_call, second_other_mock_call
|
189
|
-
latch = CountDownLatch.new 1
|
190
|
-
|
191
|
-
t = Thread.new do
|
192
|
-
calls = subject.dial [to, second_to]
|
193
|
-
latch.countdown!
|
194
|
-
calls
|
195
|
-
end
|
196
|
+
t = dial_in_thread
|
196
197
|
|
197
198
|
latch.wait(1).should be_false
|
198
199
|
|
199
200
|
other_mock_call << mock_answered
|
200
201
|
other_mock_call << Punchblock::Event::Unjoined.new(:other_call_id => call.id)
|
201
|
-
other_mock_call << mock_end
|
202
202
|
|
203
203
|
latch.wait(1).should be_false
|
204
204
|
|
@@ -207,9 +207,49 @@ module Adhearsion
|
|
207
207
|
latch.wait(2).should be_true
|
208
208
|
|
209
209
|
t.join
|
210
|
-
|
211
|
-
|
212
|
-
|
210
|
+
status = t.value
|
211
|
+
status.should be_a Dial::DialStatus
|
212
|
+
status.should have(2).calls
|
213
|
+
status.calls.each { |c| c.should be_a OutboundCall }
|
214
|
+
end
|
215
|
+
|
216
|
+
context "when all calls are rejected" do
|
217
|
+
it "has an overall dial status of :no_answer" do
|
218
|
+
t = dial_in_thread
|
219
|
+
|
220
|
+
sleep 0.5
|
221
|
+
|
222
|
+
other_mock_call << mock_end
|
223
|
+
second_other_mock_call << mock_end
|
224
|
+
|
225
|
+
latch.wait(2).should be_true
|
226
|
+
|
227
|
+
t.join
|
228
|
+
status = t.value
|
229
|
+
status.result.should == :no_answer
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
context "when a call is answered and joined" do
|
234
|
+
it "has an overall dial status of :answer" do
|
235
|
+
flexmock(other_mock_call).should_receive(:join).once.with(call)
|
236
|
+
flexmock(second_other_mock_call).should_receive(:hangup).once
|
237
|
+
|
238
|
+
t = dial_in_thread
|
239
|
+
|
240
|
+
sleep 0.5
|
241
|
+
|
242
|
+
other_mock_call << mock_answered
|
243
|
+
other_mock_call << mock_end
|
244
|
+
|
245
|
+
second_other_mock_call << mock_end
|
246
|
+
|
247
|
+
latch.wait(1).should be_true
|
248
|
+
|
249
|
+
t.join
|
250
|
+
status = t.value
|
251
|
+
status.result.should == :answer
|
252
|
+
end
|
213
253
|
end
|
214
254
|
end
|
215
255
|
|
@@ -217,26 +257,24 @@ module Adhearsion
|
|
217
257
|
let(:timeout) { 3 }
|
218
258
|
|
219
259
|
it "should abort the dial after the specified timeout" do
|
220
|
-
other_mock_call
|
221
|
-
|
222
260
|
flexmock(other_mock_call).should_receive(:dial).once
|
223
261
|
flexmock(other_mock_call).should_receive(:hangup).once
|
224
262
|
flexmock(OutboundCall).should_receive(:new).and_return other_mock_call
|
225
263
|
|
226
|
-
latch = CountDownLatch.new 1
|
227
|
-
|
228
|
-
value = nil
|
229
264
|
time = Time.now
|
230
265
|
|
231
|
-
Thread.new do
|
232
|
-
|
266
|
+
t = Thread.new do
|
267
|
+
status = subject.dial to, :timeout => timeout
|
233
268
|
latch.countdown!
|
269
|
+
status
|
234
270
|
end
|
235
271
|
|
236
272
|
latch.wait
|
237
273
|
time = Time.now - time
|
238
274
|
time.to_i.should == timeout
|
239
|
-
|
275
|
+
t.join
|
276
|
+
status = t.value
|
277
|
+
status.result.should == :timeout
|
240
278
|
end
|
241
279
|
end
|
242
280
|
|