adhearsion 2.5.4 → 2.6.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.
- 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
|