adhearsion 2.4.0 → 2.5.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/.travis.yml +3 -3
- data/CHANGELOG.md +29 -0
- data/Gemfile +0 -2
- data/Guardfile +2 -2
- data/README.markdown +3 -6
- data/Rakefile +1 -1
- data/adhearsion.gemspec +7 -2
- data/features/cli_create.feature +85 -7
- data/features/plugin_generator.feature +4 -0
- data/features/step_definitions/app_generator_steps.rb +8 -1
- data/lib/adhearsion.rb +6 -3
- data/lib/adhearsion/call.rb +101 -30
- data/lib/adhearsion/call_controller.rb +40 -12
- data/lib/adhearsion/call_controller/dial.rb +119 -36
- data/lib/adhearsion/call_controller/input.rb +11 -5
- data/lib/adhearsion/call_controller/output.rb +47 -33
- data/lib/adhearsion/call_controller/output/async_player.rb +3 -2
- data/lib/adhearsion/call_controller/output/formatter.rb +7 -2
- data/lib/adhearsion/call_controller/output/player.rb +2 -2
- data/lib/adhearsion/call_controller/record.rb +16 -13
- data/lib/adhearsion/call_controller/utility.rb +3 -3
- data/lib/adhearsion/calls.rb +21 -8
- data/lib/adhearsion/cli_commands/ahn_command.rb +1 -0
- data/lib/adhearsion/configuration.rb +2 -2
- data/lib/adhearsion/console.rb +3 -2
- data/lib/adhearsion/generators.rb +7 -9
- data/lib/adhearsion/generators/app/app_generator.rb +12 -2
- data/lib/adhearsion/generators/app/templates/Gemfile.erb +7 -9
- data/lib/adhearsion/generators/app/templates/README.md +0 -19
- data/lib/adhearsion/generators/app/templates/adhearsion.erb +37 -0
- data/lib/adhearsion/generators/app/templates/config/environment.rb +6 -1
- data/lib/adhearsion/generators/app/templates/events.erb +18 -0
- data/lib/adhearsion/generators/app/templates/routes.erb +19 -0
- data/lib/adhearsion/generators/app/templates/{lib/simon_game.rb → simon_game.rb} +0 -0
- data/lib/adhearsion/generators/app/templates/{spec/call_controllers/simon_game_spec.rb → simon_game_spec.rb} +0 -0
- data/lib/adhearsion/generators/controller/controller_generator.rb +2 -2
- data/lib/adhearsion/generators/controller/templates/lib/{controller.rb → controller.rb.erb} +0 -0
- data/lib/adhearsion/generators/controller/templates/spec/{controller_spec.rb → controller_spec.rb.erb} +0 -0
- data/lib/adhearsion/generators/plugin/plugin_generator.rb +16 -15
- data/lib/adhearsion/generators/plugin/templates/gitignore +17 -0
- data/lib/adhearsion/generators/plugin/templates/spec/plugin-template/controller_methods_spec.rb.tt +1 -1
- data/lib/adhearsion/initializer.rb +14 -2
- data/lib/adhearsion/logging.rb +1 -0
- data/lib/adhearsion/outbound_call.rb +3 -7
- data/lib/adhearsion/punchblock_plugin/initializer.rb +3 -2
- data/lib/adhearsion/router/openended_route.rb +1 -1
- data/lib/adhearsion/router/route.rb +4 -3
- data/lib/adhearsion/version.rb +1 -1
- data/spec/adhearsion/call_controller/dial_spec.rb +811 -79
- data/spec/adhearsion/call_controller/output/formatter_spec.rb +13 -1
- data/spec/adhearsion/call_controller/output_spec.rb +35 -1
- data/spec/adhearsion/call_controller_spec.rb +174 -18
- data/spec/adhearsion/call_spec.rb +423 -39
- data/spec/adhearsion/calls_spec.rb +19 -3
- data/spec/adhearsion/outbound_call_spec.rb +88 -45
- data/spec/adhearsion/punchblock_plugin/initializer_spec.rb +3 -3
- data/spec/adhearsion/router/route_spec.rb +2 -2
- data/spec/spec_helper.rb +2 -0
- metadata +92 -77
- data/features/app_generator.feature +0 -49
- data/lib/adhearsion/generators/app/templates/config/adhearsion.rb +0 -71
- data/lib/adhearsion/generators/plugin/templates/.gitignore +0 -9
@@ -19,6 +19,8 @@ module Adhearsion
|
|
19
19
|
|
20
20
|
let(:latch) { CountDownLatch.new 1 }
|
21
21
|
|
22
|
+
let(:join_options) { options[:join_options] || {} }
|
23
|
+
|
22
24
|
before do
|
23
25
|
other_mock_call.wrapped_object.stub id: other_call_id, write_command: true
|
24
26
|
second_other_mock_call.wrapped_object.stub id: second_other_call_id, write_command: true
|
@@ -96,7 +98,7 @@ module Adhearsion
|
|
96
98
|
|
97
99
|
it "joins the new call to the existing one on answer" do
|
98
100
|
call.should_receive(:answer).once
|
99
|
-
other_mock_call.should_receive(:join).once.with(call)
|
101
|
+
other_mock_call.should_receive(:join).once.with(call, {})
|
100
102
|
|
101
103
|
dial_in_thread
|
102
104
|
|
@@ -108,9 +110,110 @@ module Adhearsion
|
|
108
110
|
latch.wait(1).should be_true
|
109
111
|
end
|
110
112
|
|
113
|
+
context "with a join target specified" do
|
114
|
+
let(:options) { { join_target: {mixer_name: 'foobar'} } }
|
115
|
+
|
116
|
+
it "joins the calls to the specified target on answer" do
|
117
|
+
call.should_receive(:answer).once
|
118
|
+
call.should_receive(:join).once.with({mixer_name: 'foobar'}, {})
|
119
|
+
other_mock_call.should_receive(:join).once.with({mixer_name: 'foobar'}, {})
|
120
|
+
|
121
|
+
dial_in_thread
|
122
|
+
|
123
|
+
latch.wait(1).should be_false
|
124
|
+
|
125
|
+
other_mock_call << mock_answered
|
126
|
+
other_mock_call << mock_end
|
127
|
+
|
128
|
+
latch.wait(1).should be_true
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
context "with a pre-join callback specified" do
|
133
|
+
let(:foo) { double }
|
134
|
+
let(:options) { { pre_join: ->(call) { foo.bar call } } }
|
135
|
+
|
136
|
+
it "executes the callback prior to joining" do
|
137
|
+
foo.should_receive(:bar).once.with(other_mock_call).ordered
|
138
|
+
call.should_receive(:answer).once.ordered
|
139
|
+
other_mock_call.should_receive(:join).once.with(call, {}).ordered
|
140
|
+
|
141
|
+
dial_in_thread
|
142
|
+
|
143
|
+
latch.wait(1).should be_false
|
144
|
+
|
145
|
+
other_mock_call << mock_answered
|
146
|
+
other_mock_call << mock_end
|
147
|
+
|
148
|
+
latch.wait(1).should be_true
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
context "with ringback specified" do
|
153
|
+
let(:component) { Punchblock::Component::Output.new }
|
154
|
+
let(:options) { { ringback: ['file://tt-monkeys'] } }
|
155
|
+
|
156
|
+
before do
|
157
|
+
component.request!
|
158
|
+
component.execute!
|
159
|
+
end
|
160
|
+
|
161
|
+
it "plays the ringback asynchronously, terminating prior to joining" do
|
162
|
+
subject.should_receive(:play!).once.with(['file://tt-monkeys'], repeat_times: 0).and_return(component)
|
163
|
+
component.should_receive(:stop!).twice
|
164
|
+
call.should_receive(:answer).once.ordered
|
165
|
+
other_mock_call.should_receive(:join).once.with(call, {}).ordered
|
166
|
+
|
167
|
+
dial_in_thread
|
168
|
+
|
169
|
+
latch.wait(1).should be_false
|
170
|
+
|
171
|
+
other_mock_call << mock_answered
|
172
|
+
other_mock_call << mock_end
|
173
|
+
|
174
|
+
latch.wait(1).should be_true
|
175
|
+
end
|
176
|
+
|
177
|
+
context "as a callback" do
|
178
|
+
let(:foo) { double }
|
179
|
+
let(:options) { { ringback: -> { foo.bar; component } } }
|
180
|
+
|
181
|
+
it "calls the callback to start, and uses the return value of the callback to stop the ringback" do
|
182
|
+
foo.should_receive(:bar).once.ordered
|
183
|
+
component.should_receive(:stop!).twice
|
184
|
+
call.should_receive(:answer).once.ordered
|
185
|
+
other_mock_call.should_receive(:join).once.with(call, {}).ordered
|
186
|
+
|
187
|
+
dial_in_thread
|
188
|
+
|
189
|
+
latch.wait(1).should be_false
|
190
|
+
|
191
|
+
other_mock_call << mock_answered
|
192
|
+
other_mock_call << mock_end
|
193
|
+
|
194
|
+
latch.wait(1).should be_true
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
context "when the call is rejected" do
|
199
|
+
it "terminates the ringback before returning" do
|
200
|
+
subject.should_receive(:play!).once.with(['file://tt-monkeys'], repeat_times: 0).and_return(component)
|
201
|
+
component.should_receive(:stop!).once
|
202
|
+
|
203
|
+
t = dial_in_thread
|
204
|
+
|
205
|
+
latch.wait(1).should be_false
|
206
|
+
|
207
|
+
other_mock_call << mock_end(:reject)
|
208
|
+
|
209
|
+
latch.wait(1).should be_true
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
111
214
|
it "hangs up the new call when the root call ends" do
|
112
215
|
call.should_receive(:answer).once
|
113
|
-
other_mock_call.should_receive(:join).once.with(call)
|
216
|
+
other_mock_call.should_receive(:join).once.with(call, {})
|
114
217
|
other_mock_call.should_receive(:hangup).once
|
115
218
|
|
116
219
|
dial_in_thread
|
@@ -162,7 +265,7 @@ module Adhearsion
|
|
162
265
|
context "when the call is answered and joined" do
|
163
266
|
it "has an overall dial status of :answer" do
|
164
267
|
call.should_receive(:answer).once
|
165
|
-
other_mock_call.should_receive(:join).once.with(call)
|
268
|
+
other_mock_call.should_receive(:join).once.with(call, {})
|
166
269
|
|
167
270
|
t = dial_in_thread
|
168
271
|
|
@@ -183,7 +286,7 @@ module Adhearsion
|
|
183
286
|
|
184
287
|
it "records the duration of the join" do
|
185
288
|
call.should_receive(:answer).once
|
186
|
-
other_mock_call.should_receive(:join).once.with(call)
|
289
|
+
other_mock_call.should_receive(:join).once.with(call, {})
|
187
290
|
other_mock_call.stub hangup: true
|
188
291
|
|
189
292
|
t = dial_in_thread
|
@@ -208,26 +311,51 @@ module Adhearsion
|
|
208
311
|
joined_status = status.joins[status.calls.first]
|
209
312
|
joined_status.duration.should == 37.0
|
210
313
|
end
|
314
|
+
|
315
|
+
context "when join options are specified" do
|
316
|
+
let(:options) { { join_options: {media: :direct} } }
|
317
|
+
|
318
|
+
it "joins the calls with those options" do
|
319
|
+
call.should_receive(:answer).once
|
320
|
+
other_mock_call.should_receive(:join).once.with(call, media: :direct)
|
321
|
+
other_mock_call.stub hangup: true
|
322
|
+
|
323
|
+
t = dial_in_thread
|
324
|
+
|
325
|
+
sleep 0.5
|
326
|
+
|
327
|
+
other_mock_call << mock_answered
|
328
|
+
|
329
|
+
other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
|
330
|
+
other_mock_call << mock_end
|
331
|
+
|
332
|
+
latch.wait(1).should be_true
|
333
|
+
|
334
|
+
t.join
|
335
|
+
end
|
336
|
+
end
|
211
337
|
end
|
212
338
|
|
213
339
|
context "when a dial is split" do
|
340
|
+
let(:join_target) { call }
|
341
|
+
|
214
342
|
before do
|
215
343
|
call.should_receive(:answer).once
|
216
|
-
other_mock_call.should_receive(:join).once.with(
|
217
|
-
|
344
|
+
other_mock_call.should_receive(:join).once.with(join_target, join_options)
|
345
|
+
other_mock_call.stub(:unjoin).and_return do
|
218
346
|
call << Punchblock::Event::Unjoined.new(call_uri: other_mock_call.id)
|
219
347
|
other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
|
220
348
|
end
|
221
349
|
end
|
222
350
|
|
223
351
|
it "should unjoin the calls" do
|
224
|
-
|
352
|
+
other_mock_call.should_receive(:unjoin).once.ordered.with(call).and_return do
|
225
353
|
call << Punchblock::Event::Unjoined.new(call_uri: other_mock_call.id)
|
226
354
|
other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
|
227
355
|
end
|
228
356
|
|
229
357
|
dial = Dial::Dial.new to, options, call
|
230
|
-
dial.run
|
358
|
+
dial.run subject
|
231
359
|
|
232
360
|
waiter_thread = Thread.new do
|
233
361
|
dial.await_completion
|
@@ -249,7 +377,7 @@ module Adhearsion
|
|
249
377
|
|
250
378
|
it "should not unblock immediately" do
|
251
379
|
dial = Dial::Dial.new to, options, call
|
252
|
-
dial.run
|
380
|
+
dial.run subject
|
253
381
|
|
254
382
|
waiter_thread = Thread.new do
|
255
383
|
dial.await_completion
|
@@ -274,7 +402,7 @@ module Adhearsion
|
|
274
402
|
|
275
403
|
it "should set end time" do
|
276
404
|
dial = Dial::Dial.new to, options, call
|
277
|
-
dial.run
|
405
|
+
dial.run subject
|
278
406
|
|
279
407
|
waiter_thread = Thread.new do
|
280
408
|
dial.await_completion
|
@@ -326,7 +454,7 @@ module Adhearsion
|
|
326
454
|
|
327
455
|
it "should execute the :main controller on the originating call and :others on the outbound calls" do
|
328
456
|
dial = Dial::Dial.new to, options, call
|
329
|
-
dial.run
|
457
|
+
dial.run subject
|
330
458
|
|
331
459
|
waiter_thread = Thread.new do
|
332
460
|
dial.await_completion
|
@@ -362,13 +490,13 @@ module Adhearsion
|
|
362
490
|
|
363
491
|
context "when rejoining" do
|
364
492
|
it "should rejoin the calls" do
|
365
|
-
|
493
|
+
other_mock_call.should_receive(:unjoin).once.ordered.with(call).and_return do
|
366
494
|
call << Punchblock::Event::Unjoined.new(call_uri: other_mock_call.id)
|
367
495
|
other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
|
368
496
|
end
|
369
497
|
|
370
498
|
dial = Dial::Dial.new to, options, call
|
371
|
-
dial.run
|
499
|
+
dial.run subject
|
372
500
|
|
373
501
|
waiter_thread = Thread.new do
|
374
502
|
dial.await_completion
|
@@ -381,7 +509,7 @@ module Adhearsion
|
|
381
509
|
|
382
510
|
dial.split
|
383
511
|
|
384
|
-
other_mock_call.should_receive(:join).once.ordered.with(call)
|
512
|
+
other_mock_call.should_receive(:join).once.ordered.with(call, {})
|
385
513
|
dial.rejoin
|
386
514
|
|
387
515
|
other_mock_call << mock_end
|
@@ -392,17 +520,122 @@ module Adhearsion
|
|
392
520
|
dial.status.result.should be == :answer
|
393
521
|
end
|
394
522
|
|
523
|
+
context "when join options were set originally" do
|
524
|
+
let(:options) { { join_options: {media: :direct} } }
|
525
|
+
|
526
|
+
it "should rejoin with the same parameters" do
|
527
|
+
other_mock_call.stub(:unjoin)
|
528
|
+
|
529
|
+
dial = Dial::Dial.new to, options, call
|
530
|
+
dial.run subject
|
531
|
+
|
532
|
+
other_mock_call << mock_answered
|
533
|
+
|
534
|
+
dial.split
|
535
|
+
|
536
|
+
other_mock_call.should_receive(:join).once.ordered.with(call, media: :direct)
|
537
|
+
dial.rejoin
|
538
|
+
end
|
539
|
+
end
|
540
|
+
|
541
|
+
context "when join options are passed to rejoin" do
|
542
|
+
it "should rejoin with those parameters" do
|
543
|
+
other_mock_call.stub(:unjoin)
|
544
|
+
|
545
|
+
dial = Dial::Dial.new to, options, call
|
546
|
+
dial.run subject
|
547
|
+
|
548
|
+
other_mock_call << mock_answered
|
549
|
+
|
550
|
+
dial.split
|
551
|
+
|
552
|
+
other_mock_call.should_receive(:join).once.ordered.with(call, media: :direct)
|
553
|
+
dial.rejoin nil, media: :direct
|
554
|
+
end
|
555
|
+
end
|
556
|
+
|
557
|
+
context "when a join target was originally specified" do
|
558
|
+
let(:join_target) { {mixer_name: 'foobar'} }
|
559
|
+
let(:options) { { join_target: join_target } }
|
560
|
+
|
561
|
+
it "joins the calls to the specified target on answer" do
|
562
|
+
call.should_receive(:join).once.with(join_target, {})
|
563
|
+
other_mock_call.should_receive(:unjoin).once.ordered.with(join_target)
|
564
|
+
call.should_receive(:unjoin).once.ordered.with(join_target).and_return do
|
565
|
+
call << Punchblock::Event::Unjoined.new(join_target)
|
566
|
+
other_mock_call << Punchblock::Event::Unjoined.new(join_target)
|
567
|
+
end
|
568
|
+
|
569
|
+
dial = Dial::Dial.new to, options, call
|
570
|
+
dial.run subject
|
571
|
+
|
572
|
+
waiter_thread = Thread.new do
|
573
|
+
dial.await_completion
|
574
|
+
latch.countdown!
|
575
|
+
end
|
576
|
+
|
577
|
+
sleep 0.5
|
578
|
+
|
579
|
+
other_mock_call << mock_answered
|
580
|
+
|
581
|
+
dial.split
|
582
|
+
|
583
|
+
call.should_receive(:join).once.ordered.with({mixer_name: 'foobar'}, {})
|
584
|
+
other_mock_call.should_receive(:join).once.ordered.with({mixer_name: 'foobar'}, {})
|
585
|
+
dial.rejoin
|
586
|
+
|
587
|
+
other_mock_call << mock_end
|
588
|
+
|
589
|
+
latch.wait(1).should be_true
|
590
|
+
|
591
|
+
waiter_thread.join
|
592
|
+
dial.status.result.should be == :answer
|
593
|
+
end
|
594
|
+
end
|
595
|
+
|
395
596
|
context "to a specified mixer" do
|
396
597
|
let(:mixer) { SecureRandom.uuid }
|
397
598
|
|
398
599
|
it "should join all calls to the mixer" do
|
399
|
-
|
600
|
+
other_mock_call.should_receive(:unjoin).once.ordered.with(call).and_return do
|
601
|
+
call << Punchblock::Event::Unjoined.new(call_uri: other_mock_call.id)
|
602
|
+
other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
|
603
|
+
end
|
604
|
+
|
605
|
+
dial = Dial::Dial.new to, options, call
|
606
|
+
dial.run subject
|
607
|
+
|
608
|
+
waiter_thread = Thread.new do
|
609
|
+
dial.await_completion
|
610
|
+
latch.countdown!
|
611
|
+
end
|
612
|
+
|
613
|
+
sleep 0.5
|
614
|
+
|
615
|
+
other_mock_call << mock_answered
|
616
|
+
|
617
|
+
dial.split
|
618
|
+
|
619
|
+
call.should_receive(:join).once.ordered.with({mixer_name: mixer}, {})
|
620
|
+
other_mock_call.should_receive(:join).once.ordered.with({mixer_name: mixer}, {})
|
621
|
+
dial.rejoin mixer_name: mixer
|
622
|
+
|
623
|
+
other_mock_call << mock_end
|
624
|
+
|
625
|
+
latch.wait(1).should be_true
|
626
|
+
|
627
|
+
waiter_thread.join
|
628
|
+
dial.status.result.should be == :answer
|
629
|
+
end
|
630
|
+
|
631
|
+
it "#split should then unjoin calls from the mixer" do
|
632
|
+
other_mock_call.should_receive(:unjoin).once.ordered.with(call).and_return do
|
400
633
|
call << Punchblock::Event::Unjoined.new(call_uri: other_mock_call.id)
|
401
634
|
other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
|
402
635
|
end
|
403
636
|
|
404
637
|
dial = Dial::Dial.new to, options, call
|
405
|
-
dial.run
|
638
|
+
dial.run subject
|
406
639
|
|
407
640
|
waiter_thread = Thread.new do
|
408
641
|
dial.await_completion
|
@@ -415,10 +648,18 @@ module Adhearsion
|
|
415
648
|
|
416
649
|
dial.split
|
417
650
|
|
418
|
-
call.should_receive(:join).once.ordered.with(mixer_name: mixer)
|
419
|
-
other_mock_call.should_receive(:join).once.ordered.with(mixer_name: mixer)
|
651
|
+
call.should_receive(:join).once.ordered.with({mixer_name: mixer}, {})
|
652
|
+
other_mock_call.should_receive(:join).once.ordered.with({mixer_name: mixer}, {})
|
420
653
|
dial.rejoin mixer_name: mixer
|
421
654
|
|
655
|
+
other_mock_call.should_receive(:unjoin).once.ordered.with(mixer_name: mixer).and_return do
|
656
|
+
other_mock_call << Punchblock::Event::Unjoined.new(mixer_name: mixer)
|
657
|
+
end
|
658
|
+
call.should_receive(:unjoin).once.ordered.with(mixer_name: mixer).and_return do
|
659
|
+
call << Punchblock::Event::Unjoined.new(mixer_name: mixer)
|
660
|
+
end
|
661
|
+
dial.split
|
662
|
+
|
422
663
|
other_mock_call << mock_end
|
423
664
|
|
424
665
|
latch.wait(1).should be_true
|
@@ -440,34 +681,34 @@ module Adhearsion
|
|
440
681
|
before do
|
441
682
|
second_root_call.stub write_command: true, id: second_root_call_id
|
442
683
|
OutboundCall.should_receive(:new).and_return second_other_mock_call
|
443
|
-
second_other_mock_call.should_receive(:join).once.with(second_root_call)
|
684
|
+
second_other_mock_call.should_receive(:join).once.with(second_root_call, {})
|
444
685
|
second_other_mock_call.should_receive(:dial).once.with(second_to, options)
|
445
686
|
second_root_call.should_receive(:answer).once
|
446
687
|
|
447
688
|
SecureRandom.stub uuid: mixer
|
448
689
|
|
449
|
-
dial.run
|
450
|
-
other_dial.run
|
690
|
+
dial.run subject
|
691
|
+
other_dial.run subject
|
451
692
|
|
452
693
|
other_mock_call << mock_answered
|
453
694
|
second_other_mock_call << mock_answered
|
454
695
|
end
|
455
696
|
|
456
697
|
it "should split calls, rejoin to a mixer, and rejoin other calls to mixer" do
|
457
|
-
|
698
|
+
other_mock_call.should_receive(:unjoin).once.ordered.with(call).and_return do
|
458
699
|
call << Punchblock::Event::Unjoined.new(call_uri: other_mock_call.id)
|
459
700
|
other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
|
460
701
|
end
|
461
|
-
|
702
|
+
second_other_mock_call.should_receive(:unjoin).once.ordered.with(second_root_call).and_return do
|
462
703
|
second_root_call << Punchblock::Event::Unjoined.new(call_uri: second_other_mock_call.id)
|
463
704
|
second_other_mock_call << Punchblock::Event::Unjoined.new(call_uri: second_root_call.id)
|
464
705
|
end
|
465
706
|
|
466
|
-
call.should_receive(:join).once.ordered.with(mixer_name: mixer)
|
467
|
-
other_mock_call.should_receive(:join).once.ordered.with(mixer_name: mixer)
|
707
|
+
call.should_receive(:join).once.ordered.with({mixer_name: mixer}, {})
|
708
|
+
other_mock_call.should_receive(:join).once.ordered.with({mixer_name: mixer}, {})
|
468
709
|
|
469
|
-
second_root_call.should_receive(:join).once.ordered.with(mixer_name: mixer)
|
470
|
-
second_other_mock_call.should_receive(:join).once.ordered.with(mixer_name: mixer)
|
710
|
+
second_root_call.should_receive(:join).once.ordered.with({mixer_name: mixer}, {})
|
711
|
+
second_other_mock_call.should_receive(:join).once.ordered.with({mixer_name: mixer}, {})
|
471
712
|
|
472
713
|
dial.merge other_dial
|
473
714
|
|
@@ -488,6 +729,23 @@ module Adhearsion
|
|
488
729
|
dial.status.result.should be == :answer
|
489
730
|
end
|
490
731
|
|
732
|
+
context "when join options were specified originally" do
|
733
|
+
let(:options) { { join_options: {media: :direct} } }
|
734
|
+
|
735
|
+
it "should rejoin with default options" do
|
736
|
+
other_mock_call.stub(:unjoin)
|
737
|
+
second_other_mock_call.stub(:unjoin)
|
738
|
+
|
739
|
+
call.should_receive(:join).once.ordered.with({mixer_name: mixer}, {})
|
740
|
+
other_mock_call.should_receive(:join).once.ordered.with({mixer_name: mixer}, {})
|
741
|
+
|
742
|
+
second_root_call.should_receive(:join).once.ordered.with({mixer_name: mixer}, {})
|
743
|
+
second_other_mock_call.should_receive(:join).once.ordered.with({mixer_name: mixer}, {})
|
744
|
+
|
745
|
+
dial.merge other_dial
|
746
|
+
end
|
747
|
+
end
|
748
|
+
|
491
749
|
it "should add the merged calls to the returned status" do
|
492
750
|
[call, other_mock_call, second_root_call, second_other_mock_call].each { |c| c.stub join: true, unjoin: true }
|
493
751
|
dial.merge other_dial
|
@@ -560,16 +818,164 @@ module Adhearsion
|
|
560
818
|
dial.status.result.should be == :answer
|
561
819
|
end
|
562
820
|
|
821
|
+
it "should subsequently rejoin to a mixer" do
|
822
|
+
[call, other_mock_call, second_root_call, second_other_mock_call].each { |c| c.stub join: true, unjoin: true }
|
823
|
+
|
824
|
+
dial.merge other_dial
|
825
|
+
|
826
|
+
waiter_thread = Thread.new do
|
827
|
+
dial.await_completion
|
828
|
+
latch.countdown!
|
829
|
+
end
|
830
|
+
|
831
|
+
sleep 0.5
|
832
|
+
|
833
|
+
other_mock_call << mock_end
|
834
|
+
latch.wait(1).should be_false
|
835
|
+
|
836
|
+
[call, second_root_call, second_other_mock_call].each do |call|
|
837
|
+
call.should_receive(:unjoin).once.with(mixer_name: mixer).and_return do
|
838
|
+
call << Punchblock::Event::Unjoined.new(mixer_name: mixer)
|
839
|
+
end
|
840
|
+
end
|
841
|
+
|
842
|
+
dial.split
|
843
|
+
|
844
|
+
[call, second_root_call, second_other_mock_call].each do |call|
|
845
|
+
call.should_receive(:join).once.with({mixer_name: mixer}, {}).and_return do
|
846
|
+
call << Punchblock::Event::Joined.new(mixer_name: mixer)
|
847
|
+
end
|
848
|
+
end
|
849
|
+
|
850
|
+
dial.rejoin
|
851
|
+
end
|
852
|
+
|
853
|
+
describe "if splitting fails" do
|
854
|
+
it "should not add the merged calls to the returned status" do
|
855
|
+
[call, other_mock_call, second_root_call, second_other_mock_call].each { |c| c.stub join: true, unjoin: true }
|
856
|
+
other_dial.should_receive(:split).and_raise StandardError
|
857
|
+
expect { dial.merge other_dial }.to raise_error(StandardError)
|
858
|
+
|
859
|
+
waiter_thread = Thread.new do
|
860
|
+
dial.await_completion
|
861
|
+
latch.countdown!
|
862
|
+
end
|
863
|
+
|
864
|
+
sleep 0.5
|
865
|
+
|
866
|
+
other_mock_call.async << mock_end
|
867
|
+
second_root_call.async << mock_end
|
868
|
+
second_other_mock_call.async << mock_end
|
869
|
+
|
870
|
+
latch.wait(1).should be_true
|
871
|
+
|
872
|
+
waiter_thread.join
|
873
|
+
dial.status.result.should be == :answer
|
874
|
+
dial.status.calls.should_not include(second_root_call, second_other_mock_call)
|
875
|
+
end
|
876
|
+
|
877
|
+
it "should unblock before all joined calls end" do
|
878
|
+
[call, other_mock_call, second_root_call, second_other_mock_call].each { |c| c.stub join: true, unjoin: true }
|
879
|
+
|
880
|
+
other_dial.should_receive(:split).and_raise StandardError
|
881
|
+
expect { dial.merge other_dial }.to raise_error(StandardError)
|
882
|
+
|
883
|
+
waiter_thread = Thread.new do
|
884
|
+
dial.await_completion
|
885
|
+
latch.countdown!
|
886
|
+
end
|
887
|
+
|
888
|
+
sleep 0.5
|
889
|
+
|
890
|
+
other_mock_call << mock_end
|
891
|
+
latch.wait(1).should be_true
|
892
|
+
|
893
|
+
second_other_mock_call << mock_end
|
894
|
+
latch.wait(1).should be_true
|
895
|
+
|
896
|
+
second_root_call << mock_end
|
897
|
+
latch.wait(1).should be_true
|
898
|
+
|
899
|
+
waiter_thread.join
|
900
|
+
dial.status.result.should be == :answer
|
901
|
+
end
|
902
|
+
|
903
|
+
it "should not cleanup merged calls when the root call ends" do
|
904
|
+
[call, other_mock_call, second_root_call, second_other_mock_call].each do |c|
|
905
|
+
c.stub join: true, unjoin: true
|
906
|
+
end
|
907
|
+
other_mock_call.should_receive(:hangup).once
|
908
|
+
[second_root_call, second_other_mock_call].each do |c|
|
909
|
+
c.should_receive(:hangup).never
|
910
|
+
end
|
911
|
+
|
912
|
+
other_dial.should_receive(:split).and_raise StandardError
|
913
|
+
expect { dial.merge other_dial }.to raise_error(StandardError)
|
914
|
+
|
915
|
+
waiter_thread = Thread.new do
|
916
|
+
dial.await_completion
|
917
|
+
dial.cleanup_calls
|
918
|
+
latch.countdown!
|
919
|
+
end
|
920
|
+
|
921
|
+
sleep 0.5
|
922
|
+
|
923
|
+
call << mock_end
|
924
|
+
latch.wait(1).should be_true
|
925
|
+
|
926
|
+
waiter_thread.join
|
927
|
+
dial.status.result.should be == :answer
|
928
|
+
end
|
929
|
+
end
|
930
|
+
|
931
|
+
context "if a call hangs up" do
|
932
|
+
it "should still allow splitting and rejoining" do
|
933
|
+
[call, other_mock_call, second_root_call, second_other_mock_call].each { |c| c.stub join: true, unjoin: true }
|
934
|
+
|
935
|
+
dial.merge other_dial
|
936
|
+
|
937
|
+
waiter_thread = Thread.new do
|
938
|
+
dial.await_completion
|
939
|
+
latch.countdown!
|
940
|
+
end
|
941
|
+
|
942
|
+
sleep 0.5
|
943
|
+
|
944
|
+
[call, second_root_call, second_other_mock_call].each do |call|
|
945
|
+
call.should_receive(:unjoin).once.with(mixer_name: mixer).and_return do
|
946
|
+
call << Punchblock::Event::Unjoined.new(mixer_name: mixer)
|
947
|
+
end
|
948
|
+
end
|
949
|
+
|
950
|
+
other_mock_call.should_receive(:unjoin).and_raise Adhearsion::Call::Hangup
|
951
|
+
|
952
|
+
dial.split
|
953
|
+
|
954
|
+
other_mock_call << mock_end
|
955
|
+
latch.wait(1).should be_false
|
956
|
+
|
957
|
+
[call, second_root_call, second_other_mock_call].each do |call|
|
958
|
+
call.should_receive(:join).once.with({mixer_name: mixer}, {}).and_return do
|
959
|
+
call << Punchblock::Event::Joined.new(mixer_name: mixer)
|
960
|
+
end
|
961
|
+
end
|
962
|
+
|
963
|
+
other_mock_call.should_receive(:join).and_raise Adhearsion::Call::ExpiredError
|
964
|
+
|
965
|
+
dial.rejoin
|
966
|
+
end
|
967
|
+
end
|
968
|
+
|
563
969
|
context "if the calls were not joined" do
|
564
970
|
it "should still join to mixer" do
|
565
|
-
|
566
|
-
|
971
|
+
other_mock_call.should_receive(:unjoin).once.ordered.with(call).and_raise Punchblock::ProtocolError.new.setup(:service_unavailable)
|
972
|
+
second_other_mock_call.should_receive(:unjoin).once.ordered.with(second_root_call).and_raise Punchblock::ProtocolError.new.setup(:service_unavailable)
|
567
973
|
|
568
|
-
call.should_receive(:join).once.ordered.with(mixer_name: mixer)
|
569
|
-
other_mock_call.should_receive(:join).once.ordered.with(mixer_name: mixer)
|
974
|
+
call.should_receive(:join).once.ordered.with({mixer_name: mixer}, {})
|
975
|
+
other_mock_call.should_receive(:join).once.ordered.with({mixer_name: mixer}, {})
|
570
976
|
|
571
|
-
second_root_call.should_receive(:join).once.ordered.with(mixer_name: mixer)
|
572
|
-
second_other_mock_call.should_receive(:join).once.ordered.with(mixer_name: mixer)
|
977
|
+
second_root_call.should_receive(:join).once.ordered.with({mixer_name: mixer}, {})
|
978
|
+
second_other_mock_call.should_receive(:join).once.ordered.with({mixer_name: mixer}, {})
|
573
979
|
|
574
980
|
dial.merge other_dial
|
575
981
|
|
@@ -633,7 +1039,7 @@ module Adhearsion
|
|
633
1039
|
|
634
1040
|
it "dials all parties and joins the first one to answer, hanging up the rest" do
|
635
1041
|
call.should_receive(:answer).once
|
636
|
-
other_mock_call.should_receive(:join).once.with(call)
|
1042
|
+
other_mock_call.should_receive(:join).once.with(call, {})
|
637
1043
|
second_other_mock_call.should_receive(:hangup).once.and_return do
|
638
1044
|
second_other_mock_call << mock_end
|
639
1045
|
end
|
@@ -656,7 +1062,7 @@ module Adhearsion
|
|
656
1062
|
|
657
1063
|
it "unblocks when the joined call unjoins, allowing it to proceed further" do
|
658
1064
|
call.should_receive(:answer).once
|
659
|
-
other_mock_call.should_receive(:join).once.with(call)
|
1065
|
+
other_mock_call.should_receive(:join).once.with(call, {})
|
660
1066
|
other_mock_call.should_receive(:hangup).once
|
661
1067
|
second_other_mock_call.should_receive(:hangup).once.and_return do
|
662
1068
|
second_other_mock_call << mock_end
|
@@ -768,7 +1174,7 @@ module Adhearsion
|
|
768
1174
|
context "when a call is answered and joined, and the other ends with an error" do
|
769
1175
|
it "has an overall dial status of :answer" do
|
770
1176
|
call.should_receive(:answer).once
|
771
|
-
other_mock_call.should_receive(:join).once.with(call)
|
1177
|
+
other_mock_call.should_receive(:join).once.with(call, {})
|
772
1178
|
second_other_mock_call.should_receive(:hangup).once.and_return do
|
773
1179
|
second_other_mock_call << mock_end(:error)
|
774
1180
|
end
|
@@ -817,7 +1223,7 @@ module Adhearsion
|
|
817
1223
|
it "should not abort until the far end hangs up" do
|
818
1224
|
other_mock_call.should_receive(:dial).once.with(to, hash_including(:timeout => timeout))
|
819
1225
|
call.should_receive(:answer).once
|
820
|
-
other_mock_call.should_receive(:join).once.with(call)
|
1226
|
+
other_mock_call.should_receive(:join).once.with(call, {})
|
821
1227
|
OutboundCall.should_receive(:new).and_return other_mock_call
|
822
1228
|
|
823
1229
|
time = Time.now
|
@@ -920,7 +1326,7 @@ module Adhearsion
|
|
920
1326
|
other_mock_call.should_receive(:hangup).once
|
921
1327
|
other_mock_call['confirm'] = true
|
922
1328
|
call.should_receive(:answer).once
|
923
|
-
other_mock_call.should_receive(:join).once.with(call)
|
1329
|
+
other_mock_call.should_receive(:join).once.with(call, {})
|
924
1330
|
|
925
1331
|
t = dial_in_thread
|
926
1332
|
|
@@ -992,7 +1398,7 @@ module Adhearsion
|
|
992
1398
|
call.should_receive(:answer).once
|
993
1399
|
|
994
1400
|
other_mock_call.should_receive(:dial).once.with(to, from: nil)
|
995
|
-
other_mock_call.should_receive(:join).once.with(call)
|
1401
|
+
other_mock_call.should_receive(:join).once.with(call, {})
|
996
1402
|
other_mock_call.should_receive(:hangup).once.and_return do
|
997
1403
|
other_mock_call << mock_end
|
998
1404
|
end
|
@@ -1095,7 +1501,7 @@ module Adhearsion
|
|
1095
1501
|
|
1096
1502
|
it "joins the new call to the existing one on answer" do
|
1097
1503
|
call.should_receive(:answer).once
|
1098
|
-
other_mock_call.should_receive(:join).once.with(call)
|
1504
|
+
other_mock_call.should_receive(:join).once.with(call, {})
|
1099
1505
|
|
1100
1506
|
dial_in_thread
|
1101
1507
|
|
@@ -1107,10 +1513,111 @@ module Adhearsion
|
|
1107
1513
|
latch.wait(1).should be_true
|
1108
1514
|
end
|
1109
1515
|
|
1516
|
+
context "with a join target specified" do
|
1517
|
+
let(:options) { { join_target: {mixer_name: 'foobar'} } }
|
1518
|
+
|
1519
|
+
it "joins the calls to the specified target on answer" do
|
1520
|
+
call.should_receive(:answer).once
|
1521
|
+
call.should_receive(:join).once.with({mixer_name: 'foobar'}, {})
|
1522
|
+
other_mock_call.should_receive(:join).once.with({mixer_name: 'foobar'}, {})
|
1523
|
+
|
1524
|
+
dial_in_thread
|
1525
|
+
|
1526
|
+
latch.wait(1).should be_false
|
1527
|
+
|
1528
|
+
other_mock_call << mock_answered
|
1529
|
+
other_mock_call << mock_end
|
1530
|
+
|
1531
|
+
latch.wait(1).should be_true
|
1532
|
+
end
|
1533
|
+
end
|
1534
|
+
|
1535
|
+
context "with a pre-join callback specified" do
|
1536
|
+
let(:foo) { double }
|
1537
|
+
let(:options) { { pre_join: ->(call) { foo.bar call } } }
|
1538
|
+
|
1539
|
+
it "executes the callback prior to joining" do
|
1540
|
+
foo.should_receive(:bar).once.with(other_mock_call).ordered
|
1541
|
+
call.should_receive(:answer).once.ordered
|
1542
|
+
other_mock_call.should_receive(:join).once.with(call, {}).ordered
|
1543
|
+
|
1544
|
+
dial_in_thread
|
1545
|
+
|
1546
|
+
latch.wait(1).should be_false
|
1547
|
+
|
1548
|
+
other_mock_call << mock_answered
|
1549
|
+
other_mock_call << mock_end
|
1550
|
+
|
1551
|
+
latch.wait(1).should be_true
|
1552
|
+
end
|
1553
|
+
end
|
1554
|
+
|
1555
|
+
context "with ringback specified" do
|
1556
|
+
let(:component) { Punchblock::Component::Output.new }
|
1557
|
+
let(:options) { { ringback: ['file://tt-monkeys'] } }
|
1558
|
+
|
1559
|
+
before do
|
1560
|
+
component.request!
|
1561
|
+
component.execute!
|
1562
|
+
end
|
1563
|
+
|
1564
|
+
it "plays the ringback asynchronously, terminating prior to joining" do
|
1565
|
+
subject.should_receive(:play!).once.with(['file://tt-monkeys'], repeat_times: 0).and_return(component)
|
1566
|
+
component.should_receive(:stop!).twice
|
1567
|
+
call.should_receive(:answer).once.ordered
|
1568
|
+
other_mock_call.should_receive(:join).once.with(call, {}).ordered
|
1569
|
+
|
1570
|
+
dial_in_thread
|
1571
|
+
|
1572
|
+
latch.wait(1).should be_false
|
1573
|
+
|
1574
|
+
other_mock_call << mock_answered
|
1575
|
+
other_mock_call << mock_end
|
1576
|
+
|
1577
|
+
latch.wait(1).should be_true
|
1578
|
+
end
|
1579
|
+
|
1580
|
+
context "as a callback" do
|
1581
|
+
let(:foo) { double }
|
1582
|
+
let(:options) { { ringback: -> { foo.bar; component } } }
|
1583
|
+
|
1584
|
+
it "calls the callback to start, and uses the return value of the callback to stop the ringback" do
|
1585
|
+
foo.should_receive(:bar).once.ordered
|
1586
|
+
component.should_receive(:stop!).twice
|
1587
|
+
call.should_receive(:answer).once.ordered
|
1588
|
+
other_mock_call.should_receive(:join).once.with(call, {}).ordered
|
1589
|
+
|
1590
|
+
dial_in_thread
|
1591
|
+
|
1592
|
+
latch.wait(1).should be_false
|
1593
|
+
|
1594
|
+
other_mock_call << mock_answered
|
1595
|
+
other_mock_call << mock_end
|
1596
|
+
|
1597
|
+
latch.wait(1).should be_true
|
1598
|
+
end
|
1599
|
+
end
|
1600
|
+
|
1601
|
+
context "when the call is rejected" do
|
1602
|
+
it "terminates the ringback before returning" do
|
1603
|
+
subject.should_receive(:play!).once.with(['file://tt-monkeys'], repeat_times: 0).and_return(component)
|
1604
|
+
component.should_receive(:stop!).once
|
1605
|
+
|
1606
|
+
t = dial_in_thread
|
1607
|
+
|
1608
|
+
latch.wait(1).should be_false
|
1609
|
+
|
1610
|
+
other_mock_call << mock_end(:reject)
|
1611
|
+
|
1612
|
+
latch.wait(1).should be_true
|
1613
|
+
end
|
1614
|
+
end
|
1615
|
+
end
|
1616
|
+
|
1110
1617
|
it "hangs up the new call when the root call ends" do
|
1111
1618
|
other_mock_call.should_receive(:hangup).once
|
1112
1619
|
call.should_receive(:answer).once
|
1113
|
-
other_mock_call.should_receive(:join).once.with(call)
|
1620
|
+
other_mock_call.should_receive(:join).once.with(call, {})
|
1114
1621
|
|
1115
1622
|
dial_in_thread
|
1116
1623
|
|
@@ -1161,7 +1668,7 @@ module Adhearsion
|
|
1161
1668
|
context "when the call is answered and joined" do
|
1162
1669
|
it "has an overall dial status of :answer" do
|
1163
1670
|
call.should_receive(:answer).once
|
1164
|
-
other_mock_call.should_receive(:join).once.with(call)
|
1671
|
+
other_mock_call.should_receive(:join).once.with(call, {})
|
1165
1672
|
|
1166
1673
|
t = dial_in_thread
|
1167
1674
|
|
@@ -1182,7 +1689,7 @@ module Adhearsion
|
|
1182
1689
|
|
1183
1690
|
it "records the duration of the join" do
|
1184
1691
|
call.should_receive(:answer).once
|
1185
|
-
other_mock_call.should_receive(:join).once.with(call)
|
1692
|
+
other_mock_call.should_receive(:join).once.with(call, {})
|
1186
1693
|
other_mock_call.stub hangup: true
|
1187
1694
|
|
1188
1695
|
t = dial_in_thread
|
@@ -1207,26 +1714,51 @@ module Adhearsion
|
|
1207
1714
|
joined_status = status.joins[status.calls.first]
|
1208
1715
|
joined_status.duration.should == 37.0
|
1209
1716
|
end
|
1717
|
+
|
1718
|
+
context "when join options are specified" do
|
1719
|
+
let(:options) { { join_options: {media: :direct} } }
|
1720
|
+
|
1721
|
+
it "joins the calls with those options" do
|
1722
|
+
call.should_receive(:answer).once
|
1723
|
+
other_mock_call.should_receive(:join).once.with(call, media: :direct)
|
1724
|
+
other_mock_call.stub hangup: true
|
1725
|
+
|
1726
|
+
t = dial_in_thread
|
1727
|
+
|
1728
|
+
sleep 0.5
|
1729
|
+
|
1730
|
+
other_mock_call << mock_answered
|
1731
|
+
|
1732
|
+
other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
|
1733
|
+
other_mock_call << mock_end
|
1734
|
+
|
1735
|
+
latch.wait(1).should be_true
|
1736
|
+
|
1737
|
+
t.join
|
1738
|
+
end
|
1739
|
+
end
|
1210
1740
|
end
|
1211
1741
|
|
1212
1742
|
context "when a dial is split" do
|
1743
|
+
let(:join_target) { call }
|
1744
|
+
|
1213
1745
|
before do
|
1214
1746
|
call.should_receive(:answer).once
|
1215
|
-
other_mock_call.should_receive(:join).once.with(
|
1216
|
-
|
1747
|
+
other_mock_call.should_receive(:join).once.with(join_target, join_options)
|
1748
|
+
other_mock_call.stub(:unjoin).and_return do
|
1217
1749
|
call << Punchblock::Event::Unjoined.new(call_uri: other_mock_call.id)
|
1218
1750
|
other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
|
1219
1751
|
end
|
1220
1752
|
end
|
1221
1753
|
|
1222
1754
|
it "should unjoin the calls" do
|
1223
|
-
|
1755
|
+
other_mock_call.should_receive(:unjoin).once.ordered.with(call).and_return do
|
1224
1756
|
call << Punchblock::Event::Unjoined.new(call_uri: other_mock_call.id)
|
1225
1757
|
other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
|
1226
1758
|
end
|
1227
1759
|
|
1228
1760
|
dial = Dial::ParallelConfirmationDial.new to, options, call
|
1229
|
-
dial.run
|
1761
|
+
dial.run subject
|
1230
1762
|
|
1231
1763
|
waiter_thread = Thread.new do
|
1232
1764
|
dial.await_completion
|
@@ -1248,7 +1780,7 @@ module Adhearsion
|
|
1248
1780
|
|
1249
1781
|
it "should not unblock immediately" do
|
1250
1782
|
dial = Dial::ParallelConfirmationDial.new to, options, call
|
1251
|
-
dial.run
|
1783
|
+
dial.run subject
|
1252
1784
|
|
1253
1785
|
waiter_thread = Thread.new do
|
1254
1786
|
dial.await_completion
|
@@ -1273,7 +1805,7 @@ module Adhearsion
|
|
1273
1805
|
|
1274
1806
|
it "should set end time" do
|
1275
1807
|
dial = Dial::ParallelConfirmationDial.new to, options, call
|
1276
|
-
dial.run
|
1808
|
+
dial.run subject
|
1277
1809
|
|
1278
1810
|
waiter_thread = Thread.new do
|
1279
1811
|
dial.await_completion
|
@@ -1325,7 +1857,7 @@ module Adhearsion
|
|
1325
1857
|
|
1326
1858
|
it "should execute the :main controller on the originating call and :others on the outbound calls" do
|
1327
1859
|
dial = Dial::ParallelConfirmationDial.new to, options, call
|
1328
|
-
dial.run
|
1860
|
+
dial.run subject
|
1329
1861
|
|
1330
1862
|
waiter_thread = Thread.new do
|
1331
1863
|
dial.await_completion
|
@@ -1361,13 +1893,13 @@ module Adhearsion
|
|
1361
1893
|
|
1362
1894
|
context "when rejoining" do
|
1363
1895
|
it "should rejoin the calls" do
|
1364
|
-
|
1896
|
+
other_mock_call.should_receive(:unjoin).once.ordered.with(call).and_return do
|
1365
1897
|
call << Punchblock::Event::Unjoined.new(call_uri: other_mock_call.id)
|
1366
1898
|
other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
|
1367
1899
|
end
|
1368
1900
|
|
1369
1901
|
dial = Dial::ParallelConfirmationDial.new to, options, call
|
1370
|
-
dial.run
|
1902
|
+
dial.run subject
|
1371
1903
|
|
1372
1904
|
waiter_thread = Thread.new do
|
1373
1905
|
dial.await_completion
|
@@ -1380,7 +1912,7 @@ module Adhearsion
|
|
1380
1912
|
|
1381
1913
|
dial.split
|
1382
1914
|
|
1383
|
-
other_mock_call.should_receive(:join).once.ordered.with(call)
|
1915
|
+
other_mock_call.should_receive(:join).once.ordered.with(call, {})
|
1384
1916
|
dial.rejoin
|
1385
1917
|
|
1386
1918
|
other_mock_call << mock_end
|
@@ -1391,17 +1923,90 @@ module Adhearsion
|
|
1391
1923
|
dial.status.result.should be == :answer
|
1392
1924
|
end
|
1393
1925
|
|
1926
|
+
context "when join options were set originally" do
|
1927
|
+
let(:options) { { join_options: {media: :direct} } }
|
1928
|
+
|
1929
|
+
it "should rejoin with the same parameters" do
|
1930
|
+
other_mock_call.stub(:unjoin)
|
1931
|
+
|
1932
|
+
dial = Dial::ParallelConfirmationDial.new to, options, call
|
1933
|
+
dial.run subject
|
1934
|
+
|
1935
|
+
other_mock_call << mock_answered
|
1936
|
+
|
1937
|
+
dial.split
|
1938
|
+
|
1939
|
+
other_mock_call.should_receive(:join).once.ordered.with(call, media: :direct)
|
1940
|
+
dial.rejoin
|
1941
|
+
end
|
1942
|
+
end
|
1943
|
+
|
1944
|
+
context "when join options are passed to rejoin" do
|
1945
|
+
it "should rejoin with those parameters" do
|
1946
|
+
other_mock_call.stub(:unjoin)
|
1947
|
+
|
1948
|
+
dial = Dial::ParallelConfirmationDial.new to, options, call
|
1949
|
+
dial.run subject
|
1950
|
+
|
1951
|
+
other_mock_call << mock_answered
|
1952
|
+
|
1953
|
+
dial.split
|
1954
|
+
|
1955
|
+
other_mock_call.should_receive(:join).once.ordered.with(call, media: :direct)
|
1956
|
+
dial.rejoin nil, media: :direct
|
1957
|
+
end
|
1958
|
+
end
|
1959
|
+
|
1960
|
+
context "when a join target was originally specified" do
|
1961
|
+
let(:join_target) { {mixer_name: 'foobar'} }
|
1962
|
+
let(:options) { { join_target: join_target } }
|
1963
|
+
|
1964
|
+
it "joins the calls to the specified target on answer" do
|
1965
|
+
call.should_receive(:join).once.with(join_target, {})
|
1966
|
+
other_mock_call.should_receive(:unjoin).once.ordered.with(join_target)
|
1967
|
+
call.should_receive(:unjoin).once.ordered.with(join_target).and_return do
|
1968
|
+
call << Punchblock::Event::Unjoined.new(join_target)
|
1969
|
+
other_mock_call << Punchblock::Event::Unjoined.new(join_target)
|
1970
|
+
end
|
1971
|
+
|
1972
|
+
dial = Dial::ParallelConfirmationDial.new to, options, call
|
1973
|
+
dial.run subject
|
1974
|
+
|
1975
|
+
waiter_thread = Thread.new do
|
1976
|
+
dial.await_completion
|
1977
|
+
latch.countdown!
|
1978
|
+
end
|
1979
|
+
|
1980
|
+
sleep 0.5
|
1981
|
+
|
1982
|
+
other_mock_call << mock_answered
|
1983
|
+
|
1984
|
+
dial.split
|
1985
|
+
|
1986
|
+
call.should_receive(:join).once.ordered.with({mixer_name: 'foobar'}, {})
|
1987
|
+
other_mock_call.should_receive(:join).once.ordered.with({mixer_name: 'foobar'}, {})
|
1988
|
+
dial.rejoin
|
1989
|
+
|
1990
|
+
other_mock_call << mock_end
|
1991
|
+
|
1992
|
+
latch.wait(1).should be_true
|
1993
|
+
|
1994
|
+
waiter_thread.join
|
1995
|
+
dial.status.result.should be == :answer
|
1996
|
+
end
|
1997
|
+
end
|
1998
|
+
|
1394
1999
|
context "to a specified mixer" do
|
1395
2000
|
let(:mixer) { SecureRandom.uuid }
|
1396
2001
|
|
1397
2002
|
it "should join all calls to the mixer" do
|
1398
|
-
|
2003
|
+
other_mock_call.should_receive(:unjoin).once.ordered.with(call).and_return do
|
1399
2004
|
call << Punchblock::Event::Unjoined.new(call_uri: other_mock_call.id)
|
1400
2005
|
other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
|
1401
2006
|
end
|
1402
2007
|
|
1403
2008
|
dial = Dial::ParallelConfirmationDial.new to, options, call
|
1404
|
-
dial.run
|
2009
|
+
dial.run subject
|
1405
2010
|
|
1406
2011
|
waiter_thread = Thread.new do
|
1407
2012
|
dial.await_completion
|
@@ -1414,8 +2019,8 @@ module Adhearsion
|
|
1414
2019
|
|
1415
2020
|
dial.split
|
1416
2021
|
|
1417
|
-
call.should_receive(:join).once.ordered.with(mixer_name: mixer)
|
1418
|
-
other_mock_call.should_receive(:join).once.ordered.with(mixer_name: mixer)
|
2022
|
+
call.should_receive(:join).once.ordered.with({mixer_name: mixer}, {})
|
2023
|
+
other_mock_call.should_receive(:join).once.ordered.with({mixer_name: mixer}, {})
|
1419
2024
|
dial.rejoin mixer_name: mixer
|
1420
2025
|
|
1421
2026
|
other_mock_call << mock_end
|
@@ -1425,6 +2030,46 @@ module Adhearsion
|
|
1425
2030
|
waiter_thread.join
|
1426
2031
|
dial.status.result.should be == :answer
|
1427
2032
|
end
|
2033
|
+
|
2034
|
+
it "#split should then unjoin calls from the mixer" do
|
2035
|
+
other_mock_call.should_receive(:unjoin).once.ordered.with(call).and_return do
|
2036
|
+
call << Punchblock::Event::Unjoined.new(call_uri: other_mock_call.id)
|
2037
|
+
other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
|
2038
|
+
end
|
2039
|
+
|
2040
|
+
dial = Dial::ParallelConfirmationDial.new to, options, call
|
2041
|
+
dial.run subject
|
2042
|
+
|
2043
|
+
waiter_thread = Thread.new do
|
2044
|
+
dial.await_completion
|
2045
|
+
latch.countdown!
|
2046
|
+
end
|
2047
|
+
|
2048
|
+
sleep 0.5
|
2049
|
+
|
2050
|
+
other_mock_call << mock_answered
|
2051
|
+
|
2052
|
+
dial.split
|
2053
|
+
|
2054
|
+
call.should_receive(:join).once.ordered.with({mixer_name: mixer}, {})
|
2055
|
+
other_mock_call.should_receive(:join).once.ordered.with({mixer_name: mixer}, {})
|
2056
|
+
dial.rejoin mixer_name: mixer
|
2057
|
+
|
2058
|
+
other_mock_call.should_receive(:unjoin).once.ordered.with(mixer_name: mixer).and_return do
|
2059
|
+
other_mock_call << Punchblock::Event::Unjoined.new(mixer_name: mixer)
|
2060
|
+
end
|
2061
|
+
call.should_receive(:unjoin).once.ordered.with(mixer_name: mixer).and_return do
|
2062
|
+
call << Punchblock::Event::Unjoined.new(mixer_name: mixer)
|
2063
|
+
end
|
2064
|
+
dial.split
|
2065
|
+
|
2066
|
+
other_mock_call << mock_end
|
2067
|
+
|
2068
|
+
latch.wait(1).should be_true
|
2069
|
+
|
2070
|
+
waiter_thread.join
|
2071
|
+
dial.status.result.should be == :answer
|
2072
|
+
end
|
1428
2073
|
end
|
1429
2074
|
end
|
1430
2075
|
|
@@ -1439,34 +2084,34 @@ module Adhearsion
|
|
1439
2084
|
before do
|
1440
2085
|
second_root_call.stub write_command: true, id: second_root_call_id
|
1441
2086
|
OutboundCall.should_receive(:new).and_return second_other_mock_call
|
1442
|
-
second_other_mock_call.should_receive(:join).once.with(second_root_call)
|
2087
|
+
second_other_mock_call.should_receive(:join).once.with(second_root_call, {})
|
1443
2088
|
second_other_mock_call.should_receive(:dial).once.with(second_to, options)
|
1444
2089
|
second_root_call.should_receive(:answer).once
|
1445
2090
|
|
1446
2091
|
SecureRandom.stub uuid: mixer
|
1447
2092
|
|
1448
|
-
dial.run
|
1449
|
-
other_dial.run
|
2093
|
+
dial.run subject
|
2094
|
+
other_dial.run subject
|
1450
2095
|
|
1451
2096
|
other_mock_call << mock_answered
|
1452
2097
|
second_other_mock_call << mock_answered
|
1453
2098
|
end
|
1454
2099
|
|
1455
2100
|
it "should split calls, rejoin to a mixer, and rejoin other calls to mixer" do
|
1456
|
-
|
2101
|
+
other_mock_call.should_receive(:unjoin).once.ordered.with(call).and_return do
|
1457
2102
|
call << Punchblock::Event::Unjoined.new(call_uri: other_mock_call.id)
|
1458
2103
|
other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
|
1459
2104
|
end
|
1460
|
-
|
2105
|
+
second_other_mock_call.should_receive(:unjoin).once.ordered.with(second_root_call).and_return do
|
1461
2106
|
second_root_call << Punchblock::Event::Unjoined.new(call_uri: second_other_mock_call.id)
|
1462
2107
|
second_other_mock_call << Punchblock::Event::Unjoined.new(call_uri: second_root_call.id)
|
1463
2108
|
end
|
1464
2109
|
|
1465
|
-
call.should_receive(:join).once.ordered.with(mixer_name: mixer)
|
1466
|
-
other_mock_call.should_receive(:join).once.ordered.with(mixer_name: mixer)
|
2110
|
+
call.should_receive(:join).once.ordered.with({mixer_name: mixer}, {})
|
2111
|
+
other_mock_call.should_receive(:join).once.ordered.with({mixer_name: mixer}, {})
|
1467
2112
|
|
1468
|
-
second_root_call.should_receive(:join).once.ordered.with(mixer_name: mixer)
|
1469
|
-
second_other_mock_call.should_receive(:join).once.ordered.with(mixer_name: mixer)
|
2113
|
+
second_root_call.should_receive(:join).once.ordered.with({mixer_name: mixer}, {})
|
2114
|
+
second_other_mock_call.should_receive(:join).once.ordered.with({mixer_name: mixer}, {})
|
1470
2115
|
|
1471
2116
|
dial.merge other_dial
|
1472
2117
|
|
@@ -1487,6 +2132,23 @@ module Adhearsion
|
|
1487
2132
|
dial.status.result.should be == :answer
|
1488
2133
|
end
|
1489
2134
|
|
2135
|
+
context "when join options were specified originally" do
|
2136
|
+
let(:options) { { join_options: {media: :direct} } }
|
2137
|
+
|
2138
|
+
it "should rejoin with default options" do
|
2139
|
+
other_mock_call.stub(:unjoin)
|
2140
|
+
second_other_mock_call.stub(:unjoin)
|
2141
|
+
|
2142
|
+
call.should_receive(:join).once.ordered.with({mixer_name: mixer}, {})
|
2143
|
+
other_mock_call.should_receive(:join).once.ordered.with({mixer_name: mixer}, {})
|
2144
|
+
|
2145
|
+
second_root_call.should_receive(:join).once.ordered.with({mixer_name: mixer}, {})
|
2146
|
+
second_other_mock_call.should_receive(:join).once.ordered.with({mixer_name: mixer}, {})
|
2147
|
+
|
2148
|
+
dial.merge other_dial
|
2149
|
+
end
|
2150
|
+
end
|
2151
|
+
|
1490
2152
|
it "should add the merged calls to the returned status" do
|
1491
2153
|
[call, other_mock_call, second_root_call, second_other_mock_call].each { |c| c.stub join: true, unjoin: true }
|
1492
2154
|
dial.merge other_dial
|
@@ -1559,16 +2221,86 @@ module Adhearsion
|
|
1559
2221
|
dial.status.result.should be == :answer
|
1560
2222
|
end
|
1561
2223
|
|
2224
|
+
it "should subsequently rejoin to a mixer" do
|
2225
|
+
[call, other_mock_call, second_root_call, second_other_mock_call].each { |c| c.stub join: true, unjoin: true }
|
2226
|
+
|
2227
|
+
dial.merge other_dial
|
2228
|
+
|
2229
|
+
waiter_thread = Thread.new do
|
2230
|
+
dial.await_completion
|
2231
|
+
latch.countdown!
|
2232
|
+
end
|
2233
|
+
|
2234
|
+
sleep 0.5
|
2235
|
+
|
2236
|
+
other_mock_call << mock_end
|
2237
|
+
latch.wait(1).should be_false
|
2238
|
+
|
2239
|
+
[call, second_root_call, second_other_mock_call].each do |call|
|
2240
|
+
call.should_receive(:unjoin).once.with(mixer_name: mixer).and_return do
|
2241
|
+
call << Punchblock::Event::Unjoined.new(mixer_name: mixer)
|
2242
|
+
end
|
2243
|
+
end
|
2244
|
+
|
2245
|
+
dial.split
|
2246
|
+
|
2247
|
+
[call, other_mock_call, second_root_call, second_other_mock_call].each do |call|
|
2248
|
+
call.should_receive(:join).once.with({mixer_name: mixer}, {}).and_return do
|
2249
|
+
call << Punchblock::Event::Joined.new(mixer_name: mixer)
|
2250
|
+
end
|
2251
|
+
end
|
2252
|
+
|
2253
|
+
dial.rejoin
|
2254
|
+
end
|
2255
|
+
|
2256
|
+
context "if a call hangs up" do
|
2257
|
+
it "should still allow splitting and rejoining" do
|
2258
|
+
[call, other_mock_call, second_root_call, second_other_mock_call].each { |c| c.stub join: true, unjoin: true }
|
2259
|
+
|
2260
|
+
dial.merge other_dial
|
2261
|
+
|
2262
|
+
waiter_thread = Thread.new do
|
2263
|
+
dial.await_completion
|
2264
|
+
latch.countdown!
|
2265
|
+
end
|
2266
|
+
|
2267
|
+
sleep 0.5
|
2268
|
+
|
2269
|
+
[call, second_root_call, second_other_mock_call].each do |call|
|
2270
|
+
call.should_receive(:unjoin).once.with(mixer_name: mixer).and_return do
|
2271
|
+
call << Punchblock::Event::Unjoined.new(mixer_name: mixer)
|
2272
|
+
end
|
2273
|
+
end
|
2274
|
+
|
2275
|
+
other_mock_call.should_receive(:unjoin).and_raise Adhearsion::Call::Hangup
|
2276
|
+
|
2277
|
+
dial.split
|
2278
|
+
|
2279
|
+
other_mock_call << mock_end
|
2280
|
+
latch.wait(1).should be_false
|
2281
|
+
|
2282
|
+
[call, second_root_call, second_other_mock_call].each do |call|
|
2283
|
+
call.should_receive(:join).once.with({mixer_name: mixer}, {}).and_return do
|
2284
|
+
call << Punchblock::Event::Joined.new(mixer_name: mixer)
|
2285
|
+
end
|
2286
|
+
end
|
2287
|
+
|
2288
|
+
other_mock_call.should_receive(:join).and_raise Adhearsion::Call::ExpiredError
|
2289
|
+
|
2290
|
+
dial.rejoin
|
2291
|
+
end
|
2292
|
+
end
|
2293
|
+
|
1562
2294
|
context "if the calls were not joined" do
|
1563
2295
|
it "should still join to mixer" do
|
1564
|
-
|
1565
|
-
|
2296
|
+
other_mock_call.should_receive(:unjoin).once.ordered.with(call).and_raise Punchblock::ProtocolError.new.setup(:service_unavailable)
|
2297
|
+
second_other_mock_call.should_receive(:unjoin).once.ordered.with(second_root_call).and_raise Punchblock::ProtocolError.new.setup(:service_unavailable)
|
1566
2298
|
|
1567
|
-
call.should_receive(:join).once.ordered.with(mixer_name: mixer)
|
1568
|
-
other_mock_call.should_receive(:join).once.ordered.with(mixer_name: mixer)
|
2299
|
+
call.should_receive(:join).once.ordered.with({mixer_name: mixer}, {})
|
2300
|
+
other_mock_call.should_receive(:join).once.ordered.with({mixer_name: mixer}, {})
|
1569
2301
|
|
1570
|
-
second_root_call.should_receive(:join).once.ordered.with(mixer_name: mixer)
|
1571
|
-
second_other_mock_call.should_receive(:join).once.ordered.with(mixer_name: mixer)
|
2302
|
+
second_root_call.should_receive(:join).once.ordered.with({mixer_name: mixer}, {})
|
2303
|
+
second_other_mock_call.should_receive(:join).once.ordered.with({mixer_name: mixer}, {})
|
1572
2304
|
|
1573
2305
|
dial.merge other_dial
|
1574
2306
|
|
@@ -1632,7 +2364,7 @@ module Adhearsion
|
|
1632
2364
|
|
1633
2365
|
it "dials all parties and joins the first one to answer, hanging up the rest" do
|
1634
2366
|
call.should_receive(:answer).once
|
1635
|
-
other_mock_call.should_receive(:join).once.with(call)
|
2367
|
+
other_mock_call.should_receive(:join).once.with(call, {})
|
1636
2368
|
second_other_mock_call.should_receive(:hangup).once.and_return do
|
1637
2369
|
second_other_mock_call << mock_end
|
1638
2370
|
end
|
@@ -1655,7 +2387,7 @@ module Adhearsion
|
|
1655
2387
|
|
1656
2388
|
it "unblocks when the joined call unjoins, allowing it to proceed further" do
|
1657
2389
|
call.should_receive(:answer).once
|
1658
|
-
other_mock_call.should_receive(:join).once.with(call)
|
2390
|
+
other_mock_call.should_receive(:join).once.with(call, {})
|
1659
2391
|
other_mock_call.should_receive(:hangup).once
|
1660
2392
|
second_other_mock_call.should_receive(:hangup).once.and_return do
|
1661
2393
|
second_other_mock_call << mock_end
|
@@ -1767,7 +2499,7 @@ module Adhearsion
|
|
1767
2499
|
context "when a call is answered and joined, and the other ends with an error" do
|
1768
2500
|
it "has an overall dial status of :answer" do
|
1769
2501
|
call.should_receive(:answer).once
|
1770
|
-
other_mock_call.should_receive(:join).once.with(call)
|
2502
|
+
other_mock_call.should_receive(:join).once.with(call, {})
|
1771
2503
|
second_other_mock_call.should_receive(:hangup).once.and_return do
|
1772
2504
|
second_other_mock_call << mock_end(:error)
|
1773
2505
|
end
|
@@ -1816,7 +2548,7 @@ module Adhearsion
|
|
1816
2548
|
it "should not abort until the far end hangs up" do
|
1817
2549
|
other_mock_call.should_receive(:dial).once.with(to, hash_including(:timeout => timeout))
|
1818
2550
|
call.should_receive(:answer).once
|
1819
|
-
other_mock_call.should_receive(:join).once.with(call)
|
2551
|
+
other_mock_call.should_receive(:join).once.with(call, {})
|
1820
2552
|
OutboundCall.should_receive(:new).and_return other_mock_call
|
1821
2553
|
|
1822
2554
|
time = Time.now
|
@@ -1924,7 +2656,7 @@ module Adhearsion
|
|
1924
2656
|
end
|
1925
2657
|
other_mock_call['confirm'] = true
|
1926
2658
|
call.should_receive(:answer).once
|
1927
|
-
other_mock_call.should_receive(:join).once.with(call)
|
2659
|
+
other_mock_call.should_receive(:join).once.with(call, {})
|
1928
2660
|
|
1929
2661
|
t = dial_in_thread
|
1930
2662
|
|
@@ -2011,7 +2743,7 @@ module Adhearsion
|
|
2011
2743
|
call.should_receive(:answer).once
|
2012
2744
|
|
2013
2745
|
other_mock_call.should_receive(:dial).once.with(to, from: nil)
|
2014
|
-
other_mock_call.should_receive(:join).once.with(call)
|
2746
|
+
other_mock_call.should_receive(:join).once.with(call, {})
|
2015
2747
|
other_mock_call.should_receive(:hangup).once.and_return do
|
2016
2748
|
other_mock_call.async.deliver_message mock_end
|
2017
2749
|
end
|
@@ -2075,7 +2807,7 @@ module Adhearsion
|
|
2075
2807
|
other_mock_call.stub dial: true, join: true
|
2076
2808
|
other_mock_call.should_receive(:hangup).never
|
2077
2809
|
|
2078
|
-
subject.run
|
2810
|
+
subject.run double('controller')
|
2079
2811
|
|
2080
2812
|
subject.skip_cleanup
|
2081
2813
|
|