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,26 @@
1
+ require 'adhearsion/punchblock_plugin'
2
+
3
+ begin
4
+ Adhearsion.config # load default config vlaues
5
+ require "#{Dir.pwd}/config/adhearsion.rb"
6
+ rescue Exception => ex
7
+ STDERR.puts "\nError while loading application configuration file: #{ex}"
8
+ end
9
+
10
+ namespace :adhearsion do
11
+
12
+ namespace :config do
13
+
14
+ desc "Show configuration values in STDOUT; it accepts a parameter: [nil|platform|<plugin-name>|all]"
15
+ task :show, :name do |t, args|
16
+ name = args.name.nil? ? :all : args.name.to_sym
17
+ puts Adhearsion.config.description name, :show_values => true
18
+ end
19
+
20
+ desc "Show configuration description in STDOUT; it accepts a parameter: [nil|platform|<plugin-name>|all]"
21
+ task :desc, :name do |t, args|
22
+ name = args.name.nil? ? :all : args.name.to_sym
23
+ puts Adhearsion.config.description name, :show_values => false
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,17 @@
1
+ require 'adhearsion/punchblock_plugin'
2
+
3
+ namespace :adhearsion do
4
+
5
+ desc "List the configured plugins"
6
+ task :plugins do |t,args|
7
+ if Adhearsion::Plugin.subclasses.length > 0
8
+ puts "You have #{Adhearsion::Plugin.subclasses.length} plugin(s) in your Adhearsion application:\n"
9
+ Adhearsion::Plugin.subclasses.each do |plugin|
10
+ puts "* #{plugin.plugin_name}: #{plugin.name}"
11
+ end
12
+ else
13
+ puts "There is no Adhearsion plugin used in your application"
14
+ end
15
+ puts "\n"
16
+ end
17
+ end
@@ -1,36 +1,30 @@
1
1
  module Adhearsion #:nodoc:
2
- module VERSION #:nodoc:
3
- MAJOR = 1 unless defined? MAJOR
4
- MINOR = 2 unless defined? MINOR
5
- TINY = 6 unless defined? TINY
6
-
7
- STRING = [MAJOR, MINOR, TINY].join('.') unless defined? STRING
8
- end
2
+ VERSION = '2.0.0.alpha1'
9
3
 
10
4
  class PkgVersion
11
5
  include Comparable
12
6
 
13
7
  attr_reader :major, :minor, :revision
14
8
 
15
- def initialize(version="")
16
- version = "" if version.nil?
9
+ def initialize(version = nil)
10
+ version ||= ""
17
11
  @major, @minor, @revision, @patchlevel = version.split(".", 4).map(&:to_i)
18
12
  @major = 0 unless @major
19
13
  end
20
14
 
21
15
  def <=>(other)
22
- return @major <=> other.major if ((@major <=> other.major) != 0)
23
- return @minor <=> other.minor if ((@minor <=> other.minor) != 0)
24
- return @revision <=> other.revision if ((@revision <=> other.revision) != 0)
16
+ return @major <=> other.major unless (@major <=> other.major) == 0
17
+ return @minor <=> other.minor unless (@minor <=> other.minor) == 0
18
+ return @revision <=> other.revision unless (@revision <=> other.revision) == 0
25
19
  return 0
26
20
  end
27
21
 
28
22
  def self.sort
29
- self.sort!{|a,b| a <=> b}
23
+ self.sort! { |a,b| a <=> b }
30
24
  end
31
25
 
32
26
  def to_s
33
- @major.to_s + "." + @minor.to_s + "." + @revision.to_s
27
+ "#{@major}.#{@minor}.#{@revision}"
34
28
  end
35
29
  end
36
30
  end
@@ -0,0 +1,138 @@
1
+ require 'spec_helper'
2
+
3
+ module Adhearsion
4
+ class CallController
5
+ describe Dial do
6
+ include CallControllerTestHelpers
7
+
8
+ let(:to) { 'sip:foo@bar.com' }
9
+
10
+ let(:other_call_id) { rand }
11
+ let(:other_mock_call) { flexmock OutboundCall.new, :id => other_call_id }
12
+
13
+ let(:mock_end) { flexmock Punchblock::Event::End.new, :reason => :hangup }
14
+ let(:mock_answered) { Punchblock::Event::Answered.new }
15
+
16
+ #added for multiple dial testing
17
+ let(:second_to) { 'sip:baz@bar.com' }
18
+ let(:second_other_call_id) { rand }
19
+ let(:second_other_mock_call) { flexmock OutboundCall.new, :id => second_other_call_id }
20
+
21
+ def mock_dial
22
+ flexmock(OutboundCall).new_instances.should_receive(:dial).and_return true
23
+ end
24
+
25
+ describe "#dial" do
26
+ it "should create a new call and return it" do
27
+ mock_dial
28
+ Thread.new do
29
+ subject.dial(to).should be_a OutboundCall
30
+ end
31
+ other_mock_call << mock_end
32
+ end
33
+
34
+ it "should dial the call to the correct endpoint" do
35
+ other_mock_call
36
+ flexmock(OutboundCall).should_receive(:new).and_return other_mock_call
37
+ flexmock(other_mock_call).should_receive(:dial).with(to, :from => 'foo').once
38
+ dial_thread = Thread.new do
39
+ subject.dial to, :from => 'foo'
40
+ end
41
+ sleep 0.1
42
+ other_mock_call << mock_end
43
+ dial_thread.join.should be_true
44
+ end
45
+
46
+ describe "without a block" do
47
+ it "blocks the original dialplan until the new call ends" do
48
+ other_mock_call
49
+
50
+ flexmock(other_mock_call).should_receive(:dial).once
51
+ flexmock(OutboundCall).should_receive(:new).and_return other_mock_call
52
+
53
+ latch = CountDownLatch.new 1
54
+
55
+ Thread.new do
56
+ subject.dial to
57
+ latch.countdown!
58
+ end
59
+
60
+ latch.wait(1).should be_false
61
+
62
+ other_mock_call << mock_end
63
+
64
+ latch.wait(1).should be_true
65
+ end
66
+
67
+ it "joins the new call to the existing one on answer" do
68
+ other_mock_call
69
+
70
+ flexmock(other_mock_call).should_receive(:dial).once
71
+ flexmock(other_mock_call).should_receive(:join).once.with(call_id)
72
+ flexmock(OutboundCall).should_receive(:new).and_return other_mock_call
73
+
74
+ latch = CountDownLatch.new 1
75
+
76
+ Thread.new do
77
+ subject.dial to
78
+ latch.countdown!
79
+ end
80
+
81
+ latch.wait(1).should be_false
82
+
83
+ other_mock_call << mock_answered
84
+ other_mock_call << mock_end
85
+
86
+ latch.wait(1).should be_true
87
+ end
88
+ end
89
+
90
+ describe "with multiple third parties specified" do
91
+ it "dials all parties and joins the first one to answer, hanging up the rest" do
92
+ other_mock_call
93
+ second_other_mock_call
94
+
95
+ flexmock(other_mock_call).should_receive(:dial).once
96
+ flexmock(other_mock_call).should_receive(:join).once.with(call_id)
97
+ flexmock(other_mock_call).should_receive(:hangup!).never
98
+
99
+ flexmock(second_other_mock_call).should_receive(:dial).once
100
+ flexmock(second_other_mock_call).should_receive(:hangup!).once
101
+
102
+
103
+ flexmock(OutboundCall).should_receive(:new).and_return other_mock_call, second_other_mock_call
104
+ latch = CountDownLatch.new 1
105
+
106
+ Thread.new do
107
+ subject.dial [to, second_to]
108
+ latch.countdown!
109
+ end
110
+
111
+ latch.wait(1).should be_false
112
+
113
+ other_mock_call << mock_answered
114
+ other_mock_call << mock_end
115
+
116
+ latch.wait(1).should be_true
117
+ end
118
+ end
119
+
120
+ describe "with a timeout specified" do
121
+ it "should abort the dial after the specified timeout"
122
+ end
123
+
124
+ describe "with a from specified" do
125
+ it "originates the call from the specified caller ID"
126
+ end
127
+
128
+ describe "with a block" do
129
+ it "uses the block as the dialplan for the new call"
130
+
131
+ it "joins the new call to the existing call once the block returns"
132
+
133
+ it "does not try to join the calls if the new call is hungup when the block returns"
134
+ end
135
+ end#describe #dial
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,278 @@
1
+ require 'spec_helper'
2
+
3
+ module Adhearsion
4
+ class CallController
5
+ describe Input do
6
+ include CallControllerTestHelpers
7
+
8
+ describe "#grammar_digits" do
9
+ let(:grxml) {
10
+ RubySpeech::GRXML.draw :mode => 'dtmf', :root => 'inputdigits' do
11
+ rule id: 'inputdigits', scope: 'public' do
12
+ item repeat: '2' do
13
+ one_of do
14
+ 0.upto(9) { |d| item { d.to_s } }
15
+ end
16
+ end
17
+ end
18
+ end
19
+ }
20
+
21
+ it 'generates the correct GRXML grammar' do
22
+ subject.grammar_digits(2).to_s.should == grxml.to_s
23
+ end
24
+
25
+ end # describe #grammar_digits
26
+
27
+ describe "#grammar_accept" do
28
+ let(:grxml) {
29
+ RubySpeech::GRXML.draw :mode => 'dtmf', :root => 'inputdigits' do
30
+ rule id: 'inputdigits', scope: 'public' do
31
+ one_of do
32
+ item { '3' }
33
+ item { '5' }
34
+ end
35
+ end
36
+ end
37
+ }
38
+
39
+ it 'generates the correct GRXML grammar' do
40
+ subject.grammar_accept('35').to_s.should == grxml.to_s
41
+ end
42
+
43
+ it 'filters meaningless characters out' do
44
+ subject.grammar_accept('3+5').to_s.should == grxml.to_s
45
+ end
46
+ end # grammar_accept
47
+
48
+ describe "#parse_single_dtmf" do
49
+ it "correctly returns the parsed input" do
50
+ subject.parse_single_dtmf("dtmf-3").should == '3'
51
+ end
52
+
53
+ it "correctly returns star as *" do
54
+ subject.parse_single_dtmf("dtmf-star").should == '*'
55
+ end
56
+
57
+ it "correctly returns pound as #" do
58
+ subject.parse_single_dtmf("dtmf-pound").should == '#'
59
+ end
60
+
61
+ it "correctly returns nil when input is nil" do
62
+ subject.parse_single_dtmf(nil).should == nil
63
+ end
64
+ end # describe #grammar_accept
65
+
66
+ describe "#wait_for_digit" do
67
+ let(:timeout) { 2 }
68
+ let(:timeout_ms) { 2000 }
69
+
70
+ let(:grxml) {
71
+ RubySpeech::GRXML.draw :mode => 'dtmf', :root => 'inputdigits' do
72
+ rule id: 'inputdigits', scope: 'public' do
73
+ one_of do
74
+ 0.upto(9) { |d| item { d.to_s } }
75
+ item { "#" }
76
+ item { "*" }
77
+ end
78
+ end
79
+ end
80
+ }
81
+
82
+ let(:input_component) {
83
+ Punchblock::Component::Input.new(
84
+ { :mode => :dtmf,
85
+ :initial_timeout => timeout_ms,
86
+ :inter_digit_timeout => timeout_ms,
87
+ :grammar => {
88
+ :value => grxml.to_s
89
+ }
90
+ }
91
+ )
92
+ }
93
+
94
+ def expect_component_complete_event
95
+ complete_event = Punchblock::Event::Complete.new
96
+ flexmock(complete_event).should_receive(:reason => flexmock(:interpretation => 'dtmf-5', :name => :input))
97
+ flexmock(Punchblock::Component::Input).new_instances do |input|
98
+ input.should_receive(:complete?).and_return(false)
99
+ input.should_receive(:complete_event).and_return(complete_event)
100
+ end
101
+ end
102
+
103
+ it "sends the correct input component" do
104
+ expect_component_complete_event
105
+ subject.should_receive(:execute_component_and_await_completion).once.with(input_component).and_return input_component
106
+ subject.wait_for_digit timeout
107
+ end
108
+
109
+ it "returns the correct pressed digit" do
110
+ expect_component_complete_event
111
+ subject.should_receive(:execute_component_and_await_completion).once.with(Punchblock::Component::Input).and_return input_component
112
+ subject.wait_for_digit(timeout).should == '5'
113
+ end
114
+
115
+ context "with a nil timeout" do
116
+ let(:timeout) { nil }
117
+ let(:timeout_ms) { nil }
118
+
119
+ it "does not set a timeout on the component" do
120
+ expect_component_complete_event
121
+ subject.should_receive(:execute_component_and_await_completion).once.with(input_component).and_return input_component
122
+ subject.wait_for_digit timeout
123
+ end
124
+ end
125
+ end # wait_for_digit
126
+
127
+ describe "#input!" do
128
+ describe "simple usage" do
129
+ let(:timeout) { 3000 }
130
+
131
+ it "can be called with no arguments" do
132
+ subject.should_receive(:wait_for_digit).once.with(nil).and_return('1')
133
+ subject.should_receive(:wait_for_digit).once.with(nil).and_return('#')
134
+ subject.input!
135
+ end
136
+
137
+ it "can be called with 1 digit as an argument" do
138
+ subject.should_receive(:wait_for_digit).with(nil)
139
+ subject.input! 1
140
+ end
141
+
142
+ it "accepts a timeout argument" do
143
+ subject.should_receive(:wait_for_digit).with(3000)
144
+ subject.input! :timeout => timeout
145
+ end
146
+ end
147
+
148
+ describe "any number of digits with a terminator" do
149
+ let(:terminator) { '9' }
150
+
151
+ it "called with no arguments, it returns any number of digits taking a terminating digit" do
152
+ subject.should_receive(:wait_for_digit).once.with(nil).and_return('1')
153
+ subject.should_receive(:wait_for_digit).once.with(nil).and_return('#')
154
+ subject.input!.should == '1'
155
+ end
156
+
157
+ it "allows to set a different terminator" do
158
+ subject.should_receive(:wait_for_digit).once.with(nil).and_return('1')
159
+ subject.should_receive(:wait_for_digit).once.with(nil).and_return(terminator)
160
+ subject.input!(:terminator => terminator).should == '1'
161
+ end
162
+ end
163
+
164
+ describe "with a fixed number or digits" do
165
+ it "accepts and returns three digits without a terminator" do
166
+ subject.should_receive(:wait_for_digit).once.with(nil).and_return('1')
167
+ subject.should_receive(:wait_for_digit).once.with(nil).and_return('2')
168
+ subject.should_receive(:wait_for_digit).once.with(nil).and_return('3')
169
+ subject.input!(3).should == '123'
170
+ end
171
+ end
172
+
173
+ describe "with play arguments" do
174
+ let(:string_play) { "Thanks for calling" }
175
+ let(:ssml_play) { RubySpeech::SSML.draw { string "Please stand by" } }
176
+ let(:hash_play) { {:value => Time.parse("24/10/2011"), :strftime => "%H:%M"} }
177
+ let(:hash_value) { Time.parse "24/10/2011" }
178
+ let(:hash_options) { {:strftime => "%H:%M"} }
179
+
180
+ it "plays a string argument" do
181
+ subject.should_receive(:interruptible_play!).with(string_play)
182
+ subject.should_receive(:wait_for_digit).once.with(nil).and_return('#')
183
+ subject.input! :play => string_play
184
+ end
185
+
186
+ it "plays a SSML argument" do
187
+ subject.should_receive(:interruptible_play!).with(ssml_play)
188
+ subject.should_receive(:wait_for_digit).once.with(nil).and_return('#')
189
+ subject.input! :play => ssml_play
190
+ end
191
+
192
+ it "plays a Hash argument" do
193
+ subject.should_receive(:interruptible_play!).with([hash_value, hash_options])
194
+ subject.should_receive(:wait_for_digit).once.with(nil).and_return('#')
195
+ subject.input! :play => hash_play
196
+ end
197
+
198
+ it "plays an array of mixed arguments" do
199
+ subject.should_receive(:interruptible_play!).with(string_play)
200
+ subject.should_receive(:interruptible_play!).with(ssml_play)
201
+ subject.should_receive(:interruptible_play!).with([hash_value, hash_options])
202
+ subject.should_receive(:wait_for_digit).once.with(nil).and_return('#')
203
+ subject.input! :play => [string_play, ssml_play, hash_play]
204
+ end
205
+
206
+ it "plays a string argument, takes 1 digit and returns the input" do
207
+ subject.should_receive(:interruptible_play!).with(string_play).and_return('1')
208
+ subject.input!(1, :play => string_play).should == '1'
209
+ end
210
+
211
+ it "plays a string argument, takes 2 digits and returns the input" do
212
+ subject.should_receive(:interruptible_play!).with(string_play).and_return('1')
213
+ subject.should_receive(:wait_for_digit).once.with(nil).and_return('1')
214
+ subject.input!(2, :play => string_play).should == '11'
215
+ end
216
+
217
+ it "plays a string argument, allows for any number of digit and an accept key" do
218
+ subject.should_receive(:interruptible_play!).with(string_play).and_return('1').ordered
219
+ subject.should_receive(:wait_for_digit).once.with(nil).and_return('2').ordered
220
+ subject.should_receive(:wait_for_digit).once.with(nil).and_return('#').ordered
221
+ subject.input!(:play => string_play).should == '12'
222
+ end
223
+
224
+ it "plays an array of mixed arguments, stops playing when a key is pressed, and returns the input" do
225
+ subject.should_receive(:interruptible_play!).and_return(nil, '1', StandardError.new("should not be called"))
226
+ subject.should_receive(:wait_for_digit).once.with(nil).and_return('#')
227
+ subject.input!(:play => [string_play, ssml_play, hash_play]).should == '1'
228
+ end
229
+ end # describe with play arguments
230
+
231
+ describe "non interruptible play" do
232
+ let(:string_play) { "Thanks for calling" }
233
+
234
+ it "calls play! when passed :interruptible => false" do
235
+ subject.should_receive(:play!).with(string_play)
236
+ subject.should_receive(:wait_for_digit).once.with(nil).and_return('#')
237
+ subject.input! :play => string_play, :interruptible => false
238
+ end
239
+
240
+ it "still collects digits when passed :interruptible => false" do
241
+ subject.should_receive(:play!).with(string_play)
242
+ subject.should_receive(:wait_for_digit).once.with(nil).and_return('1')
243
+ subject.should_receive(:wait_for_digit).once.with(nil).and_return('#')
244
+ subject.input!(:play => string_play, :interruptible => false).should == '1'
245
+ end
246
+ end # describe non interruptible play
247
+
248
+ describe "speak functionality" do
249
+ let(:string_speak) { "Thanks for calling" }
250
+
251
+ it "speaks passed text" do
252
+ subject.should_receive(:interruptible_play!).with(string_speak, {})
253
+ subject.input! :speak => {:text => string_speak }
254
+ end
255
+
256
+ it "speaks passed text and collect digits" do
257
+ subject.should_receive(:interruptible_play!).with(string_speak, {}).and_return('1')
258
+ subject.should_receive(:wait_for_digit).once.with(nil).and_return('#')
259
+ subject.input!(:speak => {:text => string_speak }).should == '1'
260
+ end
261
+ end
262
+
263
+ it 'throws an exception when playback fails'
264
+ end # describe input!
265
+
266
+ describe "#input" do
267
+ let(:string_play) { "Thanks for calling" }
268
+
269
+ it "just calls #input!" do
270
+ subject.should_receive(:input!).with(:play => string_play).and_return(nil)
271
+ subject.input! :play => string_play
272
+ end
273
+
274
+ it 'does not throw exceptions when playback fails'
275
+ end # describe input
276
+ end
277
+ end
278
+ end