adhearsion 2.5.4 → 2.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +1 -0
- data/CHANGELOG.md +15 -0
- data/README.markdown +2 -1
- data/Rakefile +1 -6
- data/adhearsion.gemspec +4 -3
- data/features/cli_daemon.feature +2 -4
- data/features/cli_restart.feature +14 -5
- data/features/cli_start.feature +0 -2
- data/features/cli_stop.feature +15 -6
- data/lib/adhearsion.rb +21 -23
- data/lib/adhearsion/call.rb +49 -5
- data/lib/adhearsion/call_controller.rb +29 -11
- data/lib/adhearsion/call_controller/dial.rb +21 -9
- data/lib/adhearsion/call_controller/menu_dsl.rb +12 -12
- data/lib/adhearsion/call_controller/menu_dsl/array_match_calculator.rb +1 -1
- data/lib/adhearsion/call_controller/menu_dsl/fixnum_match_calculator.rb +1 -0
- data/lib/adhearsion/call_controller/menu_dsl/string_match_calculator.rb +1 -1
- data/lib/adhearsion/call_controller/output.rb +36 -7
- data/lib/adhearsion/call_controller/output/abstract_player.rb +4 -0
- data/lib/adhearsion/call_controller/record.rb +1 -0
- data/lib/adhearsion/cli_commands/ahn_command.rb +7 -4
- data/lib/adhearsion/cli_commands/plugin_command.rb +2 -0
- data/lib/adhearsion/generators.rb +2 -4
- data/lib/adhearsion/generators/app/templates/simon_game_spec.rb +20 -20
- data/lib/adhearsion/initializer.rb +2 -2
- data/lib/adhearsion/plugin.rb +6 -6
- data/lib/adhearsion/punchblock_plugin.rb +3 -4
- data/lib/adhearsion/punchblock_plugin/initializer.rb +2 -1
- data/lib/adhearsion/router.rb +7 -7
- data/lib/adhearsion/router/route.rb +10 -4
- data/lib/adhearsion/rspec.rb +2 -0
- data/lib/adhearsion/version.rb +1 -1
- data/spec/adhearsion/call_controller/dial_spec.rb +589 -557
- data/spec/adhearsion/call_controller/input_spec.rb +91 -91
- data/spec/adhearsion/call_controller/menu_dsl/array_match_calculator_spec.rb +29 -29
- data/spec/adhearsion/call_controller/menu_dsl/calculated_match_collection_spec.rb +6 -6
- data/spec/adhearsion/call_controller/menu_dsl/calculated_match_spec.rb +19 -19
- data/spec/adhearsion/call_controller/menu_dsl/fixnum_match_calculator_spec.rb +6 -6
- data/spec/adhearsion/call_controller/menu_dsl/match_calculator_spec.rb +1 -1
- data/spec/adhearsion/call_controller/menu_dsl/menu_builder_spec.rb +21 -17
- data/spec/adhearsion/call_controller/menu_dsl/menu_spec.rb +96 -83
- data/spec/adhearsion/call_controller/menu_dsl/range_match_calculator_spec.rb +5 -5
- data/spec/adhearsion/call_controller/menu_dsl/string_match_calculator_spec.rb +9 -9
- data/spec/adhearsion/call_controller/output/async_player_spec.rb +14 -4
- data/spec/adhearsion/call_controller/output/formatter_spec.rb +14 -14
- data/spec/adhearsion/call_controller/output/player_spec.rb +15 -5
- data/spec/adhearsion/call_controller/output_spec.rb +126 -78
- data/spec/adhearsion/call_controller/record_spec.rb +38 -26
- data/spec/adhearsion/call_controller/utility_spec.rb +11 -11
- data/spec/adhearsion/call_controller_spec.rb +176 -136
- data/spec/adhearsion/call_spec.rb +443 -218
- data/spec/adhearsion/calls_spec.rb +33 -33
- data/spec/adhearsion/configuration_spec.rb +61 -61
- data/spec/adhearsion/console_spec.rb +29 -29
- data/spec/adhearsion/events_spec.rb +14 -14
- data/spec/adhearsion/generators_spec.rb +1 -1
- data/spec/adhearsion/initializer_spec.rb +42 -42
- data/spec/adhearsion/logging_spec.rb +33 -33
- data/spec/adhearsion/outbound_call_spec.rb +69 -55
- data/spec/adhearsion/plugin_spec.rb +53 -44
- data/spec/adhearsion/process_spec.rb +21 -21
- data/spec/adhearsion/punchblock_plugin/initializer_spec.rb +68 -52
- data/spec/adhearsion/punchblock_plugin_spec.rb +6 -6
- data/spec/adhearsion/router/evented_route_spec.rb +2 -2
- data/spec/adhearsion/router/openended_route_spec.rb +9 -9
- data/spec/adhearsion/router/route_spec.rb +61 -31
- data/spec/adhearsion/router/unaccepting_route_spec.rb +13 -13
- data/spec/adhearsion/router_spec.rb +47 -33
- data/spec/adhearsion/statistics/dump_spec.rb +6 -6
- data/spec/adhearsion/statistics_spec.rb +9 -9
- data/spec/adhearsion_spec.rb +23 -20
- data/spec/spec_helper.rb +3 -6
- data/spec/support/call_controller_test_helpers.rb +7 -7
- data/spec/support/initializer_stubs.rb +1 -1
- data/spec/support/punchblock_mocks.rb +1 -1
- metadata +22 -10
- data/features/support/utils.rb +0 -9
@@ -42,7 +42,10 @@ module Adhearsion
|
|
42
42
|
|
43
43
|
subject { Recorder.new controller, options }
|
44
44
|
|
45
|
-
|
45
|
+
describe '#record_component' do
|
46
|
+
subject { super().record_component }
|
47
|
+
it { is_expected.to eq(component) }
|
48
|
+
end
|
46
49
|
|
47
50
|
context "when passing time related options" do
|
48
51
|
let :component_options do
|
@@ -56,7 +59,7 @@ module Adhearsion
|
|
56
59
|
end
|
57
60
|
|
58
61
|
it "takes seconds but sets milliseconds on the command" do
|
59
|
-
subject.record_component.
|
62
|
+
expect(subject.record_component).to eq(component)
|
60
63
|
end
|
61
64
|
end
|
62
65
|
|
@@ -78,11 +81,14 @@ module Adhearsion
|
|
78
81
|
end
|
79
82
|
|
80
83
|
context "with :interruptible => false" do
|
81
|
-
|
84
|
+
describe '#stopper_component' do
|
85
|
+
subject { super().stopper_component }
|
86
|
+
it { is_expected.to be_nil }
|
87
|
+
end
|
82
88
|
|
83
89
|
it "does not use an Input component" do
|
84
|
-
controller.
|
85
|
-
controller.
|
90
|
+
expect(controller).to receive(:execute_component_and_await_completion).once.with(component)
|
91
|
+
expect(controller).to receive(:write_and_await_response).never.with(input_component)
|
86
92
|
subject.run
|
87
93
|
end
|
88
94
|
end
|
@@ -90,7 +96,10 @@ module Adhearsion
|
|
90
96
|
context "with :interruptible => true" do
|
91
97
|
let(:interruptible) { true }
|
92
98
|
|
93
|
-
|
99
|
+
describe '#stopper_component' do
|
100
|
+
subject { super().stopper_component }
|
101
|
+
it { is_expected.to eq(input_component) }
|
102
|
+
end
|
94
103
|
|
95
104
|
describe "when the input component completes" do
|
96
105
|
let(:complete_event) { Punchblock::Event::Complete.new }
|
@@ -101,16 +110,16 @@ module Adhearsion
|
|
101
110
|
end
|
102
111
|
|
103
112
|
it "stops the recording" do
|
104
|
-
subject.record_component.
|
113
|
+
expect(subject.record_component).to receive(:stop!).once
|
105
114
|
subject.stopper_component.trigger_event_handler complete_event
|
106
115
|
end
|
107
116
|
end
|
108
117
|
|
109
118
|
describe "when the recording completes" do
|
110
119
|
it "stops the input component" do
|
111
|
-
controller.
|
112
|
-
controller.
|
113
|
-
subject.stopper_component.
|
120
|
+
expect(controller).to receive(:execute_component_and_await_completion).once.with(component)
|
121
|
+
expect(controller).to receive(:write_and_await_response).once.with(input_component)
|
122
|
+
expect(subject.stopper_component).to receive(:stop!).once
|
114
123
|
subject.run
|
115
124
|
end
|
116
125
|
end
|
@@ -132,7 +141,10 @@ module Adhearsion
|
|
132
141
|
end
|
133
142
|
end
|
134
143
|
|
135
|
-
|
144
|
+
describe '#stopper_component' do
|
145
|
+
subject { super().stopper_component }
|
146
|
+
it { is_expected.to eq(input_component) }
|
147
|
+
end
|
136
148
|
end
|
137
149
|
|
138
150
|
describe "setting completion handlers" do
|
@@ -140,7 +152,7 @@ module Adhearsion
|
|
140
152
|
|
141
153
|
it "should execute those handlers when recording completes" do
|
142
154
|
foo = double 'foo'
|
143
|
-
foo.
|
155
|
+
expect(foo).to receive(:call).once.with kind_of(Punchblock::Event::Complete)
|
144
156
|
subject.handle_record_completion { |e| foo.call e }
|
145
157
|
subject.record_component.trigger_event_handler complete_event
|
146
158
|
end
|
@@ -164,7 +176,7 @@ module Adhearsion
|
|
164
176
|
describe "with :async => true and an :on_complete callback" do
|
165
177
|
before do
|
166
178
|
component
|
167
|
-
Punchblock::Component::Record.
|
179
|
+
expect(Punchblock::Component::Record).to receive(:new).once.with(parsed_options).and_return component
|
168
180
|
expect_message_waiting_for_response component
|
169
181
|
@rec = Queue.new
|
170
182
|
subject.record(options.merge(async: true)) { |rec| @rec.push rec }
|
@@ -175,7 +187,7 @@ module Adhearsion
|
|
175
187
|
it "should execute the callback" do
|
176
188
|
component.trigger_event_handler response
|
177
189
|
Timeout::timeout 5 do
|
178
|
-
@rec.pop.
|
190
|
+
expect(@rec.pop).to be response
|
179
191
|
end
|
180
192
|
end
|
181
193
|
end
|
@@ -184,14 +196,14 @@ module Adhearsion
|
|
184
196
|
before do
|
185
197
|
TestException = Class.new StandardError
|
186
198
|
component
|
187
|
-
Punchblock::Component::Record.
|
199
|
+
expect(Punchblock::Component::Record).to receive(:new).once.with({}).and_return component
|
188
200
|
end
|
189
201
|
|
190
202
|
it "should pass the exception to the events system" do
|
191
203
|
latch = CountDownLatch.new 1
|
192
204
|
Adhearsion::Events.exception do |e, l|
|
193
|
-
e.
|
194
|
-
l.
|
205
|
+
expect(e).to be_a TestException
|
206
|
+
expect(l).to be subject.logger
|
195
207
|
latch.countdown!
|
196
208
|
end
|
197
209
|
expect_component_execution component
|
@@ -199,7 +211,7 @@ module Adhearsion
|
|
199
211
|
component.request!
|
200
212
|
component.execute!
|
201
213
|
component.trigger_event_handler response
|
202
|
-
latch.wait(1).
|
214
|
+
expect(latch.wait(1)).to be true
|
203
215
|
Adhearsion::Events.clear_handlers :exception
|
204
216
|
end
|
205
217
|
end
|
@@ -207,7 +219,7 @@ module Adhearsion
|
|
207
219
|
describe "with :async => false" do
|
208
220
|
before do
|
209
221
|
component
|
210
|
-
Punchblock::Component::Record.
|
222
|
+
expect(Punchblock::Component::Record).to receive(:new).once.with(parsed_options).and_return component
|
211
223
|
expect_component_execution component
|
212
224
|
@rec = Queue.new
|
213
225
|
subject.record(options.merge(:async => false)) { |rec| @rec.push rec }
|
@@ -218,7 +230,7 @@ module Adhearsion
|
|
218
230
|
it 'should execute a passed block' do
|
219
231
|
component.trigger_event_handler response
|
220
232
|
Timeout::timeout 5 do
|
221
|
-
@rec.pop.
|
233
|
+
expect(@rec.pop).to eq(response)
|
222
234
|
end
|
223
235
|
end
|
224
236
|
end
|
@@ -226,8 +238,8 @@ module Adhearsion
|
|
226
238
|
describe "with :interruptible => false" do
|
227
239
|
let(:input_component) { Punchblock::Component::Input.new }
|
228
240
|
it "does not use an Input component" do
|
229
|
-
subject.
|
230
|
-
subject.
|
241
|
+
expect(subject).to receive(:execute_component_and_await_completion).once.with(component)
|
242
|
+
expect(subject).to receive(:write_and_await_response).never.with(input_component)
|
231
243
|
subject.record(options.merge(:async => false, :interruptible => false)) { |rec| @rec.push rec }
|
232
244
|
end
|
233
245
|
end
|
@@ -240,8 +252,8 @@ module Adhearsion
|
|
240
252
|
|
241
253
|
expect_input_component_complete_event 'dtmf-5'
|
242
254
|
|
243
|
-
Punchblock::Component::Record.
|
244
|
-
subject.
|
255
|
+
expect_any_instance_of(Punchblock::Component::Record).to receive(:stop!)
|
256
|
+
expect(subject).to receive(:execute_component_and_await_completion).once.with(component)
|
245
257
|
subject.record(options.merge(:async => false, :interruptible => true)) { |rec| @rec.push rec }
|
246
258
|
end
|
247
259
|
|
@@ -250,9 +262,9 @@ module Adhearsion
|
|
250
262
|
describe "check for the return value" do
|
251
263
|
it "returns a Record component" do
|
252
264
|
component
|
253
|
-
Punchblock::Component::Record.
|
265
|
+
expect(Punchblock::Component::Record).to receive(:new).once.with(parsed_options).and_return component
|
254
266
|
expect_component_execution component
|
255
|
-
subject.record(options.merge(:async => false)).
|
267
|
+
expect(subject.record(options.merge(:async => false))).to eq(component)
|
256
268
|
component.request!
|
257
269
|
component.execute!
|
258
270
|
end
|
@@ -22,7 +22,7 @@ module Adhearsion
|
|
22
22
|
}
|
23
23
|
|
24
24
|
it 'generates the correct GRXML grammar' do
|
25
|
-
subject.grammar_digits(2).to_s.
|
25
|
+
expect(subject.grammar_digits(2).to_s).to eq(grxml.to_s)
|
26
26
|
end
|
27
27
|
|
28
28
|
end # describe #grammar_digits
|
@@ -40,48 +40,48 @@ module Adhearsion
|
|
40
40
|
}
|
41
41
|
|
42
42
|
it 'generates the correct GRXML grammar' do
|
43
|
-
subject.grammar_accept('35').to_s.
|
43
|
+
expect(subject.grammar_accept('35').to_s).to eq(grxml.to_s)
|
44
44
|
end
|
45
45
|
|
46
46
|
it 'filters meaningless characters out' do
|
47
|
-
subject.grammar_accept('3+5').to_s.
|
47
|
+
expect(subject.grammar_accept('3+5').to_s).to eq(grxml.to_s)
|
48
48
|
end
|
49
49
|
end # grammar_accept
|
50
50
|
|
51
51
|
describe "#parse_dtmf" do
|
52
52
|
context "with a single digit" do
|
53
53
|
it "correctly returns the parsed input" do
|
54
|
-
subject.parse_dtmf("dtmf-3").
|
54
|
+
expect(subject.parse_dtmf("dtmf-3")).to eq('3')
|
55
55
|
end
|
56
56
|
|
57
57
|
it "correctly returns star as *" do
|
58
|
-
subject.parse_dtmf("dtmf-star").
|
58
|
+
expect(subject.parse_dtmf("dtmf-star")).to eq('*')
|
59
59
|
end
|
60
60
|
|
61
61
|
it "correctly returns * as *" do
|
62
|
-
subject.parse_dtmf("*").
|
62
|
+
expect(subject.parse_dtmf("*")).to eq('*')
|
63
63
|
end
|
64
64
|
|
65
65
|
it "correctly returns pound as #" do
|
66
|
-
subject.parse_dtmf("dtmf-pound").
|
66
|
+
expect(subject.parse_dtmf("dtmf-pound")).to eq('#')
|
67
67
|
end
|
68
68
|
|
69
69
|
it "correctly returns # as #" do
|
70
|
-
subject.parse_dtmf("#").
|
70
|
+
expect(subject.parse_dtmf("#")).to eq('#')
|
71
71
|
end
|
72
72
|
|
73
73
|
it "correctly parses digits without the dtmf- prefix" do
|
74
|
-
subject.parse_dtmf('1').
|
74
|
+
expect(subject.parse_dtmf('1')).to eq('1')
|
75
75
|
end
|
76
76
|
|
77
77
|
it "correctly returns nil when input is nil" do
|
78
|
-
subject.parse_dtmf(nil).
|
78
|
+
expect(subject.parse_dtmf(nil)).to eq(nil)
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
82
82
|
context "with multiple digits separated by spaces" do
|
83
83
|
it "returns the digits without space separation" do
|
84
|
-
subject.parse_dtmf('1 dtmf-5 dtmf-star # 2').
|
84
|
+
expect(subject.parse_dtmf('1 dtmf-5 dtmf-star # 2')).to eq('15*#2')
|
85
85
|
end
|
86
86
|
end
|
87
87
|
end # describe #grammar_accept
|
@@ -11,26 +11,40 @@ module Adhearsion
|
|
11
11
|
|
12
12
|
let(:call) { Adhearsion::Call.new mock_offer(nil, :x_foo => 'bar') }
|
13
13
|
|
14
|
-
|
15
|
-
|
14
|
+
describe '#call' do
|
15
|
+
subject { super().call }
|
16
|
+
it { is_expected.to be call }
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#metadata' do
|
20
|
+
subject { super().metadata }
|
21
|
+
it { is_expected.to eq({:doo => :dah}) }
|
22
|
+
end
|
16
23
|
|
17
24
|
describe "setting meta-data" do
|
18
25
|
it "should preserve data correctly" do
|
19
|
-
subject[:foo].
|
26
|
+
expect(subject[:foo]).to be nil
|
20
27
|
subject[:foo] = 7
|
21
|
-
subject[:foo].
|
28
|
+
expect(subject[:foo]).to eq(7)
|
22
29
|
subject[:bar] = 10
|
23
|
-
subject[:bar].
|
24
|
-
subject[:foo].
|
30
|
+
expect(subject[:bar]).to eq(10)
|
31
|
+
expect(subject[:foo]).to eq(7)
|
25
32
|
end
|
26
33
|
end
|
27
34
|
|
28
|
-
|
29
|
-
|
35
|
+
describe '#logger' do
|
36
|
+
subject { super().logger }
|
37
|
+
it { is_expected.to be call.logger }
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '#variables' do
|
41
|
+
subject { super().variables }
|
42
|
+
it { is_expected.to be call.variables }
|
43
|
+
end
|
30
44
|
|
31
45
|
describe "#send_message" do
|
32
46
|
it 'should send a message' do
|
33
|
-
call.
|
47
|
+
expect(call).to receive(:send_message).with("Hello World!").once
|
34
48
|
subject.send_message "Hello World!"
|
35
49
|
end
|
36
50
|
end
|
@@ -39,46 +53,44 @@ module Adhearsion
|
|
39
53
|
before { call.terminate }
|
40
54
|
|
41
55
|
it "should use an unnamed logger" do
|
42
|
-
subject.logger.
|
43
|
-
subject.logger.name.
|
56
|
+
expect(subject.logger).to be_a ::Logging::Logger
|
57
|
+
expect(subject.logger.name).to eq("Adhearsion::CallController")
|
44
58
|
end
|
45
59
|
end
|
46
60
|
|
47
61
|
describe "execution on a call" do
|
48
62
|
before do
|
49
|
-
subject.
|
50
|
-
call.wrapped_object.
|
63
|
+
allow(subject).to receive_messages :execute_component_and_await_completion => nil
|
64
|
+
allow(call.wrapped_object).to receive_messages :write_and_await_response => nil
|
51
65
|
end
|
52
66
|
|
53
67
|
it "catches Hangup exceptions and logs the hangup" do
|
54
|
-
subject.
|
55
|
-
subject.
|
56
|
-
subject.execute!
|
68
|
+
expect(subject).to receive(:run).once.ordered.and_raise(Call::Hangup)
|
69
|
+
subject.exec
|
57
70
|
end
|
58
71
|
|
59
72
|
context "when trying to execute a command against a dead call" do
|
60
73
|
before do
|
61
|
-
subject.
|
74
|
+
expect(subject).to receive(:run).once.ordered.and_raise(Call::ExpiredError)
|
62
75
|
end
|
63
76
|
|
64
77
|
it "gracefully terminates " do
|
65
|
-
subject.
|
66
|
-
subject.execute!
|
78
|
+
subject.exec
|
67
79
|
end
|
68
80
|
end
|
69
81
|
|
70
82
|
it "catches standard errors, triggering an exception event" do
|
71
|
-
subject.
|
83
|
+
expect(subject).to receive(:run).once.ordered.and_raise(StandardError)
|
72
84
|
latch = CountDownLatch.new 1
|
73
85
|
ex = lo = nil
|
74
86
|
Events.exception do |e, l|
|
75
87
|
ex, lo = e, l
|
76
88
|
latch.countdown!
|
77
89
|
end
|
78
|
-
subject.
|
79
|
-
latch.wait(1).
|
80
|
-
ex.
|
81
|
-
lo.
|
90
|
+
expect { subject.exec }.to raise_error
|
91
|
+
expect(latch.wait(1)).to be true
|
92
|
+
expect(ex).to be_a StandardError
|
93
|
+
expect(lo).to be subject.logger
|
82
94
|
end
|
83
95
|
|
84
96
|
context "when a block is specified" do
|
@@ -88,16 +100,19 @@ module Adhearsion
|
|
88
100
|
Proc.new { foo value }
|
89
101
|
end
|
90
102
|
|
91
|
-
|
103
|
+
describe '#block' do
|
104
|
+
subject { super().block }
|
105
|
+
it { is_expected.to be block }
|
106
|
+
end
|
92
107
|
|
93
108
|
it "should execute the block in the context of the controller" do
|
94
|
-
subject.
|
95
|
-
subject.
|
109
|
+
allow(subject).to receive_messages :value => :bar
|
110
|
+
expect(subject).to receive(:foo).once.with(:bar)
|
96
111
|
subject.run
|
97
112
|
end
|
98
113
|
|
99
114
|
it "should make the block's context available" do
|
100
|
-
subject.
|
115
|
+
expect(subject).to receive(:foo).once.with(:bar)
|
101
116
|
subject.run
|
102
117
|
end
|
103
118
|
end
|
@@ -146,39 +161,39 @@ module Adhearsion
|
|
146
161
|
subject { InvokeController.new call }
|
147
162
|
|
148
163
|
before do
|
149
|
-
subject.
|
150
|
-
call.wrapped_object.
|
151
|
-
call.
|
152
|
-
Events.
|
164
|
+
allow(subject).to receive_messages :execute_component_and_await_completion => nil
|
165
|
+
allow(call.wrapped_object).to receive_messages :write_and_await_response => nil
|
166
|
+
allow(call).to receive_messages :register_controller => nil
|
167
|
+
expect(Events).to receive(:trigger).with(:exception, Exception).never
|
153
168
|
end
|
154
169
|
|
155
170
|
it "should invoke another controller before returning to the current controller" do
|
156
|
-
subject.
|
157
|
-
call.
|
158
|
-
subject.
|
171
|
+
expect(subject).to receive(:before).once.ordered
|
172
|
+
expect(call).to receive(:answer).once.ordered
|
173
|
+
expect(subject).to receive(:after).once.ordered
|
159
174
|
|
160
|
-
subject.
|
175
|
+
subject.exec
|
161
176
|
end
|
162
177
|
|
163
178
|
it "should return the outer controller's run method return value" do
|
164
|
-
SecondController.
|
165
|
-
subject.
|
166
|
-
subject.metadata[:invoke_result].
|
179
|
+
expect_any_instance_of(SecondController).to receive(:run).once.and_return(:run_result)
|
180
|
+
subject.exec
|
181
|
+
expect(subject.metadata[:invoke_result]).to eq(:run_result)
|
167
182
|
end
|
168
183
|
|
169
184
|
it "should invoke the new controller with metadata" do
|
170
|
-
SecondController.
|
171
|
-
subject.
|
185
|
+
expect_any_instance_of(SecondController).to receive(:md_check).once.with :foo => 'bar'
|
186
|
+
subject.exec
|
172
187
|
end
|
173
188
|
|
174
189
|
it "should allow the outer controller to cease execution and handle remote hangups" do
|
175
190
|
subject[:second_controller] = SecondControllerWithRemoteHangup
|
176
191
|
|
177
|
-
subject.
|
178
|
-
call.
|
179
|
-
subject.
|
192
|
+
expect(subject).to receive(:before).once.ordered
|
193
|
+
expect(call).to receive(:answer).once.ordered
|
194
|
+
expect(subject).to receive(:after).never.ordered
|
180
195
|
|
181
|
-
subject.
|
196
|
+
subject.exec
|
182
197
|
end
|
183
198
|
end
|
184
199
|
|
@@ -207,25 +222,25 @@ module Adhearsion
|
|
207
222
|
subject { pass_controller.new call }
|
208
223
|
|
209
224
|
before do
|
210
|
-
call.wrapped_object.
|
211
|
-
call.
|
212
|
-
subject.
|
213
|
-
SecondController.
|
214
|
-
Events.
|
225
|
+
allow(call.wrapped_object).to receive_messages :write_and_await_response => nil
|
226
|
+
allow(call).to receive_messages :register_controller => nil
|
227
|
+
allow(subject).to receive_messages :execute_component_and_await_completion => nil
|
228
|
+
expect_any_instance_of(SecondController).to receive(:md_check).once.with :foo => 'bar'
|
229
|
+
expect(Events).to receive(:trigger).with(:exception, Exception).never
|
215
230
|
end
|
216
231
|
|
217
232
|
it "should cease execution of the current controller, and instruct the call to execute another" do
|
218
|
-
subject.
|
219
|
-
call.
|
220
|
-
subject.
|
233
|
+
expect(subject).to receive(:before).once.ordered
|
234
|
+
expect(call).to receive(:answer).once.ordered
|
235
|
+
expect(subject).to receive(:after).never.ordered
|
221
236
|
|
222
237
|
subject.exec
|
223
238
|
end
|
224
239
|
|
225
240
|
it "should execute after_call callbacks before passing control" do
|
226
|
-
subject.
|
227
|
-
subject.
|
228
|
-
call.
|
241
|
+
expect(subject).to receive(:before).once.ordered
|
242
|
+
expect(subject).to receive(:foobar).once.ordered
|
243
|
+
expect(call).to receive(:answer).once.ordered
|
229
244
|
|
230
245
|
subject.exec
|
231
246
|
end
|
@@ -243,17 +258,17 @@ module Adhearsion
|
|
243
258
|
subject { pass_controller.new call }
|
244
259
|
|
245
260
|
before do
|
246
|
-
call.wrapped_object.
|
261
|
+
allow(call.wrapped_object).to receive(:write_and_await_response) do |command|
|
247
262
|
command.request!
|
248
263
|
command.execute!
|
249
264
|
end
|
250
|
-
call.
|
251
|
-
SecondController.
|
252
|
-
Events.
|
265
|
+
allow(call).to receive_messages register_controller: nil
|
266
|
+
expect_any_instance_of(SecondController).to receive(:md_check).once.with :foo => 'bar'
|
267
|
+
expect(Events).to receive(:trigger).with(:exception, Exception).never
|
253
268
|
end
|
254
269
|
|
255
270
|
it "should cease execution of the current controller, and instruct the call to execute another" do
|
256
|
-
call.
|
271
|
+
expect(call).to receive(:answer).once.ordered
|
257
272
|
|
258
273
|
subject.exec
|
259
274
|
end
|
@@ -278,17 +293,17 @@ module Adhearsion
|
|
278
293
|
|
279
294
|
context "but not yet received a complete event" do
|
280
295
|
it "should terminate the components" do
|
281
|
-
subject.output1.
|
282
|
-
subject.output2.
|
296
|
+
expect(subject.output1).to receive(:stop!).once
|
297
|
+
expect(subject.output2).to receive(:stop!).once
|
283
298
|
|
284
299
|
subject.exec
|
285
300
|
end
|
286
301
|
|
287
302
|
context "and some fail to terminate" do
|
288
|
-
before { subject.output1.
|
303
|
+
before { expect(subject.output1).to receive(:stop!).and_raise(Punchblock::Component::InvalidActionError) }
|
289
304
|
|
290
305
|
it "should terminate the others" do
|
291
|
-
subject.output2.
|
306
|
+
expect(subject.output2).to receive(:stop!).once
|
292
307
|
subject.exec
|
293
308
|
end
|
294
309
|
end
|
@@ -298,8 +313,8 @@ module Adhearsion
|
|
298
313
|
before { subject.output1.trigger_event_handler Punchblock::Event::Complete.new }
|
299
314
|
|
300
315
|
it "should not terminate the completed components" do
|
301
|
-
subject.output1.
|
302
|
-
subject.output2.
|
316
|
+
expect(subject.output1).to receive(:stop!).never
|
317
|
+
expect(subject.output2).to receive(:stop!).once
|
303
318
|
|
304
319
|
subject.exec
|
305
320
|
end
|
@@ -327,28 +342,28 @@ module Adhearsion
|
|
327
342
|
|
328
343
|
context "when components have been executed on the controller" do
|
329
344
|
before do
|
330
|
-
call.wrapped_object.
|
345
|
+
allow(call.wrapped_object).to receive(:write_and_await_response) do |command|
|
331
346
|
command.request!
|
332
347
|
command.execute!
|
333
348
|
end
|
334
|
-
call.
|
335
|
-
Events.
|
349
|
+
allow(call).to receive_messages register_controller: nil
|
350
|
+
expect(Events).to receive(:trigger).with(:exception, Exception).never
|
336
351
|
subject.prep_output
|
337
352
|
end
|
338
353
|
|
339
354
|
context "when they have not yet received a complete event" do
|
340
355
|
it "should terminate the components" do
|
341
|
-
subject.output1.
|
342
|
-
subject.output2.
|
356
|
+
expect(subject.output1).to receive(:stop!).once
|
357
|
+
expect(subject.output2).to receive(:stop!).once
|
343
358
|
|
344
359
|
subject.exec
|
345
360
|
end
|
346
361
|
|
347
362
|
context "and some fail to terminate" do
|
348
|
-
before { subject.output1.
|
363
|
+
before { expect(subject.output1).to receive(:stop!).and_raise(Punchblock::Component::InvalidActionError) }
|
349
364
|
|
350
365
|
it "should terminate the others" do
|
351
|
-
subject.output2.
|
366
|
+
expect(subject.output2).to receive(:stop!).once
|
352
367
|
subject.exec
|
353
368
|
end
|
354
369
|
end
|
@@ -358,8 +373,8 @@ module Adhearsion
|
|
358
373
|
before { subject.output1.trigger_event_handler Punchblock::Event::Complete.new }
|
359
374
|
|
360
375
|
it "should not terminate the completed components" do
|
361
|
-
subject.output1.
|
362
|
-
subject.output2.
|
376
|
+
expect(subject.output1).to receive(:stop!).never
|
377
|
+
expect(subject.output2).to receive(:stop!).once
|
363
378
|
|
364
379
|
subject.exec
|
365
380
|
end
|
@@ -371,10 +386,21 @@ module Adhearsion
|
|
371
386
|
let(:message) { Punchblock::Command::Accept.new }
|
372
387
|
|
373
388
|
it "delegates to the call, blocking first until it is allowed to execute" do
|
374
|
-
subject.
|
375
|
-
subject.call.
|
389
|
+
expect(subject).to receive(:block_until_resumed).once.ordered
|
390
|
+
expect(subject.call).to receive(:write_and_await_response).once.ordered.with(message)
|
376
391
|
subject.write_and_await_response message
|
377
392
|
end
|
393
|
+
|
394
|
+
it "allows complete events to bubble" do
|
395
|
+
bubbled = false
|
396
|
+
message = Punchblock::Component::Output.new
|
397
|
+
expect(subject.call).to receive(:write_and_await_response)
|
398
|
+
subject.write_and_await_response message
|
399
|
+
message.register_event_handler(Punchblock::Event::Complete) { bubbled = true }
|
400
|
+
expect(bubbled).to be false
|
401
|
+
message.trigger_event_handler Punchblock::Event::Complete.new
|
402
|
+
expect(bubbled).to be true
|
403
|
+
end
|
378
404
|
end
|
379
405
|
|
380
406
|
[ :answer,
|
@@ -382,8 +408,8 @@ module Adhearsion
|
|
382
408
|
:unmute].each do |method_name|
|
383
409
|
describe "##{method_name}" do
|
384
410
|
it "delegates to the call, blocking first until it is allowed to execute" do
|
385
|
-
subject.
|
386
|
-
subject.call.
|
411
|
+
expect(subject).to receive(:block_until_resumed).once.ordered
|
412
|
+
expect(subject.call).to receive(method_name).once.ordered
|
387
413
|
subject.send method_name
|
388
414
|
end
|
389
415
|
end
|
@@ -391,76 +417,77 @@ module Adhearsion
|
|
391
417
|
|
392
418
|
[
|
393
419
|
:hangup,
|
394
|
-
:reject
|
420
|
+
:reject,
|
421
|
+
:redirect
|
395
422
|
].each do |method_name|
|
396
423
|
describe "##{method_name}" do
|
397
424
|
it "delegates to the call, blocking first until it is allowed to execute, and raises Call::Hangup" do
|
398
|
-
subject.
|
399
|
-
subject.call.
|
400
|
-
|
425
|
+
expect(subject).to receive(:block_until_resumed).once.ordered
|
426
|
+
expect(subject.call).to receive(method_name).once.ordered
|
427
|
+
expect { subject.send method_name }.to raise_error Call::Hangup
|
401
428
|
end
|
402
429
|
end
|
403
430
|
end
|
404
431
|
|
405
432
|
describe "#join" do
|
406
433
|
it "delegates to the call, blocking first until it is allowed to execute, and unblocking when an unjoined event is received" do
|
407
|
-
subject.
|
408
|
-
call.wrapped_object.
|
434
|
+
expect(subject).to receive(:block_until_resumed).once.ordered
|
435
|
+
expect(call.wrapped_object).to receive(:write_and_await_response).once.ordered.with(Punchblock::Command::Join.new(call_uri: 'call1'))
|
409
436
|
latch = CountDownLatch.new 1
|
410
437
|
Thread.new do
|
411
438
|
subject.join 'call1', :foo => :bar
|
412
439
|
latch.countdown!
|
413
440
|
end
|
414
|
-
latch.wait(1).
|
441
|
+
expect(latch.wait(1)).to be false
|
415
442
|
subject.call << Punchblock::Event::Joined.new(call_uri: 'call1')
|
416
|
-
latch.wait(1).
|
443
|
+
expect(latch.wait(1)).to be false
|
417
444
|
subject.call << Punchblock::Event::Unjoined.new(call_uri: 'call1')
|
418
|
-
latch.wait(1).
|
445
|
+
expect(latch.wait(1)).to be true
|
419
446
|
end
|
420
447
|
|
421
448
|
context "with a mixer" do
|
422
449
|
it "delegates to the call, blocking first until it is allowed to execute, and unblocking when an unjoined event is received" do
|
423
|
-
subject.
|
424
|
-
call.wrapped_object.
|
450
|
+
expect(subject).to receive(:block_until_resumed).once.ordered
|
451
|
+
expect(call.wrapped_object).to receive(:write_and_await_response).once.ordered.with(Punchblock::Command::Join.new(mixer_name: 'foobar'))
|
425
452
|
latch = CountDownLatch.new 1
|
426
453
|
Thread.new do
|
427
454
|
subject.join :mixer_name => 'foobar', :foo => :bar
|
428
455
|
latch.countdown!
|
429
456
|
end
|
430
|
-
latch.wait(1).
|
457
|
+
expect(latch.wait(1)).to be false
|
431
458
|
subject.call << Punchblock::Event::Joined.new(:mixer_name => 'foobar')
|
432
|
-
latch.wait(1).
|
459
|
+
expect(latch.wait(1)).to be false
|
433
460
|
subject.call << Punchblock::Event::Unjoined.new(:mixer_name => 'foobar')
|
434
|
-
latch.wait(1).
|
461
|
+
expect(latch.wait(1)).to be true
|
435
462
|
end
|
436
463
|
end
|
437
464
|
|
438
465
|
context "with :async => true" do
|
439
466
|
it "delegates to the call, blocking first until it is allowed to execute, and unblocking when the joined event is received" do
|
440
|
-
subject.
|
441
|
-
call.wrapped_object.
|
467
|
+
expect(subject).to receive(:block_until_resumed).once.ordered
|
468
|
+
expect(call.wrapped_object).to receive(:write_and_await_response).once.ordered.with(Punchblock::Command::Join.new(call_uri: 'call1'))
|
442
469
|
latch = CountDownLatch.new 1
|
443
470
|
Thread.new do
|
444
471
|
subject.join 'call1', :foo => :bar, :async => true
|
445
472
|
latch.countdown!
|
446
473
|
end
|
447
|
-
latch.wait(1).
|
474
|
+
expect(latch.wait(1)).to be false
|
448
475
|
subject.call << Punchblock::Event::Joined.new(call_uri: 'call1')
|
449
|
-
latch.wait(1).
|
476
|
+
expect(latch.wait(1)).to be true
|
450
477
|
end
|
451
478
|
|
452
479
|
context "with a mixer" do
|
453
480
|
it "delegates to the call, blocking first until it is allowed to execute, and unblocking when the joined event is received" do
|
454
|
-
subject.
|
455
|
-
call.wrapped_object.
|
481
|
+
expect(subject).to receive(:block_until_resumed).once.ordered
|
482
|
+
expect(call.wrapped_object).to receive(:write_and_await_response).once.ordered.with(Punchblock::Command::Join.new(mixer_name: 'foobar'))
|
456
483
|
latch = CountDownLatch.new 1
|
457
484
|
Thread.new do
|
458
485
|
subject.join :mixer_name => 'foobar', :foo => :bar, :async => true
|
459
486
|
latch.countdown!
|
460
487
|
end
|
461
|
-
latch.wait(1).
|
488
|
+
expect(latch.wait(1)).to be false
|
462
489
|
subject.call << Punchblock::Event::Joined.new(:mixer_name => 'foobar')
|
463
|
-
latch.wait(1).
|
490
|
+
expect(latch.wait(1)).to be true
|
464
491
|
end
|
465
492
|
end
|
466
493
|
end
|
@@ -473,7 +500,7 @@ module Adhearsion
|
|
473
500
|
subject.block_until_resumed
|
474
501
|
t2 = Time.now
|
475
502
|
|
476
|
-
(t2 - t1).
|
503
|
+
expect(t2 - t1).to be < 0.2
|
477
504
|
end
|
478
505
|
end
|
479
506
|
|
@@ -494,9 +521,9 @@ module Adhearsion
|
|
494
521
|
|
495
522
|
subject.resume!
|
496
523
|
|
497
|
-
latch.wait(1).
|
524
|
+
expect(latch.wait(1)).to be_truthy
|
498
525
|
|
499
|
-
(t2 - t1).
|
526
|
+
expect(t2 - t1).to be >= 0.5
|
500
527
|
end
|
501
528
|
end
|
502
529
|
end
|
@@ -518,13 +545,13 @@ module Adhearsion
|
|
518
545
|
|
519
546
|
it "takes a block which is executed after acknowledgement but before waiting on completion" do
|
520
547
|
@comp = nil
|
521
|
-
subject.execute_component_and_await_completion(component) { |comp| @comp = comp }.
|
522
|
-
@comp.
|
548
|
+
expect(subject.execute_component_and_await_completion(component) { |comp| @comp = comp }).to eq(component)
|
549
|
+
expect(@comp).to eq(component)
|
523
550
|
end
|
524
551
|
|
525
552
|
describe "with a successful completion" do
|
526
553
|
it "returns the executed component" do
|
527
|
-
subject.execute_component_and_await_completion(component).
|
554
|
+
expect(subject.execute_component_and_await_completion(component)).to be component
|
528
555
|
end
|
529
556
|
end
|
530
557
|
|
@@ -540,7 +567,7 @@ module Adhearsion
|
|
540
567
|
let(:details) { "Oh noes, it's all borked" }
|
541
568
|
|
542
569
|
it "raises the error" do
|
543
|
-
|
570
|
+
expect { subject.execute_component_and_await_completion component }.to raise_error(Adhearsion::Error, "#{details}: #{component}")
|
544
571
|
end
|
545
572
|
end
|
546
573
|
|
@@ -554,7 +581,7 @@ module Adhearsion
|
|
554
581
|
end
|
555
582
|
starting_time = Time.now
|
556
583
|
subject.execute_component_and_await_completion slow_component
|
557
|
-
(Time.now - starting_time).
|
584
|
+
expect(Time.now - starting_time).to be > 0.5
|
558
585
|
end
|
559
586
|
end
|
560
587
|
|
@@ -563,7 +590,7 @@ module Adhearsion
|
|
563
590
|
let(:other) { CallController.new call, metadata }
|
564
591
|
|
565
592
|
it "should be equal" do
|
566
|
-
subject.
|
593
|
+
expect(subject).to eq(other)
|
567
594
|
end
|
568
595
|
end
|
569
596
|
|
@@ -571,7 +598,7 @@ module Adhearsion
|
|
571
598
|
let(:other) { Class.new(CallController).new call, metadata }
|
572
599
|
|
573
600
|
it "should not be equal" do
|
574
|
-
subject.
|
601
|
+
expect(subject).not_to eq(other)
|
575
602
|
end
|
576
603
|
end
|
577
604
|
|
@@ -579,7 +606,7 @@ module Adhearsion
|
|
579
606
|
let(:other) { CallController.new Call.new, metadata }
|
580
607
|
|
581
608
|
it "should not be equal" do
|
582
|
-
subject.
|
609
|
+
expect(subject).not_to eq(other)
|
583
610
|
end
|
584
611
|
end
|
585
612
|
|
@@ -587,7 +614,7 @@ module Adhearsion
|
|
587
614
|
let(:other) { CallController.new call, something: 'else' }
|
588
615
|
|
589
616
|
it "should not be equal" do
|
590
|
-
subject.
|
617
|
+
expect(subject).not_to eq(other)
|
591
618
|
end
|
592
619
|
end
|
593
620
|
end
|
@@ -601,12 +628,18 @@ class ExampleCallController < Adhearsion::CallController
|
|
601
628
|
after_call { clean_up_models }
|
602
629
|
after_call :clean_up_models
|
603
630
|
|
631
|
+
on_error { apologize_for_failure }
|
632
|
+
on_error :apologize_for_failure
|
633
|
+
|
604
634
|
def setup_models
|
605
635
|
end
|
606
636
|
|
607
637
|
def clean_up_models
|
608
638
|
end
|
609
639
|
|
640
|
+
def apologize_for_failure
|
641
|
+
end
|
642
|
+
|
610
643
|
def run
|
611
644
|
join_to_conference
|
612
645
|
hangup unless metadata[:skip_hangup]
|
@@ -624,44 +657,51 @@ describe ExampleCallController do
|
|
624
657
|
include CallControllerTestHelpers
|
625
658
|
|
626
659
|
before do
|
627
|
-
subject.
|
628
|
-
call.wrapped_object.
|
660
|
+
allow(subject).to receive_messages :execute_component_and_await_completion => nil
|
661
|
+
allow(call.wrapped_object).to receive_messages :write_and_await_response => nil
|
629
662
|
end
|
630
663
|
|
631
664
|
it "should execute the before_call callbacks before processing the call" do
|
632
|
-
subject.
|
633
|
-
subject.
|
634
|
-
subject.
|
665
|
+
expect(subject).to receive(:setup_models).twice.ordered
|
666
|
+
expect(subject).to receive(:join_to_conference).once.ordered
|
667
|
+
subject.exec
|
635
668
|
end
|
636
669
|
|
637
670
|
it "should execute the after_call callbacks after the call is hung up" do
|
638
|
-
subject.
|
639
|
-
subject.
|
640
|
-
subject.
|
641
|
-
subject.
|
671
|
+
expect(subject).to receive(:join_to_conference).once.ordered
|
672
|
+
expect(subject).to receive(:clean_up_models).twice.ordered
|
673
|
+
expect(subject).to receive(:foobar).never
|
674
|
+
subject.exec
|
642
675
|
end
|
643
676
|
|
644
677
|
it "should capture errors in callbacks" do
|
645
|
-
subject.
|
646
|
-
subject.
|
678
|
+
expect(subject).to receive(:setup_models).twice.and_raise StandardError
|
679
|
+
expect(subject).to receive(:clean_up_models).twice.and_raise StandardError
|
647
680
|
latch = CountDownLatch.new 4
|
648
681
|
Adhearsion::Events.exception do |e, l|
|
649
|
-
e.
|
650
|
-
l.
|
682
|
+
expect(e).to be_a StandardError
|
683
|
+
expect(l).to be subject.logger
|
651
684
|
latch.countdown!
|
652
685
|
end
|
653
|
-
subject.
|
654
|
-
latch.wait(1).
|
686
|
+
subject.exec
|
687
|
+
expect(latch.wait(1)).to be true
|
655
688
|
Adhearsion::Events.clear_handlers :exception
|
656
689
|
end
|
657
690
|
|
691
|
+
it "should call the requested method when an exception is encountered" do
|
692
|
+
expect(subject).to receive(:join_to_conference).once.and_raise StandardError
|
693
|
+
expect(subject).to receive(:apologize_for_failure).twice.ordered
|
694
|
+
|
695
|
+
expect { subject.exec }.to raise_error
|
696
|
+
end
|
697
|
+
|
658
698
|
describe "when the controller finishes without a hangup" do
|
659
699
|
it "should execute the after_call callbacks" do
|
660
700
|
subject[:skip_hangup] = true
|
661
|
-
subject.
|
662
|
-
subject.
|
663
|
-
subject.
|
664
|
-
subject.
|
701
|
+
expect(subject).to receive(:join_to_conference).once.ordered
|
702
|
+
expect(subject).to receive(:foobar).once.ordered
|
703
|
+
expect(subject).to receive(:clean_up_models).twice.ordered
|
704
|
+
subject.exec
|
665
705
|
end
|
666
706
|
end
|
667
707
|
|
@@ -670,13 +710,13 @@ describe ExampleCallController do
|
|
670
710
|
|
671
711
|
it "should allow mixing in a module globally on all CallController classes" do
|
672
712
|
Adhearsion::CallController.mixin TestBiscuit
|
673
|
-
Adhearsion::CallController.new(call).
|
713
|
+
expect(Adhearsion::CallController.new(call)).to respond_to :throwadogabone
|
674
714
|
end
|
675
715
|
|
676
716
|
it "should allow mixing in a module on a single CallController class" do
|
677
717
|
FinancialWizard.mixin MarmaladeIsBetterThanJam
|
678
|
-
FinancialWizard.new(call).
|
679
|
-
Adhearsion::CallController.new(call).
|
718
|
+
expect(FinancialWizard.new(call)).to respond_to :sobittersweet
|
719
|
+
expect(Adhearsion::CallController.new(call)).not_to respond_to :sobittersweet
|
680
720
|
end
|
681
721
|
end
|
682
722
|
end
|