adhearsion 2.4.0.beta1 → 2.4.0.beta2

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.
@@ -22,7 +22,7 @@ Adhearsion.config do |config|
22
22
  end
23
23
 
24
24
  ##
25
- # Use with Rayo (eg Voxeo PRISM)
25
+ # Use with Rayo (eg Voxeo PRISM or FreeSWITCH mod_rayo)
26
26
  #
27
27
  # config.punchblock.username = "" # Your XMPP JID for use with Rayo
28
28
  # config.punchblock.password = "" # Your XMPP password
@@ -36,7 +36,9 @@ Adhearsion.config do |config|
36
36
  # config.punchblock.host = "127.0.0.1" # Your AMI host
37
37
 
38
38
  ##
39
- # Use with FreeSWITCH
39
+ # Use with FreeSWITCH via EventSocket
40
+ #
41
+ # This configuration is no longer recommended and mod_rayo is preferred
40
42
  #
41
43
  # config.punchblock.platform = :freeswitch # Use FreeSWITCH
42
44
  # config.punchblock.password = "" # Your Inbound EventSocket password
@@ -180,6 +180,8 @@ module Adhearsion
180
180
  lib_folder = [Adhearsion.config.platform.root, Adhearsion.config.platform.lib].join '/'
181
181
  return false unless File.directory? lib_folder
182
182
 
183
+ $LOAD_PATH.unshift lib_folder
184
+
183
185
  Dir.chdir lib_folder do
184
186
  rbfiles = File.join "**", "*.rb"
185
187
  Dir.glob(rbfiles).each do |file|
@@ -103,6 +103,8 @@ module Adhearsion
103
103
 
104
104
  def fqdn
105
105
  Socket.gethostbyname(Socket.gethostname).first
106
+ rescue SocketError
107
+ Socket.gethostname
106
108
  end
107
109
 
108
110
  def self.method_missing(method_name, *args, &block)
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Adhearsion
4
- VERSION = '2.4.0.beta1'
4
+ VERSION = '2.4.0.beta2'
5
5
  end
@@ -108,7 +108,7 @@ module Adhearsion
108
108
  latch.wait(1).should be_true
109
109
  end
110
110
 
111
- it "hangs up the new call when the dial unblocks" do
111
+ it "hangs up the new call when the root call ends" do
112
112
  call.should_receive(:answer).once
113
113
  other_mock_call.should_receive(:join).once.with(call)
114
114
  other_mock_call.should_receive(:hangup).once
@@ -176,7 +176,6 @@ module Adhearsion
176
176
  t.join
177
177
  status = t.value
178
178
  status.result.should be == :answer
179
- status.joined_call.should eq(other_mock_call)
180
179
 
181
180
  joined_status = status.joins[status.calls.first]
182
181
  joined_status.result.should == :joined
@@ -206,11 +205,393 @@ module Adhearsion
206
205
  t.join
207
206
  status = t.value
208
207
  status.result.should be == :answer
209
- status.joined_call.should eq(other_mock_call)
210
208
  joined_status = status.joins[status.calls.first]
211
209
  joined_status.duration.should == 37.0
212
210
  end
213
211
  end
212
+
213
+ context "when a dial is split" do
214
+ before do
215
+ call.should_receive(:answer).once
216
+ other_mock_call.should_receive(:join).once.with(call)
217
+ call.stub(:unjoin).and_return do
218
+ call << Punchblock::Event::Unjoined.new(call_uri: other_mock_call.id)
219
+ other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
220
+ end
221
+ end
222
+
223
+ it "should unjoin the calls" do
224
+ call.should_receive(:unjoin).once.ordered.with(other_mock_call.id).and_return do
225
+ call << Punchblock::Event::Unjoined.new(call_uri: other_mock_call.id)
226
+ other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
227
+ end
228
+
229
+ dial = Dial::Dial.new to, options, call
230
+ dial.run
231
+
232
+ waiter_thread = Thread.new do
233
+ dial.await_completion
234
+ latch.countdown!
235
+ end
236
+
237
+ sleep 0.5
238
+
239
+ other_mock_call << mock_answered
240
+
241
+ dial.split
242
+ other_mock_call << mock_end
243
+
244
+ latch.wait(1).should be_true
245
+
246
+ waiter_thread.join
247
+ dial.status.result.should be == :answer
248
+ end
249
+
250
+ it "should not unblock immediately" do
251
+ dial = Dial::Dial.new to, options, call
252
+ dial.run
253
+
254
+ waiter_thread = Thread.new do
255
+ dial.await_completion
256
+ latch.countdown!
257
+ end
258
+
259
+ sleep 0.5
260
+
261
+ other_mock_call << mock_answered
262
+
263
+ dial.split
264
+
265
+ latch.wait(1).should be_false
266
+
267
+ other_mock_call << mock_end
268
+
269
+ latch.wait(1).should be_true
270
+
271
+ waiter_thread.join
272
+ dial.status.result.should be == :answer
273
+ end
274
+
275
+ it "should set end time" do
276
+ dial = Dial::Dial.new to, options, call
277
+ dial.run
278
+
279
+ waiter_thread = Thread.new do
280
+ dial.await_completion
281
+ latch.countdown!
282
+ end
283
+
284
+ sleep 0.5
285
+
286
+ base_time = Time.local(2008, 9, 1, 12, 0, 0)
287
+ Timecop.freeze base_time
288
+
289
+ other_mock_call << mock_answered
290
+
291
+ base_time = Time.local(2008, 9, 1, 12, 0, 37)
292
+ Timecop.freeze base_time
293
+ dial.split
294
+
295
+ base_time = Time.local(2008, 9, 1, 12, 0, 54)
296
+ Timecop.freeze base_time
297
+ other_mock_call << mock_end
298
+
299
+ latch.wait(1).should be_true
300
+
301
+ waiter_thread.join
302
+ status = dial.status
303
+ status.result.should be == :answer
304
+ joined_status = status.joins[status.calls.first]
305
+ joined_status.duration.should == 37.0
306
+ end
307
+
308
+ context "with new controllers specified" do
309
+ let(:split_latch) { CountDownLatch.new 2 }
310
+
311
+ let(:split_controller) do
312
+ latch = split_latch
313
+ Class.new(Adhearsion::CallController) do
314
+ @@split_latch = latch
315
+
316
+ def run
317
+ call['hit_split_controller'] = self.class
318
+ call['split_controller_metadata'] = metadata
319
+ @@split_latch.countdown!
320
+ end
321
+ end
322
+ end
323
+
324
+ let(:main_split_controller) { Class.new(split_controller) }
325
+ let(:others_split_controller) { Class.new(split_controller) }
326
+
327
+ it "should execute the :main controller on the originating call and :others on the outbound calls" do
328
+ dial = Dial::Dial.new to, options, call
329
+ dial.run
330
+
331
+ waiter_thread = Thread.new do
332
+ dial.await_completion
333
+ latch.countdown!
334
+ end
335
+
336
+ sleep 0.5
337
+
338
+ other_mock_call << mock_answered
339
+
340
+ should_receive(:callback).once.with(call)
341
+ should_receive(:callback).once.with(other_mock_call)
342
+
343
+ dial.split main: main_split_controller, others: others_split_controller, main_callback: ->(call) { self.callback(call) }, others_callback: ->(call) { self.callback(call) }
344
+
345
+ latch.wait(1).should be_false
346
+ split_latch.wait(1).should be_true
347
+
348
+ call['hit_split_controller'].should == main_split_controller
349
+ call['split_controller_metadata']['current_dial'].should be dial
350
+
351
+ other_mock_call['hit_split_controller'].should == others_split_controller
352
+ other_mock_call['split_controller_metadata']['current_dial'].should be dial
353
+
354
+ other_mock_call << mock_end
355
+
356
+ latch.wait(1).should be_true
357
+
358
+ waiter_thread.join
359
+ dial.status.result.should be == :answer
360
+ end
361
+ end
362
+
363
+ context "when rejoining" do
364
+ it "should rejoin the calls" do
365
+ call.should_receive(:unjoin).once.ordered.with(other_mock_call.id).and_return do
366
+ call << Punchblock::Event::Unjoined.new(call_uri: other_mock_call.id)
367
+ other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
368
+ end
369
+
370
+ dial = Dial::Dial.new to, options, call
371
+ dial.run
372
+
373
+ waiter_thread = Thread.new do
374
+ dial.await_completion
375
+ latch.countdown!
376
+ end
377
+
378
+ sleep 0.5
379
+
380
+ other_mock_call << mock_answered
381
+
382
+ dial.split
383
+
384
+ other_mock_call.should_receive(:join).once.ordered.with(call)
385
+ dial.rejoin
386
+
387
+ other_mock_call << mock_end
388
+
389
+ latch.wait(1).should be_true
390
+
391
+ waiter_thread.join
392
+ dial.status.result.should be == :answer
393
+ end
394
+
395
+ context "to a specified mixer" do
396
+ let(:mixer) { SecureRandom.uuid }
397
+
398
+ it "should join all calls to the mixer" do
399
+ call.should_receive(:unjoin).once.ordered.with(other_mock_call.id).and_return do
400
+ call << Punchblock::Event::Unjoined.new(call_uri: other_mock_call.id)
401
+ other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
402
+ end
403
+
404
+ dial = Dial::Dial.new to, options, call
405
+ dial.run
406
+
407
+ waiter_thread = Thread.new do
408
+ dial.await_completion
409
+ latch.countdown!
410
+ end
411
+
412
+ sleep 0.5
413
+
414
+ other_mock_call << mock_answered
415
+
416
+ dial.split
417
+
418
+ call.should_receive(:join).once.ordered.with(mixer_name: mixer)
419
+ other_mock_call.should_receive(:join).once.ordered.with(mixer_name: mixer)
420
+ dial.rejoin mixer_name: mixer
421
+
422
+ other_mock_call << mock_end
423
+
424
+ latch.wait(1).should be_true
425
+
426
+ waiter_thread.join
427
+ dial.status.result.should be == :answer
428
+ end
429
+ end
430
+ end
431
+
432
+ context "when another dial is merged in" do
433
+ let(:second_root_call_id) { new_uuid }
434
+ let(:second_root_call) { Adhearsion::Call.new }
435
+ let(:mixer) { SecureRandom.uuid }
436
+
437
+ let(:dial) { Dial::Dial.new to, options, call }
438
+ let(:other_dial) { Dial::Dial.new second_to, options, second_root_call }
439
+
440
+ before do
441
+ second_root_call.stub write_command: true, id: second_root_call_id
442
+ OutboundCall.should_receive(:new).and_return second_other_mock_call
443
+ second_other_mock_call.should_receive(:join).once.with(second_root_call)
444
+ second_other_mock_call.should_receive(:dial).once.with(second_to, options)
445
+ second_root_call.should_receive(:answer).once
446
+
447
+ SecureRandom.stub uuid: mixer
448
+
449
+ dial.run
450
+ other_dial.run
451
+
452
+ other_mock_call << mock_answered
453
+ second_other_mock_call << mock_answered
454
+ end
455
+
456
+ it "should split calls, rejoin to a mixer, and rejoin other calls to mixer" do
457
+ call.should_receive(:unjoin).once.ordered.with(other_mock_call.id).and_return do
458
+ call << Punchblock::Event::Unjoined.new(call_uri: other_mock_call.id)
459
+ other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
460
+ end
461
+ second_root_call.should_receive(:unjoin).once.ordered.with(second_other_mock_call.id).and_return do
462
+ second_root_call << Punchblock::Event::Unjoined.new(call_uri: second_other_mock_call.id)
463
+ second_other_mock_call << Punchblock::Event::Unjoined.new(call_uri: second_root_call.id)
464
+ end
465
+
466
+ call.should_receive(:join).once.ordered.with(mixer_name: mixer)
467
+ other_mock_call.should_receive(:join).once.ordered.with(mixer_name: mixer)
468
+
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)
471
+
472
+ dial.merge other_dial
473
+
474
+ waiter_thread = Thread.new do
475
+ dial.await_completion
476
+ latch.countdown!
477
+ end
478
+
479
+ sleep 0.5
480
+
481
+ other_mock_call << mock_end
482
+ second_root_call << mock_end
483
+ second_other_mock_call << mock_end
484
+
485
+ latch.wait(1).should be_true
486
+
487
+ waiter_thread.join
488
+ dial.status.result.should be == :answer
489
+ end
490
+
491
+ it "should add the merged calls to the returned status" do
492
+ [call, other_mock_call, second_root_call, second_other_mock_call].each { |c| c.stub join: true, unjoin: true }
493
+ dial.merge other_dial
494
+
495
+ waiter_thread = Thread.new do
496
+ dial.await_completion
497
+ latch.countdown!
498
+ end
499
+
500
+ sleep 0.5
501
+
502
+ other_mock_call << mock_end
503
+ second_root_call << mock_end
504
+ second_other_mock_call << mock_end
505
+
506
+ latch.wait(1).should be_true
507
+
508
+ waiter_thread.join
509
+ dial.status.result.should be == :answer
510
+ dial.status.calls.should include(second_root_call, second_other_mock_call)
511
+ end
512
+
513
+ it "should not unblock until all joined calls end" do
514
+ [call, other_mock_call, second_root_call, second_other_mock_call].each { |c| c.stub join: true, unjoin: true }
515
+
516
+ dial.merge other_dial
517
+
518
+ waiter_thread = Thread.new do
519
+ dial.await_completion
520
+ latch.countdown!
521
+ end
522
+
523
+ sleep 0.5
524
+
525
+ other_mock_call << mock_end
526
+ latch.wait(1).should be_false
527
+
528
+ second_other_mock_call << mock_end
529
+ latch.wait(1).should be_false
530
+
531
+ second_root_call << mock_end
532
+ latch.wait(1).should be_true
533
+
534
+ waiter_thread.join
535
+ dial.status.result.should be == :answer
536
+ end
537
+
538
+ it "should cleanup merged calls when the root call ends" do
539
+ [call, other_mock_call, second_root_call, second_other_mock_call].each do |c|
540
+ c.stub join: true, unjoin: true
541
+ end
542
+ [other_mock_call, second_root_call, second_other_mock_call].each do |c|
543
+ c.should_receive(:hangup).once
544
+ end
545
+
546
+ dial.merge other_dial
547
+
548
+ waiter_thread = Thread.new do
549
+ dial.await_completion
550
+ dial.cleanup_calls
551
+ latch.countdown!
552
+ end
553
+
554
+ sleep 0.5
555
+
556
+ call << mock_end
557
+ latch.wait(1).should be_true
558
+
559
+ waiter_thread.join
560
+ dial.status.result.should be == :answer
561
+ end
562
+
563
+ context "if the calls were not joined" do
564
+ it "should still join to mixer" do
565
+ call.should_receive(:unjoin).once.ordered.with(other_mock_call.id).and_raise Punchblock::ProtocolError.new.setup(:service_unavailable)
566
+ second_root_call.should_receive(:unjoin).once.ordered.with(second_other_mock_call.id).and_raise Punchblock::ProtocolError.new.setup(:service_unavailable)
567
+
568
+ call.should_receive(:join).once.ordered.with(mixer_name: mixer)
569
+ other_mock_call.should_receive(:join).once.ordered.with(mixer_name: mixer)
570
+
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)
573
+
574
+ dial.merge other_dial
575
+
576
+ waiter_thread = Thread.new do
577
+ dial.await_completion
578
+ latch.countdown!
579
+ end
580
+
581
+ sleep 0.5
582
+
583
+ other_mock_call << mock_end
584
+ second_root_call << mock_end
585
+ second_other_mock_call << mock_end
586
+
587
+ latch.wait(1).should be_true
588
+
589
+ waiter_thread.join
590
+ dial.status.result.should be == :answer
591
+ end
592
+ end
593
+ end
594
+ end
214
595
  end
215
596
 
216
597
  describe "when the caller has already hung up" do
@@ -725,7 +1106,7 @@ module Adhearsion
725
1106
  latch.wait(1).should be_true
726
1107
  end
727
1108
 
728
- it "hangs up the new call when the dial unblocks" do
1109
+ it "hangs up the new call when the root call ends" do
729
1110
  other_mock_call.should_receive(:hangup).once
730
1111
  call.should_receive(:answer).once
731
1112
  other_mock_call.should_receive(:join).once.with(call)
@@ -793,7 +1174,6 @@ module Adhearsion
793
1174
  t.join
794
1175
  status = t.value
795
1176
  status.result.should be == :answer
796
- status.joined_call.should eq(other_mock_call)
797
1177
 
798
1178
  joined_status = status.joins[status.calls.first]
799
1179
  joined_status.result.should == :joined
@@ -823,11 +1203,393 @@ module Adhearsion
823
1203
  t.join
824
1204
  status = t.value
825
1205
  status.result.should be == :answer
826
- status.joined_call.should eq(other_mock_call)
827
1206
  joined_status = status.joins[status.calls.first]
828
1207
  joined_status.duration.should == 37.0
829
1208
  end
830
1209
  end
1210
+
1211
+ context "when a dial is split" do
1212
+ before do
1213
+ call.should_receive(:answer).once
1214
+ other_mock_call.should_receive(:join).once.with(call)
1215
+ call.stub(:unjoin).and_return do
1216
+ call << Punchblock::Event::Unjoined.new(call_uri: other_mock_call.id)
1217
+ other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
1218
+ end
1219
+ end
1220
+
1221
+ it "should unjoin the calls" do
1222
+ call.should_receive(:unjoin).once.ordered.with(other_mock_call.id).and_return do
1223
+ call << Punchblock::Event::Unjoined.new(call_uri: other_mock_call.id)
1224
+ other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
1225
+ end
1226
+
1227
+ dial = Dial::ParallelConfirmationDial.new to, options, call
1228
+ dial.run
1229
+
1230
+ waiter_thread = Thread.new do
1231
+ dial.await_completion
1232
+ latch.countdown!
1233
+ end
1234
+
1235
+ sleep 0.5
1236
+
1237
+ other_mock_call << mock_answered
1238
+
1239
+ dial.split
1240
+ other_mock_call << mock_end
1241
+
1242
+ latch.wait(1).should be_true
1243
+
1244
+ waiter_thread.join
1245
+ dial.status.result.should be == :answer
1246
+ end
1247
+
1248
+ it "should not unblock immediately" do
1249
+ dial = Dial::ParallelConfirmationDial.new to, options, call
1250
+ dial.run
1251
+
1252
+ waiter_thread = Thread.new do
1253
+ dial.await_completion
1254
+ latch.countdown!
1255
+ end
1256
+
1257
+ sleep 0.5
1258
+
1259
+ other_mock_call << mock_answered
1260
+
1261
+ dial.split
1262
+
1263
+ latch.wait(1).should be_false
1264
+
1265
+ other_mock_call << mock_end
1266
+
1267
+ latch.wait(1).should be_true
1268
+
1269
+ waiter_thread.join
1270
+ dial.status.result.should be == :answer
1271
+ end
1272
+
1273
+ it "should set end time" do
1274
+ dial = Dial::ParallelConfirmationDial.new to, options, call
1275
+ dial.run
1276
+
1277
+ waiter_thread = Thread.new do
1278
+ dial.await_completion
1279
+ latch.countdown!
1280
+ end
1281
+
1282
+ sleep 0.5
1283
+
1284
+ base_time = Time.local(2008, 9, 1, 12, 0, 0)
1285
+ Timecop.freeze base_time
1286
+
1287
+ other_mock_call << mock_answered
1288
+
1289
+ base_time = Time.local(2008, 9, 1, 12, 0, 37)
1290
+ Timecop.freeze base_time
1291
+ dial.split
1292
+
1293
+ base_time = Time.local(2008, 9, 1, 12, 0, 54)
1294
+ Timecop.freeze base_time
1295
+ other_mock_call << mock_end
1296
+
1297
+ latch.wait(1).should be_true
1298
+
1299
+ waiter_thread.join
1300
+ status = dial.status
1301
+ status.result.should be == :answer
1302
+ joined_status = status.joins[status.calls.first]
1303
+ joined_status.duration.should == 37.0
1304
+ end
1305
+
1306
+ context "with new controllers specified" do
1307
+ let(:split_latch) { CountDownLatch.new 2 }
1308
+
1309
+ let(:split_controller) do
1310
+ latch = split_latch
1311
+ Class.new(Adhearsion::CallController) do
1312
+ @@split_latch = latch
1313
+
1314
+ def run
1315
+ call['hit_split_controller'] = self.class
1316
+ call['split_controller_metadata'] = metadata
1317
+ @@split_latch.countdown!
1318
+ end
1319
+ end
1320
+ end
1321
+
1322
+ let(:main_split_controller) { Class.new(split_controller) }
1323
+ let(:others_split_controller) { Class.new(split_controller) }
1324
+
1325
+ it "should execute the :main controller on the originating call and :others on the outbound calls" do
1326
+ dial = Dial::ParallelConfirmationDial.new to, options, call
1327
+ dial.run
1328
+
1329
+ waiter_thread = Thread.new do
1330
+ dial.await_completion
1331
+ latch.countdown!
1332
+ end
1333
+
1334
+ sleep 0.5
1335
+
1336
+ other_mock_call << mock_answered
1337
+
1338
+ should_receive(:callback).once.with(call)
1339
+ should_receive(:callback).once.with(other_mock_call)
1340
+
1341
+ dial.split main: main_split_controller, others: others_split_controller, main_callback: ->(call) { self.callback(call) }, others_callback: ->(call) { self.callback(call) }
1342
+
1343
+ latch.wait(1).should be_false
1344
+ split_latch.wait(1).should be_true
1345
+
1346
+ call['hit_split_controller'].should == main_split_controller
1347
+ call['split_controller_metadata']['current_dial'].should be dial
1348
+
1349
+ other_mock_call['hit_split_controller'].should == others_split_controller
1350
+ other_mock_call['split_controller_metadata']['current_dial'].should be dial
1351
+
1352
+ other_mock_call << mock_end
1353
+
1354
+ latch.wait(1).should be_true
1355
+
1356
+ waiter_thread.join
1357
+ dial.status.result.should be == :answer
1358
+ end
1359
+ end
1360
+
1361
+ context "when rejoining" do
1362
+ it "should rejoin the calls" do
1363
+ call.should_receive(:unjoin).once.ordered.with(other_mock_call.id).and_return do
1364
+ call << Punchblock::Event::Unjoined.new(call_uri: other_mock_call.id)
1365
+ other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
1366
+ end
1367
+
1368
+ dial = Dial::ParallelConfirmationDial.new to, options, call
1369
+ dial.run
1370
+
1371
+ waiter_thread = Thread.new do
1372
+ dial.await_completion
1373
+ latch.countdown!
1374
+ end
1375
+
1376
+ sleep 0.5
1377
+
1378
+ other_mock_call << mock_answered
1379
+
1380
+ dial.split
1381
+
1382
+ other_mock_call.should_receive(:join).once.ordered.with(call)
1383
+ dial.rejoin
1384
+
1385
+ other_mock_call << mock_end
1386
+
1387
+ latch.wait(1).should be_true
1388
+
1389
+ waiter_thread.join
1390
+ dial.status.result.should be == :answer
1391
+ end
1392
+
1393
+ context "to a specified mixer" do
1394
+ let(:mixer) { SecureRandom.uuid }
1395
+
1396
+ it "should join all calls to the mixer" do
1397
+ call.should_receive(:unjoin).once.ordered.with(other_mock_call.id).and_return do
1398
+ call << Punchblock::Event::Unjoined.new(call_uri: other_mock_call.id)
1399
+ other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
1400
+ end
1401
+
1402
+ dial = Dial::ParallelConfirmationDial.new to, options, call
1403
+ dial.run
1404
+
1405
+ waiter_thread = Thread.new do
1406
+ dial.await_completion
1407
+ latch.countdown!
1408
+ end
1409
+
1410
+ sleep 0.5
1411
+
1412
+ other_mock_call << mock_answered
1413
+
1414
+ dial.split
1415
+
1416
+ call.should_receive(:join).once.ordered.with(mixer_name: mixer)
1417
+ other_mock_call.should_receive(:join).once.ordered.with(mixer_name: mixer)
1418
+ dial.rejoin mixer_name: mixer
1419
+
1420
+ other_mock_call << mock_end
1421
+
1422
+ latch.wait(1).should be_true
1423
+
1424
+ waiter_thread.join
1425
+ dial.status.result.should be == :answer
1426
+ end
1427
+ end
1428
+ end
1429
+
1430
+ context "when another dial is merged in" do
1431
+ let(:second_root_call_id) { new_uuid }
1432
+ let(:second_root_call) { Adhearsion::Call.new }
1433
+ let(:mixer) { SecureRandom.uuid }
1434
+
1435
+ let(:dial) { Dial::ParallelConfirmationDial.new to, options, call }
1436
+ let(:other_dial) { Dial::ParallelConfirmationDial.new second_to, options, second_root_call }
1437
+
1438
+ before do
1439
+ second_root_call.stub write_command: true, id: second_root_call_id
1440
+ OutboundCall.should_receive(:new).and_return second_other_mock_call
1441
+ second_other_mock_call.should_receive(:join).once.with(second_root_call)
1442
+ second_other_mock_call.should_receive(:dial).once.with(second_to, options)
1443
+ second_root_call.should_receive(:answer).once
1444
+
1445
+ SecureRandom.stub uuid: mixer
1446
+
1447
+ dial.run
1448
+ other_dial.run
1449
+
1450
+ other_mock_call << mock_answered
1451
+ second_other_mock_call << mock_answered
1452
+ end
1453
+
1454
+ it "should split calls, rejoin to a mixer, and rejoin other calls to mixer" do
1455
+ call.should_receive(:unjoin).once.ordered.with(other_mock_call.id).and_return do
1456
+ call << Punchblock::Event::Unjoined.new(call_uri: other_mock_call.id)
1457
+ other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
1458
+ end
1459
+ second_root_call.should_receive(:unjoin).once.ordered.with(second_other_mock_call.id).and_return do
1460
+ second_root_call << Punchblock::Event::Unjoined.new(call_uri: second_other_mock_call.id)
1461
+ second_other_mock_call << Punchblock::Event::Unjoined.new(call_uri: second_root_call.id)
1462
+ end
1463
+
1464
+ call.should_receive(:join).once.ordered.with(mixer_name: mixer)
1465
+ other_mock_call.should_receive(:join).once.ordered.with(mixer_name: mixer)
1466
+
1467
+ second_root_call.should_receive(:join).once.ordered.with(mixer_name: mixer)
1468
+ second_other_mock_call.should_receive(:join).once.ordered.with(mixer_name: mixer)
1469
+
1470
+ dial.merge other_dial
1471
+
1472
+ waiter_thread = Thread.new do
1473
+ dial.await_completion
1474
+ latch.countdown!
1475
+ end
1476
+
1477
+ sleep 0.5
1478
+
1479
+ other_mock_call << mock_end
1480
+ second_root_call << mock_end
1481
+ second_other_mock_call << mock_end
1482
+
1483
+ latch.wait(1).should be_true
1484
+
1485
+ waiter_thread.join
1486
+ dial.status.result.should be == :answer
1487
+ end
1488
+
1489
+ it "should add the merged calls to the returned status" do
1490
+ [call, other_mock_call, second_root_call, second_other_mock_call].each { |c| c.stub join: true, unjoin: true }
1491
+ dial.merge other_dial
1492
+
1493
+ waiter_thread = Thread.new do
1494
+ dial.await_completion
1495
+ latch.countdown!
1496
+ end
1497
+
1498
+ sleep 0.5
1499
+
1500
+ other_mock_call << mock_end
1501
+ second_root_call << mock_end
1502
+ second_other_mock_call << mock_end
1503
+
1504
+ latch.wait(1).should be_true
1505
+
1506
+ waiter_thread.join
1507
+ dial.status.result.should be == :answer
1508
+ dial.status.calls.should include(second_root_call, second_other_mock_call)
1509
+ end
1510
+
1511
+ it "should not unblock until all joined calls end" do
1512
+ [call, other_mock_call, second_root_call, second_other_mock_call].each { |c| c.stub join: true, unjoin: true }
1513
+
1514
+ dial.merge other_dial
1515
+
1516
+ waiter_thread = Thread.new do
1517
+ dial.await_completion
1518
+ latch.countdown!
1519
+ end
1520
+
1521
+ sleep 0.5
1522
+
1523
+ other_mock_call << mock_end
1524
+ latch.wait(1).should be_false
1525
+
1526
+ second_other_mock_call << mock_end
1527
+ latch.wait(1).should be_false
1528
+
1529
+ second_root_call << mock_end
1530
+ latch.wait(1).should be_true
1531
+
1532
+ waiter_thread.join
1533
+ dial.status.result.should be == :answer
1534
+ end
1535
+
1536
+ it "should cleanup merged calls when the root call ends" do
1537
+ [call, other_mock_call, second_root_call, second_other_mock_call].each do |c|
1538
+ c.stub join: true, unjoin: true
1539
+ end
1540
+ [other_mock_call, second_root_call, second_other_mock_call].each do |c|
1541
+ c.should_receive(:hangup).once
1542
+ end
1543
+
1544
+ dial.merge other_dial
1545
+
1546
+ waiter_thread = Thread.new do
1547
+ dial.await_completion
1548
+ dial.cleanup_calls
1549
+ latch.countdown!
1550
+ end
1551
+
1552
+ sleep 0.5
1553
+
1554
+ call << mock_end
1555
+ latch.wait(1).should be_true
1556
+
1557
+ waiter_thread.join
1558
+ dial.status.result.should be == :answer
1559
+ end
1560
+
1561
+ context "if the calls were not joined" do
1562
+ it "should still join to mixer" do
1563
+ call.should_receive(:unjoin).once.ordered.with(other_mock_call.id).and_raise Punchblock::ProtocolError.new.setup(:service_unavailable)
1564
+ second_root_call.should_receive(:unjoin).once.ordered.with(second_other_mock_call.id).and_raise Punchblock::ProtocolError.new.setup(:service_unavailable)
1565
+
1566
+ call.should_receive(:join).once.ordered.with(mixer_name: mixer)
1567
+ other_mock_call.should_receive(:join).once.ordered.with(mixer_name: mixer)
1568
+
1569
+ second_root_call.should_receive(:join).once.ordered.with(mixer_name: mixer)
1570
+ second_other_mock_call.should_receive(:join).once.ordered.with(mixer_name: mixer)
1571
+
1572
+ dial.merge other_dial
1573
+
1574
+ waiter_thread = Thread.new do
1575
+ dial.await_completion
1576
+ latch.countdown!
1577
+ end
1578
+
1579
+ sleep 0.5
1580
+
1581
+ other_mock_call << mock_end
1582
+ second_root_call << mock_end
1583
+ second_other_mock_call << mock_end
1584
+
1585
+ latch.wait(1).should be_true
1586
+
1587
+ waiter_thread.join
1588
+ dial.status.result.should be == :answer
1589
+ end
1590
+ end
1591
+ end
1592
+ end
831
1593
  end
832
1594
 
833
1595
  describe "when the caller has already hung up" do
@@ -1289,6 +2051,46 @@ module Adhearsion
1289
2051
  end
1290
2052
  end
1291
2053
  end
2054
+
2055
+ describe Dial::Dial do
2056
+ subject { Dial::Dial.new to, {}, call }
2057
+
2058
+ describe "#prep_calls" do
2059
+ it "yields all calls to the passed block" do
2060
+ OutboundCall.should_receive(:new).and_return other_mock_call
2061
+
2062
+ gathered_calls = []
2063
+ subject.prep_calls { |call| gathered_calls << call }
2064
+
2065
+ expect(gathered_calls).to include(other_mock_call)
2066
+ end
2067
+ end
2068
+
2069
+ context "#skip_cleanup" do
2070
+ it "allows the new call to continue after the root call ends" do
2071
+ OutboundCall.should_receive(:new).and_return other_mock_call
2072
+
2073
+ call.stub answer: true
2074
+ other_mock_call.stub dial: true, join: true
2075
+ other_mock_call.should_receive(:hangup).never
2076
+
2077
+ subject.run
2078
+
2079
+ subject.skip_cleanup
2080
+
2081
+ Thread.new do
2082
+ subject.await_completion
2083
+ subject.cleanup_calls
2084
+ latch.countdown!
2085
+ end
2086
+
2087
+ other_mock_call << mock_answered
2088
+ call << mock_end
2089
+
2090
+ latch.wait(1).should be_true
2091
+ end
2092
+ end
2093
+ end
1292
2094
  end
1293
2095
  end
1294
2096
  end