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,83 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ module Adhearsion
6
+ module Translator
7
+ class Asterisk
8
+ describe Component do
9
+
10
+ end
11
+
12
+ module Component
13
+ describe Component do
14
+ let(:connection) { Adhearsion::Rayo::Connection::Asterisk.new }
15
+ let(:translator) { connection.translator }
16
+ let(:ami_client) { connection.ami_client }
17
+ let(:call) { Translator::Asterisk::Call.new 'foo', translator, ami_client, connection }
18
+ let(:command) { Adhearsion::Rayo::Component::Input.new }
19
+
20
+ subject { Component.new command, call }
21
+
22
+ before { command.request! }
23
+
24
+ describe "#send_event" do
25
+ before { command.execute! }
26
+
27
+ let :event do
28
+ Adhearsion::Event::Complete.new
29
+ end
30
+
31
+ let :expected_event do
32
+ Adhearsion::Event::Complete.new target_call_id: call.id,
33
+ component_id: subject.id, source_uri: subject.id
34
+ end
35
+
36
+ it "should send the event to the connection" do
37
+ expect(connection).to receive(:handle_event).once.with expected_event
38
+ subject.send_event event
39
+ end
40
+ end
41
+
42
+ describe "#send_complete_event" do
43
+ before { command.execute! }
44
+
45
+ let(:reason) { Adhearsion::Event::Complete::Stop.new }
46
+ let :expected_event do
47
+ Adhearsion::Event::Complete.new reason: reason
48
+ end
49
+
50
+ it "should send a complete event with the specified reason" do
51
+ expect(subject).to receive(:send_event).once.with expected_event
52
+ subject.send_complete_event reason
53
+ end
54
+ end
55
+
56
+ describe "#call_ended" do
57
+ it "should send a complete event with the call hangup reason" do
58
+ expect(subject).to receive(:send_complete_event).once.with Adhearsion::Event::Complete::Hangup.new
59
+ subject.call_ended
60
+ end
61
+ end
62
+
63
+ describe '#execute_command' do
64
+ before do
65
+ component_command.request!
66
+ end
67
+
68
+ context 'with a command we do not understand' do
69
+ let :component_command do
70
+ Adhearsion::Rayo::Component::Stop.new :component_id => subject.id
71
+ end
72
+
73
+ it 'sends an error in response to the command' do
74
+ subject.execute_command component_command
75
+ expect(component_command.response).to eq(Adhearsion::ProtocolError.new.setup('command-not-acceptable', "Did not understand command for component #{subject.id}", call.id, subject.id))
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,685 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+ require 'ostruct'
5
+
6
+ module Adhearsion
7
+ module Translator
8
+ describe Asterisk do
9
+ let(:ami_client) { double 'RubyAMI::Client' }
10
+ let(:connection) { Adhearsion::Rayo::Connection::Asterisk.new }
11
+
12
+ let(:translator) { Asterisk.new ami_client, connection }
13
+
14
+ subject { translator }
15
+
16
+ describe '#ami_client' do
17
+ subject { super().ami_client }
18
+ it { is_expected.to be ami_client }
19
+ end
20
+
21
+ describe '#connection' do
22
+ subject { super().connection }
23
+ it { is_expected.to be connection }
24
+ end
25
+
26
+ before do
27
+ connection.event_handler = ->(*) {}
28
+ end
29
+
30
+ after { translator.terminate if translator.alive? }
31
+
32
+ describe '#execute_command' do
33
+ describe 'with a call command' do
34
+ let(:command) { Adhearsion::Rayo::Command::Answer.new }
35
+ let(:call_id) { 'abc123' }
36
+
37
+ it 'executes the call command' do
38
+ expect(subject.wrapped_object).to receive(:execute_call_command).with(satisfy { |c|
39
+ expect(c).to be command
40
+ expect(c.target_call_id).to eq(call_id)
41
+ })
42
+ subject.execute_command command, :call_id => call_id
43
+ end
44
+ end
45
+
46
+ describe 'with a global component command' do
47
+ let(:command) { Adhearsion::Rayo::Component::Stop.new }
48
+ let(:component_id) { '123abc' }
49
+
50
+ it 'executes the component command' do
51
+ expect(subject.wrapped_object).to receive(:execute_component_command).with(satisfy { |c|
52
+ expect(c).to be command
53
+ expect(c.component_id).to eq(component_id)
54
+ })
55
+ subject.execute_command command, :component_id => component_id
56
+ end
57
+ end
58
+
59
+ describe 'with a global command' do
60
+ let(:command) { Adhearsion::Rayo::Command::Dial.new }
61
+
62
+ it 'executes the command directly' do
63
+ expect(subject.wrapped_object).to receive(:execute_global_command).with command
64
+ subject.execute_command command
65
+ end
66
+ end
67
+ end
68
+
69
+ describe '#send_message' do
70
+ let(:call_id) { 'abc123' }
71
+ let(:body) { 'hello world' }
72
+ let(:call) { Translator::Asterisk::Call.new 'SIP/foo', subject, ami_client, connection }
73
+
74
+ before do
75
+ allow(call).to receive(:id).and_return call_id
76
+ subject.register_call call
77
+ end
78
+
79
+ it 'sends the command to the call for execution' do
80
+ expect(call).to receive(:send_message).once.with body
81
+ subject.send_message call_id, 'example.com', body, subject: 'stuff'
82
+ end
83
+
84
+ context "when the call doesn't exist" do
85
+ it "should not crash the translator" do
86
+ subject.send_message 'oops', 'example.com', body, subject: 'stuff'
87
+ expect(subject).to be_alive
88
+ end
89
+ end
90
+ end
91
+
92
+ describe '#register_call' do
93
+ let(:call_id) { 'abc123' }
94
+ let(:channel) { 'SIP/foo' }
95
+ let(:call) { Translator::Asterisk::Call.new channel, subject, ami_client, connection }
96
+
97
+ before do
98
+ allow(call).to receive(:id).and_return call_id
99
+ subject.register_call call
100
+ end
101
+
102
+ it 'should make the call accessible by ID' do
103
+ expect(subject.call_with_id(call_id)).to be call
104
+ end
105
+
106
+ it 'should make the call accessible by channel' do
107
+ expect(subject.call_for_channel(channel)).to be call
108
+ end
109
+ end
110
+
111
+ describe '#deregister_call' do
112
+ let(:call_id) { 'abc123' }
113
+ let(:channel) { 'SIP/foo' }
114
+ let(:call) { Translator::Asterisk::Call.new channel, subject, ami_client, connection }
115
+
116
+ before do
117
+ allow(call).to receive(:id).and_return call_id
118
+ subject.register_call call
119
+ end
120
+
121
+ it 'should make the call inaccessible by ID' do
122
+ expect(subject.call_with_id(call_id)).to be call
123
+ subject.deregister_call call_id, channel
124
+ expect(subject.call_with_id(call_id)).to be_nil
125
+ end
126
+
127
+ it 'should make the call inaccessible by channel' do
128
+ expect(subject.call_for_channel(channel)).to be call
129
+ subject.deregister_call call_id, channel
130
+ expect(subject.call_for_channel(channel)).to be_nil
131
+ end
132
+ end
133
+
134
+ describe '#register_component' do
135
+ let(:component_id) { 'abc123' }
136
+ let(:component) { double 'Asterisk::Component::Asterisk::AMIAction', :id => component_id }
137
+
138
+ it 'should make the component accessible by ID' do
139
+ subject.register_component component
140
+ expect(subject.component_with_id(component_id)).to be component
141
+ end
142
+ end
143
+
144
+ describe '#execute_call_command' do
145
+ let(:call_id) { 'abc123' }
146
+ let(:command) { Adhearsion::Rayo::Command::Answer.new target_call_id: call_id }
147
+
148
+ context "with a known call ID" do
149
+ let(:call) { Translator::Asterisk::Call.new 'SIP/foo', subject, ami_client, connection }
150
+
151
+ before do
152
+ command.request!
153
+ allow(call).to receive(:id).and_return call_id
154
+ subject.register_call call
155
+ end
156
+
157
+ it 'sends the command to the call for execution' do
158
+ expect(call).to receive(:execute_command).once.with command
159
+ subject.execute_call_command command
160
+ end
161
+
162
+ context 'when it raises' do
163
+ before do
164
+ expect(call).to receive(:execute_command).and_raise StandardError
165
+ end
166
+
167
+ let(:other_command) { Adhearsion::Rayo::Command::Answer.new target_call_id: call_id }
168
+
169
+ it 'sends an error in response to the command' do
170
+ subject.execute_call_command command
171
+
172
+ expect(subject.call_with_id(call_id)).to be_nil
173
+
174
+ other_command.request!
175
+ subject.execute_call_command other_command
176
+ expect(other_command.response).to eq(Adhearsion::ProtocolError.new.setup(:item_not_found, "Could not find a call with ID #{call_id}", call_id))
177
+ end
178
+ end
179
+ end
180
+
181
+ let :end_error_event do
182
+ Adhearsion::Event::End.new reason: :error, target_call_id: call_id
183
+ end
184
+
185
+ context "with an unknown call ID" do
186
+ it 'sends an error in response to the command' do
187
+ command.request!
188
+ subject.execute_call_command command
189
+ expect(command.response).to eq(Adhearsion::ProtocolError.new.setup(:item_not_found, "Could not find a call with ID #{call_id}", call_id, nil))
190
+ end
191
+ end
192
+ end
193
+
194
+ describe '#execute_component_command' do
195
+ let(:call) { Translator::Asterisk::Call.new 'SIP/foo', subject, ami_client, connection }
196
+ let(:component_node) { Adhearsion::Rayo::Component::Output.new }
197
+ let(:component) { Translator::Asterisk::Component::Output.new(component_node, call) }
198
+
199
+ let(:command) { Adhearsion::Rayo::Component::Stop.new component_id: component.id }
200
+
201
+ before do
202
+ command.request!
203
+ end
204
+
205
+ context 'with a known component ID' do
206
+ before do
207
+ subject.register_component component
208
+ end
209
+
210
+ it 'sends the command to the component for execution' do
211
+ expect(component).to receive(:execute_command).once.with command
212
+ subject.execute_component_command command
213
+ end
214
+ end
215
+
216
+ context "with an unknown component ID" do
217
+ it 'sends an error in response to the command' do
218
+ subject.execute_component_command command
219
+ expect(command.response).to eq(Adhearsion::ProtocolError.new.setup(:item_not_found, "Could not find a component with ID #{component.id}", nil, component.id))
220
+ end
221
+ end
222
+ end
223
+
224
+ describe '#execute_global_command' do
225
+ context 'with a Dial' do
226
+ let :command do
227
+ Adhearsion::Rayo::Command::Dial.new :to => 'SIP/1234', :from => 'abc123'
228
+ end
229
+
230
+ before do
231
+ command.request!
232
+ allow(ami_client).to receive(:send_action).and_return RubyAMI::Response.new
233
+ end
234
+
235
+ it 'should be able to look up the call by channel ID' do
236
+ subject.execute_global_command command
237
+ call = subject.call_for_channel('SIP/1234')
238
+ expect(call).to be_a Asterisk::Call
239
+ end
240
+
241
+ it 'should instruct the call to send a dial' do
242
+ mock_call = double('Asterisk::Call').as_null_object
243
+ expect(Asterisk::Call).to receive(:new).once.and_return mock_call
244
+ expect(mock_call).to receive(:dial).once.with command
245
+ subject.execute_global_command command
246
+ end
247
+
248
+ context 'when requesting a specific URI' do
249
+ let(:requested_uri) { connection.new_call_uri }
250
+
251
+ before do
252
+ command.uri = requested_uri
253
+ end
254
+
255
+ it "should assign the requested URI to the call" do
256
+ subject.execute_global_command command
257
+ expect(subject.call_with_id(requested_uri).id).to eq(requested_uri)
258
+ end
259
+
260
+ context 'and the requested URI already represents a known call' do
261
+ before do
262
+ earlier_command = Adhearsion::Rayo::Command::Dial.new to: 'SIP/1234', uri: requested_uri
263
+ earlier_command.request!
264
+
265
+ subject.execute_global_command earlier_command
266
+
267
+ @first_call = subject.call_with_id(requested_uri)
268
+
269
+ subject.execute_global_command command
270
+ end
271
+
272
+ it "should set the command response to a conflict error" do
273
+ expect(command.response(0.1)).to eq(Adhearsion::ProtocolError.new.setup(:conflict, 'Call ID already in use'))
274
+ end
275
+
276
+ it "should not replace the original call in the registry" do
277
+ expect(subject.call_with_id(requested_uri)).to be @first_call
278
+ end
279
+ end
280
+ end
281
+ end
282
+
283
+ context 'with an AMI action' do
284
+ let :command do
285
+ Adhearsion::Rayo::Component::Asterisk::AMI::Action.new :name => 'Status', :params => { :channel => 'foo' }
286
+ end
287
+
288
+ let(:mock_action) { double('Asterisk::Component::Asterisk::AMIAction').as_null_object }
289
+
290
+ it 'should create a component actor and execute it asynchronously' do
291
+ expect(Asterisk::Component::Asterisk::AMIAction).to receive(:new).once.with(command, subject, ami_client).and_return mock_action
292
+ expect(mock_action).to receive(:execute).once
293
+ subject.execute_global_command command
294
+ end
295
+
296
+ it 'registers the component' do
297
+ expect(Asterisk::Component::Asterisk::AMIAction).to receive(:new).once.with(command, subject, ami_client).and_return mock_action
298
+ expect(subject.wrapped_object).to receive(:register_component).with mock_action
299
+ subject.execute_global_command command
300
+ end
301
+ end
302
+
303
+ context "with a command we don't understand" do
304
+ let :command do
305
+ Adhearsion::Rayo::Command::Answer.new
306
+ end
307
+
308
+ it 'sends an error in response to the command' do
309
+ subject.execute_command command
310
+ expect(command.response).to eq(Adhearsion::ProtocolError.new.setup('command-not-acceptable', "Did not understand command"))
311
+ end
312
+ end
313
+ end
314
+
315
+ describe '#handle_pb_event' do
316
+ it 'should forward the event to the connection' do
317
+ event = double 'Adhearsion::Event'
318
+ expect(subject.connection).to receive(:handle_event).once.with event
319
+ subject.handle_pb_event event
320
+ end
321
+ end
322
+
323
+ describe '#handle_ami_event' do
324
+ let :ami_event do
325
+ RubyAMI::Event.new 'Newchannel',
326
+ 'Channel' => "SIP/101-3f3f",
327
+ 'State' => "Ring",
328
+ 'Callerid' => "101",
329
+ 'Uniqueid' => "1094154427.10"
330
+ end
331
+
332
+ let :expected_pb_event do
333
+ Adhearsion::Event::Asterisk::AMI.new name: 'Newchannel',
334
+ headers: { 'Channel' => "SIP/101-3f3f",
335
+ 'State' => "Ring",
336
+ 'Callerid' => "101",
337
+ 'Uniqueid' => "1094154427.10"}
338
+ end
339
+
340
+ it 'should create a. AMI event object and pass it to the connection' do
341
+ expect(subject.connection).to receive(:handle_event).once.with expected_pb_event
342
+ subject.handle_ami_event ami_event
343
+ end
344
+
345
+ context "when the event doesn't pass the filter" do
346
+ before { described_class.event_filter = ->(event) { false } }
347
+ after { described_class.event_filter = nil }
348
+
349
+ it 'does not send the AMI event to the connection as a PB event' do
350
+ expect(subject.connection).to receive(:handle_event).never
351
+ subject.handle_ami_event ami_event
352
+ end
353
+ end
354
+
355
+ context 'with something that is not a RubyAMI::Event' do
356
+ it 'does not send anything to the connection' do
357
+ expect(subject.connection).to receive(:handle_event).never
358
+ subject.handle_ami_event :foo
359
+ end
360
+ end
361
+
362
+ describe 'with a FullyBooted event' do
363
+ let(:ami_event) { RubyAMI::Event.new 'FullyBooted' }
364
+
365
+ it 'sends a connected event to the event handler' do
366
+ expect(subject.connection).to receive(:handle_event).once.with Adhearsion::Rayo::Connection::Connected.new
367
+ expect(subject.wrapped_object).to receive(:run_at_fully_booted).once
368
+ subject.handle_ami_event ami_event
369
+ end
370
+ end
371
+
372
+ describe 'with an AsyncAGI Start event' do
373
+ let :ami_event do
374
+ RubyAMI::Event.new 'AsyncAGI',
375
+ 'SubEvent' => "Start",
376
+ 'Channel' => "SIP/1234-00000000",
377
+ 'Env' => "agi_request%3A%20async%0Aagi_channel%3A%20SIP%2F1234-00000000%0Aagi_language%3A%20en%0Aagi_type%3A%20SIP%0Aagi_uniqueid%3A%201320835995.0%0Aagi_version%3A%201.8.4.1%0Aagi_callerid%3A%205678%0Aagi_calleridname%3A%20Jane%20Smith%0Aagi_callingpres%3A%200%0Aagi_callingani2%3A%200%0Aagi_callington%3A%200%0Aagi_callingtns%3A%200%0Aagi_dnid%3A%201000%0Aagi_rdnis%3A%20unknown%0Aagi_context%3A%20default%0Aagi_extension%3A%201000%0Aagi_priority%3A%201%0Aagi_enhanced%3A%200.0%0Aagi_accountcode%3A%20%0Aagi_threadid%3A%204366221312%0A%0A"
378
+ end
379
+
380
+ let :expected_agi_env do
381
+ {
382
+ :agi_request => 'async',
383
+ :agi_channel => 'SIP/1234-00000000',
384
+ :agi_language => 'en',
385
+ :agi_type => 'SIP',
386
+ :agi_uniqueid => '1320835995.0',
387
+ :agi_version => '1.8.4.1',
388
+ :agi_callerid => '5678',
389
+ :agi_calleridname => 'Jane Smith',
390
+ :agi_callingpres => '0',
391
+ :agi_callingani2 => '0',
392
+ :agi_callington => '0',
393
+ :agi_callingtns => '0',
394
+ :agi_dnid => '1000',
395
+ :agi_rdnis => 'unknown',
396
+ :agi_context => 'default',
397
+ :agi_extension => '1000',
398
+ :agi_priority => '1',
399
+ :agi_enhanced => '0.0',
400
+ :agi_accountcode => '',
401
+ :agi_threadid => '4366221312'
402
+ }
403
+ end
404
+
405
+ before { allow(subject.wrapped_object).to receive :handle_pb_event }
406
+
407
+ it 'should be able to look up the call by channel ID' do
408
+ subject.handle_ami_event ami_event
409
+ call = subject.call_for_channel('SIP/1234-00000000')
410
+ expect(call).to be_a Asterisk::Call
411
+ expect(call.agi_env).to be_a Hash
412
+ expect(call.agi_env).to eq(expected_agi_env)
413
+ end
414
+
415
+ it 'should instruct the call to send an offer' do
416
+ mock_call = double('Asterisk::Call').as_null_object
417
+ expect(Asterisk::Call).to receive(:new).once.and_return mock_call
418
+ expect(mock_call).to receive(:send_offer).once
419
+ subject.handle_ami_event ami_event
420
+ end
421
+
422
+ context 'with an Asterisk 13 AsyncAGIStart event' do
423
+ let :ami_event do
424
+ RubyAMI::Event.new 'AsyncAGIStart',
425
+ 'Channel' => "SIP/1234-00000000",
426
+ 'Env' => "agi_request%3A%20async%0Aagi_channel%3A%20SIP%2F1234-00000000%0Aagi_language%3A%20en%0Aagi_type%3A%20SIP%0Aagi_uniqueid%3A%201320835995.0%0Aagi_version%3A%201.8.4.1%0Aagi_callerid%3A%205678%0Aagi_calleridname%3A%20Jane%20Smith%0Aagi_callingpres%3A%200%0Aagi_callingani2%3A%200%0Aagi_callington%3A%200%0Aagi_callingtns%3A%200%0Aagi_dnid%3A%201000%0Aagi_rdnis%3A%20unknown%0Aagi_context%3A%20default%0Aagi_extension%3A%201000%0Aagi_priority%3A%201%0Aagi_enhanced%3A%200.0%0Aagi_accountcode%3A%20%0Aagi_threadid%3A%204366221312%0A%0A"
427
+ end
428
+
429
+ it 'should be able to look up the call by channel ID' do
430
+ subject.handle_ami_event ami_event
431
+ call = subject.call_for_channel('SIP/1234-00000000')
432
+ expect(call).to be_a Asterisk::Call
433
+ expect(call.agi_env).to be_a Hash
434
+ expect(call.agi_env).to eq(expected_agi_env)
435
+ end
436
+
437
+ it 'should instruct the call to send an offer' do
438
+ mock_call = double('Asterisk::Call').as_null_object
439
+ expect(Asterisk::Call).to receive(:new).once.and_return mock_call
440
+ expect(mock_call).to receive(:send_offer).once
441
+ subject.handle_ami_event ami_event
442
+ end
443
+ end
444
+
445
+ context 'if a call already exists for a matching channel' do
446
+ let(:call) { Asterisk::Call.new "SIP/1234-00000000", subject, ami_client, connection }
447
+
448
+ before do
449
+ subject.register_call call
450
+ end
451
+
452
+ it "should not create a new call" do
453
+ expect(Asterisk::Call).to receive(:new).never
454
+ subject.handle_ami_event ami_event
455
+ end
456
+ end
457
+
458
+ context "for a 'h' extension" do
459
+ let :ami_event do
460
+ RubyAMI::Event.new 'AsyncAGI',
461
+ 'SubEvent' => "Start",
462
+ 'Channel' => "SIP/1234-00000000",
463
+ 'Env' => "agi_extension%3A%20h%0A%0A"
464
+ end
465
+
466
+ it "should not create a new call" do
467
+ expect(Asterisk::Call).to receive(:new).never
468
+ subject.handle_ami_event ami_event
469
+ end
470
+
471
+ it 'should not be able to look up the call by channel ID' do
472
+ subject.handle_ami_event ami_event
473
+ expect(subject.call_for_channel('SIP/1234-00000000')).to be nil
474
+ end
475
+ end
476
+
477
+ context "for a 'Kill' type" do
478
+ let :ami_event do
479
+ RubyAMI::Event.new 'AsyncAGI',
480
+ 'SubEvent' => "Start",
481
+ 'Channel' => "SIP/1234-00000000",
482
+ 'Env' => "agi_type%3A%20Kill%0A%0A"
483
+ end
484
+
485
+ it "should not create a new call" do
486
+ expect(Asterisk::Call).to receive(:new).never
487
+ subject.handle_ami_event ami_event
488
+ end
489
+
490
+ it 'should not be able to look up the call by channel ID' do
491
+ subject.handle_ami_event ami_event
492
+ expect(subject.call_for_channel('SIP/1234-00000000')).to be nil
493
+ end
494
+ end
495
+ end
496
+
497
+ describe 'with a VarSet event including a adhearsion_call_id' do
498
+ let :ami_event do
499
+ RubyAMI::Event.new 'VarSet',
500
+ "Privilege" => "dialplan,all",
501
+ "Channel" => "SIP/1234-00000000",
502
+ "Variable" => "adhearsion_call_id",
503
+ "Value" => call_id,
504
+ "Uniqueid" => "1326210224.0"
505
+ end
506
+
507
+ before do
508
+ ami_client.as_null_object
509
+ allow(subject.wrapped_object).to receive :handle_pb_event
510
+ end
511
+
512
+ context "matching a call that was created by a Dial command" do
513
+ let(:dial_command) { Adhearsion::Rayo::Command::Dial.new :to => 'SIP/1234', :from => 'abc123' }
514
+
515
+ before do
516
+ dial_command.request!
517
+ subject.execute_global_command dial_command
518
+ call
519
+ end
520
+
521
+ let(:call) { subject.call_for_channel 'SIP/1234' }
522
+ let(:call_id) { call.id }
523
+
524
+ it "should set the correct channel on the call" do
525
+ subject.handle_ami_event ami_event
526
+ expect(call.channel).to eq('SIP/1234-00000000')
527
+ end
528
+
529
+ it "should make it possible to look up the call by the full channel name" do
530
+ subject.handle_ami_event ami_event
531
+ expect(subject.call_for_channel("SIP/1234-00000000")).to be call
532
+ end
533
+
534
+ it "should make looking up the channel by the requested channel name impossible" do
535
+ subject.handle_ami_event ami_event
536
+ expect(subject.call_for_channel('SIP/1234')).to be_nil
537
+ end
538
+ end
539
+
540
+ context "for a call that doesn't exist" do
541
+ let(:call_id) { 'foobarbaz' }
542
+
543
+ it "should not raise" do
544
+ expect { subject.handle_ami_event ami_event }.not_to raise_error
545
+ end
546
+ end
547
+ end
548
+
549
+ describe 'with an AMI event for a known channel' do
550
+ let :ami_event do
551
+ RubyAMI::Event.new 'Hangup',
552
+ 'Uniqueid' => "1320842458.8",
553
+ 'Calleridnum' => "5678",
554
+ 'Calleridname' => "Jane Smith",
555
+ 'Cause' => "0",
556
+ 'Cause-txt' => "Unknown",
557
+ 'Channel' => "SIP/1234-00000000"
558
+ end
559
+
560
+ let(:call) do
561
+ Asterisk::Call.new "SIP/1234-00000000", subject, ami_client, connection, "agi_request%3A%20async%0Aagi_channel%3A%20SIP%2F1234-00000000%0Aagi_language%3A%20en%0Aagi_type%3A%20SIP%0Aagi_uniqueid%3A%201320835995.0%0Aagi_version%3A%201.8.4.1%0Aagi_callerid%3A%205678%0Aagi_calleridname%3A%20Jane%20Smith%0Aagi_callingpres%3A%200%0Aagi_callingani2%3A%200%0Aagi_callington%3A%200%0Aagi_callingtns%3A%200%0Aagi_dnid%3A%201000%0Aagi_rdnis%3A%20unknown%0Aagi_context%3A%20default%0Aagi_extension%3A%201000%0Aagi_priority%3A%201%0Aagi_enhanced%3A%200.0%0Aagi_accountcode%3A%20%0Aagi_threadid%3A%204366221312%0A%0A"
562
+ end
563
+
564
+ before do
565
+ subject.register_call call
566
+ end
567
+
568
+ it 'sends the AMI event to the call and to the connection as a PB event' do
569
+ expect(call).to receive(:process_ami_event).once.with ami_event
570
+ subject.handle_ami_event ami_event
571
+ end
572
+
573
+ context 'with a Channel1 and Channel2 specified on the event' do
574
+ let :ami_event do
575
+ RubyAMI::Event.new 'BridgeAction',
576
+ 'Privilege' => "call,all",
577
+ 'Response' => "Success",
578
+ 'Channel1' => "SIP/1234-00000000",
579
+ 'Channel2' => "SIP/5678-00000000"
580
+ end
581
+
582
+ context 'with calls for those channels' do
583
+ let(:call2) do
584
+ Asterisk::Call.new "SIP/5678-00000000", subject, ami_client, connection, "agi_request%3A%20async%0Aagi_channel%3A%20SIP%2F1234-00000000%0Aagi_language%3A%20en%0Aagi_type%3A%20SIP%0Aagi_uniqueid%3A%201320835995.0%0Aagi_version%3A%201.8.4.1%0Aagi_callerid%3A%205678%0Aagi_calleridname%3A%20Jane%20Smith%0Aagi_callingpres%3A%200%0Aagi_callingani2%3A%200%0Aagi_callington%3A%200%0Aagi_callingtns%3A%200%0Aagi_dnid%3A%201000%0Aagi_rdnis%3A%20unknown%0Aagi_context%3A%20default%0Aagi_extension%3A%201000%0Aagi_priority%3A%201%0Aagi_enhanced%3A%200.0%0Aagi_accountcode%3A%20%0Aagi_threadid%3A%204366221312%0A%0A"
585
+ end
586
+
587
+ before { subject.register_call call2 }
588
+
589
+ it 'should send the event to both calls and to the connection once as a PB event' do
590
+ expect(call).to receive(:process_ami_event).once.with ami_event
591
+ expect(call2).to receive(:process_ami_event).once.with ami_event
592
+ subject.handle_ami_event ami_event
593
+ end
594
+ end
595
+ end
596
+ end
597
+
598
+ describe 'with an event for a channel with Bridge and special statuses appended' do
599
+ let :ami_event do
600
+ RubyAMI::Event.new 'AGIExec',
601
+ 'SubEvent' => "End",
602
+ 'Channel' => "Bridge/SIP/1234-00000000<ZOMBIE>"
603
+ end
604
+
605
+ let :ami_event2 do
606
+ RubyAMI::Event.new 'Hangup',
607
+ 'Uniqueid' => "1320842458.8",
608
+ 'Calleridnum' => "5678",
609
+ 'Calleridname' => "Jane Smith",
610
+ 'Cause' => "0",
611
+ 'Cause-txt' => "Unknown",
612
+ 'Channel' => "Bridge/SIP/1234-00000000<ZOMBIE>"
613
+ end
614
+
615
+ let(:call) do
616
+ Asterisk::Call.new "SIP/1234-00000000", subject, ami_client, connection, "agi_request%3A%20async%0Aagi_channel%3A%20SIP%2F1234-00000000%0Aagi_language%3A%20en%0Aagi_type%3A%20SIP%0Aagi_uniqueid%3A%201320835995.0%0Aagi_version%3A%201.8.4.1%0Aagi_callerid%3A%205678%0Aagi_calleridname%3A%20Jane%20Smith%0Aagi_callingpres%3A%200%0Aagi_callingani2%3A%200%0Aagi_callington%3A%200%0Aagi_callingtns%3A%200%0Aagi_dnid%3A%201000%0Aagi_rdnis%3A%20unknown%0Aagi_context%3A%20default%0Aagi_extension%3A%201000%0Aagi_priority%3A%201%0Aagi_enhanced%3A%200.0%0Aagi_accountcode%3A%20%0Aagi_threadid%3A%204366221312%0A%0A"
617
+ end
618
+
619
+ before do
620
+ subject.register_call call
621
+ end
622
+
623
+ it 'sends the AMI event to the call and to the connection as a PB event if it is an allowed event' do
624
+ expect(call).to receive(:process_ami_event).once.with ami_event
625
+ subject.handle_ami_event ami_event
626
+ end
627
+
628
+ it 'does not send the AMI event to a bridged channel if it is not allowed' do
629
+ expect(call).to receive(:process_ami_event).never.with ami_event2
630
+ subject.handle_ami_event ami_event2
631
+ end
632
+
633
+ end
634
+ end
635
+
636
+ describe '#run_at_fully_booted' do
637
+ let(:broken_path) { "/this/is/not/a/valid/path" }
638
+
639
+ let(:passed_show) do
640
+ OpenStruct.new text_body: "[ Context 'adhearsion-redirect' created by 'pbx_config' ]\n '1' => 1. AGI(agi:async)[pbx_config]\n\n-= 1 extension (1 priority) in 1 context. =-"
641
+ end
642
+
643
+ let(:failed_show) do
644
+ OpenStruct.new text_body: "There is no existence of 'adhearsion-redirect' context\nCommand 'dialplan show adhearsion-redirect' failed."
645
+ end
646
+
647
+ it 'should send the redirect extension Command to the AMI client' do
648
+ expect(ami_client).to receive(:send_action).once.with 'Command', 'Command' => "dialplan add extension #{Asterisk::REDIRECT_EXTENSION},#{Asterisk::REDIRECT_PRIORITY},AGI,agi:async into #{Asterisk::REDIRECT_CONTEXT}"
649
+ expect(ami_client).to receive(:send_action).once.with('Command', 'Command' => "dialplan show #{Asterisk::REDIRECT_CONTEXT}").and_return(passed_show)
650
+ subject.run_at_fully_booted
651
+ end
652
+
653
+ it 'should check the context for existence and do nothing if it is there' do
654
+ expect(ami_client).to receive(:send_action).once.with 'Command', 'Command' => "dialplan add extension #{Asterisk::REDIRECT_EXTENSION},#{Asterisk::REDIRECT_PRIORITY},AGI,agi:async into #{Asterisk::REDIRECT_CONTEXT}"
655
+ expect(ami_client).to receive(:send_action).once.with('Command', 'Command' => "dialplan show #{Asterisk::REDIRECT_CONTEXT}").and_return(passed_show)
656
+ subject.run_at_fully_booted
657
+ end
658
+
659
+ it 'should check the context for existence and log an error if it is not there' do
660
+ expect(ami_client).to receive(:send_action).once.with 'Command', 'Command' => "dialplan add extension #{Asterisk::REDIRECT_EXTENSION},#{Asterisk::REDIRECT_PRIORITY},AGI,agi:async into #{Asterisk::REDIRECT_CONTEXT}"
661
+ expect(ami_client).to receive(:send_action).once.with('Command', 'Command' => "dialplan show #{Asterisk::REDIRECT_CONTEXT}").and_return(failed_show)
662
+ expect(translator.logger).to receive(:error).once.with("Adhearsion failed to add the #{Asterisk::REDIRECT_EXTENSION} extension to the #{Asterisk::REDIRECT_CONTEXT} context. Please add a [#{Asterisk::REDIRECT_CONTEXT}] entry to your dialplan.")
663
+ subject.run_at_fully_booted
664
+ end
665
+
666
+ it 'should check the recording directory for existence' do
667
+ stub_const('Adhearsion::Translator::Asterisk::Component::Record::RECORDING_BASE_PATH', broken_path)
668
+ expect(ami_client).to receive(:send_action).once.with 'Command', 'Command' => "dialplan add extension #{Asterisk::REDIRECT_EXTENSION},#{Asterisk::REDIRECT_PRIORITY},AGI,agi:async into #{Asterisk::REDIRECT_CONTEXT}"
669
+ expect(ami_client).to receive(:send_action).once.with('Command', 'Command' => "dialplan show #{Asterisk::REDIRECT_CONTEXT}").and_return(passed_show)
670
+ expect(translator.logger).to receive(:warn).once.with("Recordings directory #{broken_path} does not exist. Recording might not work. This warning can be ignored if Adhearsion is running on a separate machine than Asterisk. See http://adhearsion.com/docs/call-controllers#recording")
671
+ subject.run_at_fully_booted
672
+ end
673
+ end
674
+
675
+ describe '#check_recording_directory' do
676
+ let(:broken_path) { "/this/is/not/a/valid/path" }
677
+ it 'logs a warning if the recording directory does not exist' do
678
+ stub_const('Adhearsion::Translator::Asterisk::Component::Record::RECORDING_BASE_PATH', broken_path)
679
+ expect(translator.logger).to receive(:warn).once.with("Recordings directory #{broken_path} does not exist. Recording might not work. This warning can be ignored if Adhearsion is running on a separate machine than Asterisk. See http://adhearsion.com/docs/call-controllers#recording")
680
+ subject.check_recording_directory
681
+ end
682
+ end
683
+ end
684
+ end
685
+ end