adhearsion 1.2.6 → 2.0.0.alpha1

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