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.
- data/.gitignore +17 -10
- data/CHANGELOG.md +273 -0
- data/Gemfile +1 -1
- data/Guardfile +17 -0
- data/README.markdown +61 -9
- data/Rakefile +16 -48
- data/adhearsion.gemspec +21 -7
- data/bin/ahn +3 -1
- data/cucumber.yml +4 -0
- data/features/app_generator.feature +42 -0
- data/features/cli.feature +108 -0
- data/features/step_definitions/app_generator_steps.rb +6 -0
- data/features/step_definitions/cli_steps.rb +74 -0
- data/features/support/aruba_helper.rb +22 -0
- data/features/support/env.rb +37 -0
- data/features/support/utils.rb +8 -0
- data/lib/adhearsion.rb +85 -41
- data/lib/adhearsion/call.rb +176 -0
- data/lib/adhearsion/call_controller.rb +134 -0
- data/lib/adhearsion/call_controller/dial.rb +70 -0
- data/lib/adhearsion/call_controller/input.rb +173 -0
- data/lib/adhearsion/call_controller/menu.rb +124 -0
- data/lib/adhearsion/call_controller/output.rb +267 -0
- data/lib/adhearsion/call_controller/record.rb +42 -0
- data/lib/adhearsion/call_controller/utility.rb +60 -0
- data/lib/adhearsion/calls.rb +81 -0
- data/lib/adhearsion/cli.rb +1 -3
- data/lib/adhearsion/cli_commands.rb +142 -0
- data/lib/adhearsion/configuration.rb +149 -0
- data/lib/adhearsion/console.rb +19 -8
- data/lib/adhearsion/dialplan_controller.rb +9 -0
- data/lib/adhearsion/events.rb +84 -0
- data/lib/adhearsion/foundation/all.rb +0 -7
- data/lib/adhearsion/foundation/custom_daemonizer.rb +4 -6
- data/lib/adhearsion/foundation/exception_handler.rb +9 -0
- data/lib/adhearsion/foundation/object.rb +26 -8
- data/lib/adhearsion/foundation/synchronized_hash.rb +3 -6
- data/lib/adhearsion/foundation/thread_safety.rb +17 -1
- data/lib/adhearsion/generators/app/app_generator.rb +4 -13
- data/lib/adhearsion/generators/app/templates/Gemfile +10 -5
- data/lib/adhearsion/generators/app/templates/Procfile +1 -0
- data/lib/adhearsion/generators/app/templates/README.md +28 -0
- data/lib/adhearsion/generators/app/templates/config/adhearsion.rb +41 -0
- data/lib/adhearsion/generators/app/templates/{components/simon_game → lib}/simon_game.rb +6 -18
- data/lib/adhearsion/generators/app/templates/script/ahn +2 -2
- data/lib/adhearsion/initializer.rb +151 -293
- data/lib/adhearsion/initializer/logging.rb +33 -0
- data/lib/adhearsion/logging.rb +65 -69
- data/lib/adhearsion/menu_dsl.rb +15 -0
- data/lib/adhearsion/menu_dsl/calculated_match.rb +39 -0
- data/lib/adhearsion/menu_dsl/calculated_match_collection.rb +41 -0
- data/lib/adhearsion/menu_dsl/fixnum_match_calculator.rb +18 -0
- data/lib/adhearsion/menu_dsl/match_calculator.rb +36 -0
- data/lib/adhearsion/{voip/menu_state_machine/menu_class.rb → menu_dsl/menu.rb} +38 -40
- data/lib/adhearsion/menu_dsl/menu_builder.rb +69 -0
- data/lib/adhearsion/menu_dsl/range_match_calculator.rb +55 -0
- data/lib/adhearsion/menu_dsl/string_match_calculator.rb +21 -0
- data/lib/adhearsion/outbound_call.rb +64 -0
- data/lib/adhearsion/plugin.rb +319 -0
- data/lib/adhearsion/plugin/collection.rb +19 -0
- data/lib/adhearsion/plugin/initializer.rb +37 -0
- data/lib/adhearsion/plugin/methods_container.rb +6 -0
- data/lib/adhearsion/process.rb +94 -0
- data/lib/adhearsion/punchblock_plugin.rb +29 -0
- data/lib/adhearsion/punchblock_plugin/initializer.rb +137 -0
- data/lib/adhearsion/router.rb +30 -0
- data/lib/adhearsion/router/route.rb +42 -0
- data/lib/adhearsion/script_ahn_loader.rb +2 -2
- data/lib/adhearsion/tasks.rb +14 -9
- data/lib/adhearsion/tasks/configuration.rb +26 -0
- data/lib/adhearsion/tasks/plugins.rb +17 -0
- data/lib/adhearsion/version.rb +8 -14
- data/spec/adhearsion/call_controller/dial_spec.rb +138 -0
- data/spec/adhearsion/call_controller/input_spec.rb +278 -0
- data/spec/adhearsion/call_controller/menu_spec.rb +120 -0
- data/spec/adhearsion/call_controller/output_spec.rb +466 -0
- data/spec/adhearsion/call_controller/record_spec.rb +125 -0
- data/spec/adhearsion/call_controller_spec.rb +395 -0
- data/spec/adhearsion/call_spec.rb +438 -0
- data/spec/adhearsion/calls_spec.rb +47 -0
- data/spec/adhearsion/configuration_spec.rb +308 -0
- data/spec/adhearsion/dialplan_controller_spec.rb +26 -0
- data/spec/adhearsion/events_spec.rb +112 -0
- data/spec/adhearsion/initializer/logging_spec.rb +58 -0
- data/spec/adhearsion/initializer_spec.rb +209 -122
- data/spec/adhearsion/logging_spec.rb +58 -47
- data/spec/adhearsion/menu_dsl/calculated_match_collection_spec.rb +56 -0
- data/spec/adhearsion/menu_dsl/calculated_match_spec.rb +57 -0
- data/spec/adhearsion/menu_dsl/fixnum_match_calculator_spec.rb +33 -0
- data/spec/adhearsion/menu_dsl/match_calculator_spec.rb +13 -0
- data/spec/adhearsion/menu_dsl/menu_builder_spec.rb +118 -0
- data/spec/adhearsion/menu_dsl/menu_spec.rb +210 -0
- data/spec/adhearsion/menu_dsl/range_match_calculator_spec.rb +28 -0
- data/spec/adhearsion/menu_dsl/string_match_calculator_spec.rb +36 -0
- data/spec/adhearsion/menu_dsl_spec.rb +12 -0
- data/spec/adhearsion/outbound_call_spec.rb +174 -0
- data/spec/adhearsion/plugin_spec.rb +489 -0
- data/spec/adhearsion/process_spec.rb +34 -0
- data/spec/adhearsion/punchblock_plugin/initializer_spec.rb +294 -0
- data/spec/adhearsion/router/route_spec.rb +99 -0
- data/spec/adhearsion/router_spec.rb +106 -0
- data/spec/adhearsion_spec.rb +46 -0
- data/spec/spec_helper.rb +14 -14
- data/spec/support/call_controller_test_helpers.rb +48 -0
- data/spec/support/initializer_stubs.rb +8 -13
- data/spec/support/punchblock_mocks.rb +6 -0
- metadata +255 -253
- data/CHANGELOG +0 -174
- data/bin/ahnctl +0 -68
- data/bin/jahn +0 -43
- data/examples/asterisk_manager_interface/standalone.rb +0 -51
- data/lib/adhearsion/commands.rb +0 -302
- data/lib/adhearsion/component_manager.rb +0 -278
- data/lib/adhearsion/component_manager/component_tester.rb +0 -54
- data/lib/adhearsion/component_manager/spec_framework.rb +0 -18
- data/lib/adhearsion/events_support.rb +0 -65
- data/lib/adhearsion/foundation/blank_slate.rb +0 -3
- data/lib/adhearsion/foundation/event_socket.rb +0 -205
- data/lib/adhearsion/foundation/future_resource.rb +0 -36
- data/lib/adhearsion/foundation/metaprogramming.rb +0 -17
- data/lib/adhearsion/foundation/numeric.rb +0 -13
- data/lib/adhearsion/foundation/pseudo_guid.rb +0 -10
- data/lib/adhearsion/foundation/relationship_properties.rb +0 -42
- data/lib/adhearsion/foundation/string.rb +0 -26
- data/lib/adhearsion/generators/app/templates/.ahnrc +0 -34
- data/lib/adhearsion/generators/app/templates/README +0 -8
- data/lib/adhearsion/generators/app/templates/components/ami_remote/ami_remote.rb +0 -15
- data/lib/adhearsion/generators/app/templates/components/disabled/HOW_TO_ENABLE +0 -7
- data/lib/adhearsion/generators/app/templates/components/disabled/stomp_gateway/README.markdown +0 -47
- data/lib/adhearsion/generators/app/templates/components/disabled/stomp_gateway/stomp_gateway.rb +0 -34
- data/lib/adhearsion/generators/app/templates/components/disabled/stomp_gateway/stomp_gateway.yml +0 -12
- data/lib/adhearsion/generators/app/templates/components/disabled/xmpp_gateway/README.markdown +0 -3
- data/lib/adhearsion/generators/app/templates/components/disabled/xmpp_gateway/xmpp_gateway.rb +0 -11
- data/lib/adhearsion/generators/app/templates/components/disabled/xmpp_gateway/xmpp_gateway.yml +0 -0
- data/lib/adhearsion/generators/app/templates/config/startup.rb +0 -81
- data/lib/adhearsion/generators/app/templates/dialplan.rb +0 -3
- data/lib/adhearsion/generators/app/templates/events.rb +0 -33
- data/lib/adhearsion/host_definitions.rb +0 -67
- data/lib/adhearsion/initializer/asterisk.rb +0 -86
- data/lib/adhearsion/initializer/configuration.rb +0 -324
- data/lib/adhearsion/initializer/database.rb +0 -60
- data/lib/adhearsion/initializer/drb.rb +0 -31
- data/lib/adhearsion/initializer/freeswitch.rb +0 -22
- data/lib/adhearsion/initializer/ldap.rb +0 -57
- data/lib/adhearsion/initializer/rails.rb +0 -41
- data/lib/adhearsion/initializer/xmpp.rb +0 -42
- data/lib/adhearsion/tasks/components.rb +0 -32
- data/lib/adhearsion/tasks/database.rb +0 -5
- data/lib/adhearsion/tasks/deprecations.rb +0 -59
- data/lib/adhearsion/tasks/generating.rb +0 -20
- data/lib/adhearsion/tasks/lint.rb +0 -4
- data/lib/adhearsion/voip/asterisk.rb +0 -4
- data/lib/adhearsion/voip/asterisk/agi_server.rb +0 -121
- data/lib/adhearsion/voip/asterisk/commands.rb +0 -1966
- data/lib/adhearsion/voip/asterisk/config_generators/agents.conf.rb +0 -140
- data/lib/adhearsion/voip/asterisk/config_generators/config_generator.rb +0 -102
- data/lib/adhearsion/voip/asterisk/config_generators/queues.conf.rb +0 -250
- data/lib/adhearsion/voip/asterisk/config_generators/voicemail.conf.rb +0 -240
- data/lib/adhearsion/voip/asterisk/config_manager.rb +0 -64
- data/lib/adhearsion/voip/asterisk/manager_interface.rb +0 -697
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rb +0 -1681
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rl.rb +0 -341
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_messages.rb +0 -78
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_protocol_lexer_machine.rl +0 -87
- data/lib/adhearsion/voip/asterisk/special_dial_plan_managers.rb +0 -80
- data/lib/adhearsion/voip/call.rb +0 -521
- data/lib/adhearsion/voip/call_routing.rb +0 -64
- data/lib/adhearsion/voip/commands.rb +0 -17
- data/lib/adhearsion/voip/constants.rb +0 -39
- data/lib/adhearsion/voip/conveniences.rb +0 -18
- data/lib/adhearsion/voip/dial_plan.rb +0 -252
- data/lib/adhearsion/voip/dsl/dialing_dsl.rb +0 -151
- data/lib/adhearsion/voip/dsl/dialing_dsl/dialing_dsl_monkey_patches.rb +0 -37
- data/lib/adhearsion/voip/dsl/dialplan/control_passing_exception.rb +0 -27
- data/lib/adhearsion/voip/dsl/dialplan/dispatcher.rb +0 -124
- data/lib/adhearsion/voip/dsl/dialplan/parser.rb +0 -69
- data/lib/adhearsion/voip/dsl/dialplan/thread_mixin.rb +0 -16
- data/lib/adhearsion/voip/dsl/numerical_string.rb +0 -128
- data/lib/adhearsion/voip/freeswitch/basic_connection_manager.rb +0 -48
- data/lib/adhearsion/voip/freeswitch/event_handler.rb +0 -58
- data/lib/adhearsion/voip/freeswitch/freeswitch_dialplan_command_factory.rb +0 -129
- data/lib/adhearsion/voip/freeswitch/inbound_connection_manager.rb +0 -38
- data/lib/adhearsion/voip/freeswitch/oes_server.rb +0 -195
- data/lib/adhearsion/voip/menu_state_machine/calculated_match.rb +0 -80
- data/lib/adhearsion/voip/menu_state_machine/matchers.rb +0 -123
- data/lib/adhearsion/voip/menu_state_machine/menu_builder.rb +0 -57
- data/lib/adhearsion/xmpp/connection.rb +0 -61
- data/lib/theatre.rb +0 -147
- data/lib/theatre/README.markdown +0 -64
- data/lib/theatre/callback_definition_loader.rb +0 -86
- data/lib/theatre/guid.rb +0 -23
- data/lib/theatre/invocation.rb +0 -131
- data/lib/theatre/namespace_manager.rb +0 -153
- data/lib/theatre/version.rb +0 -2
- data/spec/adhearsion/cli_spec.rb +0 -306
- data/spec/adhearsion/component_manager_spec.rb +0 -292
- data/spec/adhearsion/constants_spec.rb +0 -8
- data/spec/adhearsion/drb_spec.rb +0 -65
- data/spec/adhearsion/fixtures/dialplan.rb +0 -3
- data/spec/adhearsion/foundation/event_socket_spec.rb +0 -168
- data/spec/adhearsion/host_definitions_spec.rb +0 -79
- data/spec/adhearsion/initializer/configuration_spec.rb +0 -291
- data/spec/adhearsion/initializer/loading_spec.rb +0 -154
- data/spec/adhearsion/initializer/paths_spec.rb +0 -74
- data/spec/adhearsion/relationship_properties_spec.rb +0 -54
- data/spec/adhearsion/voip/asterisk/agi_server_spec.rb +0 -473
- data/spec/adhearsion/voip/asterisk/ami/ami_spec.rb +0 -550
- data/spec/adhearsion/voip/asterisk/ami/lexer/ami_fixtures.yml +0 -30
- data/spec/adhearsion/voip/asterisk/ami/lexer/lexer_story +0 -291
- data/spec/adhearsion/voip/asterisk/ami/lexer/lexer_story.rb +0 -241
- data/spec/adhearsion/voip/asterisk/ami/lexer/story_helper.rb +0 -124
- data/spec/adhearsion/voip/asterisk/commands_spec.rb +0 -3241
- data/spec/adhearsion/voip/asterisk/config_file_generators/agents_spec.rb +0 -251
- data/spec/adhearsion/voip/asterisk/config_file_generators/queues_spec.rb +0 -323
- data/spec/adhearsion/voip/asterisk/config_file_generators/voicemail_spec.rb +0 -306
- data/spec/adhearsion/voip/asterisk/config_manager_spec.rb +0 -127
- data/spec/adhearsion/voip/asterisk/menu_command/calculated_match_spec.rb +0 -109
- data/spec/adhearsion/voip/asterisk/menu_command/matchers_spec.rb +0 -97
- data/spec/adhearsion/voip/call_routing_spec.rb +0 -125
- data/spec/adhearsion/voip/dialplan_manager_spec.rb +0 -468
- data/spec/adhearsion/voip/dsl/dialing_dsl_spec.rb +0 -270
- data/spec/adhearsion/voip/dsl/dispatcher_spec.rb +0 -82
- data/spec/adhearsion/voip/dsl/dispatcher_spec_helper.rb +0 -45
- data/spec/adhearsion/voip/dsl/parser_spec.rb +0 -69
- data/spec/adhearsion/voip/freeswitch/basic_connection_manager_spec.rb +0 -39
- data/spec/adhearsion/voip/freeswitch/inbound_connection_manager_spec.rb +0 -39
- data/spec/adhearsion/voip/freeswitch/oes_server_spec.rb +0 -9
- data/spec/adhearsion/voip/numerical_string_spec.rb +0 -61
- data/spec/adhearsion/voip/phone_number_spec.rb +0 -45
- data/spec/support/the_following_code.rb +0 -3
- data/spec/theatre/dsl_examples/simple_before_call.rb +0 -7
- data/spec/theatre/dsl_spec.rb +0 -69
- data/spec/theatre/invocation_spec.rb +0 -182
- data/spec/theatre/namespace_spec.rb +0 -125
- data/spec/theatre/spec_helper_spec.rb +0 -28
- 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
|
data/lib/adhearsion/version.rb
CHANGED
|
@@ -1,36 +1,30 @@
|
|
|
1
1
|
module Adhearsion #:nodoc:
|
|
2
|
-
|
|
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
|
|
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
|
|
23
|
-
return @minor
|
|
24
|
-
return @revision
|
|
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
|
|
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
|