adhearsion 2.0.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.travis.yml +4 -3
- data/CHANGELOG.md +30 -0
- data/README.markdown +1 -0
- data/adhearsion.gemspec +3 -4
- data/bin/ahn +0 -20
- data/features/cli_create.feature +1 -1
- data/features/cli_restart.feature +25 -1
- data/features/cli_start.feature +0 -2
- data/features/plugin_generator.feature +66 -15
- data/features/support/env.rb +0 -13
- data/lib/adhearsion.rb +26 -6
- data/lib/adhearsion/call.rb +42 -7
- data/lib/adhearsion/call_controller.rb +5 -2
- data/lib/adhearsion/call_controller/dial.rb +92 -50
- data/lib/adhearsion/call_controller/input.rb +19 -6
- data/lib/adhearsion/call_controller/menu_dsl/menu.rb +4 -0
- data/lib/adhearsion/call_controller/output.rb +143 -161
- data/lib/adhearsion/call_controller/output/abstract_player.rb +30 -0
- data/lib/adhearsion/call_controller/output/async_player.rb +26 -0
- data/lib/adhearsion/call_controller/output/formatter.rb +81 -0
- data/lib/adhearsion/call_controller/output/player.rb +25 -0
- data/lib/adhearsion/call_controller/record.rb +19 -2
- data/lib/adhearsion/events.rb +3 -0
- data/lib/adhearsion/foundation.rb +12 -6
- data/lib/adhearsion/foundation/exception_handler.rb +8 -6
- data/lib/adhearsion/generators/app/templates/README.md +13 -0
- data/lib/adhearsion/generators/app/templates/config/adhearsion.rb +7 -1
- data/lib/adhearsion/generators/plugin/plugin_generator.rb +1 -0
- data/lib/adhearsion/generators/plugin/templates/plugin-template.gemspec.tt +3 -7
- data/lib/adhearsion/generators/plugin/templates/spec/spec_helper.rb.tt +0 -1
- data/lib/adhearsion/outbound_call.rb +15 -5
- data/lib/adhearsion/punchblock_plugin.rb +13 -2
- data/lib/adhearsion/punchblock_plugin/initializer.rb +13 -12
- data/lib/adhearsion/router.rb +43 -2
- data/lib/adhearsion/router/evented_route.rb +15 -0
- data/lib/adhearsion/router/openended_route.rb +16 -0
- data/lib/adhearsion/router/route.rb +31 -13
- data/lib/adhearsion/router/unaccepting_route.rb +11 -0
- data/lib/adhearsion/version.rb +1 -1
- data/pre-commit +14 -1
- data/spec/adhearsion/call_controller/dial_spec.rb +105 -10
- data/spec/adhearsion/call_controller/input_spec.rb +19 -21
- data/spec/adhearsion/call_controller/output/async_player_spec.rb +67 -0
- data/spec/adhearsion/call_controller/output/formatter_spec.rb +90 -0
- data/spec/adhearsion/call_controller/output/player_spec.rb +65 -0
- data/spec/adhearsion/call_controller/output_spec.rb +436 -190
- data/spec/adhearsion/call_controller/record_spec.rb +49 -6
- data/spec/adhearsion/call_controller_spec.rb +10 -2
- data/spec/adhearsion/call_spec.rb +138 -0
- data/spec/adhearsion/calls_spec.rb +1 -1
- data/spec/adhearsion/outbound_call_spec.rb +48 -8
- data/spec/adhearsion/punchblock_plugin/initializer_spec.rb +34 -23
- data/spec/adhearsion/router/evented_route_spec.rb +34 -0
- data/spec/adhearsion/router/openended_route_spec.rb +61 -0
- data/spec/adhearsion/router/route_spec.rb +26 -4
- data/spec/adhearsion/router/unaccepting_route_spec.rb +72 -0
- data/spec/adhearsion/router_spec.rb +107 -2
- data/spec/adhearsion_spec.rb +19 -0
- data/spec/capture_warnings.rb +28 -21
- data/spec/spec_helper.rb +2 -3
- data/spec/support/call_controller_test_helpers.rb +31 -30
- metadata +32 -29
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
module Adhearsion
|
6
|
+
class Router
|
7
|
+
describe EventedRoute do
|
8
|
+
let(:name) { 'catchall' }
|
9
|
+
|
10
|
+
subject { Route.new name }
|
11
|
+
|
12
|
+
before { subject.extend described_class }
|
13
|
+
|
14
|
+
it { should be_evented }
|
15
|
+
|
16
|
+
describe "dispatching a call" do
|
17
|
+
let(:call) { Call.new }
|
18
|
+
|
19
|
+
context "via a block" do
|
20
|
+
subject :route do
|
21
|
+
Route.new 'foobar' do |c|
|
22
|
+
c.foo
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should yield the call to the block" do
|
27
|
+
flexmock(call).should_receive(:foo).once
|
28
|
+
route.dispatch call
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
module Adhearsion
|
6
|
+
class Router
|
7
|
+
describe OpenendedRoute do
|
8
|
+
let(:name) { 'catchall' }
|
9
|
+
|
10
|
+
subject { Route.new name }
|
11
|
+
|
12
|
+
before { subject.extend described_class }
|
13
|
+
|
14
|
+
it { should be_openended }
|
15
|
+
|
16
|
+
describe "dispatching a call" do
|
17
|
+
let(:call) { Call.new }
|
18
|
+
|
19
|
+
let(:latch) { CountDownLatch.new 1 }
|
20
|
+
|
21
|
+
before { flexmock(call.wrapped_object).should_receive :write_and_await_response }
|
22
|
+
|
23
|
+
context "via a call controller" do
|
24
|
+
let(:controller) { CallController }
|
25
|
+
subject(:route) { Route.new 'foobar', controller }
|
26
|
+
|
27
|
+
it "should accept the call" do
|
28
|
+
flexmock(call).should_receive(:accept).once
|
29
|
+
route.dispatch call
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should instruct the call to use an instance of the controller" do
|
33
|
+
flexmock(call).should_receive(:execute_controller).once.with controller, Proc
|
34
|
+
route.dispatch call
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should not hangup the call after all controllers have executed" do
|
38
|
+
flexmock(call).should_receive(:hangup).never
|
39
|
+
route.dispatch call, lambda { latch.countdown! }
|
40
|
+
latch.wait(2).should be true
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context "via a block" do
|
45
|
+
let :route do
|
46
|
+
Route.new 'foobar' do
|
47
|
+
:foobar
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should instruct the call to use a CallController with the correct block" do
|
52
|
+
flexmock(call).should_receive(:execute_controller).once.with(CallController, Proc).and_return do |controller|
|
53
|
+
controller.block.call.should be == :foobar
|
54
|
+
end
|
55
|
+
route.dispatch call
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -14,6 +14,11 @@ module Adhearsion
|
|
14
14
|
]
|
15
15
|
end
|
16
16
|
|
17
|
+
subject { Route.new name }
|
18
|
+
|
19
|
+
it { should_not be_evented }
|
20
|
+
it { should be_accepting }
|
21
|
+
|
17
22
|
describe "with a class target and guards" do
|
18
23
|
let(:target) { CallController }
|
19
24
|
|
@@ -104,27 +109,44 @@ module Adhearsion
|
|
104
109
|
|
105
110
|
let(:latch) { CountDownLatch.new 1 }
|
106
111
|
|
112
|
+
before { flexmock(call.wrapped_object).should_receive :write_and_await_response }
|
113
|
+
|
107
114
|
context "via a call controller" do
|
108
115
|
let(:controller) { CallController }
|
109
116
|
let(:route) { Route.new 'foobar', controller }
|
110
117
|
|
118
|
+
it "should accept the call" do
|
119
|
+
flexmock(call).should_receive(:accept).once
|
120
|
+
route.dispatch call
|
121
|
+
end
|
122
|
+
|
111
123
|
it "should instruct the call to use an instance of the controller" do
|
112
124
|
flexmock(call).should_receive(:execute_controller).once.with controller, Proc
|
113
|
-
route.
|
125
|
+
route.dispatch call
|
114
126
|
end
|
115
127
|
|
116
128
|
it "should hangup the call after all controllers have executed" do
|
117
129
|
flexmock(call).should_receive(:hangup).once
|
118
|
-
route.
|
130
|
+
route.dispatch call, lambda { latch.countdown! }
|
119
131
|
latch.wait(2).should be true
|
120
132
|
end
|
121
133
|
|
134
|
+
context 'with the :ahn_prevent_hangup call variable set' do
|
135
|
+
before { call[:ahn_prevent_hangup] = true }
|
136
|
+
|
137
|
+
it "should not hangup the call after controller execution" do
|
138
|
+
flexmock(call).should_receive(:hangup).never
|
139
|
+
route.dispatch call, lambda { latch.countdown! }
|
140
|
+
latch.wait(2).should be true
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
122
144
|
context "if hangup raises a Call::Hangup" do
|
123
145
|
before { flexmock(call).should_receive(:hangup).once.and_raise Call::Hangup }
|
124
146
|
|
125
147
|
it "should not raise an exception" do
|
126
148
|
lambda do
|
127
|
-
route.
|
149
|
+
route.dispatch call, lambda { latch.countdown! }
|
128
150
|
latch.wait(2).should be true
|
129
151
|
end.should_not raise_error
|
130
152
|
end
|
@@ -142,7 +164,7 @@ module Adhearsion
|
|
142
164
|
flexmock(call).should_receive(:execute_controller).once.with(CallController, Proc).and_return do |controller|
|
143
165
|
controller.block.call.should be == :foobar
|
144
166
|
end
|
145
|
-
route.
|
167
|
+
route.dispatch call
|
146
168
|
end
|
147
169
|
end
|
148
170
|
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
module Adhearsion
|
6
|
+
class Router
|
7
|
+
describe UnacceptingRoute do
|
8
|
+
let(:name) { 'catchall' }
|
9
|
+
|
10
|
+
subject { Route.new name }
|
11
|
+
|
12
|
+
before { subject.extend described_class }
|
13
|
+
|
14
|
+
it { should_not be_accepting }
|
15
|
+
|
16
|
+
describe "dispatching a call" do
|
17
|
+
let(:call) { Call.new }
|
18
|
+
|
19
|
+
let(:latch) { CountDownLatch.new 1 }
|
20
|
+
|
21
|
+
before { flexmock(call.wrapped_object).should_receive :write_and_await_response }
|
22
|
+
|
23
|
+
context "via a call controller" do
|
24
|
+
let(:controller) { CallController }
|
25
|
+
subject(:route) { Route.new 'foobar', controller }
|
26
|
+
|
27
|
+
it "should not accept the call" do
|
28
|
+
flexmock(call).should_receive(:accept).never
|
29
|
+
route.dispatch call
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should instruct the call to use an instance of the controller" do
|
33
|
+
flexmock(call).should_receive(:execute_controller).once.with controller, Proc
|
34
|
+
route.dispatch call
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should hangup the call after all controllers have executed" do
|
38
|
+
flexmock(call).should_receive(:hangup).once
|
39
|
+
route.dispatch call, lambda { latch.countdown! }
|
40
|
+
latch.wait(2).should be true
|
41
|
+
end
|
42
|
+
|
43
|
+
context "if hangup raises a Call::Hangup" do
|
44
|
+
before { flexmock(call).should_receive(:hangup).once.and_raise Call::Hangup }
|
45
|
+
|
46
|
+
it "should not raise an exception" do
|
47
|
+
lambda do
|
48
|
+
route.dispatch call, lambda { latch.countdown! }
|
49
|
+
latch.wait(2).should be true
|
50
|
+
end.should_not raise_error
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context "via a block" do
|
56
|
+
let :route do
|
57
|
+
Route.new 'foobar' do
|
58
|
+
:foobar
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should instruct the call to use a CallController with the correct block" do
|
63
|
+
flexmock(call).should_receive(:execute_controller).once.with(CallController, Proc).and_return do |controller|
|
64
|
+
controller.block.call.should be == :foobar
|
65
|
+
end
|
66
|
+
route.dispatch call
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -53,6 +53,82 @@ module Adhearsion
|
|
53
53
|
subject[2].guards.should be == []
|
54
54
|
subject[2].target.should be_a Proc
|
55
55
|
end
|
56
|
+
|
57
|
+
context "as evented" do
|
58
|
+
let(:router) do
|
59
|
+
Router.new do
|
60
|
+
route 'calls from fred', FooBarController, :from => 'fred'
|
61
|
+
evented do
|
62
|
+
route 'catchall' do |call|
|
63
|
+
:foo
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should create a route which is evented" do
|
70
|
+
subject[0].should_not be_evented
|
71
|
+
subject[1].should be_evented
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context "as unaccepting" do
|
76
|
+
let(:router) do
|
77
|
+
Router.new do
|
78
|
+
route 'calls from fred', FooBarController, :from => 'fred'
|
79
|
+
unaccepting do
|
80
|
+
route 'catchall' do |call|
|
81
|
+
:foo
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should create a route with is unaccepting" do
|
88
|
+
subject[0].should be_accepting
|
89
|
+
subject[1].should_not be_accepting
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
context "as openended" do
|
94
|
+
let(:router) do
|
95
|
+
Router.new do
|
96
|
+
route 'calls from fred', FooBarController, :from => 'fred'
|
97
|
+
openended do
|
98
|
+
route 'catchall' do |call|
|
99
|
+
:foo
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should create a route which is openended" do
|
106
|
+
subject[0].should_not be_openended
|
107
|
+
subject[1].should be_openended
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
context "as combined evented/unaccepting" do
|
112
|
+
let(:router) do
|
113
|
+
Router.new do
|
114
|
+
route 'calls from fred', FooBarController, :from => 'fred'
|
115
|
+
unaccepting do
|
116
|
+
evented do
|
117
|
+
route 'catchall' do |call|
|
118
|
+
:foo
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should create a route which is evented and unaccepting" do
|
126
|
+
subject[0].should be_accepting
|
127
|
+
subject[0].should_not be_evented
|
128
|
+
subject[1].should be_evented
|
129
|
+
subject[1].should_not be_accepting
|
130
|
+
end
|
131
|
+
end
|
56
132
|
end
|
57
133
|
|
58
134
|
describe "matching a call" do
|
@@ -99,8 +175,37 @@ module Adhearsion
|
|
99
175
|
let(:call) { flexmock 'Adhearsion::Call', :id => 'abc123' }
|
100
176
|
let(:route) { subject.routes.first }
|
101
177
|
|
102
|
-
it "should
|
103
|
-
|
178
|
+
it "should dispatch via the route" do
|
179
|
+
flexmock(route).should_receive(:dispatch).once.with call
|
180
|
+
subject.handle call
|
181
|
+
end
|
182
|
+
|
183
|
+
context "when there are no routes" do
|
184
|
+
subject do
|
185
|
+
Router.new {}
|
186
|
+
end
|
187
|
+
|
188
|
+
let(:call) { flexmock 'Adhearsion::Call', :id => 'abc123' }
|
189
|
+
|
190
|
+
it "should return a dispatcher which rejects the call as an error" do
|
191
|
+
call.should_receive(:reject).once.with(:error)
|
192
|
+
subject.handle call
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
context "when no routes match" do
|
197
|
+
subject do
|
198
|
+
Router.new do
|
199
|
+
route 'too-specific', FooBarController, :to => 'foo'
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
let(:call) { flexmock 'Adhearsion::Call', :id => 'abc123', :to => 'bar' }
|
204
|
+
|
205
|
+
it "should return a dispatcher which rejects the call as an error" do
|
206
|
+
call.should_receive(:reject).once.with(:error)
|
207
|
+
subject.handle call
|
208
|
+
end
|
104
209
|
end
|
105
210
|
end
|
106
211
|
end
|
data/spec/adhearsion_spec.rb
CHANGED
@@ -3,6 +3,25 @@
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
5
|
describe Adhearsion do
|
6
|
+
describe "#root=" do
|
7
|
+
it "should update properly the config root variable" do
|
8
|
+
Adhearsion.root = "./"
|
9
|
+
Adhearsion.config[:platform].root.should be == Dir.getwd
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should update properly the config root variable when path is nil" do
|
13
|
+
Adhearsion.root = nil
|
14
|
+
Adhearsion.config[:platform].root.should be_nil
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "#root" do
|
19
|
+
it "should return the set root" do
|
20
|
+
Adhearsion.root = "./"
|
21
|
+
Adhearsion.root.should be == Dir.getwd
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
6
25
|
describe "#ahn_root=" do
|
7
26
|
it "should update properly the config root variable" do
|
8
27
|
Adhearsion.ahn_root = "./"
|
data/spec/capture_warnings.rb
CHANGED
@@ -1,33 +1,40 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
require 'tempfile'
|
4
|
-
stderr_file = Tempfile.new "ahn.stderr"
|
4
|
+
stderr_file = Tempfile.new "ahn#{rand}.stderr"
|
5
|
+
warnings_filename = "tmp/ahnwarnings#{rand}.txt"
|
5
6
|
$stderr.reopen stderr_file.path
|
6
7
|
current_dir = Dir.pwd
|
7
8
|
|
8
9
|
at_exit do
|
9
|
-
|
10
|
-
|
11
|
-
|
10
|
+
begin
|
11
|
+
stderr_file.rewind
|
12
|
+
lines = stderr_file.read.split("\n").uniq
|
13
|
+
stderr_file.close!
|
12
14
|
|
13
|
-
|
15
|
+
ahn_warnings, other_warnings = lines.partition { |line| line.include?(current_dir) && !line.include?('vendor') && line.include?('warning') }
|
14
16
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
17
|
+
if ahn_warnings.any?
|
18
|
+
puts
|
19
|
+
puts "-" * 30 + " AHN Warnings: " + "-" * 30
|
20
|
+
puts
|
21
|
+
puts ahn_warnings.join("\n")
|
22
|
+
puts
|
23
|
+
puts "-" * 75
|
24
|
+
puts
|
25
|
+
end
|
24
26
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
27
|
+
if other_warnings.any?
|
28
|
+
File.open(warnings_filename, 'w') { |f| f.write other_warnings.join("\n") }
|
29
|
+
puts
|
30
|
+
puts "Non-AHN warnings written to #{warnings_filename}"
|
31
|
+
puts
|
32
|
+
end
|
31
33
|
|
32
|
-
|
34
|
+
exit 1 if ahn_warnings.any? # fail the build...
|
35
|
+
rescue => e
|
36
|
+
puts "Warning capture failed."
|
37
|
+
puts e.message
|
38
|
+
puts e.backtrace.join("\n")
|
39
|
+
end
|
33
40
|
end
|