adhearsion 2.6.4 → 3.0.0.beta1

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.
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