adhearsion 1.2.6 → 2.0.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (236) hide show
  1. data/.gitignore +17 -10
  2. data/CHANGELOG.md +273 -0
  3. data/Gemfile +1 -1
  4. data/Guardfile +17 -0
  5. data/README.markdown +61 -9
  6. data/Rakefile +16 -48
  7. data/adhearsion.gemspec +21 -7
  8. data/bin/ahn +3 -1
  9. data/cucumber.yml +4 -0
  10. data/features/app_generator.feature +42 -0
  11. data/features/cli.feature +108 -0
  12. data/features/step_definitions/app_generator_steps.rb +6 -0
  13. data/features/step_definitions/cli_steps.rb +74 -0
  14. data/features/support/aruba_helper.rb +22 -0
  15. data/features/support/env.rb +37 -0
  16. data/features/support/utils.rb +8 -0
  17. data/lib/adhearsion.rb +85 -41
  18. data/lib/adhearsion/call.rb +176 -0
  19. data/lib/adhearsion/call_controller.rb +134 -0
  20. data/lib/adhearsion/call_controller/dial.rb +70 -0
  21. data/lib/adhearsion/call_controller/input.rb +173 -0
  22. data/lib/adhearsion/call_controller/menu.rb +124 -0
  23. data/lib/adhearsion/call_controller/output.rb +267 -0
  24. data/lib/adhearsion/call_controller/record.rb +42 -0
  25. data/lib/adhearsion/call_controller/utility.rb +60 -0
  26. data/lib/adhearsion/calls.rb +81 -0
  27. data/lib/adhearsion/cli.rb +1 -3
  28. data/lib/adhearsion/cli_commands.rb +142 -0
  29. data/lib/adhearsion/configuration.rb +149 -0
  30. data/lib/adhearsion/console.rb +19 -8
  31. data/lib/adhearsion/dialplan_controller.rb +9 -0
  32. data/lib/adhearsion/events.rb +84 -0
  33. data/lib/adhearsion/foundation/all.rb +0 -7
  34. data/lib/adhearsion/foundation/custom_daemonizer.rb +4 -6
  35. data/lib/adhearsion/foundation/exception_handler.rb +9 -0
  36. data/lib/adhearsion/foundation/object.rb +26 -8
  37. data/lib/adhearsion/foundation/synchronized_hash.rb +3 -6
  38. data/lib/adhearsion/foundation/thread_safety.rb +17 -1
  39. data/lib/adhearsion/generators/app/app_generator.rb +4 -13
  40. data/lib/adhearsion/generators/app/templates/Gemfile +10 -5
  41. data/lib/adhearsion/generators/app/templates/Procfile +1 -0
  42. data/lib/adhearsion/generators/app/templates/README.md +28 -0
  43. data/lib/adhearsion/generators/app/templates/config/adhearsion.rb +41 -0
  44. data/lib/adhearsion/generators/app/templates/{components/simon_game → lib}/simon_game.rb +6 -18
  45. data/lib/adhearsion/generators/app/templates/script/ahn +2 -2
  46. data/lib/adhearsion/initializer.rb +151 -293
  47. data/lib/adhearsion/initializer/logging.rb +33 -0
  48. data/lib/adhearsion/logging.rb +65 -69
  49. data/lib/adhearsion/menu_dsl.rb +15 -0
  50. data/lib/adhearsion/menu_dsl/calculated_match.rb +39 -0
  51. data/lib/adhearsion/menu_dsl/calculated_match_collection.rb +41 -0
  52. data/lib/adhearsion/menu_dsl/fixnum_match_calculator.rb +18 -0
  53. data/lib/adhearsion/menu_dsl/match_calculator.rb +36 -0
  54. data/lib/adhearsion/{voip/menu_state_machine/menu_class.rb → menu_dsl/menu.rb} +38 -40
  55. data/lib/adhearsion/menu_dsl/menu_builder.rb +69 -0
  56. data/lib/adhearsion/menu_dsl/range_match_calculator.rb +55 -0
  57. data/lib/adhearsion/menu_dsl/string_match_calculator.rb +21 -0
  58. data/lib/adhearsion/outbound_call.rb +64 -0
  59. data/lib/adhearsion/plugin.rb +319 -0
  60. data/lib/adhearsion/plugin/collection.rb +19 -0
  61. data/lib/adhearsion/plugin/initializer.rb +37 -0
  62. data/lib/adhearsion/plugin/methods_container.rb +6 -0
  63. data/lib/adhearsion/process.rb +94 -0
  64. data/lib/adhearsion/punchblock_plugin.rb +29 -0
  65. data/lib/adhearsion/punchblock_plugin/initializer.rb +137 -0
  66. data/lib/adhearsion/router.rb +30 -0
  67. data/lib/adhearsion/router/route.rb +42 -0
  68. data/lib/adhearsion/script_ahn_loader.rb +2 -2
  69. data/lib/adhearsion/tasks.rb +14 -9
  70. data/lib/adhearsion/tasks/configuration.rb +26 -0
  71. data/lib/adhearsion/tasks/plugins.rb +17 -0
  72. data/lib/adhearsion/version.rb +8 -14
  73. data/spec/adhearsion/call_controller/dial_spec.rb +138 -0
  74. data/spec/adhearsion/call_controller/input_spec.rb +278 -0
  75. data/spec/adhearsion/call_controller/menu_spec.rb +120 -0
  76. data/spec/adhearsion/call_controller/output_spec.rb +466 -0
  77. data/spec/adhearsion/call_controller/record_spec.rb +125 -0
  78. data/spec/adhearsion/call_controller_spec.rb +395 -0
  79. data/spec/adhearsion/call_spec.rb +438 -0
  80. data/spec/adhearsion/calls_spec.rb +47 -0
  81. data/spec/adhearsion/configuration_spec.rb +308 -0
  82. data/spec/adhearsion/dialplan_controller_spec.rb +26 -0
  83. data/spec/adhearsion/events_spec.rb +112 -0
  84. data/spec/adhearsion/initializer/logging_spec.rb +58 -0
  85. data/spec/adhearsion/initializer_spec.rb +209 -122
  86. data/spec/adhearsion/logging_spec.rb +58 -47
  87. data/spec/adhearsion/menu_dsl/calculated_match_collection_spec.rb +56 -0
  88. data/spec/adhearsion/menu_dsl/calculated_match_spec.rb +57 -0
  89. data/spec/adhearsion/menu_dsl/fixnum_match_calculator_spec.rb +33 -0
  90. data/spec/adhearsion/menu_dsl/match_calculator_spec.rb +13 -0
  91. data/spec/adhearsion/menu_dsl/menu_builder_spec.rb +118 -0
  92. data/spec/adhearsion/menu_dsl/menu_spec.rb +210 -0
  93. data/spec/adhearsion/menu_dsl/range_match_calculator_spec.rb +28 -0
  94. data/spec/adhearsion/menu_dsl/string_match_calculator_spec.rb +36 -0
  95. data/spec/adhearsion/menu_dsl_spec.rb +12 -0
  96. data/spec/adhearsion/outbound_call_spec.rb +174 -0
  97. data/spec/adhearsion/plugin_spec.rb +489 -0
  98. data/spec/adhearsion/process_spec.rb +34 -0
  99. data/spec/adhearsion/punchblock_plugin/initializer_spec.rb +294 -0
  100. data/spec/adhearsion/router/route_spec.rb +99 -0
  101. data/spec/adhearsion/router_spec.rb +106 -0
  102. data/spec/adhearsion_spec.rb +46 -0
  103. data/spec/spec_helper.rb +14 -14
  104. data/spec/support/call_controller_test_helpers.rb +48 -0
  105. data/spec/support/initializer_stubs.rb +8 -13
  106. data/spec/support/punchblock_mocks.rb +6 -0
  107. metadata +255 -253
  108. data/CHANGELOG +0 -174
  109. data/bin/ahnctl +0 -68
  110. data/bin/jahn +0 -43
  111. data/examples/asterisk_manager_interface/standalone.rb +0 -51
  112. data/lib/adhearsion/commands.rb +0 -302
  113. data/lib/adhearsion/component_manager.rb +0 -278
  114. data/lib/adhearsion/component_manager/component_tester.rb +0 -54
  115. data/lib/adhearsion/component_manager/spec_framework.rb +0 -18
  116. data/lib/adhearsion/events_support.rb +0 -65
  117. data/lib/adhearsion/foundation/blank_slate.rb +0 -3
  118. data/lib/adhearsion/foundation/event_socket.rb +0 -205
  119. data/lib/adhearsion/foundation/future_resource.rb +0 -36
  120. data/lib/adhearsion/foundation/metaprogramming.rb +0 -17
  121. data/lib/adhearsion/foundation/numeric.rb +0 -13
  122. data/lib/adhearsion/foundation/pseudo_guid.rb +0 -10
  123. data/lib/adhearsion/foundation/relationship_properties.rb +0 -42
  124. data/lib/adhearsion/foundation/string.rb +0 -26
  125. data/lib/adhearsion/generators/app/templates/.ahnrc +0 -34
  126. data/lib/adhearsion/generators/app/templates/README +0 -8
  127. data/lib/adhearsion/generators/app/templates/components/ami_remote/ami_remote.rb +0 -15
  128. data/lib/adhearsion/generators/app/templates/components/disabled/HOW_TO_ENABLE +0 -7
  129. data/lib/adhearsion/generators/app/templates/components/disabled/stomp_gateway/README.markdown +0 -47
  130. data/lib/adhearsion/generators/app/templates/components/disabled/stomp_gateway/stomp_gateway.rb +0 -34
  131. data/lib/adhearsion/generators/app/templates/components/disabled/stomp_gateway/stomp_gateway.yml +0 -12
  132. data/lib/adhearsion/generators/app/templates/components/disabled/xmpp_gateway/README.markdown +0 -3
  133. data/lib/adhearsion/generators/app/templates/components/disabled/xmpp_gateway/xmpp_gateway.rb +0 -11
  134. data/lib/adhearsion/generators/app/templates/components/disabled/xmpp_gateway/xmpp_gateway.yml +0 -0
  135. data/lib/adhearsion/generators/app/templates/config/startup.rb +0 -81
  136. data/lib/adhearsion/generators/app/templates/dialplan.rb +0 -3
  137. data/lib/adhearsion/generators/app/templates/events.rb +0 -33
  138. data/lib/adhearsion/host_definitions.rb +0 -67
  139. data/lib/adhearsion/initializer/asterisk.rb +0 -86
  140. data/lib/adhearsion/initializer/configuration.rb +0 -324
  141. data/lib/adhearsion/initializer/database.rb +0 -60
  142. data/lib/adhearsion/initializer/drb.rb +0 -31
  143. data/lib/adhearsion/initializer/freeswitch.rb +0 -22
  144. data/lib/adhearsion/initializer/ldap.rb +0 -57
  145. data/lib/adhearsion/initializer/rails.rb +0 -41
  146. data/lib/adhearsion/initializer/xmpp.rb +0 -42
  147. data/lib/adhearsion/tasks/components.rb +0 -32
  148. data/lib/adhearsion/tasks/database.rb +0 -5
  149. data/lib/adhearsion/tasks/deprecations.rb +0 -59
  150. data/lib/adhearsion/tasks/generating.rb +0 -20
  151. data/lib/adhearsion/tasks/lint.rb +0 -4
  152. data/lib/adhearsion/voip/asterisk.rb +0 -4
  153. data/lib/adhearsion/voip/asterisk/agi_server.rb +0 -121
  154. data/lib/adhearsion/voip/asterisk/commands.rb +0 -1966
  155. data/lib/adhearsion/voip/asterisk/config_generators/agents.conf.rb +0 -140
  156. data/lib/adhearsion/voip/asterisk/config_generators/config_generator.rb +0 -102
  157. data/lib/adhearsion/voip/asterisk/config_generators/queues.conf.rb +0 -250
  158. data/lib/adhearsion/voip/asterisk/config_generators/voicemail.conf.rb +0 -240
  159. data/lib/adhearsion/voip/asterisk/config_manager.rb +0 -64
  160. data/lib/adhearsion/voip/asterisk/manager_interface.rb +0 -697
  161. data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rb +0 -1681
  162. data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rl.rb +0 -341
  163. data/lib/adhearsion/voip/asterisk/manager_interface/ami_messages.rb +0 -78
  164. data/lib/adhearsion/voip/asterisk/manager_interface/ami_protocol_lexer_machine.rl +0 -87
  165. data/lib/adhearsion/voip/asterisk/special_dial_plan_managers.rb +0 -80
  166. data/lib/adhearsion/voip/call.rb +0 -521
  167. data/lib/adhearsion/voip/call_routing.rb +0 -64
  168. data/lib/adhearsion/voip/commands.rb +0 -17
  169. data/lib/adhearsion/voip/constants.rb +0 -39
  170. data/lib/adhearsion/voip/conveniences.rb +0 -18
  171. data/lib/adhearsion/voip/dial_plan.rb +0 -252
  172. data/lib/adhearsion/voip/dsl/dialing_dsl.rb +0 -151
  173. data/lib/adhearsion/voip/dsl/dialing_dsl/dialing_dsl_monkey_patches.rb +0 -37
  174. data/lib/adhearsion/voip/dsl/dialplan/control_passing_exception.rb +0 -27
  175. data/lib/adhearsion/voip/dsl/dialplan/dispatcher.rb +0 -124
  176. data/lib/adhearsion/voip/dsl/dialplan/parser.rb +0 -69
  177. data/lib/adhearsion/voip/dsl/dialplan/thread_mixin.rb +0 -16
  178. data/lib/adhearsion/voip/dsl/numerical_string.rb +0 -128
  179. data/lib/adhearsion/voip/freeswitch/basic_connection_manager.rb +0 -48
  180. data/lib/adhearsion/voip/freeswitch/event_handler.rb +0 -58
  181. data/lib/adhearsion/voip/freeswitch/freeswitch_dialplan_command_factory.rb +0 -129
  182. data/lib/adhearsion/voip/freeswitch/inbound_connection_manager.rb +0 -38
  183. data/lib/adhearsion/voip/freeswitch/oes_server.rb +0 -195
  184. data/lib/adhearsion/voip/menu_state_machine/calculated_match.rb +0 -80
  185. data/lib/adhearsion/voip/menu_state_machine/matchers.rb +0 -123
  186. data/lib/adhearsion/voip/menu_state_machine/menu_builder.rb +0 -57
  187. data/lib/adhearsion/xmpp/connection.rb +0 -61
  188. data/lib/theatre.rb +0 -147
  189. data/lib/theatre/README.markdown +0 -64
  190. data/lib/theatre/callback_definition_loader.rb +0 -86
  191. data/lib/theatre/guid.rb +0 -23
  192. data/lib/theatre/invocation.rb +0 -131
  193. data/lib/theatre/namespace_manager.rb +0 -153
  194. data/lib/theatre/version.rb +0 -2
  195. data/spec/adhearsion/cli_spec.rb +0 -306
  196. data/spec/adhearsion/component_manager_spec.rb +0 -292
  197. data/spec/adhearsion/constants_spec.rb +0 -8
  198. data/spec/adhearsion/drb_spec.rb +0 -65
  199. data/spec/adhearsion/fixtures/dialplan.rb +0 -3
  200. data/spec/adhearsion/foundation/event_socket_spec.rb +0 -168
  201. data/spec/adhearsion/host_definitions_spec.rb +0 -79
  202. data/spec/adhearsion/initializer/configuration_spec.rb +0 -291
  203. data/spec/adhearsion/initializer/loading_spec.rb +0 -154
  204. data/spec/adhearsion/initializer/paths_spec.rb +0 -74
  205. data/spec/adhearsion/relationship_properties_spec.rb +0 -54
  206. data/spec/adhearsion/voip/asterisk/agi_server_spec.rb +0 -473
  207. data/spec/adhearsion/voip/asterisk/ami/ami_spec.rb +0 -550
  208. data/spec/adhearsion/voip/asterisk/ami/lexer/ami_fixtures.yml +0 -30
  209. data/spec/adhearsion/voip/asterisk/ami/lexer/lexer_story +0 -291
  210. data/spec/adhearsion/voip/asterisk/ami/lexer/lexer_story.rb +0 -241
  211. data/spec/adhearsion/voip/asterisk/ami/lexer/story_helper.rb +0 -124
  212. data/spec/adhearsion/voip/asterisk/commands_spec.rb +0 -3241
  213. data/spec/adhearsion/voip/asterisk/config_file_generators/agents_spec.rb +0 -251
  214. data/spec/adhearsion/voip/asterisk/config_file_generators/queues_spec.rb +0 -323
  215. data/spec/adhearsion/voip/asterisk/config_file_generators/voicemail_spec.rb +0 -306
  216. data/spec/adhearsion/voip/asterisk/config_manager_spec.rb +0 -127
  217. data/spec/adhearsion/voip/asterisk/menu_command/calculated_match_spec.rb +0 -109
  218. data/spec/adhearsion/voip/asterisk/menu_command/matchers_spec.rb +0 -97
  219. data/spec/adhearsion/voip/call_routing_spec.rb +0 -125
  220. data/spec/adhearsion/voip/dialplan_manager_spec.rb +0 -468
  221. data/spec/adhearsion/voip/dsl/dialing_dsl_spec.rb +0 -270
  222. data/spec/adhearsion/voip/dsl/dispatcher_spec.rb +0 -82
  223. data/spec/adhearsion/voip/dsl/dispatcher_spec_helper.rb +0 -45
  224. data/spec/adhearsion/voip/dsl/parser_spec.rb +0 -69
  225. data/spec/adhearsion/voip/freeswitch/basic_connection_manager_spec.rb +0 -39
  226. data/spec/adhearsion/voip/freeswitch/inbound_connection_manager_spec.rb +0 -39
  227. data/spec/adhearsion/voip/freeswitch/oes_server_spec.rb +0 -9
  228. data/spec/adhearsion/voip/numerical_string_spec.rb +0 -61
  229. data/spec/adhearsion/voip/phone_number_spec.rb +0 -45
  230. data/spec/support/the_following_code.rb +0 -3
  231. data/spec/theatre/dsl_examples/simple_before_call.rb +0 -7
  232. data/spec/theatre/dsl_spec.rb +0 -69
  233. data/spec/theatre/invocation_spec.rb +0 -182
  234. data/spec/theatre/namespace_spec.rb +0 -125
  235. data/spec/theatre/spec_helper_spec.rb +0 -28
  236. data/spec/theatre/theatre_class_spec.rb +0 -148
@@ -0,0 +1,125 @@
1
+ require 'spec_helper'
2
+
3
+ module Adhearsion
4
+ class CallController
5
+ describe Record do
6
+ include CallControllerTestHelpers
7
+
8
+ describe "#record" do
9
+ let(:options) do
10
+ {
11
+ :start_beep => true,
12
+ :max_duration => 5000
13
+ }
14
+ end
15
+ let(:component) { Punchblock::Component::Record.new options }
16
+ let(:response) { Punchblock::Event::Complete.new }
17
+
18
+ describe "with :async => true and an :on_complete callback" do
19
+ let(:callback) { lambda { |rec| @rec.push rec } }
20
+
21
+ before do
22
+ expect_component_execution_asynchronously component
23
+ @rec = Queue.new
24
+ options.merge! :async => true, :on_complete => callback
25
+ subject.record options
26
+ component.request!
27
+ component.execute!
28
+ end
29
+
30
+ it "should execute the callback" do
31
+ component.trigger_event_handler response
32
+ Timeout::timeout 5 do
33
+ @rec.pop.should == response
34
+ end
35
+ end
36
+
37
+ describe "when the callback raises an exception" do
38
+ before { TestException = Class.new StandardError }
39
+ let(:callback) { lambda { |rec| raise TestException } }
40
+
41
+ it "should pass the exception to the events system" do
42
+ flexmock(Events).should_receive(:trigger).once.with(:exception, TestException)
43
+ component.trigger_event_handler response
44
+ end
45
+ end
46
+ end
47
+
48
+ describe "with :async => false" do
49
+ before do
50
+ expect_component_execution component
51
+ component.request!
52
+ component.execute!
53
+ component.add_event response
54
+ @rec = Queue.new
55
+ subject.record(options.merge(:async => false)) { |rec| @rec.push rec }
56
+ end
57
+
58
+ it 'should execute a passed block' do
59
+ Timeout::timeout 5 do
60
+ @rec.pop.should == response
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ describe "#record with default options" do
67
+ let(:options) {{
68
+ :start_beep => true,
69
+ :format => 'mp3',
70
+ :start_paused => false,
71
+ :stop_beep => true,
72
+ :max_duration => 500000,
73
+ :initial_timeout => 10000,
74
+ :final_timeout => 30000
75
+ }}
76
+
77
+ let(:component) { Punchblock::Component::Record.new(options) }
78
+ let(:response) { Punchblock::Event::Complete.new }
79
+
80
+ before do
81
+ expect_message_waiting_for_response component
82
+ component.execute!
83
+ component.complete_event = response
84
+ end
85
+
86
+ it 'executes a #record with the correct options' do
87
+ subject.execute_component_and_await_completion component
88
+ end
89
+
90
+ it 'takes a block which is executed after acknowledgement but before waiting on completion' do
91
+ @comp = nil
92
+ subject.execute_component_and_await_completion(component) { |comp| @comp = comp }.should == component
93
+ @comp.should == component
94
+ end
95
+
96
+ describe "with a successful completion" do
97
+ it 'returns the executed component' do
98
+ subject.execute_component_and_await_completion(component).should be component
99
+ end
100
+ end
101
+
102
+ describe 'with an error response' do
103
+ let(:response) do
104
+ Punchblock::Event::Complete.new.tap do |complete|
105
+ complete << error
106
+ end
107
+ end
108
+
109
+ let(:error) do |error|
110
+ Punchblock::Event::Complete::Error.new.tap do |error|
111
+ error << details
112
+ end
113
+ end
114
+
115
+ let(:details) { "Something came up" }
116
+
117
+ it 'raises the error' do
118
+ lambda { subject.execute_component_and_await_completion component }.should raise_error(StandardError, details)
119
+ end
120
+ end
121
+ end
122
+
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,395 @@
1
+ require 'spec_helper'
2
+
3
+ module Adhearsion
4
+ describe CallController do
5
+ include CallControllerTestHelpers
6
+
7
+ let(:call) { Adhearsion::Call.new mock_offer(nil, :x_foo => 'bar') }
8
+
9
+ its(:call) { should be call }
10
+ its(:metadata) { should == {:doo => :dah} }
11
+
12
+ describe "setting meta-data" do
13
+ it "should preserve data correctly" do
14
+ subject[:foo].should be nil
15
+ subject[:foo] = 7
16
+ subject[:foo].should == 7
17
+ subject[:bar] = 10
18
+ subject[:bar].should == 10
19
+ subject[:foo].should == 7
20
+ end
21
+ end
22
+
23
+ it "should add plugin dialplan methods" do
24
+ subject.should respond_to :foo
25
+ end
26
+
27
+ its(:logger) { should be call.logger }
28
+ its(:variables) { should be call.variables }
29
+
30
+ describe "execution on a call" do
31
+ before do
32
+ flexmock subject, :execute_component_and_await_completion => nil
33
+ flexmock call, :write_and_await_response => nil
34
+ end
35
+
36
+ context "when auto-accept is enabled" do
37
+ before do
38
+ Adhearsion.config.platform.automatically_accept_incoming_calls = true
39
+ end
40
+
41
+ it "should accept the call" do
42
+ subject.should_receive(:accept).once.ordered
43
+ subject.should_receive(:run).once.ordered
44
+ subject.execute!
45
+ end
46
+
47
+ context "and accept is skipped" do
48
+ before { subject.skip_accept! }
49
+
50
+ it "should not accept the call" do
51
+ subject.should_receive(:accept).never
52
+ subject.should_receive(:run).once
53
+ subject.execute!
54
+ end
55
+ end
56
+ end
57
+
58
+ context "when auto-accept is disabled" do
59
+ before do
60
+ Adhearsion.config.platform.automatically_accept_incoming_calls = false
61
+ end
62
+
63
+ it "should not accept the call" do
64
+ subject.should_receive(:accept).never
65
+ subject.should_receive(:run).once
66
+ subject.execute!
67
+ end
68
+ end
69
+
70
+ it "catches Hangup exceptions and logs the hangup" do
71
+ subject.should_receive(:run).once.and_raise(Hangup).ordered
72
+ flexmock(subject.logger).should_receive(:info).once.with(/Call was hung up/).ordered
73
+ subject.execute!
74
+ end
75
+
76
+ it "catches standard errors, triggering an exception event" do
77
+ subject.should_receive(:run).once.and_raise(StandardError).ordered
78
+ flexmock(Events).should_receive(:trigger).once.with(:exception, StandardError).ordered
79
+ subject.execute!
80
+ end
81
+ end
82
+
83
+ class SecondController < CallController
84
+ def run
85
+ md_check metadata
86
+ answer
87
+ end
88
+
89
+ def md_check(md)
90
+ end
91
+ end
92
+
93
+ class SecondControllerWithRemoteHangup < SecondController
94
+ def run
95
+ super
96
+ simulate_remote_hangup
97
+ end
98
+
99
+ def simulate_remote_hangup
100
+ raise Hangup
101
+ end
102
+ end
103
+
104
+ describe "#invoke" do
105
+ class InvokeController < CallController
106
+ def run
107
+ before
108
+ invoke second_controller, :foo => 'bar'
109
+ after
110
+ end
111
+
112
+ def before
113
+ end
114
+
115
+ def after
116
+ end
117
+
118
+ def second_controller
119
+ metadata[:second_controller] || SecondController
120
+ end
121
+ end
122
+
123
+ subject { InvokeController.new call }
124
+
125
+ before do
126
+ flexmock subject, :execute_component_and_await_completion => nil
127
+ flexmock call, :write_and_await_response => nil
128
+ flexmock(Events).should_receive(:trigger).with(:exception, Exception).never
129
+ Adhearsion.config.platform.automatically_accept_incoming_calls = true
130
+ end
131
+
132
+ it "should invoke another controller before returning to the current controller" do
133
+ subject.should_receive(:before).once.ordered
134
+ call.should_receive(:answer).once.ordered
135
+ subject.should_receive(:after).once.ordered
136
+
137
+ subject.execute!
138
+ end
139
+
140
+ it "should invoke the new controller with metadata" do
141
+ flexmock(SecondController).new_instances.should_receive(:md_check).once.with :foo => 'bar'
142
+ subject.execute!
143
+ end
144
+
145
+ it "should not attempt to accept the call again" do
146
+ call.should_receive(:accept).once
147
+
148
+ subject.execute!
149
+ end
150
+
151
+ it "should allow the outer controller to cease execution and handle remote hangups" do
152
+ subject[:second_controller] = SecondControllerWithRemoteHangup
153
+
154
+ subject.should_receive(:before).once.ordered
155
+ call.should_receive(:answer).once.ordered
156
+ subject.should_receive(:after).never.ordered
157
+
158
+ subject.execute!
159
+ end
160
+ end
161
+
162
+ describe "#pass" do
163
+ class PassController < CallController
164
+ after_call :foobar
165
+
166
+ def run
167
+ before
168
+ pass SecondController, :foo => 'bar'
169
+ after
170
+ end
171
+
172
+ def before
173
+ end
174
+
175
+ def after
176
+ end
177
+
178
+ def foobar
179
+ end
180
+ end
181
+
182
+ subject { PassController.new call }
183
+
184
+ before do
185
+ flexmock(call).should_receive(:write_and_await_response).and_return nil
186
+ flexmock subject, :execute_component_and_await_completion => nil
187
+ flexmock(SecondController).new_instances.should_receive(:md_check).once.with :foo => 'bar'
188
+ flexmock(Events).should_receive(:trigger).with(:exception, Exception).never
189
+ Adhearsion.config.platform.automatically_accept_incoming_calls = true
190
+ end
191
+
192
+ let(:latch) { CountDownLatch.new 1 }
193
+
194
+ it "should cease execution of the current controller, and instruct the call to execute another" do
195
+ subject.should_receive(:before).once.ordered
196
+ call.should_receive(:answer).once.ordered
197
+ subject.should_receive(:after).never.ordered
198
+ call.should_receive(:hangup!).once.ordered
199
+
200
+ call.execute_controller subject, latch
201
+ latch.wait(1).should be_true
202
+ end
203
+
204
+ it "should not attempt to accept the call again" do
205
+ call.should_receive(:accept).once
206
+
207
+ CallController.exec subject
208
+ end
209
+
210
+ it "should execute after_call callbacks before passing control" do
211
+ subject.should_receive(:before).once.ordered
212
+ subject.should_receive(:foobar).once.ordered
213
+ call.should_receive(:answer).once.ordered
214
+
215
+ CallController.exec subject
216
+ end
217
+ end
218
+
219
+ describe '#write_and_await_response' do
220
+ let(:message) { Punchblock::Command::Accept.new }
221
+
222
+ it "delegates to the call" do
223
+ flexmock(subject.call).should_receive(:write_and_await_response).once.with(message, 20)
224
+ subject.write_and_await_response message, 20
225
+ end
226
+ end
227
+
228
+ describe "#execute_component_and_await_completion" do
229
+ let(:component) { Punchblock::Component::Output.new }
230
+ let(:response) { Punchblock::Event::Complete.new }
231
+
232
+ before do
233
+ expect_message_waiting_for_response component
234
+ component.execute!
235
+ component.complete_event = response
236
+ end
237
+
238
+ it "writes component to the server and waits on response" do
239
+ subject.execute_component_and_await_completion component
240
+ end
241
+
242
+ it "takes a block which is executed after acknowledgement but before waiting on completion" do
243
+ @comp = nil
244
+ subject.execute_component_and_await_completion(component) { |comp| @comp = comp }.should == component
245
+ @comp.should == component
246
+ end
247
+
248
+ describe "with a successful completion" do
249
+ it "returns the executed component" do
250
+ subject.execute_component_and_await_completion(component).should be component
251
+ end
252
+ end
253
+
254
+ describe "with an error response" do
255
+ let(:response) do
256
+ Punchblock::Event::Complete.new.tap do |complete|
257
+ complete << error
258
+ end
259
+ end
260
+
261
+ let(:error) do |error|
262
+ Punchblock::Event::Complete::Error.new.tap do |error|
263
+ error << details
264
+ end
265
+ end
266
+
267
+ let(:details) { "Oh noes, it's all borked" }
268
+
269
+ it "raises the error" do
270
+ lambda { subject.execute_component_and_await_completion component }.should raise_error(StandardError, details)
271
+ end
272
+ end
273
+
274
+ it "blocks until the component receives a complete event" do
275
+ slow_component = Punchblock::Component::Output.new
276
+ Thread.new do
277
+ sleep 0.5
278
+ slow_component.complete_event = response
279
+ end
280
+ starting_time = Time.now
281
+ subject.execute_component_and_await_completion slow_component
282
+ (Time.now - starting_time).should > 0.5
283
+ end
284
+ end
285
+
286
+ describe '#accept' do
287
+ it "should delegate to the call" do
288
+ flexmock(subject.call).should_receive(:accept).once.with(:foo)
289
+ subject.accept :foo
290
+ end
291
+ end
292
+
293
+ describe '#answer' do
294
+ it "should delegate to the call" do
295
+ flexmock(subject.call).should_receive(:answer).once.with(:foo)
296
+ subject.answer :foo
297
+ end
298
+ end
299
+
300
+ describe '#reject' do
301
+ it "should delegate to the call" do
302
+ flexmock(subject.call).should_receive(:reject).once.with(:foo, :bar)
303
+ subject.reject :foo, :bar
304
+ end
305
+ end
306
+
307
+ describe '#hangup' do
308
+ it "should delegate to the call" do
309
+ flexmock(subject.call).should_receive(:hangup!).once.with(:foo)
310
+ subject.hangup :foo
311
+ end
312
+ end
313
+
314
+ describe '#mute' do
315
+ it 'should send a Mute message' do
316
+ expect_message_waiting_for_response Punchblock::Command::Mute.new
317
+ subject.mute
318
+ end
319
+ end
320
+
321
+ describe '#unmute' do
322
+ it 'should send an Unmute message' do
323
+ expect_message_waiting_for_response Punchblock::Command::Unmute.new
324
+ subject.unmute
325
+ end
326
+ end
327
+ end
328
+ end
329
+
330
+ class ExampleCallController < Adhearsion::CallController
331
+ before_call { setup_models }
332
+ before_call :setup_models
333
+
334
+ after_call { clean_up_models }
335
+ after_call :clean_up_models
336
+
337
+ def setup_models
338
+ end
339
+
340
+ def clean_up_models
341
+ end
342
+
343
+ def run
344
+ join_to_conference
345
+ hangup unless metadata[:skip_hangup]
346
+ foobar
347
+ end
348
+
349
+ def join_to_conference
350
+ end
351
+
352
+ def foobar
353
+ end
354
+ end
355
+
356
+ describe ExampleCallController do
357
+ include CallControllerTestHelpers
358
+
359
+ before do
360
+ flexmock subject, :execute_component_and_await_completion => nil
361
+ flexmock call, :write_and_await_response => nil
362
+ Adhearsion.config.platform.automatically_accept_incoming_calls = true
363
+ end
364
+
365
+ it "should execute the before_call callbacks before accepting the call" do
366
+ subject.should_receive(:setup_models).twice.ordered
367
+ subject.should_receive(:accept).once.ordered
368
+ subject.should_receive(:join_to_conference).once.ordered
369
+ subject.execute!
370
+ end
371
+
372
+ it "should execute the after_call callbacks after the call is hung up" do
373
+ subject.should_receive(:join_to_conference).once.ordered
374
+ subject.should_receive(:clean_up_models).twice.ordered
375
+ subject.should_receive(:foobar).once.ordered
376
+ subject.execute!
377
+ end
378
+
379
+ it "should capture errors in callbacks" do
380
+ subject.should_receive(:setup_models).and_raise StandardError
381
+ subject.should_receive(:clean_up_models).and_raise StandardError
382
+ flexmock(Adhearsion::Events).should_receive(:trigger).times(4).with :exception, StandardError
383
+ subject.execute!
384
+ end
385
+
386
+ context "when the controller finishes without a hangup" do
387
+ it "should execute the after_call callbacks" do
388
+ subject[:skip_hangup] = true
389
+ subject.should_receive(:join_to_conference).once.ordered
390
+ subject.should_receive(:foobar).once.ordered
391
+ subject.should_receive(:clean_up_models).twice.ordered
392
+ subject.execute!
393
+ end
394
+ end
395
+ end