adhearsion 2.6.4 → 3.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (242) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +6 -9
  3. data/CHANGELOG.md +22 -7
  4. data/Gemfile +2 -0
  5. data/README.markdown +4 -5
  6. data/Rakefile +1 -2
  7. data/adhearsion.gemspec +19 -8
  8. data/features/cli_create.feature +19 -3
  9. data/features/step_definitions/cli_steps.rb +0 -11
  10. data/features/support/env.rb +3 -4
  11. data/lib/adhearsion.rb +48 -27
  12. data/lib/adhearsion/call.rb +34 -50
  13. data/lib/adhearsion/call_controller.rb +6 -12
  14. data/lib/adhearsion/call_controller/dial.rb +15 -53
  15. data/lib/adhearsion/call_controller/input.rb +39 -162
  16. data/lib/adhearsion/call_controller/input/ask_grammar_builder.rb +44 -0
  17. data/lib/adhearsion/call_controller/input/menu_builder.rb +136 -0
  18. data/lib/adhearsion/call_controller/input/prompt_builder.rb +78 -0
  19. data/lib/adhearsion/call_controller/input/result.rb +46 -0
  20. data/lib/adhearsion/call_controller/output.rb +48 -67
  21. data/lib/adhearsion/call_controller/output/abstract_player.rb +3 -3
  22. data/lib/adhearsion/call_controller/output/async_player.rb +3 -3
  23. data/lib/adhearsion/call_controller/output/player.rb +1 -1
  24. data/lib/adhearsion/call_controller/record.rb +23 -8
  25. data/lib/adhearsion/calls.rb +1 -1
  26. data/lib/adhearsion/cli_commands/ahn_command.rb +2 -65
  27. data/lib/adhearsion/cli_commands/thor_errors.rb +0 -6
  28. data/lib/adhearsion/configuration.rb +91 -39
  29. data/lib/adhearsion/core_ext/blather/stanza.rb +41 -0
  30. data/lib/adhearsion/core_ext/blather/stanza/presence.rb +13 -0
  31. data/lib/adhearsion/error.rb +5 -0
  32. data/lib/adhearsion/event.rb +21 -0
  33. data/lib/adhearsion/event/active_speaker.rb +11 -0
  34. data/lib/adhearsion/event/answered.rb +11 -0
  35. data/lib/adhearsion/event/asterisk.rb +10 -0
  36. data/lib/adhearsion/event/asterisk/ami.rb +34 -0
  37. data/lib/adhearsion/event/complete.rb +75 -0
  38. data/lib/adhearsion/event/dtmf.rb +11 -0
  39. data/lib/adhearsion/event/end.rb +22 -0
  40. data/lib/adhearsion/event/input_timers_started.rb +9 -0
  41. data/lib/adhearsion/event/joined.rb +17 -0
  42. data/lib/adhearsion/event/offer.rb +14 -0
  43. data/lib/adhearsion/event/ringing.rb +11 -0
  44. data/lib/adhearsion/event/started_speaking.rb +13 -0
  45. data/lib/adhearsion/event/stopped_speaking.rb +13 -0
  46. data/lib/adhearsion/event/unjoined.rb +17 -0
  47. data/lib/adhearsion/events.rb +47 -66
  48. data/lib/adhearsion/foundation.rb +0 -1
  49. data/lib/adhearsion/foundation/object.rb +0 -5
  50. data/lib/adhearsion/generators/app/app_generator.rb +4 -1
  51. data/lib/adhearsion/generators/app/templates/Gemfile.erb +2 -10
  52. data/lib/adhearsion/generators/app/templates/adhearsion.erb +9 -9
  53. data/lib/adhearsion/generators/app/templates/config.ru +7 -0
  54. data/lib/adhearsion/generators/app/templates/en.yml +4 -0
  55. data/lib/adhearsion/generators/app/templates/events.erb +2 -2
  56. data/lib/adhearsion/generators/app/templates/hello_world.wav +0 -0
  57. data/lib/adhearsion/generators/app/templates/simon_game.rb +2 -1
  58. data/lib/adhearsion/generators/app/templates/simon_game_spec.rb +2 -2
  59. data/lib/adhearsion/has_headers.rb +34 -0
  60. data/lib/adhearsion/http_server.rb +37 -0
  61. data/lib/adhearsion/initializer.rb +19 -153
  62. data/lib/adhearsion/logging.rb +6 -25
  63. data/lib/adhearsion/outbound_call.rb +5 -5
  64. data/lib/adhearsion/plugin.rb +1 -0
  65. data/lib/adhearsion/protocol_error.rb +26 -0
  66. data/lib/adhearsion/rayo.rb +30 -0
  67. data/lib/adhearsion/rayo/client.rb +62 -0
  68. data/lib/adhearsion/rayo/client/component_registry.rb +33 -0
  69. data/lib/adhearsion/rayo/command.rb +21 -0
  70. data/lib/adhearsion/rayo/command/accept.rb +16 -0
  71. data/lib/adhearsion/rayo/command/answer.rb +16 -0
  72. data/lib/adhearsion/rayo/command/dial.rb +57 -0
  73. data/lib/adhearsion/rayo/command/hangup.rb +16 -0
  74. data/lib/adhearsion/rayo/command/join.rb +43 -0
  75. data/lib/adhearsion/rayo/command/mute.rb +13 -0
  76. data/lib/adhearsion/rayo/command/redirect.rb +23 -0
  77. data/lib/adhearsion/rayo/command/reject.rb +40 -0
  78. data/lib/adhearsion/rayo/command/unjoin.rb +24 -0
  79. data/lib/adhearsion/rayo/command/unmute.rb +13 -0
  80. data/lib/adhearsion/rayo/command_node.rb +47 -0
  81. data/lib/adhearsion/rayo/component.rb +21 -0
  82. data/lib/adhearsion/rayo/component/asterisk.rb +13 -0
  83. data/lib/adhearsion/rayo/component/asterisk/agi.rb +14 -0
  84. data/lib/adhearsion/rayo/component/asterisk/agi/command.rb +46 -0
  85. data/lib/adhearsion/rayo/component/asterisk/ami.rb +14 -0
  86. data/lib/adhearsion/rayo/component/asterisk/ami/action.rb +61 -0
  87. data/lib/adhearsion/rayo/component/component_node.rb +90 -0
  88. data/lib/adhearsion/rayo/component/input.rb +186 -0
  89. data/lib/adhearsion/rayo/component/output.rb +471 -0
  90. data/lib/adhearsion/rayo/component/prompt.rb +53 -0
  91. data/lib/adhearsion/rayo/component/receive_fax.rb +26 -0
  92. data/lib/adhearsion/rayo/component/record.rb +165 -0
  93. data/lib/adhearsion/rayo/component/send_fax.rb +64 -0
  94. data/lib/adhearsion/rayo/component/stop.rb +11 -0
  95. data/lib/adhearsion/rayo/connection.rb +12 -0
  96. data/lib/adhearsion/rayo/connection/asterisk.rb +74 -0
  97. data/lib/adhearsion/rayo/connection/connected.rb +22 -0
  98. data/lib/adhearsion/rayo/connection/generic_connection.rb +22 -0
  99. data/lib/adhearsion/rayo/connection/xmpp.rb +198 -0
  100. data/lib/adhearsion/rayo/disconnected_error.rb +22 -0
  101. data/lib/adhearsion/{punchblock_plugin → rayo}/initializer.rb +19 -19
  102. data/lib/adhearsion/rayo/rayo_node.rb +127 -0
  103. data/lib/adhearsion/rayo/ref.rb +57 -0
  104. data/lib/adhearsion/statistics.rb +1 -1
  105. data/lib/adhearsion/tasks.rb +1 -2
  106. data/lib/adhearsion/tasks/configuration.rb +1 -1
  107. data/lib/adhearsion/tasks/environment.rb +0 -2
  108. data/lib/adhearsion/tasks/i18n.rb +49 -0
  109. data/lib/adhearsion/translator.rb +11 -0
  110. data/lib/adhearsion/translator/asterisk.rb +234 -0
  111. data/lib/adhearsion/translator/asterisk/agi_app.rb +17 -0
  112. data/lib/adhearsion/translator/asterisk/agi_command.rb +45 -0
  113. data/lib/adhearsion/translator/asterisk/ami_error_converter.rb +20 -0
  114. data/lib/adhearsion/translator/asterisk/call.rb +416 -0
  115. data/lib/adhearsion/translator/asterisk/channel.rb +43 -0
  116. data/lib/adhearsion/translator/asterisk/component.rb +88 -0
  117. data/lib/adhearsion/translator/asterisk/component/asterisk.rb +15 -0
  118. data/lib/adhearsion/translator/asterisk/component/asterisk/agi_command.rb +42 -0
  119. data/lib/adhearsion/translator/asterisk/component/asterisk/ami_action.rb +68 -0
  120. data/lib/adhearsion/translator/asterisk/component/composed_prompt.rb +76 -0
  121. data/lib/adhearsion/translator/asterisk/component/dtmf_recognizer.rb +137 -0
  122. data/lib/adhearsion/translator/asterisk/component/input.rb +34 -0
  123. data/lib/adhearsion/translator/asterisk/component/input_component.rb +90 -0
  124. data/lib/adhearsion/translator/asterisk/component/mrcp_native_prompt.rb +71 -0
  125. data/lib/adhearsion/translator/asterisk/component/mrcp_prompt.rb +55 -0
  126. data/lib/adhearsion/translator/asterisk/component/mrcp_recog_prompt.rb +165 -0
  127. data/lib/adhearsion/translator/asterisk/component/output.rb +233 -0
  128. data/lib/adhearsion/translator/asterisk/component/record.rb +101 -0
  129. data/lib/adhearsion/translator/asterisk/component/stop_by_redirect.rb +30 -0
  130. data/lib/adhearsion/translator/asterisk/unimrcp_app.rb +28 -0
  131. data/lib/adhearsion/uri_list.rb +21 -0
  132. data/lib/adhearsion/version.rb +1 -1
  133. data/spec/adhearsion/call_controller/dial_spec.rb +79 -1420
  134. data/spec/adhearsion/call_controller/input_spec.rb +1141 -237
  135. data/spec/adhearsion/call_controller/output/async_player_spec.rb +10 -10
  136. data/spec/adhearsion/call_controller/output/player_spec.rb +8 -8
  137. data/spec/adhearsion/call_controller/output_spec.rb +162 -215
  138. data/spec/adhearsion/call_controller/record_spec.rb +15 -16
  139. data/spec/adhearsion/call_controller_spec.rb +23 -40
  140. data/spec/adhearsion/call_spec.rb +123 -129
  141. data/spec/adhearsion/calls_spec.rb +3 -3
  142. data/spec/adhearsion/configuration_spec.rb +94 -108
  143. data/spec/adhearsion/event/answered_spec.rb +50 -0
  144. data/spec/adhearsion/event/asterisk/Find Results +402 -0
  145. data/spec/adhearsion/event/asterisk/ami_spec.rb +81 -0
  146. data/spec/adhearsion/event/complete_spec.rb +176 -0
  147. data/spec/adhearsion/event/dtmf_spec.rb +35 -0
  148. data/spec/adhearsion/event/end_spec.rb +85 -0
  149. data/spec/adhearsion/event/input_timers_started_spec.rb +19 -0
  150. data/spec/adhearsion/event/joined_spec.rb +53 -0
  151. data/spec/adhearsion/event/offer_spec.rb +106 -0
  152. data/spec/adhearsion/event/ringing_spec.rb +50 -0
  153. data/spec/adhearsion/event/started_speaking_spec.rb +37 -0
  154. data/spec/adhearsion/event/stopped_speaking_spec.rb +37 -0
  155. data/spec/adhearsion/event/unjoined_spec.rb +48 -0
  156. data/spec/adhearsion/event/untitled +0 -0
  157. data/spec/adhearsion/events_spec.rb +19 -45
  158. data/spec/adhearsion/initializer_spec.rb +12 -184
  159. data/spec/adhearsion/logging_spec.rb +5 -20
  160. data/spec/adhearsion/outbound_call_spec.rb +13 -13
  161. data/spec/adhearsion/plugin_spec.rb +3 -4
  162. data/spec/adhearsion/protocol_error_spec.rb +91 -0
  163. data/spec/adhearsion/rayo/client/component_registry_spec.rb +26 -0
  164. data/spec/adhearsion/rayo/client_spec.rb +134 -0
  165. data/spec/adhearsion/rayo/command/accept_spec.rb +63 -0
  166. data/spec/adhearsion/rayo/command/answer_spec.rb +73 -0
  167. data/spec/adhearsion/rayo/command/dial_spec.rb +156 -0
  168. data/spec/adhearsion/rayo/command/hangup_spec.rb +63 -0
  169. data/spec/adhearsion/rayo/command/join_spec.rb +158 -0
  170. data/spec/adhearsion/rayo/command/mute_spec.rb +32 -0
  171. data/spec/adhearsion/rayo/command/redirect_spec.rb +89 -0
  172. data/spec/adhearsion/rayo/command/reject_spec.rb +117 -0
  173. data/spec/adhearsion/rayo/command/unjoin_spec.rb +82 -0
  174. data/spec/adhearsion/rayo/command/unmute_spec.rb +32 -0
  175. data/spec/adhearsion/rayo/command_node_spec.rb +101 -0
  176. data/spec/adhearsion/rayo/component/asterisk/agi/command_spec.rb +111 -0
  177. data/spec/adhearsion/rayo/component/asterisk/ami/action_spec.rb +173 -0
  178. data/spec/adhearsion/rayo/component/component_node_spec.rb +110 -0
  179. data/spec/adhearsion/rayo/component/input_spec.rb +715 -0
  180. data/spec/adhearsion/rayo/component/output_spec.rb +1030 -0
  181. data/spec/adhearsion/rayo/component/prompt_spec.rb +171 -0
  182. data/spec/adhearsion/rayo/component/receive_fax_spec.rb +136 -0
  183. data/spec/adhearsion/rayo/component/record_spec.rb +497 -0
  184. data/spec/adhearsion/rayo/component/send_fax_spec.rb +144 -0
  185. data/spec/adhearsion/rayo/connection/asterisk_spec.rb +118 -0
  186. data/spec/adhearsion/rayo/connection/xmpp_spec.rb +449 -0
  187. data/spec/adhearsion/rayo/initializer_spec.rb +353 -0
  188. data/spec/adhearsion/rayo/ref_spec.rb +168 -0
  189. data/spec/adhearsion/rayo_spec.rb +7 -0
  190. data/spec/adhearsion/router/route_spec.rb +1 -1
  191. data/spec/adhearsion/statistics_spec.rb +2 -5
  192. data/spec/adhearsion/translator/asterisk/call_spec.rb +2047 -0
  193. data/spec/adhearsion/translator/asterisk/component/asterisk/agi_command_spec.rb +256 -0
  194. data/spec/adhearsion/translator/asterisk/component/asterisk/ami_action_spec.rb +151 -0
  195. data/spec/adhearsion/translator/asterisk/component/composed_prompt_spec.rb +257 -0
  196. data/spec/adhearsion/translator/asterisk/component/input_spec.rb +571 -0
  197. data/spec/adhearsion/translator/asterisk/component/mrcp_native_prompt_spec.rb +774 -0
  198. data/spec/adhearsion/translator/asterisk/component/mrcp_prompt_spec.rb +1244 -0
  199. data/spec/adhearsion/translator/asterisk/component/output_spec.rb +1850 -0
  200. data/spec/adhearsion/translator/asterisk/component/record_spec.rb +426 -0
  201. data/spec/adhearsion/translator/asterisk/component/stop_by_redirect_spec.rb +62 -0
  202. data/spec/adhearsion/translator/asterisk/component_spec.rb +83 -0
  203. data/spec/adhearsion/translator/asterisk_spec.rb +685 -0
  204. data/spec/adhearsion/uri_list_spec.rb +88 -0
  205. data/spec/adhearsion_spec.rb +89 -14
  206. data/spec/fixtures/locale/en.yml +13 -0
  207. data/spec/fixtures/locale/it.yml +13 -0
  208. data/spec/spec_helper.rb +18 -5
  209. data/spec/support/call_controller_test_helpers.rb +3 -2
  210. data/spec/support/initializer_stubs.rb +3 -1
  211. data/spec/support/punchblock_examples.rb +65 -0
  212. data/spec/support/punchblock_mocks.rb +12 -0
  213. metadata +412 -70
  214. data/features/cli_daemon.feature +0 -20
  215. data/features/cli_restart.feature +0 -52
  216. data/features/cli_stop.feature +0 -50
  217. data/lib/adhearsion/call_controller/menu_dsl.rb +0 -21
  218. data/lib/adhearsion/call_controller/menu_dsl/array_match_calculator.rb +0 -26
  219. data/lib/adhearsion/call_controller/menu_dsl/calculated_match.rb +0 -43
  220. data/lib/adhearsion/call_controller/menu_dsl/calculated_match_collection.rb +0 -45
  221. data/lib/adhearsion/call_controller/menu_dsl/fixnum_match_calculator.rb +0 -11
  222. data/lib/adhearsion/call_controller/menu_dsl/match_calculator.rb +0 -40
  223. data/lib/adhearsion/call_controller/menu_dsl/menu.rb +0 -207
  224. data/lib/adhearsion/call_controller/menu_dsl/menu_builder.rb +0 -92
  225. data/lib/adhearsion/call_controller/menu_dsl/range_match_calculator.rb +0 -60
  226. data/lib/adhearsion/call_controller/menu_dsl/string_match_calculator.rb +0 -25
  227. data/lib/adhearsion/call_controller/utility.rb +0 -77
  228. data/lib/adhearsion/foundation/custom_daemonizer.rb +0 -52
  229. data/lib/adhearsion/punchblock_plugin.rb +0 -63
  230. data/scripts/cloc-1.64.pl +0 -10483
  231. data/spec/adhearsion/call_controller/menu_dsl/array_match_calculator_spec.rb +0 -76
  232. data/spec/adhearsion/call_controller/menu_dsl/calculated_match_collection_spec.rb +0 -60
  233. data/spec/adhearsion/call_controller/menu_dsl/calculated_match_spec.rb +0 -61
  234. data/spec/adhearsion/call_controller/menu_dsl/fixnum_match_calculator_spec.rb +0 -39
  235. data/spec/adhearsion/call_controller/menu_dsl/match_calculator_spec.rb +0 -17
  236. data/spec/adhearsion/call_controller/menu_dsl/menu_builder_spec.rb +0 -165
  237. data/spec/adhearsion/call_controller/menu_dsl/menu_spec.rb +0 -420
  238. data/spec/adhearsion/call_controller/menu_dsl/range_match_calculator_spec.rb +0 -32
  239. data/spec/adhearsion/call_controller/menu_dsl/string_match_calculator_spec.rb +0 -40
  240. data/spec/adhearsion/call_controller/utility_spec.rb +0 -90
  241. data/spec/adhearsion/punchblock_plugin/initializer_spec.rb +0 -356
  242. data/spec/adhearsion/punchblock_plugin_spec.rb +0 -59
@@ -0,0 +1,101 @@
1
+ # encoding: utf-8
2
+
3
+ module Adhearsion
4
+ module Translator
5
+ class Asterisk
6
+ module Component
7
+ class Record < Component
8
+ RECORDING_BASE_PATH = '/var/adhearsion/record'
9
+
10
+ def setup
11
+ @complete_reason = nil
12
+ end
13
+
14
+ def execute
15
+ max_duration = @component_node.max_duration || -1
16
+
17
+ raise OptionError, 'Record cannot be used on a call that is not answered.' unless @call.answered?
18
+ raise OptionError, 'A start-paused value of true is unsupported.' if @component_node.start_paused
19
+ raise OptionError, 'An initial-timeout value is unsupported.' if @component_node.initial_timeout && @component_node.initial_timeout != -1
20
+ raise OptionError, 'A final-timeout value is unsupported.' if @component_node.final_timeout && @component_node.final_timeout != -1
21
+ raise OptionError, 'A max-duration value that is negative (and not -1) is invalid.' unless max_duration >= -1
22
+
23
+ @format = @component_node.format || 'wav'
24
+
25
+ call.register_tmp_handler :ami, :name => 'MonitorStop' do |event|
26
+ finished
27
+ end
28
+
29
+ if @component_node.start_beep
30
+ @call.execute_agi_command 'STREAM FILE', 'beep', '""'
31
+ end
32
+
33
+ ami_client.send_action 'Monitor', 'Channel' => call.channel, 'File' => filename, 'Format' => @format, 'Mix' => true
34
+ unless max_duration == -1
35
+ call.after max_duration/1000 do
36
+ stop
37
+ end
38
+ end
39
+
40
+ send_ref
41
+ rescue ChannelGoneError
42
+ set_node_response Adhearsion::ProtocolError.new.setup(:item_not_found, "Could not find a call with ID #{call_id}", call_id)
43
+ rescue RubyAMI::Error => e
44
+ with_error :platform_error, "Terminated due to AMI error '#{e.message}'"
45
+ rescue OptionError => e
46
+ with_error 'option error', e.message
47
+ end
48
+
49
+ def execute_command(command)
50
+ case command
51
+ when Adhearsion::Rayo::Component::Stop
52
+ command.response = true
53
+ ami_client.send_action 'StopMonitor', 'Channel' => call.channel
54
+ @complete_reason = stop_reason
55
+ when Adhearsion::Rayo::Component::Record::Pause
56
+ ami_client.send_action 'PauseMonitor', 'Channel' => call.channel
57
+ command.response = true
58
+ when Adhearsion::Rayo::Component::Record::Resume
59
+ ami_client.send_action 'ResumeMonitor', 'Channel' => call.channel
60
+ command.response = true
61
+ else
62
+ super
63
+ end
64
+ end
65
+
66
+ def finished
67
+ send_complete_event(@complete_reason || max_duration_reason)
68
+ end
69
+
70
+ private
71
+
72
+ def stop
73
+ AMIErrorConverter.convert(nil) do
74
+ ami_client.send_action 'StopMonitor', 'Channel' => call.channel
75
+ end
76
+ end
77
+
78
+ def filename
79
+ File.join RECORDING_BASE_PATH, id
80
+ end
81
+
82
+ def recording
83
+ Adhearsion::Rayo::Component::Record::Recording.new :uri => "file://#{filename}.#{@format}"
84
+ end
85
+
86
+ def stop_reason
87
+ Adhearsion::Event::Complete::Stop.new
88
+ end
89
+
90
+ def max_duration_reason
91
+ Adhearsion::Rayo::Component::Record::Complete::MaxDuration.new
92
+ end
93
+
94
+ def send_complete_event(reason)
95
+ super reason, recording
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,30 @@
1
+ # encoding: utf-8
2
+
3
+ require 'active_support/core_ext/string/filters'
4
+
5
+ module Adhearsion
6
+ module Translator
7
+ class Asterisk
8
+ module Component
9
+ module StopByRedirect
10
+ def execute_command(command)
11
+ return super unless command.is_a?(Adhearsion::Rayo::Component::Stop)
12
+ if @complete
13
+ command.response = Adhearsion::ProtocolError.new.setup 'component-already-stopped', "Component #{id} is already stopped", call_id, id
14
+ else
15
+ stop_by_redirect Adhearsion::Event::Complete::Stop.new
16
+ command.response = true
17
+ end
18
+ end
19
+
20
+ def stop_by_redirect(complete_reason)
21
+ call.register_handler :ami, [{name: 'AsyncAGI', [:[], 'SubEvent'] => 'Start'}, {name: 'AsyncAGIExec'}] do |event|
22
+ send_complete_event complete_reason
23
+ end
24
+ call.redirect_back
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,28 @@
1
+ # encoding: utf-8
2
+
3
+ require 'adhearsion/translator/asterisk/agi_app'
4
+ require 'active_support/core_ext/string/filters'
5
+
6
+ module Adhearsion
7
+ module Translator
8
+ class Asterisk
9
+ class UniMRCPApp
10
+ def initialize(app, *args, options)
11
+ args.map! { |o| "\"#{o.to_s.squish.gsub('"', '\"')}\"" }
12
+ args << prepare_options(options)
13
+ @agi_app = AGIApp.new(app, *args)
14
+ end
15
+
16
+ def execute(call)
17
+ @agi_app.execute call
18
+ end
19
+
20
+ private
21
+
22
+ def prepare_options(options)
23
+ options.map { |o| o.join '=' }.join '&'
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,21 @@
1
+ # encoding: utf-8
2
+
3
+ module Adhearsion
4
+ class URIList < SimpleDelegator
5
+ def self.import(string)
6
+ new string.strip.split("\n").map(&:strip)
7
+ end
8
+
9
+ def initialize(*list)
10
+ super list.flatten
11
+ end
12
+
13
+ def to_s
14
+ join("\n")
15
+ end
16
+
17
+ def ==(other)
18
+ self.__getobj__ == other.to_ary
19
+ end
20
+ end
21
+ end
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Adhearsion
4
- VERSION = '2.6.4'
4
+ VERSION = '3.0.0.beta1'
5
5
  end
@@ -15,7 +15,7 @@ module Adhearsion
15
15
  let(:second_other_call_id) { new_uuid }
16
16
  let(:second_other_mock_call) { OutboundCall.new }
17
17
 
18
- let(:mock_answered) { Punchblock::Event::Answered.new }
18
+ let(:mock_answered) { Adhearsion::Event::Answered.new }
19
19
 
20
20
  let(:latch) { CountDownLatch.new 1 }
21
21
 
@@ -27,7 +27,7 @@ module Adhearsion
27
27
  end
28
28
 
29
29
  def mock_end(reason = :hangup_command)
30
- Punchblock::Event::End.new.tap { |event| allow(event).to receive_messages reason: reason }
30
+ Adhearsion::Event::End.new.tap { |event| allow(event).to receive_messages reason: reason }
31
31
  end
32
32
 
33
33
  describe "#dial" do
@@ -150,7 +150,7 @@ module Adhearsion
150
150
  end
151
151
 
152
152
  context "with ringback specified" do
153
- let(:component) { Punchblock::Component::Output.new }
153
+ let(:component) { Adhearsion::Rayo::Component::Output.new }
154
154
  let(:options) { { ringback: ['file://tt-monkeys'] } }
155
155
 
156
156
  before do
@@ -212,9 +212,9 @@ module Adhearsion
212
212
  end
213
213
 
214
214
  it "hangs up the new call when the root call ends" do
215
+ expect(other_mock_call).to receive(:hangup).once
215
216
  expect(call).to receive(:answer).once
216
217
  expect(other_mock_call).to receive(:join).once.with(call, {})
217
- expect(other_mock_call).to receive(:hangup).once
218
218
 
219
219
  dial_in_thread
220
220
 
@@ -266,8 +266,8 @@ module Adhearsion
266
266
  it "has an overall dial status of :answer" do
267
267
  expect(call).to receive(:answer).once
268
268
  expect(other_mock_call).to receive(:join).once.with(call, {}) do
269
- call << Punchblock::Event::Joined.new(call_uri: other_mock_call.id)
270
- other_mock_call << Punchblock::Event::Joined.new(call_uri: call.id)
269
+ call << Adhearsion::Event::Joined.new(call_uri: other_mock_call.id)
270
+ other_mock_call << Adhearsion::Event::Joined.new(call_uri: call.id)
271
271
  end
272
272
 
273
273
  t = dial_in_thread
@@ -290,8 +290,8 @@ module Adhearsion
290
290
  it "records the duration of the join" do
291
291
  expect(call).to receive(:answer).once
292
292
  expect(other_mock_call).to receive(:join).once.with(call, {}) do
293
- call << Punchblock::Event::Joined.new(call_uri: other_mock_call.id)
294
- other_mock_call << Punchblock::Event::Joined.new(call_uri: call.id)
293
+ call << Adhearsion::Event::Joined.new(call_uri: other_mock_call.id)
294
+ other_mock_call << Adhearsion::Event::Joined.new(call_uri: call.id)
295
295
  end
296
296
  allow(other_mock_call).to receive_messages hangup: true
297
297
 
@@ -306,7 +306,7 @@ module Adhearsion
306
306
 
307
307
  base_time = Time.local(2008, 9, 1, 12, 0, 37)
308
308
  Timecop.freeze base_time
309
- other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
309
+ other_mock_call << Adhearsion::Event::Unjoined.new(call_uri: call.id)
310
310
  other_mock_call << mock_end
311
311
 
312
312
  expect(latch.wait(2)).to be_truthy
@@ -323,7 +323,10 @@ module Adhearsion
323
323
 
324
324
  it "joins the calls with those options" do
325
325
  expect(call).to receive(:answer).once
326
- expect(other_mock_call).to receive(:join).once.with(call, media: :direct)
326
+ expect(other_mock_call).to receive(:join).once.with(call, media: :direct) do
327
+ call << Adhearsion::Event::Joined.new(call_uri: other_mock_call.id)
328
+ other_mock_call << Adhearsion::Event::Joined.new(call_uri: call.id)
329
+ end
327
330
  allow(other_mock_call).to receive_messages hangup: true
328
331
 
329
332
  t = dial_in_thread
@@ -332,7 +335,7 @@ module Adhearsion
332
335
 
333
336
  other_mock_call << mock_answered
334
337
 
335
- other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
338
+ other_mock_call << Adhearsion::Event::Unjoined.new(call_uri: call.id)
336
339
  other_mock_call << mock_end
337
340
 
338
341
  expect(latch.wait(2)).to be_truthy
@@ -348,19 +351,19 @@ module Adhearsion
348
351
  before do
349
352
  expect(call).to receive(:answer).once
350
353
  expect(other_mock_call).to receive(:join).once.with(join_target, join_options) do
351
- call << Punchblock::Event::Joined.new(call_uri: other_mock_call.id)
352
- other_mock_call << Punchblock::Event::Joined.new(call_uri: call.id)
354
+ call << Adhearsion::Event::Joined.new(call_uri: other_mock_call.id)
355
+ other_mock_call << Adhearsion::Event::Joined.new(call_uri: call.id)
353
356
  end
354
357
  allow(other_mock_call).to receive(:unjoin) do
355
- call << Punchblock::Event::Unjoined.new(call_uri: other_mock_call.id)
356
- other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
358
+ call << Adhearsion::Event::Unjoined.new(call_uri: other_mock_call.id)
359
+ other_mock_call << Adhearsion::Event::Unjoined.new(call_uri: call.id)
357
360
  end
358
361
  end
359
362
 
360
363
  it "should unjoin the calls" do
361
364
  expect(other_mock_call).to receive(:unjoin).once.ordered.with(call) do
362
- call << Punchblock::Event::Unjoined.new(call_uri: other_mock_call.id)
363
- other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
365
+ call << Adhearsion::Event::Unjoined.new(call_uri: other_mock_call.id)
366
+ other_mock_call << Adhearsion::Event::Unjoined.new(call_uri: call.id)
364
367
  end
365
368
 
366
369
  dial = Dial::Dial.new to, options, call
@@ -500,8 +503,8 @@ module Adhearsion
500
503
  context "when rejoining" do
501
504
  it "should rejoin the calls" do
502
505
  expect(other_mock_call).to receive(:unjoin).once.ordered.with(call) do
503
- call << Punchblock::Event::Unjoined.new(call_uri: other_mock_call.id)
504
- other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
506
+ call << Adhearsion::Event::Unjoined.new(call_uri: other_mock_call.id)
507
+ other_mock_call << Adhearsion::Event::Unjoined.new(call_uri: call.id)
505
508
  end
506
509
 
507
510
  dial = Dial::Dial.new to, options, call
@@ -518,7 +521,10 @@ module Adhearsion
518
521
 
519
522
  dial.split
520
523
 
521
- expect(other_mock_call).to receive(:join).once.ordered.with(call, {})
524
+ expect(other_mock_call).to receive(:join).once.ordered.with(call, {}) do
525
+ call << Adhearsion::Event::Joined.new(call_uri: other_mock_call.id)
526
+ other_mock_call << Adhearsion::Event::Joined.new(call_uri: call.id)
527
+ end
522
528
  dial.rejoin
523
529
 
524
530
  other_mock_call << mock_end
@@ -542,7 +548,10 @@ module Adhearsion
542
548
 
543
549
  dial.split
544
550
 
545
- expect(other_mock_call).to receive(:join).once.ordered.with(call, media: :direct)
551
+ expect(other_mock_call).to receive(:join).once.ordered.with(call, media: :direct) do
552
+ call << Adhearsion::Event::Joined.new(call_uri: other_mock_call.id)
553
+ other_mock_call << Adhearsion::Event::Joined.new(call_uri: call.id)
554
+ end
546
555
  dial.rejoin
547
556
  end
548
557
  end
@@ -558,7 +567,10 @@ module Adhearsion
558
567
 
559
568
  dial.split
560
569
 
561
- expect(other_mock_call).to receive(:join).once.ordered.with(call, media: :direct)
570
+ expect(other_mock_call).to receive(:join).once.ordered.with(call, media: :direct) do
571
+ call << Adhearsion::Event::Joined.new(call_uri: other_mock_call.id)
572
+ other_mock_call << Adhearsion::Event::Joined.new(call_uri: call.id)
573
+ end
562
574
  dial.rejoin nil, media: :direct
563
575
  end
564
576
  end
@@ -571,8 +583,8 @@ module Adhearsion
571
583
  expect(call).to receive(:join).once.with(join_target, {})
572
584
  expect(other_mock_call).to receive(:unjoin).once.ordered.with(join_target)
573
585
  expect(call).to receive(:unjoin).once.ordered.with(join_target) do
574
- call << Punchblock::Event::Unjoined.new(join_target)
575
- other_mock_call << Punchblock::Event::Unjoined.new(join_target)
586
+ call << Adhearsion::Event::Unjoined.new(join_target)
587
+ other_mock_call << Adhearsion::Event::Unjoined.new(join_target)
576
588
  end
577
589
 
578
590
  dial = Dial::Dial.new to, options, call
@@ -607,8 +619,8 @@ module Adhearsion
607
619
 
608
620
  it "should join all calls to the mixer" do
609
621
  expect(other_mock_call).to receive(:unjoin).once.ordered.with(call) do
610
- call << Punchblock::Event::Unjoined.new(call_uri: other_mock_call.id)
611
- other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
622
+ call << Adhearsion::Event::Unjoined.new(call_uri: other_mock_call.id)
623
+ other_mock_call << Adhearsion::Event::Unjoined.new(call_uri: call.id)
612
624
  end
613
625
 
614
626
  dial = Dial::Dial.new to, options, call
@@ -639,8 +651,8 @@ module Adhearsion
639
651
 
640
652
  it "#split should then unjoin calls from the mixer" do
641
653
  expect(other_mock_call).to receive(:unjoin).once.ordered.with(call) do
642
- call << Punchblock::Event::Unjoined.new(call_uri: other_mock_call.id)
643
- other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
654
+ call << Adhearsion::Event::Unjoined.new(call_uri: other_mock_call.id)
655
+ other_mock_call << Adhearsion::Event::Unjoined.new(call_uri: call.id)
644
656
  end
645
657
 
646
658
  dial = Dial::Dial.new to, options, call
@@ -662,16 +674,16 @@ module Adhearsion
662
674
  dial.rejoin mixer_name: mixer
663
675
 
664
676
  expect(other_mock_call).to receive(:unjoin).once.ordered.with(mixer_name: mixer) do
665
- other_mock_call << Punchblock::Event::Unjoined.new(mixer_name: mixer)
677
+ other_mock_call << Adhearsion::Event::Unjoined.new(mixer_name: mixer)
666
678
  end
667
679
  expect(call).to receive(:unjoin).once.ordered.with(mixer_name: mixer) do
668
- call << Punchblock::Event::Unjoined.new(mixer_name: mixer)
680
+ call << Adhearsion::Event::Unjoined.new(mixer_name: mixer)
669
681
  end
670
682
  dial.split
671
683
 
672
684
  other_mock_call << mock_end
673
685
 
674
- expect(latch.wait(10)).to be_truthy
686
+ expect(latch.wait(2)).to be_truthy
675
687
 
676
688
  waiter_thread.join
677
689
  expect(dial.status.result).to eq(:answer)
@@ -705,12 +717,12 @@ module Adhearsion
705
717
 
706
718
  it "should split calls, rejoin to a mixer, and rejoin other calls to mixer" do
707
719
  expect(other_mock_call).to receive(:unjoin).once.ordered.with(call) do
708
- call << Punchblock::Event::Unjoined.new(call_uri: other_mock_call.id)
709
- other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
720
+ call << Adhearsion::Event::Unjoined.new(call_uri: other_mock_call.id)
721
+ other_mock_call << Adhearsion::Event::Unjoined.new(call_uri: call.id)
710
722
  end
711
723
  expect(second_other_mock_call).to receive(:unjoin).once.ordered.with(second_root_call) do
712
- second_root_call << Punchblock::Event::Unjoined.new(call_uri: second_other_mock_call.id)
713
- second_other_mock_call << Punchblock::Event::Unjoined.new(call_uri: second_root_call.id)
724
+ second_root_call << Adhearsion::Event::Unjoined.new(call_uri: second_other_mock_call.id)
725
+ second_other_mock_call << Adhearsion::Event::Unjoined.new(call_uri: second_root_call.id)
714
726
  end
715
727
 
716
728
  expect(call).to receive(:join).once.ordered.with({mixer_name: mixer}, {})
@@ -844,15 +856,15 @@ module Adhearsion
844
856
 
845
857
  [call, second_root_call, second_other_mock_call].each do |call|
846
858
  expect(call).to receive(:unjoin).once.with(mixer_name: mixer) do
847
- call << Punchblock::Event::Unjoined.new(mixer_name: mixer)
859
+ call << Adhearsion::Event::Unjoined.new(mixer_name: mixer)
848
860
  end
849
861
  end
850
862
 
851
863
  dial.split
852
864
 
853
- [call, second_root_call, second_other_mock_call].each do |call|
865
+ [call, other_mock_call, second_root_call, second_other_mock_call].each do |call|
854
866
  expect(call).to receive(:join).once.with({mixer_name: mixer}, {}) do
855
- call << Punchblock::Event::Joined.new(mixer_name: mixer)
867
+ call << Adhearsion::Event::Joined.new(mixer_name: mixer)
856
868
  end
857
869
  end
858
870
 
@@ -952,7 +964,7 @@ module Adhearsion
952
964
 
953
965
  [call, second_root_call, second_other_mock_call].each do |call|
954
966
  expect(call).to receive(:unjoin).once.with(mixer_name: mixer) do
955
- call << Punchblock::Event::Unjoined.new(mixer_name: mixer)
967
+ call << Adhearsion::Event::Unjoined.new(mixer_name: mixer)
956
968
  end
957
969
  end
958
970
 
@@ -965,7 +977,7 @@ module Adhearsion
965
977
 
966
978
  [call, second_root_call, second_other_mock_call].each do |call|
967
979
  expect(call).to receive(:join).once.with({mixer_name: mixer}, {}) do
968
- call << Punchblock::Event::Joined.new(mixer_name: mixer)
980
+ call << Adhearsion::Event::Joined.new(mixer_name: mixer)
969
981
  end
970
982
  end
971
983
 
@@ -977,8 +989,8 @@ module Adhearsion
977
989
 
978
990
  context "if the calls were not joined" do
979
991
  it "should still join to mixer" do
980
- expect(other_mock_call).to receive(:unjoin).once.ordered.with(call).and_raise Punchblock::ProtocolError.new.setup(:service_unavailable)
981
- expect(second_other_mock_call).to receive(:unjoin).once.ordered.with(second_root_call).and_raise Punchblock::ProtocolError.new.setup(:service_unavailable)
992
+ expect(other_mock_call).to receive(:unjoin).once.ordered.with(call).and_raise Adhearsion::ProtocolError.new.setup(:service_unavailable)
993
+ expect(second_other_mock_call).to receive(:unjoin).once.ordered.with(second_root_call).and_raise Adhearsion::ProtocolError.new.setup(:service_unavailable)
982
994
 
983
995
  expect(call).to receive(:join).once.ordered.with({mixer_name: mixer}, {})
984
996
  expect(other_mock_call).to receive(:join).once.ordered.with({mixer_name: mixer}, {})
@@ -1020,7 +1032,7 @@ module Adhearsion
1020
1032
 
1021
1033
  it "should not make any outbound calls" do
1022
1034
  expect(OutboundCall).to receive(:new).never
1023
- expect { subject.dial to, options }.to raise_error
1035
+ expect { subject.dial to, options }.to raise_error(Call::Hangup)
1024
1036
  end
1025
1037
  end
1026
1038
 
@@ -1082,7 +1094,7 @@ module Adhearsion
1082
1094
  expect(latch.wait(2)).to be_falsey
1083
1095
 
1084
1096
  other_mock_call << mock_answered
1085
- other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
1097
+ other_mock_call << Adhearsion::Event::Unjoined.new(call_uri: call.id)
1086
1098
 
1087
1099
  expect(latch.wait(2)).to be_truthy
1088
1100
 
@@ -1273,6 +1285,9 @@ module Adhearsion
1273
1285
  call[key] = value
1274
1286
  end
1275
1287
  @@confirmation_latch.countdown!
1288
+ if delay = call['confirmation_delay']
1289
+ sleep delay
1290
+ end
1276
1291
  call['confirm'] || hangup
1277
1292
  end
1278
1293
  end
@@ -1332,14 +1347,14 @@ module Adhearsion
1332
1347
  end
1333
1348
 
1334
1349
  it "should join the calls if the call is still active after execution of the call controller" do
1350
+ expect(other_mock_call).to receive(:hangup).once do
1351
+ other_mock_call << mock_end
1352
+ end
1335
1353
  other_mock_call['confirm'] = true
1336
1354
  expect(call).to receive(:answer).once
1337
1355
  expect(other_mock_call).to receive(:join).once.with(call, {}) do
1338
- call << Punchblock::Event::Joined.new(call_uri: other_mock_call.id)
1339
- other_mock_call << Punchblock::Event::Joined.new(call_uri: call.id)
1340
- end
1341
- expect(other_mock_call).to receive(:hangup).once do
1342
- other_mock_call << mock_end
1356
+ call << Adhearsion::Event::Joined.new(call_uri: other_mock_call.id)
1357
+ other_mock_call << Adhearsion::Event::Joined.new(call_uri: call.id)
1343
1358
  end
1344
1359
 
1345
1360
  t = dial_in_thread
@@ -1353,9 +1368,9 @@ module Adhearsion
1353
1368
 
1354
1369
  base_time = Time.local(2008, 9, 1, 12, 0, 42)
1355
1370
  Timecop.freeze base_time
1356
- other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
1371
+ other_mock_call << Adhearsion::Event::Unjoined.new(call_uri: call.id)
1357
1372
 
1358
- expect(latch.wait(3)).to be_truthy
1373
+ expect(latch.wait(2)).to be_truthy
1359
1374
 
1360
1375
  t.join
1361
1376
  status = t.value
@@ -1393,1381 +1408,25 @@ module Adhearsion
1393
1408
  end
1394
1409
 
1395
1410
  context "when multiple calls are made" do
1396
- before do
1397
- expect(OutboundCall).to receive(:new).and_return other_mock_call, second_other_mock_call
1398
- end
1399
-
1400
- def dial_in_thread
1401
- Thread.new do
1402
- status = subject.dial [to, second_to], options
1403
- latch.countdown!
1404
- status
1405
- end
1406
- end
1407
-
1408
- context "when one answers" do
1409
- it "should only execute the confirmation controller on the first call to answer, immediately hanging up all others" do
1410
- other_mock_call['confirm'] = true
1411
- expect(call).to receive(:answer).once
1412
-
1413
- expect(other_mock_call).to receive(:dial).once.with(to, from: nil)
1414
- expect(other_mock_call).to receive(:join).once.with(call, {}) do
1415
- call << Punchblock::Event::Joined.new(call_uri: other_mock_call.id)
1416
- other_mock_call << Punchblock::Event::Joined.new(call_uri: call.id)
1417
- end
1418
- expect(other_mock_call).to receive(:hangup).once do
1419
- other_mock_call << mock_end
1420
- end
1421
-
1422
- expect(second_other_mock_call).to receive(:dial).once.with(second_to, from: nil)
1423
- expect(second_other_mock_call).to receive(:join).never
1424
- expect(second_other_mock_call).to receive(:execute_controller).never
1425
- expect(second_other_mock_call).to receive(:hangup).once do
1426
- second_other_mock_call << mock_end(:foo)
1411
+ let(:confirmation_latch) { CountDownLatch.new 2 }
1412
+ let(:apology_controller) do
1413
+ Class.new(Adhearsion::CallController) do
1414
+ def run
1415
+ logger.info "Apologising..."
1416
+ call['apology_metadata'] = metadata
1417
+ call['apology_done'] = true
1427
1418
  end
1428
-
1429
- t = dial_in_thread
1430
-
1431
- expect(latch.wait(2)).to be_falsey
1432
-
1433
- other_mock_call << mock_answered
1434
- expect(confirmation_latch.wait(2)).to be_truthy
1435
-
1436
- other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
1437
-
1438
- expect(latch.wait(2)).to be_truthy
1439
-
1440
- t.join
1441
- status = t.value
1442
- expect(status).to be_a Dial::DialStatus
1443
- expect(status.calls.size).to eq(2)
1444
- status.calls.each { |c| expect(c).to be_a OutboundCall }
1445
- expect(status.result).to eq(:answer)
1446
1419
  end
1447
1420
  end
1448
- end
1449
- end
1450
- end
1451
-
1452
- describe "#dial_and_confirm" do
1453
- it "should dial the call to the correct endpoint and return a dial status object" do
1454
- expect(OutboundCall).to receive(:new).and_return other_mock_call
1455
- expect(other_mock_call).to receive(:dial).with(to, :from => 'foo').once
1456
- dial_thread = Thread.new do
1457
- status = subject.dial_and_confirm(to, :from => 'foo')
1458
-
1459
- expect(status).to be_a Dial::DialStatus
1460
- joined_status = status.joins[status.calls.first]
1461
- expect(joined_status.duration).to eq(0.0)
1462
- expect(joined_status.result).to eq(:no_answer)
1463
- end
1464
- sleep 0.1
1465
- other_mock_call << mock_end
1466
- expect(dial_thread.join).to be_truthy
1467
- end
1468
-
1469
- it "should default the caller ID to that of the original call" do
1470
- allow(call).to receive_messages :from => 'sip:foo@bar.com'
1471
- expect(OutboundCall).to receive(:new).and_return other_mock_call
1472
- expect(other_mock_call).to receive(:dial).with(to, :from => 'sip:foo@bar.com').once
1473
- dial_thread = Thread.new do
1474
- subject.dial_and_confirm to
1475
- end
1476
- sleep 0.1
1477
- other_mock_call << mock_end
1478
- expect(dial_thread.join).to be_truthy
1479
- end
1480
-
1481
- let(:options) { { :foo => :bar } }
1482
-
1483
- def dial_in_thread
1484
- Thread.new do
1485
- status = subject.dial_and_confirm to, options
1486
- latch.countdown!
1487
- status
1488
- end
1489
- end
1490
-
1491
- describe "without a block" do
1492
- before do
1493
- expect(other_mock_call).to receive(:dial).once.with(to, options)
1494
- expect(OutboundCall).to receive(:new).and_return other_mock_call
1495
- end
1496
-
1497
- it "blocks the original controller until the new call ends" do
1498
- dial_in_thread
1499
-
1500
- expect(latch.wait(2)).to be_falsey
1501
-
1502
- other_mock_call << mock_end
1503
-
1504
- expect(latch.wait(2)).to be_truthy
1505
- end
1506
-
1507
- it "unblocks the original controller if the original call ends" do
1508
- expect(other_mock_call).to receive(:hangup).once
1509
- dial_in_thread
1510
-
1511
- expect(latch.wait(2)).to be_falsey
1512
-
1513
- call << mock_end
1514
-
1515
- expect(latch.wait(2)).to be_truthy
1516
- end
1517
-
1518
- it "joins the new call to the existing one on answer" do
1519
- expect(call).to receive(:answer).once
1520
- expect(other_mock_call).to receive(:join).once.with(call, {})
1521
-
1522
- dial_in_thread
1523
-
1524
- expect(latch.wait(2)).to be_falsey
1525
-
1526
- other_mock_call << mock_answered
1527
- other_mock_call << mock_end
1528
-
1529
- expect(latch.wait(2)).to be_truthy
1530
- end
1531
-
1532
- context "with a join target specified" do
1533
- let(:options) { { join_target: {mixer_name: 'foobar'} } }
1534
-
1535
- it "joins the calls to the specified target on answer" do
1536
- expect(call).to receive(:answer).once
1537
- expect(call).to receive(:join).once.with({mixer_name: 'foobar'}, {})
1538
- expect(other_mock_call).to receive(:join).once.with({mixer_name: 'foobar'}, {})
1539
-
1540
- dial_in_thread
1541
-
1542
- expect(latch.wait(2)).to be_falsey
1543
-
1544
- other_mock_call << mock_answered
1545
- other_mock_call << mock_end
1546
-
1547
- expect(latch.wait(2)).to be_truthy
1548
- end
1549
- end
1550
-
1551
- context "with a pre-join callback specified" do
1552
- let(:foo) { double }
1553
- let(:options) { { pre_join: ->(call) { foo.bar call } } }
1554
-
1555
- it "executes the callback prior to joining" do
1556
- expect(foo).to receive(:bar).once.with(other_mock_call).ordered
1557
- expect(call).to receive(:answer).once.ordered
1558
- expect(other_mock_call).to receive(:join).once.with(call, {}).ordered
1559
-
1560
- dial_in_thread
1561
-
1562
- expect(latch.wait(2)).to be_falsey
1563
-
1564
- other_mock_call << mock_answered
1565
- other_mock_call << mock_end
1566
-
1567
- expect(latch.wait(2)).to be_truthy
1568
- end
1569
- end
1570
-
1571
- context "with ringback specified" do
1572
- let(:component) { Punchblock::Component::Output.new }
1573
- let(:options) { { ringback: ['file://tt-monkeys'] } }
1421
+ let(:options) { {confirm: confirmation_controller, confirm_metadata: {'foo' => 'bar'}, apology: apology_controller} }
1574
1422
 
1575
1423
  before do
1576
- component.request!
1577
- component.execute!
1578
- end
1579
-
1580
- it "plays the ringback asynchronously, terminating prior to joining" do
1581
- expect(subject).to receive(:play!).once.with(['file://tt-monkeys'], repeat_times: 0).and_return(component)
1582
- expect(component).to receive(:stop!).twice
1583
- expect(call).to receive(:answer).once.ordered
1584
- expect(other_mock_call).to receive(:join).once.with(call, {}).ordered
1585
-
1586
- dial_in_thread
1587
-
1588
- expect(latch.wait(2)).to be_falsey
1589
-
1590
- other_mock_call << mock_answered
1591
- other_mock_call << mock_end
1592
-
1593
- expect(latch.wait(2)).to be_truthy
1594
- end
1595
-
1596
- context "as a callback" do
1597
- let(:foo) { double }
1598
- let(:options) { { ringback: -> { foo.bar; component } } }
1599
-
1600
- it "calls the callback to start, and uses the return value of the callback to stop the ringback" do
1601
- expect(foo).to receive(:bar).once.ordered
1602
- expect(component).to receive(:stop!).twice
1603
- expect(call).to receive(:answer).once.ordered
1604
- expect(other_mock_call).to receive(:join).once.with(call, {}).ordered
1605
-
1606
- dial_in_thread
1607
-
1608
- expect(latch.wait(2)).to be_falsey
1609
-
1610
- other_mock_call << mock_answered
1611
- other_mock_call << mock_end
1612
-
1613
- expect(latch.wait(2)).to be_truthy
1614
- end
1615
- end
1616
-
1617
- context "when the call is rejected" do
1618
- it "terminates the ringback before returning" do
1619
- expect(subject).to receive(:play!).once.with(['file://tt-monkeys'], repeat_times: 0).and_return(component)
1620
- expect(component).to receive(:stop!).once
1621
-
1622
- t = dial_in_thread
1623
-
1624
- expect(latch.wait(2)).to be_falsey
1625
-
1626
- other_mock_call << mock_end(:reject)
1627
-
1628
- expect(latch.wait(2)).to be_truthy
1629
- end
1630
- end
1631
- end
1632
-
1633
- it "hangs up the new call when the root call ends" do
1634
- expect(other_mock_call).to receive(:hangup).once
1635
- expect(call).to receive(:answer).once
1636
- expect(other_mock_call).to receive(:join).once.with(call, {})
1637
-
1638
- dial_in_thread
1639
-
1640
- expect(latch.wait(2)).to be_falsey
1641
-
1642
- other_mock_call << mock_answered
1643
- call << mock_end
1644
-
1645
- expect(latch.wait(2)).to be_truthy
1646
- end
1647
-
1648
- context "when the call is rejected" do
1649
- it "has an overall dial status of :no_answer" do
1650
- t = dial_in_thread
1651
-
1652
- sleep 0.5
1653
-
1654
- other_mock_call << mock_end(:reject)
1655
-
1656
- expect(latch.wait(2)).to be_truthy
1657
-
1658
- t.join
1659
- status = t.value
1660
- expect(status.result).to eq(:no_answer)
1661
- end
1662
- end
1663
-
1664
- context "when the call ends with an error" do
1665
- it "has an overall dial status of :error" do
1666
- t = dial_in_thread
1667
-
1668
- sleep 0.5
1669
-
1670
- other_mock_call << mock_end(:error)
1671
-
1672
- expect(latch.wait(2)).to be_truthy
1673
-
1674
- t.join
1675
- status = t.value
1676
- expect(status.result).to eq(:error)
1677
-
1678
- joined_status = status.joins[status.calls.first]
1679
- expect(joined_status.duration).to eq(0.0)
1680
- expect(joined_status.result).to eq(:error)
1681
- end
1682
- end
1683
-
1684
- context "when the call is answered and joined" do
1685
- it "has an overall dial status of :answer" do
1686
- expect(call).to receive(:answer).once
1687
- expect(other_mock_call).to receive(:join).once.with(call, {}) do
1688
- call << Punchblock::Event::Joined.new(call_uri: other_mock_call.id)
1689
- other_mock_call << Punchblock::Event::Joined.new(call_uri: call.id)
1690
- end
1691
-
1692
- t = dial_in_thread
1693
-
1694
- sleep 0.5
1695
-
1696
- other_mock_call << mock_answered
1697
- other_mock_call << mock_end
1698
-
1699
- expect(latch.wait(2)).to be_truthy
1700
-
1701
- t.join
1702
- status = t.value
1703
- expect(status.result).to eq(:answer)
1704
-
1705
- joined_status = status.joins[status.calls.first]
1706
- expect(joined_status.result).to eq(:joined)
1707
- end
1708
-
1709
- it "records the duration of the join" do
1710
- expect(call).to receive(:answer).once
1711
- expect(other_mock_call).to receive(:join).once.with(call, {}) do
1712
- call << Punchblock::Event::Joined.new(call_uri: other_mock_call.id)
1713
- other_mock_call << Punchblock::Event::Joined.new(call_uri: call.id)
1714
- end
1715
- allow(other_mock_call).to receive_messages hangup: true
1716
-
1717
- t = dial_in_thread
1718
-
1719
- sleep 0.5
1720
-
1721
- base_time = Time.local(2008, 9, 1, 12, 0, 0)
1722
- Timecop.freeze base_time
1723
-
1724
- other_mock_call << mock_answered
1725
-
1726
- base_time = Time.local(2008, 9, 1, 12, 0, 37)
1727
- Timecop.freeze base_time
1728
- other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
1729
- other_mock_call << mock_end
1730
-
1731
- expect(latch.wait(2)).to be_truthy
1732
-
1733
- t.join
1734
- status = t.value
1735
- expect(status.result).to eq(:answer)
1736
- joined_status = status.joins[status.calls.first]
1737
- expect(joined_status.duration).to eq(37.0)
1738
- end
1739
-
1740
- context "when join options are specified" do
1741
- let(:options) { { join_options: {media: :direct} } }
1742
-
1743
- it "joins the calls with those options" do
1744
- expect(call).to receive(:answer).once
1745
- expect(other_mock_call).to receive(:join).once.with(call, media: :direct) do
1746
- call << Punchblock::Event::Joined.new(call_uri: other_mock_call.id)
1747
- other_mock_call << Punchblock::Event::Joined.new(call_uri: call.id)
1748
- end
1749
- allow(other_mock_call).to receive_messages hangup: true
1750
-
1751
- t = dial_in_thread
1752
-
1753
- sleep 0.5
1754
-
1755
- other_mock_call << mock_answered
1756
-
1757
- other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
1758
- other_mock_call << mock_end
1759
-
1760
- expect(latch.wait(2)).to be_truthy
1761
-
1762
- t.join
1763
- end
1764
- end
1765
- end
1766
-
1767
- context "when a dial is split" do
1768
- let(:join_target) { call }
1769
-
1770
- before do
1771
- expect(call).to receive(:answer).once
1772
- expect(other_mock_call).to receive(:join).once.with(join_target, join_options) do
1773
- call << Punchblock::Event::Joined.new(call_uri: other_mock_call.id)
1774
- other_mock_call << Punchblock::Event::Joined.new(call_uri: call.id)
1775
- end
1776
- allow(other_mock_call).to receive(:unjoin) do
1777
- call << Punchblock::Event::Unjoined.new(call_uri: other_mock_call.id)
1778
- other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
1779
- end
1780
- end
1781
-
1782
- it "should unjoin the calls" do
1783
- expect(other_mock_call).to receive(:unjoin).once.ordered.with(call) do
1784
- call << Punchblock::Event::Unjoined.new(call_uri: other_mock_call.id)
1785
- other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
1786
- end
1787
-
1788
- dial = Dial::ParallelConfirmationDial.new to, options, call
1789
- dial.run subject
1790
-
1791
- waiter_thread = Thread.new do
1792
- dial.await_completion
1793
- latch.countdown!
1794
- end
1795
-
1796
- sleep 0.5
1797
-
1798
- other_mock_call << mock_answered
1799
-
1800
- dial.split
1801
- other_mock_call << mock_end
1802
-
1803
- expect(latch.wait(2)).to be_truthy
1804
-
1805
- waiter_thread.join
1806
- expect(dial.status.result).to eq(:answer)
1807
- end
1808
-
1809
- it "should not unblock immediately" do
1810
- dial = Dial::ParallelConfirmationDial.new to, options, call
1811
- dial.run subject
1812
-
1813
- waiter_thread = Thread.new do
1814
- dial.await_completion
1815
- latch.countdown!
1816
- end
1817
-
1818
- sleep 0.5
1819
-
1820
- other_mock_call << mock_answered
1821
-
1822
- dial.split
1823
-
1824
- expect(latch.wait(2)).to be_falsey
1825
-
1826
- other_mock_call << mock_end
1827
-
1828
- expect(latch.wait(2)).to be_truthy
1829
-
1830
- waiter_thread.join
1831
- expect(dial.status.result).to eq(:answer)
1832
- end
1833
-
1834
- it "should set end time" do
1835
- dial = Dial::ParallelConfirmationDial.new to, options, call
1836
- dial.run subject
1837
-
1838
- waiter_thread = Thread.new do
1839
- dial.await_completion
1840
- latch.countdown!
1841
- end
1842
-
1843
- sleep 0.5
1844
-
1845
- base_time = Time.local(2008, 9, 1, 12, 0, 0)
1846
- Timecop.freeze base_time
1847
-
1848
- other_mock_call << mock_answered
1849
-
1850
- base_time = Time.local(2008, 9, 1, 12, 0, 37)
1851
- Timecop.freeze base_time
1852
- dial.split
1853
-
1854
- base_time = Time.local(2008, 9, 1, 12, 0, 54)
1855
- Timecop.freeze base_time
1856
- other_mock_call << mock_end
1857
-
1858
- expect(latch.wait(2)).to be_truthy
1859
-
1860
- waiter_thread.join
1861
- status = dial.status
1862
- expect(status.result).to eq(:answer)
1863
- joined_status = status.joins[status.calls.first]
1864
- expect(joined_status.duration).to eq(37.0)
1865
- end
1866
-
1867
- context "with new controllers specified" do
1868
- let(:split_latch) { CountDownLatch.new 2 }
1869
-
1870
- let(:split_controller) do
1871
- latch = split_latch
1872
- Class.new(Adhearsion::CallController) do
1873
- @@split_latch = latch
1874
-
1875
- def run
1876
- call['hit_split_controller'] = self.class
1877
- call['split_controller_metadata'] = metadata
1878
- @@split_latch.countdown!
1879
- end
1880
- end
1881
- end
1882
-
1883
- let(:main_split_controller) { Class.new(split_controller) }
1884
- let(:others_split_controller) { Class.new(split_controller) }
1885
-
1886
- it "should execute the :main controller on the originating call and :others on the outbound calls" do
1887
- dial = Dial::ParallelConfirmationDial.new to, options, call
1888
- dial.run subject
1889
-
1890
- waiter_thread = Thread.new do
1891
- dial.await_completion
1892
- latch.countdown!
1893
- end
1894
-
1895
- sleep 0.5
1896
-
1897
- other_mock_call << mock_answered
1898
-
1899
- expect(self).to receive(:callback).once.with(call)
1900
- expect(self).to receive(:callback).once.with(other_mock_call)
1901
-
1902
- dial.split main: main_split_controller, others: others_split_controller, main_callback: ->(call) { self.callback(call) }, others_callback: ->(call) { self.callback(call) }
1903
-
1904
- expect(latch.wait(2)).to be_falsey
1905
- expect(split_latch.wait(2)).to be_truthy
1906
-
1907
- expect(call['hit_split_controller']).to eq(main_split_controller)
1908
- expect(call['split_controller_metadata']['current_dial']).to be dial
1909
-
1910
- expect(other_mock_call['hit_split_controller']).to eq(others_split_controller)
1911
- expect(other_mock_call['split_controller_metadata']['current_dial']).to be dial
1912
-
1913
- other_mock_call << mock_end
1914
-
1915
- expect(latch.wait(2)).to be_truthy
1916
-
1917
- waiter_thread.join
1918
- expect(dial.status.result).to eq(:answer)
1919
- end
1920
- end
1921
-
1922
- context "when rejoining" do
1923
- it "should rejoin the calls" do
1924
- expect(other_mock_call).to receive(:unjoin).once.ordered.with(call) do
1925
- call << Punchblock::Event::Unjoined.new(call_uri: other_mock_call.id)
1926
- other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
1927
- end
1928
-
1929
- dial = Dial::ParallelConfirmationDial.new to, options, call
1930
- dial.run subject
1931
-
1932
- waiter_thread = Thread.new do
1933
- dial.await_completion
1934
- latch.countdown!
1935
- end
1936
-
1937
- sleep 0.5
1938
-
1939
- other_mock_call << mock_answered
1940
-
1941
- dial.split
1942
-
1943
- expect(other_mock_call).to receive(:join).once.ordered.with(call, {}) do
1944
- call << Punchblock::Event::Joined.new(call_uri: other_mock_call.id)
1945
- other_mock_call << Punchblock::Event::Joined.new(call_uri: call.id)
1946
- end
1947
- dial.rejoin
1948
-
1949
- other_mock_call << mock_end
1950
-
1951
- expect(latch.wait(2)).to be_truthy
1952
-
1953
- waiter_thread.join
1954
- expect(dial.status.result).to eq(:answer)
1955
- end
1956
-
1957
- context "when join options were set originally" do
1958
- let(:options) { { join_options: {media: :direct} } }
1959
-
1960
- it "should rejoin with the same parameters" do
1961
- allow(other_mock_call).to receive(:unjoin)
1962
-
1963
- dial = Dial::ParallelConfirmationDial.new to, options, call
1964
- dial.run subject
1965
-
1966
- other_mock_call << mock_answered
1967
-
1968
- dial.split
1969
-
1970
- expect(other_mock_call).to receive(:join).once.ordered.with(call, media: :direct) do
1971
- call << Punchblock::Event::Joined.new(call_uri: other_mock_call.id)
1972
- other_mock_call << Punchblock::Event::Joined.new(call_uri: call.id)
1973
- end
1974
- dial.rejoin
1975
- end
1976
- end
1977
-
1978
- context "when join options are passed to rejoin" do
1979
- it "should rejoin with those parameters" do
1980
- allow(other_mock_call).to receive(:unjoin)
1981
-
1982
- dial = Dial::ParallelConfirmationDial.new to, options, call
1983
- dial.run subject
1984
-
1985
- other_mock_call << mock_answered
1986
-
1987
- dial.split
1988
-
1989
- expect(other_mock_call).to receive(:join).once.ordered.with(call, media: :direct) do
1990
- call << Punchblock::Event::Joined.new(call_uri: other_mock_call.id)
1991
- other_mock_call << Punchblock::Event::Joined.new(call_uri: call.id)
1992
- end
1993
- dial.rejoin nil, media: :direct
1994
- end
1995
- end
1996
-
1997
- context "when a join target was originally specified" do
1998
- let(:join_target) { {mixer_name: 'foobar'} }
1999
- let(:options) { { join_target: join_target } }
2000
-
2001
- it "joins the calls to the specified target on answer" do
2002
- expect(call).to receive(:join).once.with(join_target, {})
2003
- expect(other_mock_call).to receive(:unjoin).once.ordered.with(join_target)
2004
- expect(call).to receive(:unjoin).once.ordered.with(join_target) do
2005
- call << Punchblock::Event::Unjoined.new(join_target)
2006
- other_mock_call << Punchblock::Event::Unjoined.new(join_target)
2007
- end
2008
-
2009
- dial = Dial::ParallelConfirmationDial.new to, options, call
2010
- dial.run subject
2011
-
2012
- waiter_thread = Thread.new do
2013
- dial.await_completion
2014
- latch.countdown!
2015
- end
2016
-
2017
- sleep 0.5
2018
-
2019
- other_mock_call << mock_answered
2020
-
2021
- dial.split
2022
-
2023
- expect(call).to receive(:join).once.ordered.with({mixer_name: 'foobar'}, {})
2024
- expect(other_mock_call).to receive(:join).once.ordered.with({mixer_name: 'foobar'}, {})
2025
- dial.rejoin
2026
-
2027
- other_mock_call << mock_end
2028
-
2029
- expect(latch.wait(2)).to be_truthy
2030
-
2031
- waiter_thread.join
2032
- expect(dial.status.result).to eq(:answer)
2033
- end
2034
- end
2035
-
2036
- context "to a specified mixer" do
2037
- let(:mixer) { SecureRandom.uuid }
2038
-
2039
- it "should join all calls to the mixer" do
2040
- expect(other_mock_call).to receive(:unjoin).once.ordered.with(call) do
2041
- call << Punchblock::Event::Unjoined.new(call_uri: other_mock_call.id)
2042
- other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
2043
- end
2044
-
2045
- dial = Dial::ParallelConfirmationDial.new to, options, call
2046
- dial.run subject
2047
-
2048
- waiter_thread = Thread.new do
2049
- dial.await_completion
2050
- latch.countdown!
2051
- end
2052
-
2053
- sleep 0.5
2054
-
2055
- other_mock_call << mock_answered
2056
-
2057
- dial.split
2058
-
2059
- expect(call).to receive(:join).once.ordered.with({mixer_name: mixer}, {})
2060
- expect(other_mock_call).to receive(:join).once.ordered.with({mixer_name: mixer}, {})
2061
- dial.rejoin mixer_name: mixer
2062
-
2063
- other_mock_call << mock_end
2064
-
2065
- expect(latch.wait(2)).to be_truthy
2066
-
2067
- waiter_thread.join
2068
- expect(dial.status.result).to eq(:answer)
2069
- end
2070
-
2071
- it "#split should then unjoin calls from the mixer" do
2072
- expect(other_mock_call).to receive(:unjoin).once.ordered.with(call) do
2073
- call << Punchblock::Event::Unjoined.new(call_uri: other_mock_call.id)
2074
- other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
2075
- end
2076
-
2077
- dial = Dial::ParallelConfirmationDial.new to, options, call
2078
- dial.run subject
2079
-
2080
- waiter_thread = Thread.new do
2081
- dial.await_completion
2082
- latch.countdown!
2083
- end
2084
-
2085
- sleep 0.5
2086
-
2087
- other_mock_call << mock_answered
2088
-
2089
- dial.split
2090
-
2091
- expect(call).to receive(:join).once.ordered.with({mixer_name: mixer}, {})
2092
- expect(other_mock_call).to receive(:join).once.ordered.with({mixer_name: mixer}, {})
2093
- dial.rejoin mixer_name: mixer
2094
-
2095
- expect(other_mock_call).to receive(:unjoin).once.ordered.with(mixer_name: mixer) do
2096
- other_mock_call << Punchblock::Event::Unjoined.new(mixer_name: mixer)
2097
- end
2098
- expect(call).to receive(:unjoin).once.ordered.with(mixer_name: mixer) do
2099
- call << Punchblock::Event::Unjoined.new(mixer_name: mixer)
2100
- end
2101
- dial.split
2102
-
2103
- other_mock_call << mock_end
2104
-
2105
- expect(latch.wait(2)).to be_truthy
2106
-
2107
- waiter_thread.join
2108
- expect(dial.status.result).to eq(:answer)
2109
- end
2110
- end
2111
- end
2112
-
2113
- context "when another dial is merged in" do
2114
- let(:second_root_call_id) { new_uuid }
2115
- let(:second_root_call) { Adhearsion::Call.new }
2116
- let(:mixer) { SecureRandom.uuid }
2117
-
2118
- let(:dial) { Dial::ParallelConfirmationDial.new to, options, call }
2119
- let(:other_dial) { Dial::ParallelConfirmationDial.new second_to, options, second_root_call }
2120
-
2121
- before do
2122
- allow(second_root_call).to receive_messages write_command: true, id: second_root_call_id
2123
- expect(OutboundCall).to receive(:new).and_return second_other_mock_call
2124
- expect(second_other_mock_call).to receive(:join).once.with(second_root_call, {})
2125
- expect(second_other_mock_call).to receive(:dial).once.with(second_to, options)
2126
- expect(second_root_call).to receive(:answer).once
2127
-
2128
- allow(SecureRandom).to receive_messages uuid: mixer
2129
-
2130
- dial.run subject
2131
- other_dial.run subject
2132
-
2133
- other_mock_call << mock_answered
2134
- second_other_mock_call << mock_answered
2135
- end
2136
-
2137
- it "should split calls, rejoin to a mixer, and rejoin other calls to mixer" do
2138
- expect(other_mock_call).to receive(:unjoin).once.ordered.with(call) do
2139
- call << Punchblock::Event::Unjoined.new(call_uri: other_mock_call.id)
2140
- other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
2141
- end
2142
- expect(second_other_mock_call).to receive(:unjoin).once.ordered.with(second_root_call) do
2143
- second_root_call << Punchblock::Event::Unjoined.new(call_uri: second_other_mock_call.id)
2144
- second_other_mock_call << Punchblock::Event::Unjoined.new(call_uri: second_root_call.id)
2145
- end
2146
-
2147
- expect(call).to receive(:join).once.ordered.with({mixer_name: mixer}, {})
2148
- expect(other_mock_call).to receive(:join).once.ordered.with({mixer_name: mixer}, {})
2149
-
2150
- expect(second_root_call).to receive(:join).once.ordered.with({mixer_name: mixer}, {})
2151
- expect(second_other_mock_call).to receive(:join).once.ordered.with({mixer_name: mixer}, {})
2152
-
2153
- dial.merge other_dial
2154
-
2155
- waiter_thread = Thread.new do
2156
- dial.await_completion
2157
- latch.countdown!
2158
- end
2159
-
2160
- sleep 0.5
2161
-
2162
- other_mock_call.async << mock_end
2163
- second_root_call.async << mock_end
2164
- second_other_mock_call.async << mock_end
2165
-
2166
- expect(latch.wait(2)).to be_truthy
2167
-
2168
- waiter_thread.join
2169
- expect(dial.status.result).to eq(:answer)
2170
- end
2171
-
2172
- context "when join options were specified originally" do
2173
- let(:options) { { join_options: {media: :direct} } }
2174
-
2175
- it "should rejoin with default options" do
2176
- allow(other_mock_call).to receive(:unjoin)
2177
- allow(second_other_mock_call).to receive(:unjoin)
2178
-
2179
- expect(call).to receive(:join).once.ordered.with({mixer_name: mixer}, {})
2180
- expect(other_mock_call).to receive(:join).once.ordered.with({mixer_name: mixer}, {})
2181
-
2182
- expect(second_root_call).to receive(:join).once.ordered.with({mixer_name: mixer}, {})
2183
- expect(second_other_mock_call).to receive(:join).once.ordered.with({mixer_name: mixer}, {})
2184
-
2185
- dial.merge other_dial
2186
- end
2187
- end
2188
-
2189
- it "should add the merged calls to the returned status" do
2190
- [call, other_mock_call, second_root_call, second_other_mock_call].each { |c| allow(c).to receive_messages join: true, unjoin: true }
2191
- dial.merge other_dial
2192
-
2193
- waiter_thread = Thread.new do
2194
- dial.await_completion
2195
- latch.countdown!
2196
- end
2197
-
2198
- sleep 0.5
2199
-
2200
- other_mock_call.async << mock_end
2201
- second_root_call.async << mock_end
2202
- second_other_mock_call.async << mock_end
2203
-
2204
- expect(latch.wait(2)).to be_truthy
2205
-
2206
- waiter_thread.join
2207
- expect(dial.status.result).to eq(:answer)
2208
- expect(dial.status.calls).to include(second_root_call, second_other_mock_call)
2209
- end
2210
-
2211
- it "should not unblock until all joined calls end" do
2212
- [call, other_mock_call, second_root_call, second_other_mock_call].each { |c| allow(c).to receive_messages join: true, unjoin: true }
2213
-
2214
- dial.merge other_dial
2215
-
2216
- waiter_thread = Thread.new do
2217
- dial.await_completion
2218
- latch.countdown!
2219
- end
2220
-
2221
- sleep 0.5
2222
-
2223
- other_mock_call << mock_end
2224
- expect(latch.wait(2)).to be_falsey
2225
-
2226
- second_other_mock_call << mock_end
2227
- expect(latch.wait(2)).to be_falsey
2228
-
2229
- second_root_call << mock_end
2230
- expect(latch.wait(2)).to be_truthy
2231
-
2232
- waiter_thread.join
2233
- expect(dial.status.result).to eq(:answer)
2234
- end
2235
-
2236
- it "should cleanup merged calls when the root call ends" do
2237
- [call, other_mock_call, second_root_call, second_other_mock_call].each do |c|
2238
- allow(c).to receive_messages join: true, unjoin: true
2239
- end
2240
- [other_mock_call, second_root_call, second_other_mock_call].each do |c|
2241
- expect(c).to receive(:hangup).once
2242
- end
2243
-
2244
- dial.merge other_dial
2245
-
2246
- waiter_thread = Thread.new do
2247
- dial.await_completion
2248
- dial.cleanup_calls
2249
- latch.countdown!
2250
- end
2251
-
2252
- sleep 0.5
2253
-
2254
- call << mock_end
2255
- expect(latch.wait(2)).to be_truthy
2256
-
2257
- waiter_thread.join
2258
- expect(dial.status.result).to eq(:answer)
2259
- end
2260
-
2261
- it "should subsequently rejoin to a mixer" do
2262
- [call, other_mock_call, second_root_call, second_other_mock_call].each { |c| allow(c).to receive_messages join: true, unjoin: true }
2263
-
2264
- dial.merge other_dial
2265
-
2266
- waiter_thread = Thread.new do
2267
- dial.await_completion
2268
- latch.countdown!
2269
- end
2270
-
2271
- sleep 0.5
2272
-
2273
- other_mock_call << mock_end
2274
- expect(latch.wait(2)).to be_falsey
2275
-
2276
- [call, second_root_call, second_other_mock_call].each do |call|
2277
- expect(call).to receive(:unjoin).once.with(mixer_name: mixer) do
2278
- call << Punchblock::Event::Unjoined.new(mixer_name: mixer)
2279
- end
2280
- end
2281
-
2282
- dial.split
2283
-
2284
- [call, other_mock_call, second_root_call, second_other_mock_call].each do |call|
2285
- expect(call).to receive(:join).once.with({mixer_name: mixer}, {}) do
2286
- call << Punchblock::Event::Joined.new(mixer_name: mixer)
2287
- end
2288
- end
2289
-
2290
- dial.rejoin
2291
- end
2292
-
2293
- context "if a call hangs up" do
2294
- it "should still allow splitting and rejoining" do
2295
- [call, other_mock_call, second_root_call, second_other_mock_call].each { |c| allow(c).to receive_messages join: true, unjoin: true }
2296
-
2297
- dial.merge other_dial
2298
-
2299
- waiter_thread = Thread.new do
2300
- dial.await_completion
2301
- latch.countdown!
2302
- end
2303
-
2304
- sleep 0.5
2305
-
2306
- [call, second_root_call, second_other_mock_call].each do |call|
2307
- expect(call).to receive(:unjoin).once.with(mixer_name: mixer) do
2308
- call << Punchblock::Event::Unjoined.new(mixer_name: mixer)
2309
- end
2310
- end
2311
-
2312
- expect(other_mock_call).to receive(:unjoin).and_raise Adhearsion::Call::Hangup
2313
-
2314
- dial.split
2315
-
2316
- other_mock_call << mock_end
2317
- expect(latch.wait(2)).to be_falsey
2318
-
2319
- [call, second_root_call, second_other_mock_call].each do |call|
2320
- expect(call).to receive(:join).once.with({mixer_name: mixer}, {}) do
2321
- call << Punchblock::Event::Joined.new(mixer_name: mixer)
2322
- end
2323
- end
2324
-
2325
- expect(other_mock_call).to receive(:join).and_raise Adhearsion::Call::ExpiredError
2326
-
2327
- dial.rejoin
2328
- end
2329
- end
2330
-
2331
- context "if the calls were not joined" do
2332
- it "should still join to mixer" do
2333
- expect(other_mock_call).to receive(:unjoin).once.ordered.with(call).and_raise Punchblock::ProtocolError.new.setup(:service_unavailable)
2334
- expect(second_other_mock_call).to receive(:unjoin).once.ordered.with(second_root_call).and_raise Punchblock::ProtocolError.new.setup(:service_unavailable)
2335
-
2336
- expect(call).to receive(:join).once.ordered.with({mixer_name: mixer}, {})
2337
- expect(other_mock_call).to receive(:join).once.ordered.with({mixer_name: mixer}, {})
2338
-
2339
- expect(second_root_call).to receive(:join).once.ordered.with({mixer_name: mixer}, {})
2340
- expect(second_other_mock_call).to receive(:join).once.ordered.with({mixer_name: mixer}, {})
2341
-
2342
- dial.merge other_dial
2343
-
2344
- waiter_thread = Thread.new do
2345
- dial.await_completion
2346
- latch.countdown!
2347
- end
2348
-
2349
- sleep 0.5
2350
-
2351
- other_mock_call.async << mock_end
2352
- second_root_call.async << mock_end
2353
- second_other_mock_call.async << mock_end
2354
-
2355
- expect(latch.wait(2)).to be_truthy
2356
-
2357
- waiter_thread.join
2358
- expect(dial.status.result).to eq(:answer)
2359
- end
2360
- end
2361
- end
2362
- end
2363
- end
2364
-
2365
- describe "when the caller has already hung up" do
2366
- before do
2367
- call << mock_end
2368
- end
2369
-
2370
- it "should raise Call::Hangup" do
2371
- expect { subject.dial_and_confirm to, options }.to raise_error(Call::Hangup)
2372
- end
2373
-
2374
- it "should not make any outbound calls" do
2375
- expect(OutboundCall).to receive(:new).never
2376
- expect { subject.dial_and_confirm to, options }.to raise_error
2377
- end
2378
- end
2379
-
2380
- describe "with multiple third parties specified" do
2381
- let(:options) { {} }
2382
- let(:other_options) { options }
2383
- let(:second_other_options) { options }
2384
-
2385
- before do
2386
- expect(OutboundCall).to receive(:new).and_return other_mock_call, second_other_mock_call
2387
-
2388
- expect(other_mock_call).to receive(:dial).once.with(to, other_options)
2389
-
2390
- expect(second_other_mock_call).to receive(:dial).once.with(second_to, second_other_options)
2391
- expect(second_other_mock_call).to receive(:join).never
2392
- end
2393
-
2394
- def dial_in_thread
2395
- Thread.new do
2396
- status = subject.dial_and_confirm [to, second_to], options
2397
- latch.countdown!
2398
- status
2399
- end
2400
- end
2401
-
2402
- it "dials all parties and joins the first one to answer, hanging up the rest" do
2403
- expect(call).to receive(:answer).once
2404
- expect(other_mock_call).to receive(:join).once.with(call, {})
2405
- expect(second_other_mock_call).to receive(:hangup).once do
2406
- second_other_mock_call << mock_end
2407
- end
2408
-
2409
- t = dial_in_thread
2410
-
2411
- expect(latch.wait(2)).to be_falsey
2412
-
2413
- other_mock_call << mock_answered
2414
- other_mock_call << mock_end
2415
-
2416
- expect(latch.wait(2)).to be_truthy
2417
-
2418
- t.join
2419
- status = t.value
2420
- expect(status).to be_a Dial::DialStatus
2421
- expect(status.calls.size).to eq(2)
2422
- status.calls.each { |c| expect(c).to be_a OutboundCall }
2423
- end
2424
-
2425
- it "unblocks when the joined call unjoins, allowing it to proceed further" do
2426
- expect(call).to receive(:answer).once
2427
- expect(other_mock_call).to receive(:join).once.with(call, {})
2428
- expect(other_mock_call).to receive(:hangup).once
2429
- expect(second_other_mock_call).to receive(:hangup).once do
2430
- second_other_mock_call << mock_end
2431
- end
2432
-
2433
- t = dial_in_thread
2434
-
2435
- expect(latch.wait(2)).to be_falsey
2436
-
2437
- other_mock_call << mock_answered
2438
- other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
2439
-
2440
- expect(latch.wait(2)).to be_truthy
2441
-
2442
- t.join
2443
- status = t.value
2444
- expect(status).to be_a Dial::DialStatus
2445
- expect(status.calls.size).to eq(2)
2446
- status.calls.each { |c| expect(c).to be_a OutboundCall }
2447
- end
2448
-
2449
- describe "with options overrides" do
2450
- let(:options) do
2451
- {
2452
- :from => 'foo',
2453
- :timeout => 3000,
2454
- :headers => {
2455
- :x_foo => 'bar'
2456
- }
2457
- }
2458
- end
2459
-
2460
- let(:dial_other_options) do
2461
- {
2462
- :foo => 'bar',
2463
- :headers => {
2464
- :x_foo => 'buzz'
2465
- }
2466
- }
2467
- end
2468
-
2469
- let(:other_options) do
2470
- {
2471
- :from => 'foo',
2472
- :timeout => 3000,
2473
- :foo => 'bar',
2474
- :headers => {
2475
- :x_foo => 'buzz'
2476
- }
2477
-
2478
- }
2479
- end
2480
-
2481
- let(:dial_second_other_options) do
2482
- {
2483
- :timeout => 5000,
2484
- :headers => {
2485
- :x_bar => 'barbuzz'
2486
- }
2487
- }
2488
- end
2489
-
2490
- let(:second_other_options) do
2491
- {
2492
- :from => 'foo',
2493
- :timeout => 5000,
2494
- :headers => {
2495
- :x_foo => 'bar',
2496
- :x_bar => 'barbuzz'
2497
- }
2498
- }
2499
- end
2500
-
2501
- it "with multiple destinations as an hash, with overrides for each, and an options hash, it dials each call with specified options" do
2502
- t = Thread.new do
2503
- subject.dial_and_confirm({
2504
- to => dial_other_options,
2505
- second_to => dial_second_other_options
2506
- }, options)
2507
- latch.countdown!
2508
- end
2509
-
2510
- expect(latch.wait(2)).to be_falsey
2511
- other_mock_call << mock_end
2512
- expect(latch.wait(2)).to be_falsey
2513
- second_other_mock_call << mock_end
2514
- expect(latch.wait(2)).to be_truthy
2515
- t.join
2516
- end
2517
- end
2518
-
2519
- context "when all calls are rejected" do
2520
- it "has an overall dial status of :no_answer" do
2521
- t = dial_in_thread
2522
-
2523
- sleep 0.5
2524
-
2525
- other_mock_call << mock_end(:reject)
2526
- second_other_mock_call << mock_end(:reject)
2527
-
2528
- expect(latch.wait(2)).to be_truthy
2529
-
2530
- t.join
2531
- status = t.value
2532
- expect(status.result).to eq(:no_answer)
2533
- end
2534
- end
2535
-
2536
- context "when a call is answered and joined, and the other ends with an error" do
2537
- it "has an overall dial status of :answer" do
2538
- expect(call).to receive(:answer).once
2539
- expect(other_mock_call).to receive(:join).once.with(call, {})
2540
- expect(second_other_mock_call).to receive(:hangup).once do
2541
- second_other_mock_call << mock_end(:error)
2542
- end
2543
-
2544
- t = dial_in_thread
2545
-
2546
- sleep 0.5
2547
-
2548
- other_mock_call << mock_answered
2549
- other_mock_call << mock_end
2550
-
2551
- expect(latch.wait(2)).to be_truthy
2552
-
2553
- t.join
2554
- status = t.value
2555
- expect(status.result).to eq(:answer)
2556
- end
2557
- end
2558
- end
2559
-
2560
- describe "with a timeout specified" do
2561
- let(:timeout) { 3 }
2562
-
2563
- it "should abort the dial after the specified timeout" do
2564
- expect(other_mock_call).to receive(:dial).once
2565
- expect(other_mock_call).to receive(:hangup).once
2566
- expect(OutboundCall).to receive(:new).and_return other_mock_call
2567
-
2568
- time = Time.now
2569
-
2570
- t = Thread.new do
2571
- status = subject.dial_and_confirm to, :timeout => timeout
2572
- latch.countdown!
2573
- status
2574
- end
2575
-
2576
- latch.wait
2577
- time = Time.now - time
2578
- expect(time.round).to eq(timeout)
2579
- t.join
2580
- status = t.value
2581
- expect(status.result).to eq(:timeout)
2582
- end
2583
-
2584
- describe "if someone answers before the timeout elapses" do
2585
- it "should not abort until the far end hangs up" do
2586
- expect(other_mock_call).to receive(:dial).once.with(to, hash_including(:timeout => timeout))
2587
- expect(call).to receive(:answer).once
2588
- expect(other_mock_call).to receive(:join).once.with(call, {})
2589
- expect(OutboundCall).to receive(:new).and_return other_mock_call
2590
-
2591
- time = Time.now
2592
-
2593
- t = Thread.new do
2594
- status = subject.dial_and_confirm to, :timeout => timeout
2595
- latch.countdown!
2596
- status
2597
- end
2598
-
2599
- expect(latch.wait(2)).to be_falsey
2600
-
2601
- other_mock_call << mock_answered
2602
-
2603
- expect(latch.wait(2)).to be_falsey
2604
-
2605
- other_mock_call << mock_end
2606
-
2607
- expect(latch.wait(0.1)).to be_truthy
2608
- time = Time.now - time
2609
- expect(time.to_i).to be > timeout
2610
- t.join
2611
- status = t.value
2612
- expect(status.result).to eq(:answer)
2613
- end
2614
- end
2615
- end
2616
-
2617
- describe "with a confirmation controller" do
2618
- let(:confirmation_controller) do
2619
- latch = confirmation_latch
2620
- Class.new(Adhearsion::CallController) do
2621
- @@confirmation_latch = latch
2622
-
2623
- def run
2624
- # Copy metadata onto call variables so we can assert it later. Ugly hack
2625
- metadata.each_pair do |key, value|
2626
- call[key] = value
2627
- end
2628
- @@confirmation_latch.countdown!
2629
- if delay = call['confirmation_delay']
2630
- sleep delay
2631
- end
2632
- call['confirm'] || hangup
2633
- end
2634
- end
2635
- end
2636
-
2637
- let(:confirmation_latch) { CountDownLatch.new 1 }
2638
-
2639
- let(:options) { {:confirm => confirmation_controller} }
2640
-
2641
- context "with confirmation controller metadata specified" do
2642
- let(:options) { {:confirm => confirmation_controller, :confirm_metadata => {:foo => 'bar'}} }
2643
-
2644
- before do
2645
- expect(other_mock_call).to receive(:dial).once
2646
- expect(OutboundCall).to receive(:new).and_return other_mock_call
2647
- end
2648
-
2649
- it "should set the metadata on the controller" do
2650
- expect(other_mock_call).to receive(:hangup).once do
2651
- other_mock_call << mock_end
2652
- end
2653
- other_mock_call['confirm'] = false
2654
-
2655
- dial_in_thread
2656
-
2657
- expect(latch.wait(0.1)).to be_falsey
2658
-
2659
- other_mock_call << mock_answered
2660
-
2661
- expect(confirmation_latch.wait(2)).to be_truthy
2662
- expect(latch.wait(2)).to be_truthy
2663
-
2664
- expect(other_mock_call[:foo]).to eq('bar')
2665
- end
2666
- end
2667
-
2668
- context "when an outbound call is answered" do
2669
- before do
2670
- expect(other_mock_call).to receive(:dial).once
2671
- expect(OutboundCall).to receive(:new).and_return other_mock_call
2672
- end
2673
-
2674
- it "should execute the specified confirmation controller" do
2675
- expect(other_mock_call).to receive(:hangup).once do
2676
- other_mock_call << mock_end
2677
- end
2678
- other_mock_call['confirm'] = false
2679
-
2680
- dial_in_thread
2681
-
2682
- expect(latch.wait(0.1)).to be_falsey
2683
-
2684
- other_mock_call << mock_answered
2685
-
2686
- expect(confirmation_latch.wait(2)).to be_truthy
2687
- expect(latch.wait(2)).to be_truthy
2688
- end
2689
-
2690
- it "should join the calls if the call is still active after execution of the call controller" do
2691
- expect(other_mock_call).to receive(:hangup).once do
2692
- other_mock_call << mock_end
2693
- end
2694
- other_mock_call['confirm'] = true
2695
- expect(call).to receive(:answer).once
2696
- expect(other_mock_call).to receive(:join).once.with(call, {}) do
2697
- call << Punchblock::Event::Joined.new(call_uri: other_mock_call.id)
2698
- other_mock_call << Punchblock::Event::Joined.new(call_uri: call.id)
2699
- end
2700
-
2701
- t = dial_in_thread
2702
-
2703
- expect(latch.wait(2)).to be_falsey
2704
-
2705
- base_time = Time.local(2008, 9, 1, 12, 0, 0)
2706
- Timecop.freeze base_time
2707
-
2708
- other_mock_call << mock_answered
2709
-
2710
- base_time = Time.local(2008, 9, 1, 12, 0, 42)
2711
- Timecop.freeze base_time
2712
- other_mock_call << Punchblock::Event::Unjoined.new(call_uri: call.id)
2713
-
2714
- expect(latch.wait(2)).to be_truthy
2715
-
2716
- t.join
2717
- status = t.value
2718
- expect(status.result).to eq(:answer)
2719
-
2720
- joined_status = status.joins[status.calls.first]
2721
- expect(joined_status.duration).to eq(42.0)
2722
- expect(joined_status.result).to eq(:joined)
2723
- end
2724
-
2725
- it "should not join the calls if the call is not active after execution of the call controller" do
2726
- expect(other_mock_call).to receive(:hangup).once do
2727
- other_mock_call << mock_end
2728
- end
2729
- other_mock_call['confirm'] = false
2730
- expect(call).to receive(:answer).never
2731
- expect(other_mock_call).to receive(:join).never.with(call)
2732
-
2733
- t = dial_in_thread
2734
-
2735
- expect(latch.wait(2)).to be_falsey
2736
-
2737
- other_mock_call << mock_answered
2738
-
2739
- expect(latch.wait(2)).to be_truthy
2740
-
2741
- t.join
2742
- status = t.value
2743
- expect(status.result).to eq(:unconfirmed)
2744
-
2745
- joined_status = status.joins[status.calls.first]
2746
- expect(joined_status.duration).to eq(0.0)
2747
- expect(joined_status.result).to eq(:unconfirmed)
2748
- end
2749
- end
2750
-
2751
- context "when multiple calls are made" do
2752
- let(:confirmation_latch) { CountDownLatch.new 2 }
2753
- let(:apology_controller) do
2754
- Class.new(Adhearsion::CallController) do
2755
- def run
2756
- logger.info "Apologising..."
2757
- call['apology_metadata'] = metadata
2758
- call['apology_done'] = true
2759
- end
2760
- end
2761
- end
2762
- let(:options) { {confirm: confirmation_controller, confirm_metadata: {'foo' => 'bar'}, apology: apology_controller} }
2763
-
2764
- before do
2765
- expect(OutboundCall).to receive(:new).and_return other_mock_call, second_other_mock_call
1424
+ expect(OutboundCall).to receive(:new).and_return other_mock_call, second_other_mock_call
2766
1425
  end
2767
1426
 
2768
1427
  def dial_in_thread
2769
1428
  Thread.new do
2770
- status = subject.dial_and_confirm [to, second_to], options
1429
+ status = subject.dial [to, second_to], options
2771
1430
  latch.countdown!
2772
1431
  status
2773
1432
  end
@@ -2784,8 +1443,8 @@ module Adhearsion
2784
1443
 
2785
1444
  expect(other_mock_call).to receive(:dial).once.with(to, from: nil)
2786
1445
  expect(other_mock_call).to receive(:join).once.with(call, {}) do
2787
- call << Punchblock::Event::Joined.new(call_uri: other_mock_call.id)
2788
- other_mock_call << Punchblock::Event::Joined.new(call_uri: call.id)
1446
+ call << Adhearsion::Event::Joined.new(call_uri: other_mock_call.id)
1447
+ other_mock_call << Adhearsion::Event::Joined.new(call_uri: call.id)
2789
1448
  end
2790
1449
  expect(other_mock_call).to receive(:hangup).once do
2791
1450
  other_mock_call.async.deliver_message mock_end
@@ -2807,7 +1466,7 @@ module Adhearsion
2807
1466
 
2808
1467
  sleep 2
2809
1468
 
2810
- other_mock_call.async.deliver_message Punchblock::Event::Unjoined.new(call_uri: call.id)
1469
+ other_mock_call.async.deliver_message Adhearsion::Event::Unjoined.new(call_uri: call.id)
2811
1470
 
2812
1471
  expect(latch.wait(2)).to be_truthy
2813
1472