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
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
require 'rubygems'
|
|
2
|
-
gem 'rspec', "= 1.1.4"
|
|
3
|
-
require 'spec/story'
|
|
4
|
-
require File.dirname(__FILE__) + "/../../../../../lib/adhearsion"
|
|
5
|
-
|
|
6
|
-
RAGEL_FILES = %w[lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rl.rb]
|
|
7
|
-
|
|
8
|
-
def regenerate_ragel
|
|
9
|
-
# Check Ragel version:
|
|
10
|
-
ragel_version_match = `ragel --version`.match(/(\d)\.(\d)+/)
|
|
11
|
-
abort "Could not get Ragel version! Is it installed? You must have at least version 6.3" unless ragel_version_match
|
|
12
|
-
big, small = ragel_version_match.captures.map { |n| n.to_i }
|
|
13
|
-
if big < 6 || (big == 6 && small < 3)
|
|
14
|
-
abort "Please upgrade Ragel! You're on version #{ragel_version_match[0]} and must be on 6.3 or later"
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
RAGEL_FILES.each do |ragel_file|
|
|
18
|
-
ruby_file = ragel_file.sub(".rl.rb", ".rb")
|
|
19
|
-
puts `ragel -n -R #{ragel_file} -o #{ruby_file} 2>&1`
|
|
20
|
-
raise "Failed generating code from Ragel file #{ragel_file}" if $?.to_i.nonzero?
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
Dir.chdir(File.dirname(__FILE__) + "/../../../../..") { regenerate_ragel }
|
|
25
|
-
|
|
26
|
-
require 'adhearsion/voip/asterisk/manager_interface/ami_lexer'
|
|
27
|
-
|
|
28
|
-
FIXTURES = YAML.load_file File.dirname(__FILE__) + "/ami_fixtures.yml"
|
|
29
|
-
|
|
30
|
-
def fixture(path, overrides={})
|
|
31
|
-
path_segments = path.split '/'
|
|
32
|
-
selected_event = path_segments.inject(FIXTURES.clone) do |hash, segment|
|
|
33
|
-
raise ArgumentError, path + " not found!" unless hash
|
|
34
|
-
hash[segment.to_sym]
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
# Downcase all keys in the event and the overrides
|
|
38
|
-
selected_event = selected_event.inject({}) do |downcased_hash,(key,value)|
|
|
39
|
-
downcased_hash[key.to_s.downcase] = value
|
|
40
|
-
downcased_hash
|
|
41
|
-
end
|
|
42
|
-
overrides = overrides.inject({}) do |downcased_hash,(key,value)|
|
|
43
|
-
downcased_hash[key.to_s.downcase] = value
|
|
44
|
-
downcased_hash
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
# Replace variables in the selected_event with any overrides, ignoring case of the key
|
|
48
|
-
keys_with_variables = selected_event.select { |(key, value)| value.kind_of?(Symbol) || value.kind_of?(Hash) }
|
|
49
|
-
|
|
50
|
-
keys_with_variables.each do |original_key, variable_type|
|
|
51
|
-
# Does an override an exist in the supplied list?
|
|
52
|
-
if overriden_pair = overrides.find { |(key, value)| key == original_key }
|
|
53
|
-
# We have an override! Let's replace the template value in the event with the overriden value
|
|
54
|
-
selected_event[original_key] = overriden_pair.last
|
|
55
|
-
else
|
|
56
|
-
# Based on the type, let's generate a placeholder.
|
|
57
|
-
selected_event[original_key] = case variable_type
|
|
58
|
-
when :string
|
|
59
|
-
rand(100000).to_s
|
|
60
|
-
when Hash
|
|
61
|
-
if variable_type.has_key? "one_of"
|
|
62
|
-
# Choose a random possibility
|
|
63
|
-
possibilities = variable_type['one_of']
|
|
64
|
-
possibilities[rand(possibilities.size)]
|
|
65
|
-
else
|
|
66
|
-
raise "Unrecognized Hash fixture property! ##{variable_type.keys.to_sentence}"
|
|
67
|
-
end
|
|
68
|
-
else
|
|
69
|
-
raise "Unrecognized fixture variable type #{variable_type}!"
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
end
|
|
74
|
-
hash_to_stanza(selected_event).tap do |event|
|
|
75
|
-
selected_event.each_pair do |key, value|
|
|
76
|
-
event.meta_def(key) { value }
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
def hash_to_stanza(hash)
|
|
82
|
-
ordered_hash = hash.to_a
|
|
83
|
-
starter = hash.find { |(key, value)| key.strip =~ /^(Response|Action)$/i }
|
|
84
|
-
ordered_hash.unshift ordered_hash.delete(starter) if starter
|
|
85
|
-
ordered_hash.inject(String.new) do |stanza,(key, value)|
|
|
86
|
-
stanza + "#{key}: #{value}\r\n"
|
|
87
|
-
end + "\r\n"
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
def format_newlines(string)
|
|
91
|
-
# HOLY FUCK THIS IS UGLY
|
|
92
|
-
tmp_replacement = random_string
|
|
93
|
-
string.gsub("\r\n", tmp_replacement).
|
|
94
|
-
gsub("\n", "\r\n").
|
|
95
|
-
gsub(tmp_replacement, "\r\n")
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
def random_string
|
|
99
|
-
(rand(1_000_000_000_000) + 1_000_000_000).to_s
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
def follows_body_text(name)
|
|
103
|
-
case name
|
|
104
|
-
when "ragel_description"
|
|
105
|
-
"Ragel is a software development tool that allows user actions to
|
|
106
|
-
be embedded into the transitions of a regular expression's corresponding state machine,
|
|
107
|
-
eliminating the need to switch from the regular expression engine and user code execution
|
|
108
|
-
environment and back again."
|
|
109
|
-
when "with_colon_after_first_line"
|
|
110
|
-
"Host Username Refresh State Reg.Time \r\nlax.teliax.net:5060 jicksta 105 Registered Tue, 11 Nov 2008 02:29:55"
|
|
111
|
-
when "show_channels_from_wayne"
|
|
112
|
-
"Channel Location State Application(Data)\r\n0 active channels\r\n0 active calls"
|
|
113
|
-
when "empty_string"
|
|
114
|
-
""
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
def syntax_error_data(name)
|
|
120
|
-
case name
|
|
121
|
-
when "immediate_packet_with_colon"
|
|
122
|
-
"!IJ@MHY:!&@B*!B @ ! @^! @ !@ !\r!@ ! @ !@ ! !!m, \n\\n\n"
|
|
123
|
-
end
|
|
124
|
-
end
|
|
@@ -1,3241 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'adhearsion/voip/menu_state_machine/menu_class'
|
|
3
|
-
require 'adhearsion/voip/menu_state_machine/menu_builder'
|
|
4
|
-
|
|
5
|
-
module DialplanCommandTestHelpers
|
|
6
|
-
def self.included(test_case)
|
|
7
|
-
test_case.send(:attr_reader, :mock_call, :input, :output)
|
|
8
|
-
|
|
9
|
-
test_case.before do
|
|
10
|
-
Adhearsion::Configuration.configure { |config| config.enable_asterisk() }
|
|
11
|
-
|
|
12
|
-
@input = MockSocket.new
|
|
13
|
-
@output = MockSocket.new
|
|
14
|
-
@mock_call = Object.new
|
|
15
|
-
@mock_call.metaclass.send(:attr_reader, :call)
|
|
16
|
-
@mock_call.instance_variable_set(:@call, MockCall.new)
|
|
17
|
-
mock_call.extend(Adhearsion::VoIP::Asterisk::Commands)
|
|
18
|
-
flexmock(mock_call) do |call|
|
|
19
|
-
call.should_receive(:from_pbx).and_return(input)
|
|
20
|
-
call.should_receive(:to_pbx).and_return(output)
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
test_case.after do
|
|
25
|
-
pbx_output_should_be_empty
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
class MockCall
|
|
30
|
-
attr_accessor :variables
|
|
31
|
-
|
|
32
|
-
def initialize
|
|
33
|
-
@variables = {}
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def with_command_lock
|
|
37
|
-
yield
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
class MockSocket
|
|
42
|
-
|
|
43
|
-
def empty?
|
|
44
|
-
messages.empty?
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def print(message)
|
|
48
|
-
messages << message
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def puts(message)
|
|
52
|
-
messages << message.chomp + "\n"
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def read
|
|
56
|
-
messages.shift
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def gets
|
|
60
|
-
read
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def messages
|
|
64
|
-
@messages ||= []
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
private
|
|
70
|
-
|
|
71
|
-
def should_pass_control_to_a_context_that_throws(symbol, &block)
|
|
72
|
-
did_the_rescue_block_get_executed = false
|
|
73
|
-
begin
|
|
74
|
-
yield
|
|
75
|
-
rescue Adhearsion::VoIP::DSL::Dialplan::ControlPassingException => cpe
|
|
76
|
-
did_the_rescue_block_get_executed = true
|
|
77
|
-
cpe.target.should throw_symbol symbol
|
|
78
|
-
rescue => e
|
|
79
|
-
did_the_rescue_block_get_executed = true
|
|
80
|
-
raise e
|
|
81
|
-
ensure
|
|
82
|
-
did_the_rescue_block_get_executed.should be true
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def should_throw(sym=nil,&block)
|
|
87
|
-
block.should throw_symbol(*[sym].compact)
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
def mock_route_calculation_with(*definitions)
|
|
91
|
-
flexmock(Adhearsion::VoIP::DSL::DialingDSL).should_receive(:calculate_routes_for).and_return(definitions)
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
def pbx_should_have_been_sent(message)
|
|
95
|
-
output.gets.chomp.should == message
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
def pbx_should_respond_with(message)
|
|
99
|
-
input.print message
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
def pbx_should_respond_with_digits(string_of_digits)
|
|
103
|
-
pbx_should_respond_with "200 result=#{string_of_digits}"
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
def pbx_should_respond_with_digits_and_timeout(string_of_digits)
|
|
107
|
-
pbx_should_respond_with "200 result=#{string_of_digits} (timeout)"
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
def pbx_should_respond_to_timeout(timeout)
|
|
111
|
-
pbx_should_respond_with "200 result=#{timeout}"
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
def pbx_should_respond_with_value(value)
|
|
115
|
-
pbx_should_respond_with pbx_value_response value
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
def pbx_should_respond_with_success(success_code = nil)
|
|
119
|
-
pbx_should_respond_with pbx_success_response(success_code)
|
|
120
|
-
end
|
|
121
|
-
alias does_not_read_data_back pbx_should_respond_with_success
|
|
122
|
-
|
|
123
|
-
def pbx_should_respond_with_failure(failure_code = nil)
|
|
124
|
-
pbx_should_respond_with(pbx_failure_response(failure_code))
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
def pbx_should_respond_with_successful_background_response(digit=0)
|
|
128
|
-
pbx_should_respond_with_success digit.kind_of?(String) ? digit[0] : digit
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
def pbx_should_respond_with_playback_success
|
|
132
|
-
pbx_should_respond_with pbx_raw_response
|
|
133
|
-
mock_call.should_receive(:get_variable).once.with('PLAYBACKSTATUS').and_return 'SUCCESS'
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
def pbx_should_respond_with_playback_failure
|
|
137
|
-
pbx_should_respond_with pbx_raw_response
|
|
138
|
-
mock_call.should_receive(:get_variable).once.with('PLAYBACKSTATUS').and_return 'FAILED'
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
def pbx_should_respond_with_stream_file_success(success_code = nil, endpos = '20000')
|
|
142
|
-
pbx_should_respond_with pbx_raw_stream_file_response(success_code, endpos)
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
def pbx_should_respond_with_stream_file_failure_on_open(endpos = nil)
|
|
146
|
-
pbx_should_respond_with pbx_raw_stream_file_response(nil, endpos)
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
def pbx_should_respond_with_a_wait_for_digit_timeout
|
|
150
|
-
pbx_should_respond_with_successful_background_response 0
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
def pbx_success_response(success_code = nil)
|
|
154
|
-
"200 result=#{success_code || default_success_code}"
|
|
155
|
-
end
|
|
156
|
-
|
|
157
|
-
def pbx_raw_response(code = nil)
|
|
158
|
-
"200 result=#{code || default_code}\n"
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
def pbx_raw_stream_file_response(code = nil, endpos = nil)
|
|
162
|
-
"200 result=#{code || default_code} endpos=#{endpos || default_code}\n"
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
def pbx_value_response(value)
|
|
166
|
-
"200 result=1 (#{value})"
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
def pbx_result_response(value)
|
|
170
|
-
"200 result=#{value.ord}"
|
|
171
|
-
end
|
|
172
|
-
|
|
173
|
-
def default_success_code
|
|
174
|
-
'1'
|
|
175
|
-
end
|
|
176
|
-
|
|
177
|
-
def default_code
|
|
178
|
-
'0'
|
|
179
|
-
end
|
|
180
|
-
|
|
181
|
-
def pbx_failure_response(failure_code = nil)
|
|
182
|
-
"200 result=#{failure_code || default_failure_code}"
|
|
183
|
-
end
|
|
184
|
-
|
|
185
|
-
def default_failure_code
|
|
186
|
-
'-1'
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
def output_stream_matches(pattern)
|
|
190
|
-
output.gets.should match pattern
|
|
191
|
-
end
|
|
192
|
-
|
|
193
|
-
module OutputStreamMatchers
|
|
194
|
-
def pbx_was_asked_to_play(*audio_files)
|
|
195
|
-
audio_files.flatten.each do |audio_file|
|
|
196
|
-
output_stream_matches(/playback "#{audio_file}"/)
|
|
197
|
-
end
|
|
198
|
-
end
|
|
199
|
-
|
|
200
|
-
def pbx_was_asked_to_play_number(number)
|
|
201
|
-
output_stream_matches(/saynumber "#{number}"/)
|
|
202
|
-
end
|
|
203
|
-
|
|
204
|
-
def pbx_was_asked_to_play_time(number)
|
|
205
|
-
output_stream_matches(/sayunixtime "#{number}"/)
|
|
206
|
-
end
|
|
207
|
-
|
|
208
|
-
def pbx_was_asked_to_stream(*audio_files)
|
|
209
|
-
audio_files.flatten.each do |audio_file|
|
|
210
|
-
output_stream_matches /^STREAM FILE "#{audio_file}" "1234567890\*#"\n$/
|
|
211
|
-
end
|
|
212
|
-
end
|
|
213
|
-
|
|
214
|
-
def pbx_was_asked_to_execute(application, *options)
|
|
215
|
-
output_stream_matches(/exec saydigits "#{options.join('|')}"/i)
|
|
216
|
-
end
|
|
217
|
-
|
|
218
|
-
def pbx_output_should_be_empty
|
|
219
|
-
output.messages.should be_empty, output.messages.inspect
|
|
220
|
-
end
|
|
221
|
-
end
|
|
222
|
-
include OutputStreamMatchers
|
|
223
|
-
|
|
224
|
-
def assert_success(response)
|
|
225
|
-
response.should == pbx_success_response
|
|
226
|
-
end
|
|
227
|
-
|
|
228
|
-
end
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
module MenuBuilderTestHelper
|
|
232
|
-
def builder_should_match_with_these_quantities_of_calculated_matches(checks)
|
|
233
|
-
checks.each do |check,hash|
|
|
234
|
-
hash.each_pair do |method_name,intended_quantity|
|
|
235
|
-
builder.calculate_matches_for(check).send(method_name).should == intended_quantity
|
|
236
|
-
end
|
|
237
|
-
end
|
|
238
|
-
end
|
|
239
|
-
end
|
|
240
|
-
|
|
241
|
-
module MenuTestHelper
|
|
242
|
-
|
|
243
|
-
def pbx_should_send_digits(*digits)
|
|
244
|
-
digits.each do |digit|
|
|
245
|
-
digit = nil if digit == :timeout
|
|
246
|
-
mock_call.should_receive(:interruptible_play).once.and_return(digit)
|
|
247
|
-
end
|
|
248
|
-
end
|
|
249
|
-
end
|
|
250
|
-
|
|
251
|
-
module ConfirmationManagerTestHelper
|
|
252
|
-
def encode_hash(hash)
|
|
253
|
-
Adhearsion::DialPlan::ConfirmationManager.encode_hash_for_dial_macro_argument(hash)
|
|
254
|
-
end
|
|
255
|
-
end
|
|
256
|
-
|
|
257
|
-
describe 'Asterisk VoIP Commands' do
|
|
258
|
-
include DialplanCommandTestHelpers
|
|
259
|
-
|
|
260
|
-
it "a call can write back to the PBX" do
|
|
261
|
-
message = 'oh hai'
|
|
262
|
-
mock_call.write message
|
|
263
|
-
pbx_should_have_been_sent message
|
|
264
|
-
end
|
|
265
|
-
end
|
|
266
|
-
describe 'hangup command' do
|
|
267
|
-
include DialplanCommandTestHelpers
|
|
268
|
-
|
|
269
|
-
it "hanging up a call succesfully writes HANGUP back to the PBX and a success resopnse is returned" do
|
|
270
|
-
pbx_should_respond_with_success
|
|
271
|
-
response = mock_call.hangup
|
|
272
|
-
pbx_should_have_been_sent 'HANGUP'
|
|
273
|
-
response.should == pbx_success_response
|
|
274
|
-
end
|
|
275
|
-
end
|
|
276
|
-
|
|
277
|
-
describe 'receiving a hangup' do
|
|
278
|
-
include DialplanCommandTestHelpers
|
|
279
|
-
|
|
280
|
-
it "should treat a ECONNRESET as a hangup" do
|
|
281
|
-
pbx_should_respond_with_success
|
|
282
|
-
def input.gets()
|
|
283
|
-
raise Errno::ECONNRESET
|
|
284
|
-
end
|
|
285
|
-
the_following_code {
|
|
286
|
-
mock_call.read()
|
|
287
|
-
}.should raise_error(Adhearsion::Hangup)
|
|
288
|
-
end
|
|
289
|
-
end
|
|
290
|
-
|
|
291
|
-
describe "writing a command" do
|
|
292
|
-
include DialplanCommandTestHelpers
|
|
293
|
-
|
|
294
|
-
it "should strip out excess whitespace" do
|
|
295
|
-
pbx_should_respond_with_success
|
|
296
|
-
mock_call.should_receive(:write).with "EXEC Ringing"
|
|
297
|
-
mock_call.raw_response "EXEC \nRinging\n\n"
|
|
298
|
-
end
|
|
299
|
-
end
|
|
300
|
-
|
|
301
|
-
describe 'The #interruptible_play method' do
|
|
302
|
-
|
|
303
|
-
include DialplanCommandTestHelpers
|
|
304
|
-
|
|
305
|
-
it 'should return a string for the digit that was pressed' do
|
|
306
|
-
digits = %w{0 1 # * 9}.map{|c| c.ord}
|
|
307
|
-
file = "file_doesnt_matter"
|
|
308
|
-
digits.each { |digit| pbx_should_respond_with_stream_file_success digit }
|
|
309
|
-
digits.map { |digit| mock_call.interruptible_play file }.should == digits.map(&:chr)
|
|
310
|
-
digits.size.times { pbx_was_asked_to_stream file }
|
|
311
|
-
end
|
|
312
|
-
|
|
313
|
-
it "should return nil if no digit was pressed" do
|
|
314
|
-
pbx_should_respond_with_stream_file_success 0
|
|
315
|
-
file = 'foobar'
|
|
316
|
-
mock_call.interruptible_play(file).should be nil
|
|
317
|
-
pbx_was_asked_to_stream file
|
|
318
|
-
end
|
|
319
|
-
|
|
320
|
-
it 'should return nil if no digit was pressed, even if the sound file is not found' do
|
|
321
|
-
pbx_should_respond_with_stream_file_failure_on_open
|
|
322
|
-
file = 'foobar'
|
|
323
|
-
mock_call.interruptible_play(file).should be nil
|
|
324
|
-
pbx_was_asked_to_stream file
|
|
325
|
-
end
|
|
326
|
-
|
|
327
|
-
it "should play a series of files, stopping the series when a digit is played" do
|
|
328
|
-
stubbed_keypad_input = [0, 0, ?3.ord]
|
|
329
|
-
stubbed_keypad_input.each do |digit|
|
|
330
|
-
pbx_should_respond_with_stream_file_success digit
|
|
331
|
-
end
|
|
332
|
-
|
|
333
|
-
play_files = (100..105).map &:to_s
|
|
334
|
-
played_files = (100..102).map &:to_s
|
|
335
|
-
mock_call.interruptible_play(*play_files).should == '3'
|
|
336
|
-
pbx_was_asked_to_stream played_files
|
|
337
|
-
end
|
|
338
|
-
|
|
339
|
-
it 'should play a series of files, stopping the series when a digit is played, even if the sound files cannot be found' do
|
|
340
|
-
pbx_should_respond_with_stream_file_success 0
|
|
341
|
-
pbx_should_respond_with_stream_file_success 0
|
|
342
|
-
pbx_should_respond_with_stream_file_failure_on_open
|
|
343
|
-
pbx_should_respond_with_stream_file_success ?9.ord
|
|
344
|
-
|
|
345
|
-
play_files = ('sound1'..'sound6').map &:to_s
|
|
346
|
-
played_files = ('sound1'..'sound4').map &:to_s
|
|
347
|
-
mock_call.interruptible_play(*play_files).should == '9'
|
|
348
|
-
pbx_was_asked_to_stream played_files
|
|
349
|
-
end
|
|
350
|
-
end
|
|
351
|
-
|
|
352
|
-
describe 'The #interruptible_play! method' do
|
|
353
|
-
include DialplanCommandTestHelpers
|
|
354
|
-
|
|
355
|
-
it 'should return a string for the digit that was pressed' do
|
|
356
|
-
digits = %w{0 1 # * 9}.map{|c| c.ord}
|
|
357
|
-
file = "file_doesnt_matter"
|
|
358
|
-
digits.each { |digit| pbx_should_respond_with_stream_file_success digit }
|
|
359
|
-
digits.map { |digit| mock_call.interruptible_play! file }.should == digits.map(&:chr)
|
|
360
|
-
digits.size.times { pbx_was_asked_to_stream file }
|
|
361
|
-
end
|
|
362
|
-
|
|
363
|
-
it "should return nil if no digit was pressed" do
|
|
364
|
-
pbx_should_respond_with_stream_file_success 0
|
|
365
|
-
file = 'foobar'
|
|
366
|
-
mock_call.interruptible_play!(file).should be nil
|
|
367
|
-
pbx_was_asked_to_stream file
|
|
368
|
-
end
|
|
369
|
-
|
|
370
|
-
it 'should raise an error when the sound file is not found' do
|
|
371
|
-
pbx_should_respond_with_stream_file_failure_on_open
|
|
372
|
-
file = 'foobar'
|
|
373
|
-
the_following_code {
|
|
374
|
-
mock_call.interruptible_play! file
|
|
375
|
-
}.should raise_error Adhearsion::VoIP::PlaybackError
|
|
376
|
-
pbx_was_asked_to_stream file
|
|
377
|
-
end
|
|
378
|
-
|
|
379
|
-
it "should play a series of files, stopping the series when a digit is played" do
|
|
380
|
-
stubbed_keypad_input = [0, 0, ?3.ord]
|
|
381
|
-
stubbed_keypad_input.each do |digit|
|
|
382
|
-
pbx_should_respond_with_stream_file_success digit
|
|
383
|
-
end
|
|
384
|
-
|
|
385
|
-
play_files = (100..105).map &:to_s
|
|
386
|
-
played_files = (100..102).map &:to_s
|
|
387
|
-
mock_call.interruptible_play!(*play_files).should == '3'
|
|
388
|
-
pbx_was_asked_to_stream played_files
|
|
389
|
-
end
|
|
390
|
-
|
|
391
|
-
it 'should play a series of files, raising an error if a sound file cannot be found' do
|
|
392
|
-
pbx_should_respond_with_stream_file_success 0
|
|
393
|
-
pbx_should_respond_with_stream_file_failure_on_open
|
|
394
|
-
|
|
395
|
-
play_files = ('sound1'..'sound6').map &:to_s
|
|
396
|
-
played_files = ('sound1'..'sound2').map &:to_s
|
|
397
|
-
the_following_code {
|
|
398
|
-
mock_call.interruptible_play! *play_files
|
|
399
|
-
}.should raise_error Adhearsion::VoIP::PlaybackError
|
|
400
|
-
pbx_was_asked_to_stream played_files
|
|
401
|
-
end
|
|
402
|
-
|
|
403
|
-
it 'should raise an error if an audio file cannot be found' do
|
|
404
|
-
pbx_should_respond_with_stream_file_failure_on_open
|
|
405
|
-
audio_file = 'nixon-tapes'
|
|
406
|
-
the_following_code {
|
|
407
|
-
mock_call.interruptible_play! audio_file
|
|
408
|
-
}.should raise_error Adhearsion::VoIP::PlaybackError
|
|
409
|
-
pbx_was_asked_to_stream audio_file
|
|
410
|
-
end
|
|
411
|
-
|
|
412
|
-
it 'should raise an error when audio files cannot be found' do
|
|
413
|
-
pbx_should_respond_with_stream_file_success
|
|
414
|
-
pbx_should_respond_with_stream_file_failure_on_open # 'paperz' is the only audio that is missing
|
|
415
|
-
audio_files = ['rock', 'paperz', 'scissors']
|
|
416
|
-
|
|
417
|
-
the_following_code {
|
|
418
|
-
mock_call.interruptible_play! audio_files
|
|
419
|
-
}.should raise_error Adhearsion::VoIP::PlaybackError
|
|
420
|
-
pbx_was_asked_to_stream ['rock', 'paperz'] # stop short before playing with scissors!
|
|
421
|
-
end
|
|
422
|
-
end
|
|
423
|
-
|
|
424
|
-
describe 'The #wait_for_digit method' do
|
|
425
|
-
|
|
426
|
-
include DialplanCommandTestHelpers
|
|
427
|
-
|
|
428
|
-
it 'should return a string for the digit that was pressed' do
|
|
429
|
-
digits = %w{0 1 # * 9}.map{|c| c.ord}
|
|
430
|
-
digits.each { |digit| pbx_should_respond_with_success digit }
|
|
431
|
-
digits.map { |digit| mock_call.send(:wait_for_digit) }.should == digits.map(&:chr)
|
|
432
|
-
digits.size.times { pbx_should_have_been_sent 'WAIT FOR DIGIT "-1"' }
|
|
433
|
-
end
|
|
434
|
-
|
|
435
|
-
it "the timeout given must be converted to milliseconds" do
|
|
436
|
-
pbx_should_respond_with_success 0
|
|
437
|
-
mock_call.send(:wait_for_digit, 1)
|
|
438
|
-
pbx_should_have_been_sent 'WAIT FOR DIGIT "1000"'
|
|
439
|
-
end
|
|
440
|
-
end
|
|
441
|
-
|
|
442
|
-
describe 'The #answer method' do
|
|
443
|
-
include DialplanCommandTestHelpers
|
|
444
|
-
|
|
445
|
-
it 'should send ANSWER over the AGI socket' do
|
|
446
|
-
does_not_read_data_back
|
|
447
|
-
mock_call.answer
|
|
448
|
-
pbx_should_have_been_sent 'ANSWER'
|
|
449
|
-
end
|
|
450
|
-
|
|
451
|
-
end
|
|
452
|
-
|
|
453
|
-
describe 'The #execute method' do
|
|
454
|
-
include DialplanCommandTestHelpers
|
|
455
|
-
|
|
456
|
-
it 'execute writes exec and app name to the PBX' do
|
|
457
|
-
pbx_should_respond_with_success
|
|
458
|
-
assert_success mock_call.execute(:foo)
|
|
459
|
-
pbx_should_have_been_sent 'EXEC foo'
|
|
460
|
-
end
|
|
461
|
-
|
|
462
|
-
it 'execute returns false if the command was not executed successfully by the PBX' do
|
|
463
|
-
pbx_should_respond_with_failure
|
|
464
|
-
mock_call.execute(:foo).should_not be true
|
|
465
|
-
pbx_should_have_been_sent 'EXEC foo'
|
|
466
|
-
end
|
|
467
|
-
|
|
468
|
-
it 'execute can accept arguments after the app name which get translated into pipe-delimited arguments to the PBX' do
|
|
469
|
-
pbx_should_respond_with_success
|
|
470
|
-
mock_call.execute :foo, 'bar', 'baz', 'hi'
|
|
471
|
-
pbx_should_have_been_sent 'EXEC foo "bar"|"baz"|"hi"'
|
|
472
|
-
end
|
|
473
|
-
|
|
474
|
-
it "should raise a Hangup exception when nil is returned when reading a command from Asterisk" do
|
|
475
|
-
flexmock(input).should_receive(:gets).once.and_return nil
|
|
476
|
-
the_following_code {
|
|
477
|
-
mock_call.execute :foo, "bar"
|
|
478
|
-
}.should raise_error Adhearsion::Hangup
|
|
479
|
-
pbx_should_have_been_sent 'EXEC foo "bar"'
|
|
480
|
-
end
|
|
481
|
-
|
|
482
|
-
it "should raise a ArgumentError if given a null byte in the arguments" do
|
|
483
|
-
the_following_code {
|
|
484
|
-
mock_call.execute :foo, "bar\0"
|
|
485
|
-
}.should raise_error ArgumentError
|
|
486
|
-
end
|
|
487
|
-
end
|
|
488
|
-
|
|
489
|
-
describe 'The #inline_return_value method' do
|
|
490
|
-
include DialplanCommandTestHelpers
|
|
491
|
-
|
|
492
|
-
it 'should return nil when given false or nil' do
|
|
493
|
-
mock_call.inline_return_value(false).should be nil
|
|
494
|
-
mock_call.inline_return_value(nil).should be nil
|
|
495
|
-
end
|
|
496
|
-
|
|
497
|
-
it 'should return nil when given an empty AGI value (0)' do
|
|
498
|
-
mock_call.inline_return_value(pbx_result_response(0)).should be nil
|
|
499
|
-
end
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
it 'should raise AGIProtocolError with an invalid response' do
|
|
503
|
-
expect {
|
|
504
|
-
mock_call.inline_return_value("500 result=foo\n")
|
|
505
|
-
}.to raise_error Adhearsion::VoIP::Asterisk::AGIProtocolError
|
|
506
|
-
|
|
507
|
-
expect {
|
|
508
|
-
mock_call.inline_return_value('Hey man, not so loud!')
|
|
509
|
-
}.to raise_error Adhearsion::VoIP::Asterisk::AGIProtocolError
|
|
510
|
-
end
|
|
511
|
-
|
|
512
|
-
it 'should parse the return value' do
|
|
513
|
-
mock_call.inline_return_value(pbx_result_response(5)).should == '5'
|
|
514
|
-
end
|
|
515
|
-
end
|
|
516
|
-
|
|
517
|
-
describe 'The #inline_result_with_return_value method' do
|
|
518
|
-
include DialplanCommandTestHelpers
|
|
519
|
-
|
|
520
|
-
it 'should return nil when given false or nil' do
|
|
521
|
-
mock_call.inline_result_with_return_value(false).should be nil
|
|
522
|
-
mock_call.inline_result_with_return_value(nil).should be nil
|
|
523
|
-
end
|
|
524
|
-
|
|
525
|
-
it 'should return nil when given an empty AGI value (0)' do
|
|
526
|
-
mock_call.inline_result_with_return_value(pbx_result_response(0)).should be nil
|
|
527
|
-
end
|
|
528
|
-
|
|
529
|
-
it 'should raise AGIProtocolError with an invalid response' do
|
|
530
|
-
expect {
|
|
531
|
-
mock_call.inline_result_with_return_value("500 result=1 (foo)\n")
|
|
532
|
-
}.to raise_error Adhearsion::VoIP::Asterisk::AGIProtocolError
|
|
533
|
-
|
|
534
|
-
expect {
|
|
535
|
-
mock_call.inline_result_with_return_value('Hey man, not so loud!')
|
|
536
|
-
}.to raise_error Adhearsion::VoIP::Asterisk::AGIProtocolError
|
|
537
|
-
end
|
|
538
|
-
|
|
539
|
-
it 'should parse the return value' do
|
|
540
|
-
mock_call.inline_result_with_return_value(pbx_value_response(5)).should == '5'
|
|
541
|
-
end
|
|
542
|
-
end
|
|
543
|
-
|
|
544
|
-
describe 'The #play_or_speak method' do
|
|
545
|
-
include DialplanCommandTestHelpers
|
|
546
|
-
|
|
547
|
-
it 'should play a sound file if one exists' do
|
|
548
|
-
pbx_should_respond_with_playback_success
|
|
549
|
-
audio_file = "cents-per-minute"
|
|
550
|
-
mock_call.play_or_speak({audio_file => {}}).should be nil
|
|
551
|
-
pbx_was_asked_to_play audio_file
|
|
552
|
-
end
|
|
553
|
-
|
|
554
|
-
it 'should play a sound file via interruptible_play if file exists and interrupbible set and return key pressed and return the key press value' do
|
|
555
|
-
audio_file = "cents-per-minute"
|
|
556
|
-
mock_call.should_receive(:interruptible_play!).with(audio_file).once.and_return '#'
|
|
557
|
-
mock_call.play_or_speak({audio_file => {:interruptible => true}}).should == '#'
|
|
558
|
-
end
|
|
559
|
-
|
|
560
|
-
it 'should play a sound file via interruptible_play if file exists and interrupbible set' do
|
|
561
|
-
audio_file = "cents-per-minute"
|
|
562
|
-
mock_call.should_receive(:interruptible_play!).with(audio_file).once.and_return nil
|
|
563
|
-
mock_call.play_or_speak({audio_file => {:interruptible => true}}).should == nil
|
|
564
|
-
end
|
|
565
|
-
|
|
566
|
-
it 'should raise and error if a sound file does not exist and there is not text specified to fall back to' do
|
|
567
|
-
audio_file = "nixon tapes"
|
|
568
|
-
mock_call.should_receive(:play!).with(audio_file).and_raise Adhearsion::VoIP::PlaybackError
|
|
569
|
-
the_following_code {
|
|
570
|
-
mock_call.play_or_speak({audio_file => { :engine => :unimrcp}})
|
|
571
|
-
}.should raise_error ArgumentError
|
|
572
|
-
end
|
|
573
|
-
|
|
574
|
-
it 'should not send the command to play if the audio file is blank' do
|
|
575
|
-
mock_call.should_receive(:speak).with('hello', {:engine=>:unimrcp}).once.and_return nil
|
|
576
|
-
mock_call.play_or_speak({'' => { :text => 'hello', :engine => :unimrcp }}).should be nil
|
|
577
|
-
end
|
|
578
|
-
|
|
579
|
-
it 'should not send the command to play if the audio file is nil' do
|
|
580
|
-
mock_call.should_receive(:speak).with('hello', {:engine=>:unimrcp}).once.and_return nil
|
|
581
|
-
mock_call.play_or_speak({nil => { :text => 'hello', :engine => :unimrcp }}).should be nil
|
|
582
|
-
end
|
|
583
|
-
|
|
584
|
-
it 'should speak the text if a sound file does not exist' do
|
|
585
|
-
audio_file = "nixon tapes"
|
|
586
|
-
mock_call.should_receive(:play!).with(audio_file).and_raise Adhearsion::VoIP::PlaybackError
|
|
587
|
-
mock_call.should_receive(:speak).with('hello', {:engine=>:unimrcp}).once.and_return nil
|
|
588
|
-
mock_call.play_or_speak({audio_file => { :text => 'hello', :engine => :unimrcp }}).should be nil
|
|
589
|
-
end
|
|
590
|
-
|
|
591
|
-
it 'should speak the text if a sound file does not exist and pass back the entered text if a key is pressed' do
|
|
592
|
-
audio_file = "nixon tapes"
|
|
593
|
-
mock_call.should_receive(:interruptible_play!).with(audio_file).and_raise Adhearsion::VoIP::PlaybackError
|
|
594
|
-
mock_call.should_receive(:speak).with('hello', {:engine=>:unimrcp, :interruptible => true}).once.and_return '5'
|
|
595
|
-
mock_call.play_or_speak({audio_file => { :text => 'hello', :engine => :unimrcp, :interruptible => true
|
|
596
|
-
}}).should == '5'
|
|
597
|
-
end
|
|
598
|
-
|
|
599
|
-
end
|
|
600
|
-
|
|
601
|
-
describe 'The #play method' do
|
|
602
|
-
include DialplanCommandTestHelpers
|
|
603
|
-
|
|
604
|
-
it 'passing a single string to play results in the playback application being executed with that file name on the PBX' do
|
|
605
|
-
pbx_should_respond_with_playback_success
|
|
606
|
-
audio_file = "cents-per-minute"
|
|
607
|
-
mock_call.play(audio_file).should be true
|
|
608
|
-
pbx_was_asked_to_play audio_file
|
|
609
|
-
end
|
|
610
|
-
|
|
611
|
-
it 'multiple strings can be passed to play, causing multiple playback commands to be issued' do
|
|
612
|
-
2.times do
|
|
613
|
-
pbx_should_respond_with_playback_success
|
|
614
|
-
end
|
|
615
|
-
audio_files = ["cents-per-minute", 'o-hai']
|
|
616
|
-
mock_call.play(audio_files).should be true
|
|
617
|
-
pbx_was_asked_to_play audio_files
|
|
618
|
-
end
|
|
619
|
-
|
|
620
|
-
it 'should return false if an audio file cannot be found' do
|
|
621
|
-
pbx_should_respond_with_playback_failure
|
|
622
|
-
audio_file = 'nixon-tapes'
|
|
623
|
-
mock_call.play(audio_file).should be false
|
|
624
|
-
pbx_was_asked_to_play audio_file
|
|
625
|
-
end
|
|
626
|
-
|
|
627
|
-
it 'should return false when audio files cannot be found' do
|
|
628
|
-
pbx_should_respond_with_playback_success
|
|
629
|
-
pbx_should_respond_with_playback_failure # 'paperz' is the only audio that is missing
|
|
630
|
-
pbx_should_respond_with_playback_success
|
|
631
|
-
audio_files = ['rock', 'paperz', 'scissors']
|
|
632
|
-
|
|
633
|
-
mock_call.play(audio_files).should be false
|
|
634
|
-
pbx_was_asked_to_play audio_files
|
|
635
|
-
end
|
|
636
|
-
|
|
637
|
-
it 'If a number is passed to play(), the saynumber application is executed with the number as an argument' do
|
|
638
|
-
pbx_should_respond_with_success
|
|
639
|
-
mock_call.play(123).should be true
|
|
640
|
-
pbx_was_asked_to_play_number(123)
|
|
641
|
-
end
|
|
642
|
-
|
|
643
|
-
it 'if a string representation of a number is passed to play(), the saynumber application is executed with the number as an argument' do
|
|
644
|
-
pbx_should_respond_with_success
|
|
645
|
-
mock_call.play('123').should be true
|
|
646
|
-
pbx_was_asked_to_play_number(123)
|
|
647
|
-
end
|
|
648
|
-
|
|
649
|
-
it 'If a Time is passed to play(), the SayUnixTime application will be executed with the time since the UNIX epoch in seconds as an argument' do
|
|
650
|
-
time = Time.parse("12/5/2000")
|
|
651
|
-
pbx_should_respond_with_success
|
|
652
|
-
mock_call.play(time).should be true
|
|
653
|
-
pbx_was_asked_to_play_time(time.to_i)
|
|
654
|
-
end
|
|
655
|
-
|
|
656
|
-
it 'If a Date is passed to play(), the SayUnixTime application will be executed with the date passed in' do
|
|
657
|
-
date = Date.parse('2011-01-23')
|
|
658
|
-
mock_call.should_receive(:execute).once.with(:sayunixtime, date.to_time.to_i, "",'BdY').and_return pbx_raw_response
|
|
659
|
-
mock_call.play(date).should be true
|
|
660
|
-
end
|
|
661
|
-
|
|
662
|
-
it 'If a Date or Time is passed to play_time(), the SayUnixTime application will be executed with the date and format passed in' do
|
|
663
|
-
date, format = Date.parse('2011-01-23'), 'ABdY'
|
|
664
|
-
mock_call.should_receive(:execute).once.with(:sayunixtime, date.to_time.to_i, "",format).and_return "200 result=0\n"
|
|
665
|
-
mock_call.play_time(date, :format => format).should == pbx_raw_response
|
|
666
|
-
|
|
667
|
-
time, format = Time.at(875121313), 'BdY \'digits/at\' IMp'
|
|
668
|
-
mock_call.should_receive(:execute).once.with(:sayunixtime, time.to_i, "",format).and_return pbx_raw_response
|
|
669
|
-
mock_call.play_time(time, :format => format).should == pbx_raw_response
|
|
670
|
-
end
|
|
671
|
-
|
|
672
|
-
it 'If a Time object is passed to play_time, the SayUnixTime application will be executed with the default parameters' do
|
|
673
|
-
time = Time.at(875121313)
|
|
674
|
-
mock_call.should_receive(:execute).once.with(:sayunixtime, time.to_i, "",'').and_return pbx_raw_response
|
|
675
|
-
mock_call.play_time(time).should == pbx_raw_response
|
|
676
|
-
end
|
|
677
|
-
|
|
678
|
-
it 'If an object other than Time, DateTime, or Date is passed to play_time false will be returned' do
|
|
679
|
-
non_time = 'blah'
|
|
680
|
-
mock_call.play_time(non_time).should be false
|
|
681
|
-
end
|
|
682
|
-
|
|
683
|
-
it 'If an array containing a Date/DateTime/Time object and a hash is passed to play(), the SayUnixTime application will be executed with the object passed in with the specified format and timezone' do
|
|
684
|
-
date, format = Date.parse('2011-01-23'), 'ABdY'
|
|
685
|
-
mock_call.should_receive(:execute).once.with(:sayunixtime, date.to_time.to_i, "",format).and_return pbx_raw_response
|
|
686
|
-
mock_call.play([date, {:format => format}]).should be true
|
|
687
|
-
|
|
688
|
-
time, timezone = Time.at(1295843084), 'US/Eastern'
|
|
689
|
-
mock_call.should_receive(:execute).once.with(:sayunixtime, time.to_i, timezone,'').and_return pbx_raw_response
|
|
690
|
-
mock_call.play([time, {:timezone => timezone}]).should be true
|
|
691
|
-
|
|
692
|
-
time, timezone, format = Time.at(1295843084), 'US/Eastern', 'ABdY \'digits/at\' IMp'
|
|
693
|
-
mock_call.should_receive(:execute).once.with(:sayunixtime, time.to_i, timezone,format).and_return pbx_raw_response
|
|
694
|
-
mock_call.play([time, {:timezone => timezone, :format => format}]).should be true
|
|
695
|
-
end
|
|
696
|
-
|
|
697
|
-
it 'If a string matching dollars and (optionally) cents is passed to play(), a series of command will be executed to read the dollar amount', :ignore => true do
|
|
698
|
-
#TODO: I think we should not have this be part of play(). Too much functionality in one method. Too much overloading. When we want to support multiple
|
|
699
|
-
# currencies, it'll be completely unwieldy. I'd suggest play_currency as a separate method. - Chad
|
|
700
|
-
end
|
|
701
|
-
end
|
|
702
|
-
|
|
703
|
-
describe 'The #play! method' do
|
|
704
|
-
include DialplanCommandTestHelpers
|
|
705
|
-
|
|
706
|
-
it 'should accept multiple strings to play, causing multiple playback commands to be issued' do
|
|
707
|
-
2.times do
|
|
708
|
-
pbx_should_respond_with_playback_success
|
|
709
|
-
end
|
|
710
|
-
audio_files = ["cents-per-minute", 'o-hai']
|
|
711
|
-
mock_call.play!(audio_files).should be true
|
|
712
|
-
pbx_was_asked_to_play audio_files
|
|
713
|
-
end
|
|
714
|
-
|
|
715
|
-
it 'should raise an error if an audio file cannot be found' do
|
|
716
|
-
pbx_should_respond_with_playback_failure
|
|
717
|
-
audio_file = 'nixon-tapes'
|
|
718
|
-
the_following_code {
|
|
719
|
-
mock_call.play! audio_file
|
|
720
|
-
}.should raise_error Adhearsion::VoIP::PlaybackError
|
|
721
|
-
pbx_was_asked_to_play audio_file
|
|
722
|
-
end
|
|
723
|
-
|
|
724
|
-
it 'should raise an error when audio files cannot be found' do
|
|
725
|
-
pbx_should_respond_with_playback_success
|
|
726
|
-
pbx_should_respond_with_playback_failure # 'paperz' is the only audio that is missing
|
|
727
|
-
audio_files = ['rock', 'paperz', 'scissors']
|
|
728
|
-
|
|
729
|
-
the_following_code {
|
|
730
|
-
mock_call.play! audio_files
|
|
731
|
-
}.should raise_error Adhearsion::VoIP::PlaybackError
|
|
732
|
-
pbx_was_asked_to_play ['rock', 'paperz'] # stop short before playing with scissors!
|
|
733
|
-
end
|
|
734
|
-
end
|
|
735
|
-
|
|
736
|
-
describe 'the #record method' do
|
|
737
|
-
include DialplanCommandTestHelpers
|
|
738
|
-
|
|
739
|
-
it 'should return the recorded file name if the user hangs up during the recording' do
|
|
740
|
-
mock_call.should_receive(:response).once.with('RECORD FILE', 'foo', 'gsm', '#', -1, 0, 'BEEP').and_return("200 result=-1 (hangup) endpos=167840\n")
|
|
741
|
-
mock_call.record('foo').should == 'foo.gsm'
|
|
742
|
-
end
|
|
743
|
-
|
|
744
|
-
it 'create a default filename if no file is specifed and icrement it on subsequent calls' do
|
|
745
|
-
mock_call.call.variables.delete :recording_counter
|
|
746
|
-
mock_call.should_receive(:response).once.with('RECORD FILE', '/tmp/recording_0', 'gsm', '26', -1, 0).and_return("200 result=0 (timeout) endpos=21600\n")
|
|
747
|
-
mock_call.should_receive(:response).once.with('RECORD FILE', '/tmp/recording_1', 'gsm', '26', -1, 0).and_return("200 result=0 (timeout) endpos=21600\n")
|
|
748
|
-
mock_call.record(:beep => nil, :escapedigits => '26').should == '/tmp/recording_0.gsm'
|
|
749
|
-
mock_call.record(:beep => nil, :escapedigits => '26').should == '/tmp/recording_1.gsm'
|
|
750
|
-
end
|
|
751
|
-
|
|
752
|
-
it 'should not modify the passed-in file name' do
|
|
753
|
-
mock_call.should_receive(:response).once.with('RECORD FILE', 'foo', 'wav', '#', -1, 0, 'BEEP').and_return("200 result=-1 (hangup) endpos=167840\n")
|
|
754
|
-
filename = 'foo.wav'
|
|
755
|
-
mock_call.record(filename).should == 'foo.wav'
|
|
756
|
-
filename.should == 'foo.wav'
|
|
757
|
-
end
|
|
758
|
-
|
|
759
|
-
it 'determine the format from the filename' do
|
|
760
|
-
mock_call.should_receive(:response).once.with('RECORD FILE', 'foo', 'wav', '26', -1, 0).and_return("200 result=0 (timeout) endpos=21600\n")
|
|
761
|
-
mock_call.record('foo.wav', :beep => nil, :escapedigits => '26').should == 'foo.wav'
|
|
762
|
-
end
|
|
763
|
-
|
|
764
|
-
it 'set the format of a file via the :format option' do
|
|
765
|
-
mock_call.should_receive(:response).once.with("RECORD FILE", "foo", "wav", "#", 2000, 0).and_return("200 result=0 (timeout) endpos=21600\n")
|
|
766
|
-
mock_call.record('foo', :beep => nil, :maxduration => 2, :format => 'wav').should == 'foo.wav'
|
|
767
|
-
end
|
|
768
|
-
|
|
769
|
-
it 'set the format of a file via the :format option over-riding a implicit format' do
|
|
770
|
-
mock_call.should_receive(:response).once.with("RECORD FILE", "foo.wav", "mpeg", "#", 2000, 0).and_return("200 result=0 (timeout) endpos=21600\n")
|
|
771
|
-
mock_call.record('foo.wav', :beep => nil, :maxduration => 2, :format => 'mpeg').should == 'foo.wav.mpeg'
|
|
772
|
-
end
|
|
773
|
-
end
|
|
774
|
-
|
|
775
|
-
describe 'the #record_to_file method' do
|
|
776
|
-
include DialplanCommandTestHelpers
|
|
777
|
-
|
|
778
|
-
it 'should return :hangup if the user hangs up during the recording' do
|
|
779
|
-
mock_call.should_receive(:response).once.with("RECORD FILE", "foo", "gsm", "#", -1, 0, "BEEP").and_return("200 result=-1 (hangup) endpos=167840\n")
|
|
780
|
-
mock_call.record_to_file('foo').should == :hangup
|
|
781
|
-
end
|
|
782
|
-
|
|
783
|
-
it 'should return :write error if the recording had a problem writing the file' do
|
|
784
|
-
mock_call.should_receive(:response).once.with("RECORD FILE", "foo", "gsm", "#", -1, 0, "BEEP").and_return("200 result=-1 (writefile) endpos=167840\n")
|
|
785
|
-
mock_call.record_to_file('foo').should == :write_error
|
|
786
|
-
end
|
|
787
|
-
|
|
788
|
-
it 'should return :success_dtmf if the recording was completed successfully with a dtmf tone to end' do
|
|
789
|
-
mock_call.should_receive(:response).once.with("RECORD FILE", "foo", "gsm", "#", -1, 0, "BEEP").and_return("200 result=35 (dtmf) endpos=29120\n")
|
|
790
|
-
mock_call.record_to_file('foo').should == :success_dtmf
|
|
791
|
-
end
|
|
792
|
-
|
|
793
|
-
it 'should return :success_timeout if the recording was completed successfully by timing out with silence' do
|
|
794
|
-
mock_call.should_receive(:response).once.with("RECORD FILE", "foo", "gsm", "#", -1, 0, "BEEP").and_return("200 result=0 (timeout) endpos=21600\n")
|
|
795
|
-
mock_call.record_to_file('foo').should == :success_timeout
|
|
796
|
-
end
|
|
797
|
-
|
|
798
|
-
it 'not send a beep if a :beep=>nil is passed in' do
|
|
799
|
-
mock_call.should_receive(:response).once.with("RECORD FILE", "foo", "gsm", "#", -1, 0).and_return("200 result=0 (timeout) endpos=21600\n")
|
|
800
|
-
mock_call.record_to_file('foo', :beep => nil).should == :success_timeout
|
|
801
|
-
end
|
|
802
|
-
|
|
803
|
-
it 'set the silence if it is passed in' do
|
|
804
|
-
mock_call.should_receive(:response).once.with("RECORD FILE", "foo", "gsm", "#", -1, 0, 's=2').and_return("200 result=0 (timeout) endpos=21600\n")
|
|
805
|
-
mock_call.record_to_file('foo', :beep => nil, :silence => 2).should == :success_timeout
|
|
806
|
-
end
|
|
807
|
-
|
|
808
|
-
it 'set the maxduration if it is passed in' do
|
|
809
|
-
mock_call.should_receive(:response).once.with("RECORD FILE", "foo", "gsm", "#", 2000, 0).and_return("200 result=0 (timeout) endpos=21600\n")
|
|
810
|
-
mock_call.record_to_file('foo', :beep => nil, :maxduration => 2).should == :success_timeout
|
|
811
|
-
end
|
|
812
|
-
|
|
813
|
-
it 'set the format of a file via the :format option' do
|
|
814
|
-
mock_call.should_receive(:response).once.with("RECORD FILE", "foo", "wav", "#", 2000, 0).and_return("200 result=0 (timeout) endpos=21600\n")
|
|
815
|
-
mock_call.record_to_file('foo', :beep => nil, :maxduration => 2, :format => 'wav').should == :success_timeout
|
|
816
|
-
end
|
|
817
|
-
|
|
818
|
-
it 'set the format of a file via the :format option over-riding a implicit format' do
|
|
819
|
-
mock_call.should_receive(:response).once.with("RECORD FILE", "foo.wav", "mpeg", "#", 2000, 0).and_return("200 result=0 (timeout) endpos=21600\n")
|
|
820
|
-
mock_call.record_to_file('foo.wav', :beep => nil, :maxduration => 2, :format => 'mpeg').should == :success_timeout
|
|
821
|
-
end
|
|
822
|
-
|
|
823
|
-
it 'set the escapedigits if it is passed in' do
|
|
824
|
-
mock_call.should_receive(:response).once.with("RECORD FILE", "foo", "gsm", "26", -1, 0).and_return("200 result=0 (timeout) endpos=21600\n")
|
|
825
|
-
mock_call.record_to_file('foo', :beep => nil, :escapedigits => '26').should == :success_timeout
|
|
826
|
-
end
|
|
827
|
-
|
|
828
|
-
it 'play a passed in beep file if it is passed in' do
|
|
829
|
-
mock_call.should_receive(:execute).once.with(:playback, 'my_awesome_beep.wav').and_return(true)
|
|
830
|
-
pbx_should_respond_with_playback_success
|
|
831
|
-
pbx_should_respond_with_playback_success
|
|
832
|
-
mock_call.should_receive(:response).once.with("RECORD FILE", "foo", "gsm", "26", -1, 0).and_return("200 result=0 (timeout) endpos=21600\n")
|
|
833
|
-
mock_call.record_to_file('foo', :beep => 'my_awesome_beep.wav', :escapedigits => '26').should == :success_timeout
|
|
834
|
-
end
|
|
835
|
-
|
|
836
|
-
it "should silently fail if the beep file passed in can't be played" do
|
|
837
|
-
mock_call.should_receive(:execute).once.with(:playback, 'my_awesome_beep.wav').and_return(true)
|
|
838
|
-
pbx_should_respond_with_playback_failure
|
|
839
|
-
pbx_should_respond_with_playback_failure
|
|
840
|
-
mock_call.should_receive(:response).once.with("RECORD FILE", "foo", "gsm", "26", -1, 0).and_return("200 result=0 (timeout) endpos=21600\n")
|
|
841
|
-
mock_call.record_to_file('foo', :beep => 'my_awesome_beep.wav', :escapedigits => '26').should == :success_timeout
|
|
842
|
-
end
|
|
843
|
-
|
|
844
|
-
it 'determine the format from the filename' do
|
|
845
|
-
mock_call.should_receive(:response).once.with("RECORD FILE", "foo", "wav", "26", -1, 0).and_return("200 result=0 (timeout) endpos=21600\n")
|
|
846
|
-
mock_call.record_to_file('foo.wav', :beep => nil, :escapedigits => '26').should == :success_timeout
|
|
847
|
-
end
|
|
848
|
-
|
|
849
|
-
it 'create a default filename if no file is specifed and icrement it on subsequent calls' do
|
|
850
|
-
mock_call.should_receive(:new_guid).once.and_return('2345')
|
|
851
|
-
mock_call.should_receive(:new_guid).once.and_return('4322')
|
|
852
|
-
mock_call.should_receive(:response).once.with("RECORD FILE", "/tmp/recording_2345_0", "gsm", "26", -1, 0).and_return("200 result=0 (timeout) endpos=21600\n")
|
|
853
|
-
mock_call.should_receive(:response).once.with("RECORD FILE", "/tmp/recording_4322_1", "gsm", "26", -1, 0).and_return("200 result=0 (timeout) endpos=21600\n")
|
|
854
|
-
mock_call.record_to_file(:beep => nil, :escapedigits => '26').should == :success_timeout
|
|
855
|
-
mock_call.record_to_file(:beep => nil, :escapedigits => '26').should == :success_timeout
|
|
856
|
-
end
|
|
857
|
-
end
|
|
858
|
-
|
|
859
|
-
describe 'The #record_to_file! method' do
|
|
860
|
-
include DialplanCommandTestHelpers
|
|
861
|
-
|
|
862
|
-
it "should throw an exception the beep file passed in can't be played" do
|
|
863
|
-
mock_call.should_receive(:execute).once.with(:playback, 'my_awesome_beep.wav').and_return(false)
|
|
864
|
-
pbx_should_respond_with_playback_failure
|
|
865
|
-
pbx_should_respond_with_playback_failure
|
|
866
|
-
mock_call.should_receive(:response).once.with("RECORD FILE", "foo", "gsm", "26", -1, 0).and_return("200 result=0 (timeout) endpos=21600\n")
|
|
867
|
-
the_following_code {
|
|
868
|
-
mock_call.record_to_file!('foo', :beep => 'my_awesome_beep.wav', :escapedigits => '26').should == :success_timeout
|
|
869
|
-
}.should raise_error Adhearsion::VoIP::PlaybackError
|
|
870
|
-
end
|
|
871
|
-
|
|
872
|
-
it 'should throw RecordError if the recording had a problem writing the file' do
|
|
873
|
-
mock_call.should_receive(:response).once.with("RECORD FILE", "foo", "gsm", "#", -1, 0, "BEEP").and_return("200 result=-1 (writefile) endpos=167840\n")
|
|
874
|
-
the_following_code {
|
|
875
|
-
mock_call.record_to_file!('foo').should == :write_error
|
|
876
|
-
}.should raise_error Adhearsion::VoIP::RecordError
|
|
877
|
-
end
|
|
878
|
-
|
|
879
|
-
it 'should be able get a response from a successfull call' do
|
|
880
|
-
mock_call.should_receive(:response).once.with("RECORD FILE", "foo", "wav", "26", -1, 0).and_return("200 result=0 (timeout) endpos=21600\n")
|
|
881
|
-
mock_call.record_to_file!('foo.wav', :beep => nil, :escapedigits => '26').should == :success_timeout
|
|
882
|
-
end
|
|
883
|
-
end
|
|
884
|
-
|
|
885
|
-
describe 'The #input method' do
|
|
886
|
-
|
|
887
|
-
include DialplanCommandTestHelpers
|
|
888
|
-
|
|
889
|
-
it 'should raise an error when the number of digits expected is -1 (this is deprecated behavior)' do
|
|
890
|
-
the_following_code {
|
|
891
|
-
mock_call.input(-1)
|
|
892
|
-
}.should raise_error ArgumentError
|
|
893
|
-
end
|
|
894
|
-
|
|
895
|
-
it 'input() calls wait_for_digit the specified number of times (when no sound files are given)' do
|
|
896
|
-
mock_call.should_receive(:interruptible_play!).never
|
|
897
|
-
mock_call.should_receive(:wait_for_digit).times(4).with(-1).and_return('1', '2', '3', '4')
|
|
898
|
-
mock_call.input(4).should == '1234'
|
|
899
|
-
end
|
|
900
|
-
|
|
901
|
-
it 'should execute wait_for_digit if no digit is pressed during interruptible_play!' do
|
|
902
|
-
sound_files = %w[one two three]
|
|
903
|
-
mock_call.should_receive(:interruptible_play!).once.with('one').and_return nil
|
|
904
|
-
mock_call.should_receive(:interruptible_play!).once.with('two').and_return nil
|
|
905
|
-
mock_call.should_receive(:interruptible_play!).once.with('three').and_return nil
|
|
906
|
-
mock_call.should_receive(:wait_for_digit).once.with(-1).and_throw :digit_request
|
|
907
|
-
should_throw(:digit_request) { mock_call.input(10, :play => sound_files) }
|
|
908
|
-
end
|
|
909
|
-
|
|
910
|
-
it 'waits for digits with :initial_timeout and :interdigit_timeout' do
|
|
911
|
-
initial_timeout = 6.seconds
|
|
912
|
-
interdigit_timeout = 3.seconds
|
|
913
|
-
mock_call.should_receive(:interruptible_play!).never
|
|
914
|
-
mock_call.should_receive(:wait_for_digit).once.with(initial_timeout).and_return '1'
|
|
915
|
-
mock_call.should_receive(:wait_for_digit).times(3).with(interdigit_timeout).and_return '2', '3', '4'
|
|
916
|
-
mock_call.input(4, :initial_timeout => initial_timeout, :interdigit_timeout => interdigit_timeout).should eq '1234'
|
|
917
|
-
end
|
|
918
|
-
|
|
919
|
-
it 'waits for digits with :initial_timeout when nothing is pressed' do
|
|
920
|
-
initial_timeout = 6.seconds
|
|
921
|
-
interdigit_timeout = 3.seconds
|
|
922
|
-
mock_call.should_receive(:interruptible_play!).never
|
|
923
|
-
mock_call.should_receive(:wait_for_digit).once.with(initial_timeout).and_return nil
|
|
924
|
-
mock_call.input(4, :initial_timeout => initial_timeout, :interdigit_timeout => interdigit_timeout).should eq ''
|
|
925
|
-
end
|
|
926
|
-
|
|
927
|
-
it 'waits for digits, ignoring :timeout if :initial_timeout and :interdigit_timeout are provided' do
|
|
928
|
-
timeout = 99.hours
|
|
929
|
-
initial_timeout = 2.seconds
|
|
930
|
-
interdigit_timeout = 1.second
|
|
931
|
-
mock_call.should_receive(:wait_for_digit).once.with(initial_timeout).and_return '1'
|
|
932
|
-
mock_call.should_receive(:wait_for_digit).times(3).with(interdigit_timeout).and_return '2', '3', '4'
|
|
933
|
-
mock_call.input(4, :timeout => timeout, :initial_timeout => initial_timeout, :interdigit_timeout => interdigit_timeout).should eq '1234'
|
|
934
|
-
end
|
|
935
|
-
|
|
936
|
-
it 'waits for digits, and given a :timeout and :initial_timeout, defaults :interdigit_timeout to :timeout' do
|
|
937
|
-
initial_timeout = 20.seconds
|
|
938
|
-
timeout = 10.seconds
|
|
939
|
-
mock_call.should_receive(:wait_for_digit).once.with(initial_timeout).and_return '1'
|
|
940
|
-
mock_call.should_receive(:wait_for_digit).times(2).with(timeout).and_return '2', '3'
|
|
941
|
-
mock_call.input(3, :timeout => timeout, :initial_timeout => initial_timeout).should eq '123'
|
|
942
|
-
end
|
|
943
|
-
|
|
944
|
-
it 'waits for digits, and given a :timeout and :interdigit_timeout, defaults :initial_timeout to :timeout' do
|
|
945
|
-
timeout = 12.seconds
|
|
946
|
-
interdigit_timeout = 6.seconds
|
|
947
|
-
mock_call.should_receive(:wait_for_digit).once.with(timeout).and_return '1'
|
|
948
|
-
mock_call.should_receive(:wait_for_digit).times(4).with(interdigit_timeout).and_return '2', '3', '4', '5'
|
|
949
|
-
mock_call.input(5, :timeout => timeout, :interdigit_timeout => interdigit_timeout).should eq '12345'
|
|
950
|
-
end
|
|
951
|
-
|
|
952
|
-
it 'waits for digits for :initial_timeout if sound playback is not interrupted' do
|
|
953
|
-
initial_timeout = 8.seconds
|
|
954
|
-
interdigit_timeout = 4.seconds
|
|
955
|
-
sound_files = %w[ready set go]
|
|
956
|
-
mock_call.should_receive(:interruptible_play!).once.with('ready').and_return nil
|
|
957
|
-
mock_call.should_receive(:interruptible_play!).once.with('set').and_return nil
|
|
958
|
-
mock_call.should_receive(:interruptible_play!).once.with('go').and_return nil
|
|
959
|
-
mock_call.should_receive(:wait_for_digit).once.with(initial_timeout).and_return '1'
|
|
960
|
-
mock_call.should_receive(:wait_for_digit).times(4).with(interdigit_timeout).and_return '2', '3', '4', '5'
|
|
961
|
-
mock_call.input(5, :play => sound_files, :initial_timeout => initial_timeout, :interdigit_timeout => interdigit_timeout).should eq '12345'
|
|
962
|
-
end
|
|
963
|
-
|
|
964
|
-
it 'ignores :initial_timeout if sound playback is interrupted' do
|
|
965
|
-
initial_timeout = 8.seconds
|
|
966
|
-
interdigit_timeout = 4.seconds
|
|
967
|
-
sound_files = %w[ready set go]
|
|
968
|
-
mock_call.should_receive(:interruptible_play!).once.with('ready').and_return nil
|
|
969
|
-
mock_call.should_receive(:interruptible_play!).once.with('set').and_return '*'
|
|
970
|
-
mock_call.should_receive(:wait_for_digit).times(4).with(interdigit_timeout).and_return '2', '3', '4', '5'
|
|
971
|
-
mock_call.input(5, :play => sound_files, :initial_timeout => initial_timeout, :interdigit_timeout => interdigit_timeout).should eq '*2345'
|
|
972
|
-
end
|
|
973
|
-
|
|
974
|
-
it 'waits for digits for :initial_timeout if speech is not interrupted' do
|
|
975
|
-
initial_timeout = 10.seconds
|
|
976
|
-
interdigit_timeout = 5.seconds
|
|
977
|
-
text = "What's your area code?"
|
|
978
|
-
mock_call.should_receive(:speak).once.with(text, :interruptible => true).and_return nil
|
|
979
|
-
mock_call.should_receive(:wait_for_digit).once.with(initial_timeout).and_return '1'
|
|
980
|
-
mock_call.should_receive(:wait_for_digit).times(2).with(interdigit_timeout).and_return '2', '0'
|
|
981
|
-
mock_call.input(3, :initial_timeout => initial_timeout, :interdigit_timeout => interdigit_timeout, :speak => {:text => text}).should eq '120'
|
|
982
|
-
end
|
|
983
|
-
|
|
984
|
-
it 'ignores :initial_timeout if speech is interrupted' do
|
|
985
|
-
initial_timeout = 10.seconds
|
|
986
|
-
interdigit_timeout = 5.seconds
|
|
987
|
-
text = "What's your area code?"
|
|
988
|
-
mock_call.should_receive(:speak).once.with(text, :interruptible => true).and_return '3'
|
|
989
|
-
mock_call.should_receive(:wait_for_digit).times(2).with(interdigit_timeout).and_return '1', '2'
|
|
990
|
-
mock_call.input(3, :initial_timeout => initial_timeout, :interdigit_timeout => interdigit_timeout, :speak => {:text => text}).should eq '312'
|
|
991
|
-
end
|
|
992
|
-
|
|
993
|
-
it 'should default the :accept_key to "#" when unlimited digits are to be collected' do
|
|
994
|
-
mock_call.should_receive(:wait_for_digit).times(2).with(-1).and_return '*', '#'
|
|
995
|
-
mock_call.input.should == '*'
|
|
996
|
-
end
|
|
997
|
-
|
|
998
|
-
it 'should raise an exception when unlimited digits are to be collected and :accept_key => false' do
|
|
999
|
-
flexstub(mock_call).should_receive(:read).and_return
|
|
1000
|
-
the_following_code {
|
|
1001
|
-
mock_call.input(:accept_key => false)
|
|
1002
|
-
}.should raise_error ArgumentError
|
|
1003
|
-
pbx_should_have_been_sent 'WAIT FOR DIGIT "-1"'
|
|
1004
|
-
end
|
|
1005
|
-
|
|
1006
|
-
it 'when :accept_key is false and input() is collecting a finite number of digits, it should allow all DTMFs' do
|
|
1007
|
-
all_digits = %w[0 1 2 3 # * 4 5 6 7 8 9]
|
|
1008
|
-
mock_call.should_receive(:wait_for_digit).times(all_digits.size).with(-1).and_return(*all_digits)
|
|
1009
|
-
the_following_code {
|
|
1010
|
-
mock_call.input(all_digits.size, :accept_key => false)
|
|
1011
|
-
}.should_not raise_error ArgumentError
|
|
1012
|
-
end
|
|
1013
|
-
|
|
1014
|
-
it 'should terminate early when the passed block returns something truthy' do
|
|
1015
|
-
three_digits = %w[9 3 0]
|
|
1016
|
-
mock_call.should_receive(:wait_for_digit).times(2).with(-1).and_return(*three_digits)
|
|
1017
|
-
mock_call.input(3, :accept_key => false) { |buffer| buffer.size == 2 }.should == '93'
|
|
1018
|
-
end
|
|
1019
|
-
|
|
1020
|
-
it "Input timing out when digits are pressed returns only the collected digits" do
|
|
1021
|
-
timeout = 1.day
|
|
1022
|
-
mock_call.should_receive(:wait_for_digit).twice.with(timeout).and_return '5', nil
|
|
1023
|
-
mock_call.input(9, :timeout => timeout).should == '5'
|
|
1024
|
-
end
|
|
1025
|
-
|
|
1026
|
-
it 'passes wait_for_digit the :timeout option when one is given' do
|
|
1027
|
-
timeout = 1.minute
|
|
1028
|
-
mock_call.should_receive(:interruptible_play!).never
|
|
1029
|
-
mock_call.should_receive(:wait_for_digit).twice.with(timeout).and_return '1', '2'
|
|
1030
|
-
mock_call.input(2, :timeout => timeout).should == '12'
|
|
1031
|
-
end
|
|
1032
|
-
|
|
1033
|
-
it 'executes interruptible_play!() with all of the files given to :play' do
|
|
1034
|
-
sound_files = %w[foo bar qaz]
|
|
1035
|
-
mock_call.should_receive(:interruptible_play!).once.with('foo').and_return nil
|
|
1036
|
-
mock_call.should_receive(:interruptible_play!).once.with('bar').and_return nil
|
|
1037
|
-
mock_call.should_receive(:interruptible_play!).once.with('qaz').and_return '#'
|
|
1038
|
-
mock_call.should_receive(:wait_for_digit).once.with(-1).and_return '*'
|
|
1039
|
-
mock_call.input(2, :play => sound_files).should == '#*'
|
|
1040
|
-
end
|
|
1041
|
-
|
|
1042
|
-
it 'executes #play! when :interruptible is set to false' do
|
|
1043
|
-
sound_files = %w[foo bar qaz]
|
|
1044
|
-
mock_call.should_receive(:play!).once.with('foo').and_return true
|
|
1045
|
-
mock_call.should_receive(:play!).once.with('bar').and_return true
|
|
1046
|
-
mock_call.should_receive(:play!).once.with('qaz').and_return true
|
|
1047
|
-
mock_call.should_receive(:wait_for_digit).once.with(-1).and_return '*'
|
|
1048
|
-
mock_call.input(1, :play => sound_files, :interruptible => false).should == '*'
|
|
1049
|
-
end
|
|
1050
|
-
|
|
1051
|
-
it 'pressing the terminating key before any other digits returns an empty string' do
|
|
1052
|
-
mock_call.should_receive(:wait_for_digit).once.with(-1).and_return '*'
|
|
1053
|
-
mock_call.input(:accept_key => '*').should == ''
|
|
1054
|
-
end
|
|
1055
|
-
|
|
1056
|
-
it 'should execute wait_for_digit first if no sound files are given' do
|
|
1057
|
-
mock_call.should_receive(:interruptible_play!).never
|
|
1058
|
-
mock_call.should_receive(:wait_for_digit).once.with(-1).and_throw :digit_request
|
|
1059
|
-
should_throw(:digit_request) { mock_call.input(1) }
|
|
1060
|
-
end
|
|
1061
|
-
|
|
1062
|
-
it "Input timing out when digits are pressed returns only the collected digits" do
|
|
1063
|
-
timeout = 1.day
|
|
1064
|
-
mock_call.should_receive(:wait_for_digit).twice.with(timeout).and_return '5', nil
|
|
1065
|
-
mock_call.input(9, :timeout => timeout).should == '5'
|
|
1066
|
-
end
|
|
1067
|
-
|
|
1068
|
-
it 'should execute wait_for_digit, even if some interruptible sound files are not found' do
|
|
1069
|
-
pbx_should_respond_with_stream_file_failure_on_open
|
|
1070
|
-
file = 'foobar'
|
|
1071
|
-
initial_timeout = 1.hour
|
|
1072
|
-
interdigit_timeout = 1.minute
|
|
1073
|
-
mock_call.should_receive(:wait_for_digit).once.with(initial_timeout).and_return '8'
|
|
1074
|
-
mock_call.should_receive(:wait_for_digit).once.with(interdigit_timeout).and_return '9'
|
|
1075
|
-
mock_call.input(2, :initial_timeout => initial_timeout, :interdigit_timeout => interdigit_timeout, :play => file).should == '89'
|
|
1076
|
-
pbx_was_asked_to_stream file
|
|
1077
|
-
end
|
|
1078
|
-
|
|
1079
|
-
it 'should execute wait_for_digit, even if some uninterruptible sound files are not found' do
|
|
1080
|
-
pbx_should_respond_with_playback_failure
|
|
1081
|
-
file = 'foobar'
|
|
1082
|
-
initial_timeout = 1.hour
|
|
1083
|
-
interdigit_timeout = 1.minute
|
|
1084
|
-
mock_call.should_receive(:wait_for_digit).once.with(initial_timeout).and_return '8'
|
|
1085
|
-
mock_call.should_receive(:wait_for_digit).once.with(interdigit_timeout).and_return '9'
|
|
1086
|
-
mock_call.input(2, :initial_timeout => initial_timeout, :interdigit_timeout => interdigit_timeout, :play => file, :interruptible => false).should == '89'
|
|
1087
|
-
pbx_was_asked_to_play file
|
|
1088
|
-
end
|
|
1089
|
-
|
|
1090
|
-
it 'should return an empty string if no keys are pressed, even if the sound file is not found' do
|
|
1091
|
-
pbx_should_respond_with_stream_file_failure_on_open
|
|
1092
|
-
file = 'foobar'
|
|
1093
|
-
timeout = 1.second
|
|
1094
|
-
mock_call.should_receive(:wait_for_digit).once.with(timeout).and_return nil
|
|
1095
|
-
mock_call.input(5, :timeout => timeout, :play => file).should == ''
|
|
1096
|
-
pbx_was_asked_to_stream file
|
|
1097
|
-
end
|
|
1098
|
-
|
|
1099
|
-
it 'should play a series of files, collecting digits even if some of the sound files cannot be found' do
|
|
1100
|
-
pbx_should_respond_with_stream_file_success 0
|
|
1101
|
-
pbx_should_respond_with_stream_file_success 0
|
|
1102
|
-
pbx_should_respond_with_stream_file_failure_on_open
|
|
1103
|
-
pbx_should_respond_with_stream_file_success ?1.ord
|
|
1104
|
-
|
|
1105
|
-
play_files = ('sound1'..'sound6').map &:to_s
|
|
1106
|
-
played_files = ('sound1'..'sound4').map &:to_s
|
|
1107
|
-
timeout = 1.minute
|
|
1108
|
-
mock_call.should_receive(:wait_for_digit).twice.with(timeout).and_return '2', '3'
|
|
1109
|
-
mock_call.input(3, :timeout => timeout, :play => play_files).should == '123'
|
|
1110
|
-
pbx_was_asked_to_stream played_files
|
|
1111
|
-
end
|
|
1112
|
-
|
|
1113
|
-
it 'should play a series of 4 interruptible sounds, collecting digits even if some of the sound files cannot be found' do
|
|
1114
|
-
pbx_should_respond_with_stream_file_success 0
|
|
1115
|
-
pbx_should_respond_with_stream_file_success 0
|
|
1116
|
-
pbx_should_respond_with_stream_file_failure_on_open
|
|
1117
|
-
pbx_should_respond_with_stream_file_success 0
|
|
1118
|
-
pbx_should_respond_with_stream_file_success ?1.ord
|
|
1119
|
-
|
|
1120
|
-
play_files = ('sound1'..'sound8').map &:to_s
|
|
1121
|
-
played_files = ('sound1'..'sound5').map &:to_s
|
|
1122
|
-
timeout = 1.second
|
|
1123
|
-
mock_call.should_receive(:wait_for_digit).times(3).with(timeout).and_return '2', '3', '4'
|
|
1124
|
-
mock_call.input(4, :timeout => timeout, :play => play_files).should == '1234'
|
|
1125
|
-
pbx_was_asked_to_stream played_files
|
|
1126
|
-
end
|
|
1127
|
-
|
|
1128
|
-
it 'should not raise an exception if the sound file is unplayable' do
|
|
1129
|
-
pbx_should_respond_with_stream_file_failure_on_open
|
|
1130
|
-
file = 'foobar'
|
|
1131
|
-
mock_call.should_receive(:wait_for_digit).once.with -1
|
|
1132
|
-
the_following_code {
|
|
1133
|
-
mock_call.input 1, :play => file
|
|
1134
|
-
}.should_not raise_error
|
|
1135
|
-
pbx_was_asked_to_stream file
|
|
1136
|
-
end
|
|
1137
|
-
|
|
1138
|
-
it 'should default to playing interruptible prompts' do
|
|
1139
|
-
mock_call.should_receive(:interruptible_play!).once.with('does_not_matter')
|
|
1140
|
-
mock_call.should_receive(:wait_for_digit).once.with -1
|
|
1141
|
-
mock_call.input(1, :play => 'does_not_matter')
|
|
1142
|
-
end
|
|
1143
|
-
|
|
1144
|
-
it 'should render uninterruptible prompts' do
|
|
1145
|
-
mock_call.should_receive(:play!).once.with('does_not_matter')
|
|
1146
|
-
mock_call.should_receive(:wait_for_digit).once.with -1
|
|
1147
|
-
mock_call.input(1, :play => 'does_not_matter', :interruptible => false)
|
|
1148
|
-
end
|
|
1149
|
-
|
|
1150
|
-
it 'should fall back to speaking TTS if sound file is unplayable' do
|
|
1151
|
-
pbx_should_respond_with_stream_file_failure_on_open
|
|
1152
|
-
mock_call.should_receive(:speak).once.with("The sound file was not available", :interruptible => true)
|
|
1153
|
-
mock_call.should_receive(:wait_for_digit).once.with -1
|
|
1154
|
-
mock_call.input(1, :play => 'unavailable sound file', :speak => {:text => "The sound file was not available"})
|
|
1155
|
-
@output.read.should == "STREAM FILE \"unavailable sound file\" \"1234567890*#\"\n"
|
|
1156
|
-
end
|
|
1157
|
-
|
|
1158
|
-
it 'waits for digits for :initial_timeout if fall back TTS is not interrupted' do
|
|
1159
|
-
initial_timeout = 10.seconds
|
|
1160
|
-
interdigit_timeout = 5.seconds
|
|
1161
|
-
text = "What's your sign?"
|
|
1162
|
-
missing_sound_file = 'missing-sound-file'
|
|
1163
|
-
pbx_should_respond_with_stream_file_failure_on_open
|
|
1164
|
-
mock_call.should_receive(:speak).once.with(text, :interruptible => true).and_return nil
|
|
1165
|
-
mock_call.should_receive(:wait_for_digit).once.with(initial_timeout).and_return '1'
|
|
1166
|
-
mock_call.should_receive(:wait_for_digit).once.with(interdigit_timeout).and_return '2'
|
|
1167
|
-
mock_call.input(2, :play => missing_sound_file, :speak => {:text => text}, :initial_timeout => initial_timeout, :interdigit_timeout => interdigit_timeout).should eq '12'
|
|
1168
|
-
@output.read.should == "STREAM FILE \"#{missing_sound_file}\" \"1234567890*#\"\n"
|
|
1169
|
-
end
|
|
1170
|
-
|
|
1171
|
-
it 'ignores :initial_timeout if fall back TTS is interrupted' do
|
|
1172
|
-
initial_timeout = 10.seconds
|
|
1173
|
-
interdigit_timeout = 5.seconds
|
|
1174
|
-
text = "What's your sign?"
|
|
1175
|
-
missing_sound_file = 'missing-sound-file'
|
|
1176
|
-
pbx_should_respond_with_stream_file_failure_on_open
|
|
1177
|
-
mock_call.should_receive(:speak).once.with(text, :interruptible => true).and_return '1'
|
|
1178
|
-
mock_call.should_receive(:wait_for_digit).once.with(interdigit_timeout).and_return '2'
|
|
1179
|
-
mock_call.input(2, :play => missing_sound_file, :speak => {:text => text}, :initial_timeout => initial_timeout, :interdigit_timeout => interdigit_timeout).should eq '12'
|
|
1180
|
-
@output.read.should == "STREAM FILE \"#{missing_sound_file}\" \"1234567890*#\"\n"
|
|
1181
|
-
end
|
|
1182
|
-
|
|
1183
|
-
it 'should allow uninterruptible TTS prompts' do
|
|
1184
|
-
mock_call.should_receive(:speak).once.with("The sound file was not available", :interruptible => false)
|
|
1185
|
-
mock_call.should_receive(:wait_for_digit).once.with -1
|
|
1186
|
-
mock_call.input(1, :speak => {:text => "The sound file was not available"}, :interruptible => false)
|
|
1187
|
-
end
|
|
1188
|
-
|
|
1189
|
-
it 'should play a series of 4 uninterruptible sounds, collecting digits even if some of the sound files cannot be found' do
|
|
1190
|
-
pbx_should_respond_with_playback_success
|
|
1191
|
-
pbx_should_respond_with_playback_failure
|
|
1192
|
-
pbx_should_respond_with_playback_success
|
|
1193
|
-
|
|
1194
|
-
files = ('sound1'..'sound3').map &:to_s
|
|
1195
|
-
timeout = 1.second
|
|
1196
|
-
mock_call.should_receive(:wait_for_digit).twice.with(timeout).and_return '6', '7'
|
|
1197
|
-
mock_call.input(2, :timeout => timeout, :play => files, :interruptible => false).should == '67'
|
|
1198
|
-
pbx_was_asked_to_play files
|
|
1199
|
-
end
|
|
1200
|
-
|
|
1201
|
-
it 'should raise ArgumentError if passed an empty :accept_key' do
|
|
1202
|
-
expect { mock_call.input 1, :accept_key => "" }.to raise_error ArgumentError
|
|
1203
|
-
end
|
|
1204
|
-
|
|
1205
|
-
end
|
|
1206
|
-
|
|
1207
|
-
describe 'The #input! method' do
|
|
1208
|
-
|
|
1209
|
-
include DialplanCommandTestHelpers
|
|
1210
|
-
|
|
1211
|
-
it 'should raise an error when the number of digits expected is -1 (this is deprecated behavior)' do
|
|
1212
|
-
the_following_code {
|
|
1213
|
-
mock_call.input! -1
|
|
1214
|
-
}.should raise_error ArgumentError
|
|
1215
|
-
end
|
|
1216
|
-
|
|
1217
|
-
it 'should execute wait_for_digit if no digit is pressed during interruptible_play!' do
|
|
1218
|
-
sound_files = %w[one two three]
|
|
1219
|
-
mock_call.should_receive(:interruptible_play!).once.with('one').and_return nil
|
|
1220
|
-
mock_call.should_receive(:interruptible_play!).once.with('two').and_return nil
|
|
1221
|
-
mock_call.should_receive(:interruptible_play!).once.with('three').and_return nil
|
|
1222
|
-
mock_call.should_receive(:wait_for_digit).once.with(-1).and_throw :digit_request
|
|
1223
|
-
should_throw(:digit_request) { mock_call.input! 10, :play => sound_files }
|
|
1224
|
-
end
|
|
1225
|
-
|
|
1226
|
-
it 'waits for digits with :initial_timeout and :interdigit_timeout' do
|
|
1227
|
-
initial_timeout = 6.seconds
|
|
1228
|
-
interdigit_timeout = 3.seconds
|
|
1229
|
-
mock_call.should_receive(:interruptible_play!).never
|
|
1230
|
-
mock_call.should_receive(:wait_for_digit).once.with(initial_timeout).and_return '1'
|
|
1231
|
-
mock_call.should_receive(:wait_for_digit).times(3).with(interdigit_timeout).and_return '2', '3', '4'
|
|
1232
|
-
mock_call.input!(4, :initial_timeout => initial_timeout, :interdigit_timeout => interdigit_timeout).should eq '1234'
|
|
1233
|
-
end
|
|
1234
|
-
|
|
1235
|
-
it 'waits for digits with :initial_timeout when nothing is pressed' do
|
|
1236
|
-
initial_timeout = 6.seconds
|
|
1237
|
-
interdigit_timeout = 3.seconds
|
|
1238
|
-
mock_call.should_receive(:interruptible_play!).never
|
|
1239
|
-
mock_call.should_receive(:wait_for_digit).once.with(initial_timeout).and_return nil
|
|
1240
|
-
mock_call.input!(4, :initial_timeout => initial_timeout, :interdigit_timeout => interdigit_timeout).should eq ''
|
|
1241
|
-
end
|
|
1242
|
-
|
|
1243
|
-
it 'waits for digits, ignoring :timeout if :initial_timeout and :interdigit_timeout are provided' do
|
|
1244
|
-
timeout = 99.hours
|
|
1245
|
-
initial_timeout = 2.seconds
|
|
1246
|
-
interdigit_timeout = 1.second
|
|
1247
|
-
mock_call.should_receive(:wait_for_digit).once.with(initial_timeout).and_return '1'
|
|
1248
|
-
mock_call.should_receive(:wait_for_digit).times(3).with(interdigit_timeout).and_return '2', '3', '4'
|
|
1249
|
-
mock_call.input!(4, :timeout => timeout, :initial_timeout => initial_timeout, :interdigit_timeout => interdigit_timeout).should eq '1234'
|
|
1250
|
-
end
|
|
1251
|
-
|
|
1252
|
-
it 'waits for digits, and given a :timeout and :initial_timeout, defaults :interdigit_timeout to :timeout' do
|
|
1253
|
-
initial_timeout = 20.seconds
|
|
1254
|
-
timeout = 10.seconds
|
|
1255
|
-
mock_call.should_receive(:wait_for_digit).once.with(initial_timeout).and_return '1'
|
|
1256
|
-
mock_call.should_receive(:wait_for_digit).times(2).with(timeout).and_return '2', '3'
|
|
1257
|
-
mock_call.input!(3, :timeout => timeout, :initial_timeout => initial_timeout).should eq '123'
|
|
1258
|
-
end
|
|
1259
|
-
|
|
1260
|
-
it 'waits for digits, and given a :timeout and :interdigit_timeout, defaults :initial_timeout to :timeout' do
|
|
1261
|
-
timeout = 12.seconds
|
|
1262
|
-
interdigit_timeout = 6.seconds
|
|
1263
|
-
mock_call.should_receive(:wait_for_digit).once.with(timeout).and_return '1'
|
|
1264
|
-
mock_call.should_receive(:wait_for_digit).times(4).with(interdigit_timeout).and_return '2', '3', '4', '5'
|
|
1265
|
-
mock_call.input!(5, :timeout => timeout, :interdigit_timeout => interdigit_timeout).should eq '12345'
|
|
1266
|
-
end
|
|
1267
|
-
|
|
1268
|
-
it 'waits for digits for :initial_timeout if sound playback is not interrupted' do
|
|
1269
|
-
initial_timeout = 8.seconds
|
|
1270
|
-
interdigit_timeout = 4.seconds
|
|
1271
|
-
sound_files = %w[ready set go]
|
|
1272
|
-
mock_call.should_receive(:interruptible_play!).once.with('ready').and_return nil
|
|
1273
|
-
mock_call.should_receive(:interruptible_play!).once.with('set').and_return nil
|
|
1274
|
-
mock_call.should_receive(:interruptible_play!).once.with('go').and_return nil
|
|
1275
|
-
mock_call.should_receive(:wait_for_digit).once.with(initial_timeout).and_return '1'
|
|
1276
|
-
mock_call.should_receive(:wait_for_digit).times(4).with(interdigit_timeout).and_return '2', '3', '4', '5'
|
|
1277
|
-
mock_call.input!(5, :play => sound_files, :initial_timeout => initial_timeout, :interdigit_timeout => interdigit_timeout).should eq '12345'
|
|
1278
|
-
end
|
|
1279
|
-
|
|
1280
|
-
it 'ignores :initial_timeout if sound playback is interrupted' do
|
|
1281
|
-
initial_timeout = 8.seconds
|
|
1282
|
-
interdigit_timeout = 4.seconds
|
|
1283
|
-
sound_files = %w[ready set go]
|
|
1284
|
-
mock_call.should_receive(:interruptible_play!).once.with('ready').and_return nil
|
|
1285
|
-
mock_call.should_receive(:interruptible_play!).once.with('set').and_return '*'
|
|
1286
|
-
mock_call.should_receive(:wait_for_digit).times(4).with(interdigit_timeout).and_return '2', '3', '4', '5'
|
|
1287
|
-
mock_call.input!(5, :play => sound_files, :initial_timeout => initial_timeout, :interdigit_timeout => interdigit_timeout).should eq '*2345'
|
|
1288
|
-
end
|
|
1289
|
-
|
|
1290
|
-
it 'waits for digits for :initial_timeout if speech is not interrupted' do
|
|
1291
|
-
initial_timeout = 10.seconds
|
|
1292
|
-
interdigit_timeout = 5.seconds
|
|
1293
|
-
text = "What's your area code?"
|
|
1294
|
-
mock_call.should_receive(:speak).once.with(text, :interruptible => true).and_return nil
|
|
1295
|
-
mock_call.should_receive(:wait_for_digit).once.with(initial_timeout).and_return '1'
|
|
1296
|
-
mock_call.should_receive(:wait_for_digit).times(2).with(interdigit_timeout).and_return '2', '0'
|
|
1297
|
-
mock_call.input!(3, :initial_timeout => initial_timeout, :interdigit_timeout => interdigit_timeout, :speak => {:text => text}).should eq '120'
|
|
1298
|
-
end
|
|
1299
|
-
|
|
1300
|
-
it 'ignores :initial_timeout if speech is interrupted' do
|
|
1301
|
-
initial_timeout = 10.seconds
|
|
1302
|
-
interdigit_timeout = 5.seconds
|
|
1303
|
-
text = "What's your area code?"
|
|
1304
|
-
mock_call.should_receive(:speak).once.with(text, :interruptible => true).and_return '3'
|
|
1305
|
-
mock_call.should_receive(:wait_for_digit).times(2).with(interdigit_timeout).and_return '1', '2'
|
|
1306
|
-
mock_call.input!(3, :initial_timeout => initial_timeout, :interdigit_timeout => interdigit_timeout, :speak => {:text => text}).should eq '312'
|
|
1307
|
-
end
|
|
1308
|
-
|
|
1309
|
-
it 'executes interruptible_play!() with all of the files given to :play' do
|
|
1310
|
-
sound_files = %w[foo bar qaz]
|
|
1311
|
-
mock_call.should_receive(:interruptible_play!).once.with('foo').and_return nil
|
|
1312
|
-
mock_call.should_receive(:interruptible_play!).once.with('bar').and_return nil
|
|
1313
|
-
mock_call.should_receive(:interruptible_play!).once.with('qaz').and_return '#'
|
|
1314
|
-
mock_call.should_receive(:wait_for_digit).once.with(-1).and_return '*'
|
|
1315
|
-
mock_call.input!(2, :play => sound_files).should == '#*'
|
|
1316
|
-
end
|
|
1317
|
-
|
|
1318
|
-
it 'executes play!() with all of the files given to :play' do
|
|
1319
|
-
sound_files = %w[foo bar qaz]
|
|
1320
|
-
mock_call.should_receive(:play!).once.with('foo').and_return true
|
|
1321
|
-
mock_call.should_receive(:play!).once.with('bar').and_return true
|
|
1322
|
-
mock_call.should_receive(:play!).once.with('qaz').and_return true
|
|
1323
|
-
mock_call.should_receive(:wait_for_digit).once.with(-1).and_return '*'
|
|
1324
|
-
mock_call.input!(1, :play => sound_files, :interruptible => false).should == '*'
|
|
1325
|
-
end
|
|
1326
|
-
|
|
1327
|
-
it 'should execute wait_for_digit first if no sound files are given' do
|
|
1328
|
-
mock_call.should_receive(:interruptible_play!).never
|
|
1329
|
-
mock_call.should_receive(:wait_for_digit).once.with(-1).and_throw :digit_request
|
|
1330
|
-
should_throw(:digit_request) { mock_call.input! 1 }
|
|
1331
|
-
end
|
|
1332
|
-
|
|
1333
|
-
it 'should raise an error when the sound file is not found' do
|
|
1334
|
-
pbx_should_respond_with_stream_file_failure_on_open
|
|
1335
|
-
file = 'foobar'
|
|
1336
|
-
mock_call.should_receive(:wait_for_digit).never
|
|
1337
|
-
the_following_code {
|
|
1338
|
-
mock_call.input! 1, :play => file
|
|
1339
|
-
}.should raise_error Adhearsion::VoIP::PlaybackError
|
|
1340
|
-
pbx_was_asked_to_stream file
|
|
1341
|
-
end
|
|
1342
|
-
|
|
1343
|
-
it 'should fall back to speaking TTS if sound file is unplayable' do
|
|
1344
|
-
pbx_should_respond_with_stream_file_failure_on_open
|
|
1345
|
-
mock_call.should_receive(:speak).once.with("The sound file was not available", :interruptible => true)
|
|
1346
|
-
mock_call.should_receive(:wait_for_digit).once.with -1
|
|
1347
|
-
mock_call.input!(1, :play => 'unavailable sound file', :speak => {:text => "The sound file was not available"})
|
|
1348
|
-
@output.read.should == "STREAM FILE \"unavailable sound file\" \"1234567890*#\"\n"
|
|
1349
|
-
end
|
|
1350
|
-
|
|
1351
|
-
it 'waits for digits for :initial_timeout if fall back TTS is not interrupted' do
|
|
1352
|
-
initial_timeout = 10.seconds
|
|
1353
|
-
interdigit_timeout = 5.seconds
|
|
1354
|
-
text = "What's your sign?"
|
|
1355
|
-
missing_sound_file = 'missing-sound-file'
|
|
1356
|
-
pbx_should_respond_with_stream_file_failure_on_open
|
|
1357
|
-
mock_call.should_receive(:speak).once.with(text, :interruptible => true).and_return nil
|
|
1358
|
-
mock_call.should_receive(:wait_for_digit).once.with(initial_timeout).and_return '1'
|
|
1359
|
-
mock_call.should_receive(:wait_for_digit).once.with(interdigit_timeout).and_return '2'
|
|
1360
|
-
mock_call.input!(2, :play => missing_sound_file, :speak => {:text => text}, :initial_timeout => initial_timeout, :interdigit_timeout => interdigit_timeout).should eq '12'
|
|
1361
|
-
@output.read.should == "STREAM FILE \"#{missing_sound_file}\" \"1234567890*#\"\n"
|
|
1362
|
-
end
|
|
1363
|
-
|
|
1364
|
-
it 'ignores :initial_timeout if fall back TTS is interrupted' do
|
|
1365
|
-
initial_timeout = 10.seconds
|
|
1366
|
-
interdigit_timeout = 5.seconds
|
|
1367
|
-
text = "What's your sign?"
|
|
1368
|
-
missing_sound_file = 'missing-sound-file'
|
|
1369
|
-
pbx_should_respond_with_stream_file_failure_on_open
|
|
1370
|
-
mock_call.should_receive(:speak).once.with(text, :interruptible => true).and_return '1'
|
|
1371
|
-
mock_call.should_receive(:wait_for_digit).once.with(interdigit_timeout).and_return '2'
|
|
1372
|
-
mock_call.input!(2, :play => missing_sound_file, :speak => {:text => text}, :initial_timeout => initial_timeout, :interdigit_timeout => interdigit_timeout).should eq '12'
|
|
1373
|
-
@output.read.should == "STREAM FILE \"#{missing_sound_file}\" \"1234567890*#\"\n"
|
|
1374
|
-
end
|
|
1375
|
-
|
|
1376
|
-
it 'should play a series of interruptible files, raising an error if a sound file cannot be found' do
|
|
1377
|
-
pbx_should_respond_with_stream_file_success 0
|
|
1378
|
-
pbx_should_respond_with_stream_file_failure_on_open
|
|
1379
|
-
mock_call.should_receive(:wait_for_digit).never
|
|
1380
|
-
|
|
1381
|
-
play_files = ('sound1'..'sound6').map &:to_s
|
|
1382
|
-
played_files = ('sound1'..'sound2').map &:to_s
|
|
1383
|
-
the_following_code {
|
|
1384
|
-
mock_call.input! 10, :play => play_files, :timeout => 5.seconds
|
|
1385
|
-
}.should raise_error Adhearsion::VoIP::PlaybackError
|
|
1386
|
-
pbx_was_asked_to_stream played_files
|
|
1387
|
-
end
|
|
1388
|
-
|
|
1389
|
-
it 'should play a series of uninterruptible files, raising an error if a sound file cannot be found' do
|
|
1390
|
-
pbx_should_respond_with_playback_success
|
|
1391
|
-
pbx_should_respond_with_playback_failure
|
|
1392
|
-
|
|
1393
|
-
play_files = ('sound1'..'sound6').map &:to_s
|
|
1394
|
-
played_files = ('sound1'..'sound2').map &:to_s
|
|
1395
|
-
the_following_code {
|
|
1396
|
-
mock_call.input! 10, :play => play_files, :timeout => 5.seconds, :interruptible => false
|
|
1397
|
-
}.should raise_error Adhearsion::VoIP::PlaybackError
|
|
1398
|
-
pbx_was_asked_to_play played_files
|
|
1399
|
-
end
|
|
1400
|
-
|
|
1401
|
-
it 'should raise ArgumentError if passed an empty :accept_key' do
|
|
1402
|
-
expect { mock_call.input 1, :accept_key => "" }.to raise_error ArgumentError
|
|
1403
|
-
end
|
|
1404
|
-
|
|
1405
|
-
end
|
|
1406
|
-
|
|
1407
|
-
describe "The #variable method" do
|
|
1408
|
-
|
|
1409
|
-
include DialplanCommandTestHelpers
|
|
1410
|
-
|
|
1411
|
-
it "should call set_variable for every Hash-key argument given" do
|
|
1412
|
-
args = [:ohai, "ur_home_erly"]
|
|
1413
|
-
mock_call.should_receive(:set_variable).once.with(*args)
|
|
1414
|
-
mock_call.variable Hash[*args]
|
|
1415
|
-
end
|
|
1416
|
-
|
|
1417
|
-
it "should call set_variable for every Hash-key argument given" do
|
|
1418
|
-
many_args = { :a => :b, :c => :d, :e => :f, :g => :h}
|
|
1419
|
-
mock_call.should_receive(:set_variable).times(many_args.size)
|
|
1420
|
-
mock_call.variable many_args
|
|
1421
|
-
end
|
|
1422
|
-
|
|
1423
|
-
it "should call get_variable for every String given" do
|
|
1424
|
-
variables = ["foo", "bar", :qaz, :qwerty, :baz]
|
|
1425
|
-
variables.each do |var|
|
|
1426
|
-
mock_call.should_receive(:get_variable).once.with(var).and_return("X")
|
|
1427
|
-
end
|
|
1428
|
-
mock_call.variable(*variables)
|
|
1429
|
-
end
|
|
1430
|
-
|
|
1431
|
-
it "should NOT return an Array when just one arg is given" do
|
|
1432
|
-
mock_call.should_receive(:get_variable).once.and_return "lol"
|
|
1433
|
-
mock_call.variable(:foo).should_not be_a_kind_of Array
|
|
1434
|
-
end
|
|
1435
|
-
|
|
1436
|
-
it "should raise an ArgumentError when a Hash and normal args are given" do
|
|
1437
|
-
the_following_code {
|
|
1438
|
-
mock_call.variable 5,4,3,2,1, :foo => :bar
|
|
1439
|
-
}.should raise_error ArgumentError
|
|
1440
|
-
end
|
|
1441
|
-
|
|
1442
|
-
end
|
|
1443
|
-
|
|
1444
|
-
describe "The #set_variable method" do
|
|
1445
|
-
|
|
1446
|
-
include DialplanCommandTestHelpers
|
|
1447
|
-
|
|
1448
|
-
it "variables and values are properly quoted" do
|
|
1449
|
-
mock_call.should_receive(:raw_response).once.with 'SET VARIABLE "foo" "i can \\" has ruby?"'
|
|
1450
|
-
mock_call.set_variable 'foo', 'i can " has ruby?'
|
|
1451
|
-
end
|
|
1452
|
-
|
|
1453
|
-
it "to_s() is effectively called on both the key and the value" do
|
|
1454
|
-
mock_call.should_receive(:raw_response).once.with 'SET VARIABLE "QAZ" "QWERTY"'
|
|
1455
|
-
mock_call.set_variable :QAZ, :QWERTY
|
|
1456
|
-
end
|
|
1457
|
-
|
|
1458
|
-
end
|
|
1459
|
-
|
|
1460
|
-
describe "The #sip_add_header method" do
|
|
1461
|
-
include DialplanCommandTestHelpers
|
|
1462
|
-
|
|
1463
|
-
it "values are properly quoted" do
|
|
1464
|
-
mock_call.should_receive(:raw_response).once.with 'EXEC SIPAddHeader "x-ahn-header: rubyrox"'
|
|
1465
|
-
mock_call.sip_add_header "x-ahn-header", "rubyrox"
|
|
1466
|
-
end
|
|
1467
|
-
end
|
|
1468
|
-
|
|
1469
|
-
describe "The #sip_get_header method" do
|
|
1470
|
-
include DialplanCommandTestHelpers
|
|
1471
|
-
|
|
1472
|
-
it "properly formats the AGI request" do
|
|
1473
|
-
value = 'jason-was-here'
|
|
1474
|
-
mock_call.should_receive(:raw_response).once.with('GET VARIABLE "SIP_HEADER(x-ahn-header)"').and_return "200 result=1 (#{value})"
|
|
1475
|
-
mock_call.sip_get_header("x-ahn-header").should == value
|
|
1476
|
-
end
|
|
1477
|
-
|
|
1478
|
-
it "properly formats the AGI request using the method alias" do
|
|
1479
|
-
value = 'jason-was-here'
|
|
1480
|
-
mock_call.should_receive(:raw_response).once.with('GET VARIABLE "SIP_HEADER(x-ahn-header)"').and_return "200 result=1 (#{value})"
|
|
1481
|
-
mock_call.sip_header("x-ahn-header").should == value
|
|
1482
|
-
end
|
|
1483
|
-
end
|
|
1484
|
-
|
|
1485
|
-
describe 'The #voicemail command' do
|
|
1486
|
-
|
|
1487
|
-
include DialplanCommandTestHelpers
|
|
1488
|
-
|
|
1489
|
-
it 'should not send the context name when none is given' do
|
|
1490
|
-
mailbox_number = 123
|
|
1491
|
-
mock_call.should_receive(:execute).once.with('voicemail', 123, '').and_throw :sent_voicemail!
|
|
1492
|
-
should_throw(:sent_voicemail!) { mock_call.voicemail 123 }
|
|
1493
|
-
end
|
|
1494
|
-
|
|
1495
|
-
it 'should send the context name when one is given' do
|
|
1496
|
-
mailbox_number, context_name = 333, 'doesntmatter'
|
|
1497
|
-
mock_call.should_receive(:execute).once.with('voicemail', "#{mailbox_number}@#{context_name}", '').and_throw :sent_voicemail!
|
|
1498
|
-
should_throw(:sent_voicemail!) { mock_call.voicemail(context_name => mailbox_number) }
|
|
1499
|
-
end
|
|
1500
|
-
|
|
1501
|
-
it 'should pass in the s option if :skip => true' do
|
|
1502
|
-
mailbox_number = '012'
|
|
1503
|
-
mock_call.should_receive(:execute).once.with('voicemail', mailbox_number, 's').and_throw :sent_voicemail!
|
|
1504
|
-
should_throw(:sent_voicemail!) { mock_call.voicemail(mailbox_number, :skip => true) }
|
|
1505
|
-
end
|
|
1506
|
-
|
|
1507
|
-
it 'should combine mailbox numbers with the context name given when both are given' do
|
|
1508
|
-
pbx_should_respond_with_value 'SUCCESS'
|
|
1509
|
-
context = "lolcats"
|
|
1510
|
-
mailboxes = [1,2,3,4,5]
|
|
1511
|
-
mailboxes_with_context = mailboxes.map { |mailbox| "#{mailbox}@#{context}"}
|
|
1512
|
-
mock_call.should_receive(:execute).once.with('voicemail', mailboxes_with_context.join('&'), '')
|
|
1513
|
-
mock_call.voicemail context => mailboxes
|
|
1514
|
-
pbx_should_have_been_sent 'GET VARIABLE "VMSTATUS"'
|
|
1515
|
-
end
|
|
1516
|
-
|
|
1517
|
-
it 'should raise an argument error if the mailbox number is not numerical' do
|
|
1518
|
-
the_following_code {
|
|
1519
|
-
mock_call.voicemail :foo => "bar"
|
|
1520
|
-
}.should raise_error ArgumentError
|
|
1521
|
-
end
|
|
1522
|
-
|
|
1523
|
-
it 'should raise an argument error if too many arguments are supplied' do
|
|
1524
|
-
the_following_code {
|
|
1525
|
-
mock_call.voicemail "wtfisthisargument", :context_name => 123, :greeting => :busy
|
|
1526
|
-
}.should raise_error ArgumentError
|
|
1527
|
-
end
|
|
1528
|
-
|
|
1529
|
-
it 'should raise an ArgumentError if multiple context names are given' do
|
|
1530
|
-
the_following_code {
|
|
1531
|
-
mock_call.voicemail :one => [1,2,3], :two => [11,22,33]
|
|
1532
|
-
}.should raise_error ArgumentError
|
|
1533
|
-
end
|
|
1534
|
-
|
|
1535
|
-
it "should raise an ArgumentError when the :greeting value isn't recognized" do
|
|
1536
|
-
the_following_code {
|
|
1537
|
-
mock_call.voicemail :context_name => 123, :greeting => :zomgz
|
|
1538
|
-
}.should raise_error ArgumentError
|
|
1539
|
-
end
|
|
1540
|
-
|
|
1541
|
-
it 'should pass in the u option if :greeting => :unavailable' do
|
|
1542
|
-
mailbox_number = '776'
|
|
1543
|
-
mock_call.should_receive(:execute).once.with('voicemail', mailbox_number, 'u').and_throw :sent_voicemail!
|
|
1544
|
-
should_throw(:sent_voicemail!) { mock_call.voicemail(mailbox_number, :greeting => :unavailable) }
|
|
1545
|
-
end
|
|
1546
|
-
|
|
1547
|
-
it 'should pass in both the skip and greeting options if both are supplied' do
|
|
1548
|
-
mailbox_number = '4'
|
|
1549
|
-
mock_call.should_receive(:execute).once.with('voicemail', mailbox_number, 'u').and_throw :sent_voicemail!
|
|
1550
|
-
should_throw(:sent_voicemail!) { mock_call.voicemail(mailbox_number, :greeting => :unavailable) }
|
|
1551
|
-
end
|
|
1552
|
-
|
|
1553
|
-
it 'should raise an ArgumentError if mailbox_number is blank?()' do
|
|
1554
|
-
the_following_code {
|
|
1555
|
-
mock_call.voicemail ''
|
|
1556
|
-
}.should raise_error ArgumentError
|
|
1557
|
-
|
|
1558
|
-
the_following_code {
|
|
1559
|
-
mock_call.voicemail nil
|
|
1560
|
-
}.should raise_error ArgumentError
|
|
1561
|
-
end
|
|
1562
|
-
|
|
1563
|
-
it 'should pass in the b option if :gretting => :busy' do
|
|
1564
|
-
mailbox_number = '1'
|
|
1565
|
-
mock_call.should_receive(:execute).once.with('voicemail', mailbox_number, 'b').and_throw :sent_voicemail!
|
|
1566
|
-
should_throw(:sent_voicemail!) { mock_call.voicemail(mailbox_number, :greeting => :busy) }
|
|
1567
|
-
end
|
|
1568
|
-
|
|
1569
|
-
it 'should return true if VMSTATUS == "SUCCESS"' do
|
|
1570
|
-
mock_call.should_receive(:execute).once
|
|
1571
|
-
mock_call.should_receive(:variable).once.with('VMSTATUS').and_return "SUCCESS"
|
|
1572
|
-
mock_call.voicemail(3).should be true
|
|
1573
|
-
end
|
|
1574
|
-
|
|
1575
|
-
it 'should return false if VMSTATUS == "USEREXIT"' do
|
|
1576
|
-
mock_call.should_receive(:execute).once
|
|
1577
|
-
mock_call.should_receive(:variable).once.with('VMSTATUS').and_return "USEREXIT"
|
|
1578
|
-
mock_call.voicemail(2).should be false
|
|
1579
|
-
end
|
|
1580
|
-
|
|
1581
|
-
it 'should return nil if VMSTATUS == "FAILED"' do
|
|
1582
|
-
mock_call.should_receive(:execute).once
|
|
1583
|
-
mock_call.should_receive(:variable).once.with('VMSTATUS').and_return "FAILED"
|
|
1584
|
-
mock_call.voicemail(2).should be nil
|
|
1585
|
-
end
|
|
1586
|
-
|
|
1587
|
-
end
|
|
1588
|
-
|
|
1589
|
-
describe 'The voicemail_main command' do
|
|
1590
|
-
|
|
1591
|
-
include DialplanCommandTestHelpers
|
|
1592
|
-
|
|
1593
|
-
#it "should not pass in the context or the delimiting @ sign if you don't supply one"
|
|
1594
|
-
|
|
1595
|
-
it "the :folder Hash key argument should wrap the value in a()" do
|
|
1596
|
-
folder = "foobar"
|
|
1597
|
-
mailbox = 81
|
|
1598
|
-
mock_call.should_receive(:execute).once.with("VoiceMailMain", "#{mailbox}","a(#{folder})")
|
|
1599
|
-
mock_call.voicemail_main :mailbox => mailbox, :folder => folder
|
|
1600
|
-
end
|
|
1601
|
-
|
|
1602
|
-
it ':authenticate should pass in the "s" option if given false' do
|
|
1603
|
-
mailbox = 333
|
|
1604
|
-
mock_call.should_receive(:execute).once.with("VoiceMailMain", "#{mailbox}","s")
|
|
1605
|
-
mock_call.voicemail_main :mailbox => mailbox, :authenticate => false
|
|
1606
|
-
end
|
|
1607
|
-
|
|
1608
|
-
it ':authenticate should pass in the s option if given false' do
|
|
1609
|
-
mailbox = 55
|
|
1610
|
-
mock_call.should_receive(:execute).once.with("VoiceMailMain", "#{mailbox}")
|
|
1611
|
-
mock_call.voicemail_main :mailbox => mailbox, :authenticate => true
|
|
1612
|
-
end
|
|
1613
|
-
|
|
1614
|
-
it 'should not pass any flags only a mailbox is given' do
|
|
1615
|
-
mailbox = "1"
|
|
1616
|
-
mock_call.should_receive(:execute).once.with("VoiceMailMain", "#{mailbox}")
|
|
1617
|
-
mock_call.voicemail_main :mailbox => mailbox
|
|
1618
|
-
end
|
|
1619
|
-
|
|
1620
|
-
it 'when given no mailbox or context an empty string should be passed to execute as the first argument' do
|
|
1621
|
-
mock_call.should_receive(:execute).once.with("VoiceMailMain", "", "s")
|
|
1622
|
-
mock_call.voicemail_main :authenticate => false
|
|
1623
|
-
end
|
|
1624
|
-
|
|
1625
|
-
it 'should properly concatenate the options when given multiple ones' do
|
|
1626
|
-
folder = "ohai"
|
|
1627
|
-
mailbox = 9999
|
|
1628
|
-
mock_call.should_receive(:execute).once.with("VoiceMailMain", "#{mailbox}", "sa(#{folder})")
|
|
1629
|
-
mock_call.voicemail_main :mailbox => mailbox, :authenticate => false, :folder => folder
|
|
1630
|
-
end
|
|
1631
|
-
|
|
1632
|
-
it 'should not require any arguments' do
|
|
1633
|
-
mock_call.should_receive(:execute).once.with("VoiceMailMain")
|
|
1634
|
-
mock_call.voicemail_main
|
|
1635
|
-
end
|
|
1636
|
-
|
|
1637
|
-
it 'should pass in the "@context_name" part in if a :context is given and no mailbox is given' do
|
|
1638
|
-
context_name = "icanhascheezburger"
|
|
1639
|
-
mock_call.should_receive(:execute).once.with("VoiceMailMain", "@#{context_name}")
|
|
1640
|
-
mock_call.voicemail_main :context => context_name
|
|
1641
|
-
end
|
|
1642
|
-
|
|
1643
|
-
it "should raise an exception if the folder has a space or malformed characters in it" do
|
|
1644
|
-
["i has a space", "exclaim!", ",", ""].each do |bad_folder_name|
|
|
1645
|
-
the_following_code {
|
|
1646
|
-
mock_call.voicemail_main :mailbox => 123, :folder => bad_folder_name
|
|
1647
|
-
}.should raise_error ArgumentError
|
|
1648
|
-
end
|
|
1649
|
-
end
|
|
1650
|
-
|
|
1651
|
-
end
|
|
1652
|
-
|
|
1653
|
-
describe 'the check_voicemail command' do
|
|
1654
|
-
|
|
1655
|
-
include DialplanCommandTestHelpers
|
|
1656
|
-
|
|
1657
|
-
it "should simply execute voicemail_main with no arguments after warning" do
|
|
1658
|
-
flexmock(ahn_log.agi).should_receive(:warn).once.with(String)
|
|
1659
|
-
mock_call.should_receive(:voicemail_main).once.and_return :mocked_out
|
|
1660
|
-
mock_call.check_voicemail.should be :mocked_out
|
|
1661
|
-
end
|
|
1662
|
-
|
|
1663
|
-
end
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
describe "The queue management abstractions" do
|
|
1667
|
-
|
|
1668
|
-
include DialplanCommandTestHelpers
|
|
1669
|
-
|
|
1670
|
-
it 'should not create separate objects for queues with basically the same name' do
|
|
1671
|
-
mock_call.queue('foo').should be mock_call.queue('foo')
|
|
1672
|
-
mock_call.queue('bar').should be mock_call.queue(:bar)
|
|
1673
|
-
end
|
|
1674
|
-
|
|
1675
|
-
it "queue() should return an instance of QueueProxy" do
|
|
1676
|
-
mock_call.queue("foobar").should be_a_kind_of Adhearsion::VoIP::Asterisk::Commands::QueueProxy
|
|
1677
|
-
end
|
|
1678
|
-
|
|
1679
|
-
it "a QueueProxy should respond to join!(), members()" do
|
|
1680
|
-
%w[join! agents].each do |method|
|
|
1681
|
-
mock_call.queue('foobar').should respond_to(method)
|
|
1682
|
-
end
|
|
1683
|
-
end
|
|
1684
|
-
|
|
1685
|
-
it 'a QueueProxy should return a QueueAgentsListProxy when members() is called' do
|
|
1686
|
-
mock_call.queue('foobar').agents.should be_a_kind_of(Adhearsion::VoIP::Asterisk::Commands::QueueProxy::QueueAgentsListProxy)
|
|
1687
|
-
end
|
|
1688
|
-
|
|
1689
|
-
it 'join! should properly join a queue' do
|
|
1690
|
-
mock_call.should_receive(:execute).once.with("queue", "foobaz", "", '', '', '', '')
|
|
1691
|
-
mock_call.should_receive(:get_variable).once.with("QUEUESTATUS").and_return "FULL"
|
|
1692
|
-
mock_call.queue("foobaz").join!
|
|
1693
|
-
end
|
|
1694
|
-
|
|
1695
|
-
it 'should return a symbol representing the result of joining the queue' do
|
|
1696
|
-
does_not_read_data_back
|
|
1697
|
-
mock_call.should_receive(:get_variable).once.with("QUEUESTATUS").and_return "TIMEOUT"
|
|
1698
|
-
mock_call.queue('monkey').join!.should be :timeout
|
|
1699
|
-
pbx_should_have_been_sent 'EXEC queue "monkey"|""|""|""|""|""'
|
|
1700
|
-
end
|
|
1701
|
-
|
|
1702
|
-
it 'should return :completed after joining the queue and being connected' do
|
|
1703
|
-
does_not_read_data_back
|
|
1704
|
-
mock_call.should_receive(:get_variable).once.with("QUEUESTATUS").and_return nil
|
|
1705
|
-
mock_call.queue('monkey').join!.should be :completed
|
|
1706
|
-
pbx_should_have_been_sent 'EXEC queue "monkey"|""|""|""|""|""'
|
|
1707
|
-
end
|
|
1708
|
-
|
|
1709
|
-
it 'should join a queue with a timeout properly' do
|
|
1710
|
-
mock_call.should_receive(:execute).once.with("queue", "foobaz", "", '', '', '60', '')
|
|
1711
|
-
mock_call.should_receive(:get_variable).once.with("QUEUESTATUS").and_return "JOINEMPTY"
|
|
1712
|
-
mock_call.queue("foobaz").join! :timeout => 1.minute
|
|
1713
|
-
end
|
|
1714
|
-
|
|
1715
|
-
it 'should join a queue with an announcement file properly' do
|
|
1716
|
-
mock_call.should_receive(:execute).once.with("queue", "roflcopter", "", '', 'custom_announcement_file_here', '', '')
|
|
1717
|
-
mock_call.should_receive(:get_variable).once.with("QUEUESTATUS").and_return "JOINEMPTY"
|
|
1718
|
-
mock_call.queue("roflcopter").join! :announce => 'custom_announcement_file_here'
|
|
1719
|
-
end
|
|
1720
|
-
|
|
1721
|
-
it 'should join a queue with an agi script properly' do
|
|
1722
|
-
mock_call.should_receive(:execute).once.with("queue", 'support', '', '', '', '','agi://localhost/queue_agi_test')
|
|
1723
|
-
mock_call.should_receive(:get_variable).once.with("QUEUESTATUS").and_return "JOINUNAVAIL"
|
|
1724
|
-
mock_call.queue("support").join! :agi => 'agi://localhost/queue_agi_test'
|
|
1725
|
-
end
|
|
1726
|
-
|
|
1727
|
-
it 'should join a queue with allow_transfer properly' do
|
|
1728
|
-
mock_call.should_receive(:execute).once.with("queue", "roflcopter", "Tt", '', '', '', '')
|
|
1729
|
-
mock_call.should_receive(:get_variable).once.with("QUEUESTATUS").and_return "JOINEMPTY"
|
|
1730
|
-
mock_call.queue("roflcopter").join! :allow_transfer => :everyone
|
|
1731
|
-
|
|
1732
|
-
mock_call.should_receive(:execute).once.with("queue", "roflcopter", "T", '', '', '', '')
|
|
1733
|
-
mock_call.should_receive(:get_variable).once.with("QUEUESTATUS").and_return "JOINEMPTY"
|
|
1734
|
-
mock_call.queue("roflcopter").join! :allow_transfer => :caller
|
|
1735
|
-
|
|
1736
|
-
mock_call.should_receive(:execute).once.with("queue", "roflcopter", "t", '', '', '', '')
|
|
1737
|
-
mock_call.should_receive(:get_variable).once.with("QUEUESTATUS").and_return "JOINEMPTY"
|
|
1738
|
-
mock_call.queue("roflcopter").join! :allow_transfer => :agent
|
|
1739
|
-
end
|
|
1740
|
-
|
|
1741
|
-
it 'should join a queue with allow_hangup properly' do
|
|
1742
|
-
mock_call.should_receive(:execute).once.with("queue", "roflcopter", "Hh", '', '', '', '')
|
|
1743
|
-
mock_call.should_receive(:get_variable).once.with("QUEUESTATUS").and_return "JOINEMPTY"
|
|
1744
|
-
mock_call.queue("roflcopter").join! :allow_hangup => :everyone
|
|
1745
|
-
|
|
1746
|
-
mock_call.should_receive(:execute).once.with("queue", "roflcopter", "H", '', '', '', '')
|
|
1747
|
-
mock_call.should_receive(:get_variable).once.with("QUEUESTATUS").and_return "JOINEMPTY"
|
|
1748
|
-
mock_call.queue("roflcopter").join! :allow_hangup => :caller
|
|
1749
|
-
|
|
1750
|
-
mock_call.should_receive(:execute).once.with("queue", "roflcopter", "h", '', '', '', '')
|
|
1751
|
-
mock_call.should_receive(:get_variable).once.with("QUEUESTATUS").and_return "JOINEMPTY"
|
|
1752
|
-
mock_call.queue("roflcopter").join! :allow_hangup => :agent
|
|
1753
|
-
end
|
|
1754
|
-
|
|
1755
|
-
it 'should join a queue properly with the :play argument' do
|
|
1756
|
-
mock_call.should_receive(:execute).once.with("queue", "roflcopter", "r", '', '', '', '')
|
|
1757
|
-
mock_call.should_receive(:get_variable).once.with("QUEUESTATUS").and_return "JOINEMPTY"
|
|
1758
|
-
mock_call.queue("roflcopter").join! :play => :ringing
|
|
1759
|
-
|
|
1760
|
-
mock_call.should_receive(:execute).once.with("queue", "roflcopter", "", '', '', '', '')
|
|
1761
|
-
mock_call.should_receive(:get_variable).once.with("QUEUESTATUS").and_return "JOINEMPTY"
|
|
1762
|
-
mock_call.queue("roflcopter").join! :play => :music
|
|
1763
|
-
end
|
|
1764
|
-
|
|
1765
|
-
it 'joining a queue with many options specified' do
|
|
1766
|
-
mock_call.should_receive(:execute).once.with("queue", "q", "rtHh", '', '', '120', '')
|
|
1767
|
-
mock_call.should_receive(:get_variable).once.with("QUEUESTATUS").and_return "JOINEMPTY"
|
|
1768
|
-
mock_call.queue('q').join! :allow_transfer => :agent, :timeout => 2.minutes,
|
|
1769
|
-
:play => :ringing, :allow_hangup => :everyone
|
|
1770
|
-
end
|
|
1771
|
-
|
|
1772
|
-
it 'join!() should raise an ArgumentError when unrecognized Hash key arguments are given' do
|
|
1773
|
-
the_following_code {
|
|
1774
|
-
mock_call.queue('iwearmysunglassesatnight').join! :misspelled => true
|
|
1775
|
-
}.should raise_error ArgumentError
|
|
1776
|
-
end
|
|
1777
|
-
|
|
1778
|
-
it 'should fetch the members with the name given to queue()' do
|
|
1779
|
-
mock_call.should_receive(:variable).once.with("QUEUE_MEMBER_COUNT(jay)").and_return 5
|
|
1780
|
-
mock_call.queue('jay').agents.size.should == 5
|
|
1781
|
-
end
|
|
1782
|
-
|
|
1783
|
-
it 'should not fetch a QUEUE_MEMBER_COUNT each time count() is called when caching is enabled' do
|
|
1784
|
-
mock_call.should_receive(:variable).once.with("QUEUE_MEMBER_COUNT(sales)").and_return 0
|
|
1785
|
-
10.times do
|
|
1786
|
-
mock_call.queue('sales').agents(:cache => true).size
|
|
1787
|
-
end
|
|
1788
|
-
end
|
|
1789
|
-
|
|
1790
|
-
it 'should raise an argument error if the members() method receives an unrecognized symbol' do
|
|
1791
|
-
the_following_code {
|
|
1792
|
-
mock_call.queue('foobarz').agents(:cached => true) # common typo
|
|
1793
|
-
}.should raise_error ArgumentError
|
|
1794
|
-
end
|
|
1795
|
-
|
|
1796
|
-
it 'when fetching agents, it should properly split by the supported delimiters' do
|
|
1797
|
-
queue_name = "doesnt_matter"
|
|
1798
|
-
mock_call.should_receive(:get_variable).with("QUEUE_MEMBER_LIST(#{queue_name})").and_return('Agent/007,Agent/003,Zap/2')
|
|
1799
|
-
mock_call.queue(queue_name).agents(:cache => true).to_a.size.should == 3
|
|
1800
|
-
end
|
|
1801
|
-
|
|
1802
|
-
it 'when fetching agents, each array index should be an instance of AgentProxy' do
|
|
1803
|
-
queue_name = 'doesnt_matter'
|
|
1804
|
-
mock_call.should_receive(:get_variable).with("QUEUE_MEMBER_LIST(#{queue_name})").and_return('Agent/007,Agent/003,Zap/2')
|
|
1805
|
-
agents = mock_call.queue(queue_name).agents(:cache => true).to_a
|
|
1806
|
-
agents.size.should > 0
|
|
1807
|
-
agents.each do |agent|
|
|
1808
|
-
agent.should be_a_kind_of Adhearsion::VoIP::Asterisk::Commands::QueueProxy::AgentProxy
|
|
1809
|
-
end
|
|
1810
|
-
end
|
|
1811
|
-
|
|
1812
|
-
it 'should properly retrieve metadata for an AgentProxy instance' do
|
|
1813
|
-
agent_id, metadata_name = '22', 'status'
|
|
1814
|
-
mock_env = flexmock "a mock ExecutionEnvironment"
|
|
1815
|
-
mock_queue = flexmock "a queue that references our mock ExecutionEnvironment", :environment => mock_env, :name => "doesntmatter"
|
|
1816
|
-
mock_env.should_receive(:variable).once.with("AGENT(#{agent_id}:#{metadata_name})")
|
|
1817
|
-
agent = Adhearsion::VoIP::Asterisk::Commands::QueueProxy::AgentProxy.new("Agent/#{agent_id}", mock_queue)
|
|
1818
|
-
agent.send(:agent_metadata, metadata_name)
|
|
1819
|
-
end
|
|
1820
|
-
|
|
1821
|
-
it 'AgentProxy#logged_in? should return true if the "state" of an agent == LOGGEDIN' do
|
|
1822
|
-
mock_env = flexmock "a mock ExecutionEnvironment"
|
|
1823
|
-
mock_queue = flexmock "a queue that references our mock ExecutionEnvironment", :environment => mock_env, :name => "doesntmatter"
|
|
1824
|
-
|
|
1825
|
-
agent = Adhearsion::VoIP::Asterisk::Commands::QueueProxy::AgentProxy.new('Agent/123', mock_queue)
|
|
1826
|
-
flexmock(agent).should_receive(:agent_metadata).once.with('status').and_return 'LOGGEDIN'
|
|
1827
|
-
agent.logged_in?.should be true
|
|
1828
|
-
|
|
1829
|
-
flexmock(agent).should_receive(:agent_metadata).once.with('status').and_return 'LOGGEDOUT'
|
|
1830
|
-
agent.logged_in?.should_not be true
|
|
1831
|
-
end
|
|
1832
|
-
|
|
1833
|
-
it 'the AgentProxy should populate its own "id" property to the numerical ID of the "interface" with which it was constructed' do
|
|
1834
|
-
mock_queue = flexmock :name => "doesntmatter"
|
|
1835
|
-
id = '123'
|
|
1836
|
-
|
|
1837
|
-
agent = Adhearsion::VoIP::Asterisk::Commands::QueueProxy::AgentProxy.new("Agent/#{id}", mock_queue)
|
|
1838
|
-
agent.id.should == id
|
|
1839
|
-
|
|
1840
|
-
agent = Adhearsion::VoIP::Asterisk::Commands::QueueProxy::AgentProxy.new(id, mock_queue)
|
|
1841
|
-
agent.id.should == id
|
|
1842
|
-
end
|
|
1843
|
-
|
|
1844
|
-
it 'QueueAgentsListProxy#<<() should new the channel driver given as the argument to the system' do
|
|
1845
|
-
queue_name, agent_channel = "metasyntacticvariablesftw", "Agent/123"
|
|
1846
|
-
mock_call.should_receive('execute').once.with("AddQueueMember", queue_name, agent_channel, "", "", "", "")
|
|
1847
|
-
mock_call.should_receive(:get_variable).once.with('AQMSTATUS').and_return('ADDED')
|
|
1848
|
-
mock_call.should_receive(:get_variable).once.with("QUEUE_MEMBER_LIST(#{queue_name})").and_return "Agent/007,SIP/2302,Local/2510@from-internal"
|
|
1849
|
-
mock_call.queue(queue_name).agents.new agent_channel
|
|
1850
|
-
end
|
|
1851
|
-
|
|
1852
|
-
it 'when a queue agent is dynamically added and the queue does not exist, a QueueDoesNotExistError should be raised' do
|
|
1853
|
-
does_not_read_data_back
|
|
1854
|
-
mock_call.should_receive(:get_variable).once.with('AQMSTATUS').and_return('NOSUCHQUEUE')
|
|
1855
|
-
the_following_code {
|
|
1856
|
-
mock_call.queue('this_should_not_exist').agents.new 'Agent/911'
|
|
1857
|
-
}.should raise_error Adhearsion::VoIP::Asterisk::Commands::QueueProxy::QueueDoesNotExistError
|
|
1858
|
-
pbx_should_have_been_sent 'EXEC AddQueueMember "this_should_not_exist"|"Agent/911"|""|""|""|""'
|
|
1859
|
-
end
|
|
1860
|
-
|
|
1861
|
-
it 'when a queue agent is dynamiaclly added and the adding was successful, an AgentProxy should be returned' do
|
|
1862
|
-
mock_call.should_receive(:get_variable).once.with("AQMSTATUS").and_return("ADDED")
|
|
1863
|
-
mock_call.should_receive(:execute).once.with("AddQueueMember", "lalala", "Agent/007", "", "", "", "")
|
|
1864
|
-
mock_call.should_receive(:get_variable).once.with("QUEUE_MEMBER_LIST(lalala)").and_return "Agent/007,SIP/2302,Local/2510@from-internal"
|
|
1865
|
-
return_value = mock_call.queue('lalala').agents.new "Agent/007"
|
|
1866
|
-
return_value.kind_of?(Adhearsion::VoIP::Asterisk::Commands::QueueProxy::AgentProxy).should be true
|
|
1867
|
-
end
|
|
1868
|
-
|
|
1869
|
-
it 'when a queue agent is dynamiaclly added and the adding was unsuccessful, a false should be returned' do
|
|
1870
|
-
mock_call.should_receive(:get_variable).once.with("AQMSTATUS").and_return("MEMBERALREADY")
|
|
1871
|
-
mock_call.should_receive(:execute).once.with("AddQueueMember", "lalala", "Agent/007", "", "", "", "")
|
|
1872
|
-
return_value = mock_call.queue('lalala').agents.new "Agent/007"
|
|
1873
|
-
return_value.should be false
|
|
1874
|
-
end
|
|
1875
|
-
|
|
1876
|
-
it 'should raise an argument when an unrecognized key is given to add()' do
|
|
1877
|
-
the_following_code {
|
|
1878
|
-
mock_call.queue('q').agents.new :foo => "bar"
|
|
1879
|
-
}.should raise_error ArgumentError
|
|
1880
|
-
end
|
|
1881
|
-
|
|
1882
|
-
it 'should execute AddQueueMember with the penalty properly' do
|
|
1883
|
-
queue_name = 'name_does_not_matter'
|
|
1884
|
-
mock_call.should_receive(:execute).once.with('AddQueueMember', queue_name, 'Agent/007', 10, '', '','')
|
|
1885
|
-
mock_call.should_receive(:get_variable).once.with('AQMSTATUS').and_return('ADDED')
|
|
1886
|
-
mock_call.should_receive(:get_variable).once.with("QUEUE_MEMBER_LIST(#{queue_name})").and_return "Agent/007,SIP/2302,Local/2510@from-internal"
|
|
1887
|
-
mock_call.queue(queue_name).agents.new 'Agent/007', :penalty => 10
|
|
1888
|
-
end
|
|
1889
|
-
|
|
1890
|
-
it 'should execute AddQueueMember with the state_interface properly' do
|
|
1891
|
-
queue_name = 'name_does_not_matter'
|
|
1892
|
-
mock_call.should_receive(:execute).once.with('AddQueueMember', queue_name, 'Agent/007', '', '', '','SIP/2302')
|
|
1893
|
-
mock_call.should_receive(:get_variable).once.with('AQMSTATUS').and_return('ADDED')
|
|
1894
|
-
mock_call.should_receive(:get_variable).once.with("QUEUE_MEMBER_LIST(#{queue_name})").and_return "Agent/007,SIP/2302,Local/2510@from-internal"
|
|
1895
|
-
mock_call.queue(queue_name).agents.new 'Agent/007', :state_interface => 'SIP/2302'
|
|
1896
|
-
end
|
|
1897
|
-
|
|
1898
|
-
it 'should execute AddQueueMember properly when the name is given' do
|
|
1899
|
-
queue_name, agent_name = 'name_does_not_matter', 'Jay Phillips'
|
|
1900
|
-
mock_call.should_receive(:execute).once.with('AddQueueMember', queue_name, 'Agents/007', '', '', agent_name,'')
|
|
1901
|
-
mock_call.should_receive(:get_variable).once.with('AQMSTATUS').and_return('ADDED')
|
|
1902
|
-
mock_call.should_receive(:get_variable).once.with("QUEUE_MEMBER_LIST(#{queue_name})").and_return "Agent/007,SIP/2302,Local/2510@from-internal"
|
|
1903
|
-
mock_call.queue(queue_name).agents.new 'Agents/007', :name => agent_name
|
|
1904
|
-
end
|
|
1905
|
-
|
|
1906
|
-
it 'should execute AddQueueMember properly when the name, penalty, and interface is given' do
|
|
1907
|
-
queue_name, agent_name, interface, penalty = 'name_does_not_matter', 'Jay Phillips', 'Agent/007', 4
|
|
1908
|
-
mock_call.should_receive(:execute).once.with('AddQueueMember', queue_name, interface, penalty, '', agent_name,'')
|
|
1909
|
-
mock_call.should_receive(:get_variable).once.with('AQMSTATUS').and_return('ADDED')
|
|
1910
|
-
mock_call.should_receive(:get_variable).once.with("QUEUE_MEMBER_LIST(#{queue_name})").and_return "Agent/007,SIP/2302,Local/2510@from-internal"
|
|
1911
|
-
mock_call.queue(queue_name).agents.new interface, :name => agent_name, :penalty => penalty
|
|
1912
|
-
end
|
|
1913
|
-
|
|
1914
|
-
it 'should execute AddQueueMember properly when the name, penalty, interface, and state_interface is given' do
|
|
1915
|
-
queue_name, agent_name, interface, penalty, state_interface = 'name_does_not_matter', 'Jay Phillips', 'Agent/007', 4, 'SIP/2302'
|
|
1916
|
-
mock_call.should_receive(:execute).once.with('AddQueueMember', queue_name, interface, penalty, '', agent_name, state_interface)
|
|
1917
|
-
mock_call.should_receive(:get_variable).once.with('AQMSTATUS').and_return('ADDED')
|
|
1918
|
-
mock_call.should_receive(:get_variable).once.with("QUEUE_MEMBER_LIST(#{queue_name})").and_return "Agent/007,SIP/2302,Local/2510@from-internal"
|
|
1919
|
-
mock_call.queue(queue_name).agents.new interface, :name => agent_name, :penalty => penalty, :state_interface => state_interface
|
|
1920
|
-
end
|
|
1921
|
-
|
|
1922
|
-
it 'should return a correct boolean for exists?()' do
|
|
1923
|
-
mock_call.should_receive(:execute).once.with("RemoveQueueMember", "kablamm", "SIP/AdhearsionQueueExistenceCheck")
|
|
1924
|
-
mock_call.should_receive(:get_variable).once.with("RQMSTATUS").and_return "NOTINQUEUE"
|
|
1925
|
-
mock_call.queue("kablamm").exists?.should be true
|
|
1926
|
-
|
|
1927
|
-
mock_call.should_receive(:execute).once.with("RemoveQueueMember", "monkey", "SIP/AdhearsionQueueExistenceCheck")
|
|
1928
|
-
mock_call.should_receive(:get_variable).once.with("RQMSTATUS").and_return "NOSUCHQUEUE"
|
|
1929
|
-
mock_call.queue("monkey").exists?.should be false
|
|
1930
|
-
end
|
|
1931
|
-
|
|
1932
|
-
it 'should pause an agent properly from a certain queue' do
|
|
1933
|
-
does_not_read_data_back
|
|
1934
|
-
mock_call.should_receive(:get_variable).once.with("QUEUE_MEMBER_LIST(lolcats)").and_return "Agent/007,Agent/008"
|
|
1935
|
-
mock_call.should_receive(:get_variable).once.with("PQMSTATUS").and_return "PAUSED"
|
|
1936
|
-
|
|
1937
|
-
agents = mock_call.queue('lolcats').agents :cache => true
|
|
1938
|
-
agents.last.pause!.should be true
|
|
1939
|
-
pbx_should_have_been_sent 'EXEC PauseQueueMember "lolcats"|"Agent/008"'
|
|
1940
|
-
end
|
|
1941
|
-
|
|
1942
|
-
it 'should pause an agent properly from a certain queue and return false when the agent did not exist' do
|
|
1943
|
-
mock_call.should_receive(:get_variable).once.with("QUEUE_MEMBER_LIST(lolcats)").and_return "Agent/007,Agent/008"
|
|
1944
|
-
mock_call.should_receive(:get_variable).once.with("PQMSTATUS").and_return "NOTFOUND"
|
|
1945
|
-
mock_call.should_receive(:execute).once.with("PauseQueueMember", 'lolcats', "Agent/008")
|
|
1946
|
-
|
|
1947
|
-
agents = mock_call.queue('lolcats').agents :cache => true
|
|
1948
|
-
agents.last.pause!.should be false
|
|
1949
|
-
end
|
|
1950
|
-
|
|
1951
|
-
it 'should pause an agent globally properly' do
|
|
1952
|
-
mock_call.should_receive(:get_variable).once.with("QUEUE_MEMBER_LIST(family)").and_return "Agent/Jay"
|
|
1953
|
-
mock_call.should_receive(:get_variable).once.with("PQMSTATUS").and_return "PAUSED"
|
|
1954
|
-
mock_call.should_receive(:execute).once.with("PauseQueueMember", nil, "Agent/Jay")
|
|
1955
|
-
|
|
1956
|
-
mock_call.queue('family').agents.first.pause! :everywhere => true
|
|
1957
|
-
end
|
|
1958
|
-
|
|
1959
|
-
it 'should unpause an agent properly' do
|
|
1960
|
-
queue_name = "name with spaces"
|
|
1961
|
-
mock_call.should_receive(:get_variable).once.with("QUEUE_MEMBER_LIST(#{queue_name})").and_return "Agent/Jay"
|
|
1962
|
-
mock_call.should_receive(:get_variable).once.with("UPQMSTATUS").and_return "UNPAUSED"
|
|
1963
|
-
mock_call.should_receive(:execute).once.with("UnpauseQueueMember", queue_name, "Agent/Jay")
|
|
1964
|
-
|
|
1965
|
-
mock_call.queue(queue_name).agents.first.unpause!.should be true
|
|
1966
|
-
end
|
|
1967
|
-
|
|
1968
|
-
it 'should unpause an agent globally properly' do
|
|
1969
|
-
mock_call.should_receive(:get_variable).once.with("QUEUE_MEMBER_LIST(FOO)").and_return "Agent/Tom"
|
|
1970
|
-
mock_call.should_receive(:get_variable).once.with("UPQMSTATUS").and_return "UNPAUSED"
|
|
1971
|
-
mock_call.should_receive(:execute).once.with("UnpauseQueueMember", nil, "Agent/Tom")
|
|
1972
|
-
|
|
1973
|
-
mock_call.queue('FOO').agents.first.unpause!(:everywhere => true).should be true
|
|
1974
|
-
end
|
|
1975
|
-
|
|
1976
|
-
it 'waiting_count for a queue that does exist' do
|
|
1977
|
-
mock_call.should_receive(:get_variable).once.with("QUEUE_WAITING_COUNT(q)").and_return "50"
|
|
1978
|
-
flexmock(mock_call.queue('q')).should_receive(:exists?).once.and_return true
|
|
1979
|
-
mock_call.queue('q').waiting_count.should == 50
|
|
1980
|
-
end
|
|
1981
|
-
|
|
1982
|
-
it 'waiting_count for a queue that does not exist' do
|
|
1983
|
-
the_following_code {
|
|
1984
|
-
flexmock(mock_call.queue('q')).should_receive(:exists?).once.and_return false
|
|
1985
|
-
mock_call.queue('q').waiting_count
|
|
1986
|
-
}.should raise_error Adhearsion::VoIP::Asterisk::Commands::QueueProxy::QueueDoesNotExistError
|
|
1987
|
-
end
|
|
1988
|
-
|
|
1989
|
-
it 'empty? should call waiting_count' do
|
|
1990
|
-
queue = mock_call.queue 'testing_empty'
|
|
1991
|
-
flexmock(queue).should_receive(:waiting_count).once.and_return 0
|
|
1992
|
-
queue.empty?.should be true
|
|
1993
|
-
|
|
1994
|
-
queue = mock_call.queue 'testing_empty'
|
|
1995
|
-
flexmock(queue).should_receive(:waiting_count).once.and_return 99
|
|
1996
|
-
queue.empty?.should_not be true
|
|
1997
|
-
end
|
|
1998
|
-
|
|
1999
|
-
it 'any? should call waiting_count' do
|
|
2000
|
-
queue = mock_call.queue 'testing_empty'
|
|
2001
|
-
flexmock(queue).should_receive(:waiting_count).once.and_return 0
|
|
2002
|
-
queue.any?.should be false
|
|
2003
|
-
|
|
2004
|
-
queue = mock_call.queue 'testing_empty'
|
|
2005
|
-
flexmock(queue).should_receive(:waiting_count).once.and_return 99
|
|
2006
|
-
queue.any?.should be true
|
|
2007
|
-
end
|
|
2008
|
-
|
|
2009
|
-
it 'should remove an agent properly' do
|
|
2010
|
-
mock_call.should_receive(:get_variable).once.with("QUEUE_MEMBER_LIST(FOO)").and_return "Agent/Tom"
|
|
2011
|
-
mock_call.should_receive(:execute).once.with('RemoveQueueMember', 'FOO', 'Agent/Tom')
|
|
2012
|
-
mock_call.should_receive(:get_variable).once.with("RQMSTATUS").and_return "REMOVED"
|
|
2013
|
-
mock_call.queue('FOO').agents.first.remove!.should be true
|
|
2014
|
-
end
|
|
2015
|
-
|
|
2016
|
-
it 'should remove an agent properly' do
|
|
2017
|
-
mock_call.should_receive(:get_variable).once.with("QUEUE_MEMBER_LIST(FOO)").and_return "Agent/Tom"
|
|
2018
|
-
mock_call.should_receive(:execute).once.with('RemoveQueueMember', 'FOO', 'Agent/Tom')
|
|
2019
|
-
mock_call.should_receive(:get_variable).once.with("RQMSTATUS").and_return "NOTINQUEUE"
|
|
2020
|
-
mock_call.queue('FOO').agents.first.remove!.should be false
|
|
2021
|
-
end
|
|
2022
|
-
|
|
2023
|
-
it "should raise a QueueDoesNotExistError when removing an agent from a queue that doesn't exist" do
|
|
2024
|
-
mock_call.should_receive(:get_variable).once.with("QUEUE_MEMBER_LIST(cool_people)").and_return "Agent/ZeroCool"
|
|
2025
|
-
mock_call.should_receive(:execute).once.with("RemoveQueueMember", "cool_people", "Agent/ZeroCool")
|
|
2026
|
-
mock_call.should_receive(:get_variable).once.with("RQMSTATUS").and_return "NOSUCHQUEUE"
|
|
2027
|
-
the_following_code {
|
|
2028
|
-
mock_call.queue("cool_people").agents.first.remove!
|
|
2029
|
-
}.should raise_error Adhearsion::VoIP::Asterisk::Commands::QueueProxy::QueueDoesNotExistError
|
|
2030
|
-
end
|
|
2031
|
-
|
|
2032
|
-
it "should log an agent in properly with no agent id given" do
|
|
2033
|
-
mock_call.should_receive(:execute).once.with('AgentLogin', nil, 's')
|
|
2034
|
-
mock_call.queue('barrel_o_agents').agents.login!
|
|
2035
|
-
end
|
|
2036
|
-
|
|
2037
|
-
it 'should remove "Agent/" before the agent ID given if necessary when logging an agent in' do
|
|
2038
|
-
mock_call.should_receive(:execute).once.with('AgentLogin', '007', 's')
|
|
2039
|
-
mock_call.queue('barrel_o_agents').agents.login! 'Agent/007'
|
|
2040
|
-
|
|
2041
|
-
mock_call.should_receive(:execute).once.with('AgentLogin', '007', 's')
|
|
2042
|
-
mock_call.queue('barrel_o_agents').agents.login! '007'
|
|
2043
|
-
end
|
|
2044
|
-
|
|
2045
|
-
it 'should add an agent silently properly' do
|
|
2046
|
-
mock_call.should_receive(:execute).once.with('AgentLogin', '007', '')
|
|
2047
|
-
mock_call.queue('barrel_o_agents').agents.login! 'Agent/007', :silent => false
|
|
2048
|
-
|
|
2049
|
-
mock_call.should_receive(:execute).once.with('AgentLogin', '008', 's')
|
|
2050
|
-
mock_call.queue('barrel_o_agents').agents.login! 'Agent/008', :silent => true
|
|
2051
|
-
end
|
|
2052
|
-
|
|
2053
|
-
it 'logging an agent in should raise an ArgumentError is unrecognized arguments are given' do
|
|
2054
|
-
the_following_code {
|
|
2055
|
-
mock_call.queue('ohai').agents.login! 1,2,3,4,5
|
|
2056
|
-
}.should raise_error ArgumentError
|
|
2057
|
-
|
|
2058
|
-
the_following_code {
|
|
2059
|
-
mock_call.queue('lols').agents.login! 1337, :sssssilent => false
|
|
2060
|
-
}.should raise_error ArgumentError
|
|
2061
|
-
|
|
2062
|
-
the_following_code {
|
|
2063
|
-
mock_call.queue('qwerty').agents.login! 777, 6,5,4,3,2,1, :wee => :wee
|
|
2064
|
-
}.should raise_error ArgumentError
|
|
2065
|
-
end
|
|
2066
|
-
|
|
2067
|
-
end
|
|
2068
|
-
|
|
2069
|
-
describe 'the menu() method' do
|
|
2070
|
-
|
|
2071
|
-
include DialplanCommandTestHelpers
|
|
2072
|
-
|
|
2073
|
-
it "should instantiate a new Menu object with only the Hash given as menu() options" do
|
|
2074
|
-
args = [1,2,3,4,5, {:timeout => 1.year, :tries => (1.0/0.0)}]
|
|
2075
|
-
|
|
2076
|
-
flexmock(Adhearsion::VoIP::Menu).should_receive(:new).once.
|
|
2077
|
-
with(args.last).and_throw(:instantiating_menu!)
|
|
2078
|
-
|
|
2079
|
-
should_throw(:instantiating_menu!) { mock_call.menu(*args) }
|
|
2080
|
-
end
|
|
2081
|
-
|
|
2082
|
-
it "should jump to a context when a timeout is encountered and there is at least one exact match" do
|
|
2083
|
-
pbx_should_respond_with_successful_background_response ?5.ord
|
|
2084
|
-
pbx_should_respond_with_successful_background_response ?4.ord
|
|
2085
|
-
pbx_should_respond_with_a_wait_for_digit_timeout
|
|
2086
|
-
|
|
2087
|
-
context_named_main = Adhearsion::DialPlan::DialplanContextProc.new(:main) { throw :inside_main! }
|
|
2088
|
-
context_named_other = Adhearsion::DialPlan::DialplanContextProc.new(:other) { throw :inside_other! }
|
|
2089
|
-
flexmock(mock_call).should_receive(:main).once.and_return(context_named_main)
|
|
2090
|
-
flexmock(mock_call).should_receive(:other).never
|
|
2091
|
-
|
|
2092
|
-
should_pass_control_to_a_context_that_throws :inside_main! do
|
|
2093
|
-
mock_call.menu do |link|
|
|
2094
|
-
link.main 54
|
|
2095
|
-
link.other 543
|
|
2096
|
-
end
|
|
2097
|
-
end
|
|
2098
|
-
3.times { pbx_should_have_been_sent 'WAIT FOR DIGIT "5000"' }
|
|
2099
|
-
end
|
|
2100
|
-
|
|
2101
|
-
it "when the 'extension' variable is changed, it should be an instance of PhoneNumber" do
|
|
2102
|
-
pbx_should_respond_with_successful_background_response ?5.ord
|
|
2103
|
-
foobar_context = Adhearsion::DialPlan::DialplanContextProc.new(:foobar) { throw :foobar! }
|
|
2104
|
-
mock_call.should_receive(:foobar).once.and_return foobar_context
|
|
2105
|
-
should_pass_control_to_a_context_that_throws :foobar! do
|
|
2106
|
-
mock_call.menu do |link|
|
|
2107
|
-
link.foobar 5
|
|
2108
|
-
end
|
|
2109
|
-
end
|
|
2110
|
-
5.should === mock_call.extension
|
|
2111
|
-
mock_call.extension.__real_string.should == "5"
|
|
2112
|
-
pbx_should_have_been_sent 'WAIT FOR DIGIT "5000"'
|
|
2113
|
-
end
|
|
2114
|
-
|
|
2115
|
-
end
|
|
2116
|
-
|
|
2117
|
-
describe 'the Menu class' do
|
|
2118
|
-
|
|
2119
|
-
include DialplanCommandTestHelpers
|
|
2120
|
-
|
|
2121
|
-
it "should yield a MenuBuilder when instantiated" do
|
|
2122
|
-
lambda {
|
|
2123
|
-
Adhearsion::VoIP::Menu.new do |block_argument|
|
|
2124
|
-
block_argument.should be_a_kind_of Adhearsion::VoIP::MenuBuilder
|
|
2125
|
-
throw :inside_block
|
|
2126
|
-
end
|
|
2127
|
-
}.should throw_symbol :inside_block
|
|
2128
|
-
end
|
|
2129
|
-
|
|
2130
|
-
it "should invoke wait_for_digit instead of interruptible_play when no sound files are given" do
|
|
2131
|
-
mock_call.should_receive(:wait_for_digit).once.with(5).and_return '#'
|
|
2132
|
-
mock_call.menu { |link| link.does_not_match 3 }
|
|
2133
|
-
end
|
|
2134
|
-
|
|
2135
|
-
it 'should invoke interruptible_play when sound files are given only for the first digit' do
|
|
2136
|
-
sound_files = %w[i like big butts and i cannot lie]
|
|
2137
|
-
timeout = 1337
|
|
2138
|
-
|
|
2139
|
-
mock_call.should_receive(:interruptible_play).once.with(*sound_files).and_return nil
|
|
2140
|
-
mock_call.should_receive(:wait_for_digit).once.with(timeout).and_return nil
|
|
2141
|
-
|
|
2142
|
-
mock_call.menu(sound_files, :timeout => timeout) { |link| link.qwerty 12345 }
|
|
2143
|
-
end
|
|
2144
|
-
|
|
2145
|
-
it 'if the call to interruptible_play receives a timeout, it should execute wait_for_digit with the timeout given' do
|
|
2146
|
-
sound_files = %w[i like big butts and i cannot lie]
|
|
2147
|
-
timeout = 987
|
|
2148
|
-
|
|
2149
|
-
mock_call.should_receive(:interruptible_play).once.with(*sound_files).and_return nil
|
|
2150
|
-
mock_call.should_receive(:wait_for_digit).with(timeout).and_return
|
|
2151
|
-
|
|
2152
|
-
mock_call.menu(sound_files, :timeout => timeout) { |link| link.foobar 911 }
|
|
2153
|
-
end
|
|
2154
|
-
|
|
2155
|
-
it "should work when no files are given to be played and a timeout is reached on the first digit" do
|
|
2156
|
-
timeout = 12
|
|
2157
|
-
[:on_premature_timeout, :on_failure].each do |usage_case|
|
|
2158
|
-
should_throw :got_here! do
|
|
2159
|
-
mock_call.should_receive(:wait_for_digit).once.with(timeout).and_return nil # Simulates timeout
|
|
2160
|
-
mock_call.menu :timeout => timeout do |link|
|
|
2161
|
-
link.foobar 0
|
|
2162
|
-
link.__send__(usage_case) { throw :got_here! }
|
|
2163
|
-
end
|
|
2164
|
-
end
|
|
2165
|
-
end
|
|
2166
|
-
end
|
|
2167
|
-
|
|
2168
|
-
it "should default the timeout to five seconds" do
|
|
2169
|
-
mock_call.should_receive(:wait_for_digit).once.with(5).and_return nil
|
|
2170
|
-
mock_call.menu { |link| link.foobar 22 }
|
|
2171
|
-
end
|
|
2172
|
-
|
|
2173
|
-
it "when matches fail due to timeouts, the menu should repeat :tries times" do
|
|
2174
|
-
tries, times_timed_out = 10, 0
|
|
2175
|
-
|
|
2176
|
-
tries.times do
|
|
2177
|
-
pbx_should_respond_with_successful_background_response ?4.ord
|
|
2178
|
-
pbx_should_respond_with_successful_background_response ?0.ord
|
|
2179
|
-
pbx_should_respond_with_a_wait_for_digit_timeout
|
|
2180
|
-
end
|
|
2181
|
-
|
|
2182
|
-
should_throw :inside_failure_callback do
|
|
2183
|
-
mock_call.menu :tries => tries do |link|
|
|
2184
|
-
link.pattern_longer_than_our_test_input 400
|
|
2185
|
-
link.on_premature_timeout { times_timed_out += 1 }
|
|
2186
|
-
link.on_invalid { raise "should never get here!" }
|
|
2187
|
-
link.on_failure { throw :inside_failure_callback }
|
|
2188
|
-
end
|
|
2189
|
-
end
|
|
2190
|
-
times_timed_out.should be tries
|
|
2191
|
-
30.times { pbx_should_have_been_sent 'WAIT FOR DIGIT "5000"' }
|
|
2192
|
-
end
|
|
2193
|
-
|
|
2194
|
-
it "when matches fail due to invalid input, the menu should repeat :tries times" do
|
|
2195
|
-
tries = 10
|
|
2196
|
-
times_invalid = 0
|
|
2197
|
-
|
|
2198
|
-
tries.times do
|
|
2199
|
-
pbx_should_respond_with_successful_background_response ?0.ord
|
|
2200
|
-
end
|
|
2201
|
-
|
|
2202
|
-
should_throw :inside_failure_callback do
|
|
2203
|
-
mock_call.menu :tries => tries do |link|
|
|
2204
|
-
link.be_leet 1337
|
|
2205
|
-
link.on_premature_timeout { raise "should never get here!" }
|
|
2206
|
-
link.on_invalid { times_invalid += 1 }
|
|
2207
|
-
link.on_failure { throw :inside_failure_callback }
|
|
2208
|
-
end
|
|
2209
|
-
end
|
|
2210
|
-
times_invalid.should be tries
|
|
2211
|
-
10.times { pbx_should_have_been_sent 'WAIT FOR DIGIT "5000"' }
|
|
2212
|
-
end
|
|
2213
|
-
|
|
2214
|
-
it "invoke on_invalid callback when an invalid extension was entered" do
|
|
2215
|
-
pbx_should_respond_with_successful_background_response ?5.ord
|
|
2216
|
-
pbx_should_respond_with_successful_background_response ?5.ord
|
|
2217
|
-
pbx_should_respond_with_successful_background_response ?5.ord
|
|
2218
|
-
should_throw :inside_invalid_callback do
|
|
2219
|
-
mock_call.menu do |link|
|
|
2220
|
-
link.onetwothree 123
|
|
2221
|
-
link.on_invalid { throw :inside_invalid_callback }
|
|
2222
|
-
end
|
|
2223
|
-
end
|
|
2224
|
-
pbx_should_have_been_sent 'WAIT FOR DIGIT "5000"'
|
|
2225
|
-
end
|
|
2226
|
-
|
|
2227
|
-
it "invoke on_premature_timeout when a timeout is encountered" do
|
|
2228
|
-
pbx_should_respond_with_successful_background_response ?9.ord
|
|
2229
|
-
pbx_should_respond_with_a_wait_for_digit_timeout
|
|
2230
|
-
|
|
2231
|
-
should_throw :inside_timeout do
|
|
2232
|
-
mock_call.menu :timeout => 1 do |link|
|
|
2233
|
-
link.something 999
|
|
2234
|
-
link.on_premature_timeout { throw :inside_timeout }
|
|
2235
|
-
end
|
|
2236
|
-
end
|
|
2237
|
-
2.times { pbx_should_have_been_sent 'WAIT FOR DIGIT "1000"' }
|
|
2238
|
-
end
|
|
2239
|
-
|
|
2240
|
-
end
|
|
2241
|
-
|
|
2242
|
-
describe "the Menu class's high-level judgment" do
|
|
2243
|
-
|
|
2244
|
-
include DialplanCommandTestHelpers
|
|
2245
|
-
|
|
2246
|
-
it "should match things in ambiguous ranges properly" do
|
|
2247
|
-
pbx_should_respond_with_successful_background_response ?1.ord
|
|
2248
|
-
pbx_should_respond_with_successful_background_response ?1.ord
|
|
2249
|
-
pbx_should_respond_with_successful_background_response ?1.ord
|
|
2250
|
-
pbx_should_respond_with_a_wait_for_digit_timeout
|
|
2251
|
-
|
|
2252
|
-
main_context = Adhearsion::DialPlan::DialplanContextProc.new(:main) { throw :got_here! }
|
|
2253
|
-
mock_call.should_receive(:main).and_return main_context
|
|
2254
|
-
|
|
2255
|
-
should_pass_control_to_a_context_that_throws :got_here! do
|
|
2256
|
-
mock_call.menu do |link|
|
|
2257
|
-
link.blah 1
|
|
2258
|
-
link.main 11..11111
|
|
2259
|
-
end
|
|
2260
|
-
end
|
|
2261
|
-
111.should === mock_call.extension
|
|
2262
|
-
4.times { pbx_should_have_been_sent 'WAIT FOR DIGIT "5000"' }
|
|
2263
|
-
end
|
|
2264
|
-
|
|
2265
|
-
it 'should match things in a range when there are many other non-matching patterns' do
|
|
2266
|
-
pbx_should_respond_with_successful_background_response ?9.ord
|
|
2267
|
-
pbx_should_respond_with_successful_background_response ?9.ord
|
|
2268
|
-
pbx_should_respond_with_successful_background_response ?5.ord
|
|
2269
|
-
|
|
2270
|
-
conferences_context = Adhearsion::DialPlan::DialplanContextProc.new(:conferences) { throw :got_here! }
|
|
2271
|
-
mock_call.should_receive(:conferences).and_return conferences_context
|
|
2272
|
-
|
|
2273
|
-
should_pass_control_to_a_context_that_throws :got_here! do
|
|
2274
|
-
mock_call.menu do |link|
|
|
2275
|
-
link.sales 1
|
|
2276
|
-
link.tech_support 2
|
|
2277
|
-
link.finance 3
|
|
2278
|
-
link.conferences 900..999
|
|
2279
|
-
end
|
|
2280
|
-
end
|
|
2281
|
-
3.times { pbx_should_have_been_sent 'WAIT FOR DIGIT "5000"' }
|
|
2282
|
-
end
|
|
2283
|
-
|
|
2284
|
-
end
|
|
2285
|
-
|
|
2286
|
-
describe 'the MenuBuilder' do
|
|
2287
|
-
|
|
2288
|
-
include MenuBuilderTestHelper
|
|
2289
|
-
|
|
2290
|
-
attr_reader :builder
|
|
2291
|
-
before(:each) do
|
|
2292
|
-
@builder = Adhearsion::VoIP::MenuBuilder.new
|
|
2293
|
-
end
|
|
2294
|
-
|
|
2295
|
-
it "should convert each pattern given to it into a MatchCalculator instance" do
|
|
2296
|
-
builder.tap do |link|
|
|
2297
|
-
link.foo 1,2,3
|
|
2298
|
-
link.bar "4", "5", 6
|
|
2299
|
-
end
|
|
2300
|
-
|
|
2301
|
-
builder.weighted_match_calculators.size.should == 6
|
|
2302
|
-
builder.weighted_match_calculators.each do |match_calculator|
|
|
2303
|
-
match_calculator.should be_a_kind_of Adhearsion::VoIP::MatchCalculator
|
|
2304
|
-
end
|
|
2305
|
-
end
|
|
2306
|
-
|
|
2307
|
-
it "conflicting ranges" do
|
|
2308
|
-
builder.tap do |link|
|
|
2309
|
-
link.hundreds 100...200
|
|
2310
|
-
link.thousands 1_000...2_000
|
|
2311
|
-
link.tenthousands 10_000...20_000
|
|
2312
|
-
end
|
|
2313
|
-
|
|
2314
|
-
builder_should_match_with_these_quantities_of_calculated_matches \
|
|
2315
|
-
1 => { :exact_match_count => 0, :potential_match_count => 11100 },
|
|
2316
|
-
10 => { :exact_match_count => 0, :potential_match_count => 1110 },
|
|
2317
|
-
100 => { :exact_match_count => 1, :potential_match_count => 110 },
|
|
2318
|
-
1_000 => { :exact_match_count => 1, :potential_match_count => 10 },
|
|
2319
|
-
10_000 => { :exact_match_count => 1, :potential_match_count => 0 },
|
|
2320
|
-
100_000 => { :exact_match_count => 0, :potential_match_count => 0 }
|
|
2321
|
-
|
|
2322
|
-
end
|
|
2323
|
-
|
|
2324
|
-
it 'a String query ran against multiple Numeric patterns and a range' do
|
|
2325
|
-
builder.tap do |link|
|
|
2326
|
-
link.sales 1
|
|
2327
|
-
link.tech_support 2
|
|
2328
|
-
link.finance 3
|
|
2329
|
-
link.conferences 900..999
|
|
2330
|
-
end
|
|
2331
|
-
match = builder.calculate_matches_for "995"
|
|
2332
|
-
require 'pp'
|
|
2333
|
-
# pp match
|
|
2334
|
-
match.potential_match?.should_not be true
|
|
2335
|
-
match.exact_match?.should be true
|
|
2336
|
-
match.actual_exact_matches.should == ["995"]
|
|
2337
|
-
end
|
|
2338
|
-
|
|
2339
|
-
it "multiple patterns given at once" do
|
|
2340
|
-
builder.tap do |link|
|
|
2341
|
-
link.multiple_patterns 1,2,3,4,5,6,7,8,9
|
|
2342
|
-
link.multiple_patterns 100..199, 200..299, 300..399, 400..499, 500..599,
|
|
2343
|
-
600..699, 700..799, 800..899, 900..999
|
|
2344
|
-
end
|
|
2345
|
-
1.upto 9 do |num|
|
|
2346
|
-
builder.calculate_matches_for(num).tap do |matches_of_num|
|
|
2347
|
-
matches_of_num.potential_match_count.should == 100
|
|
2348
|
-
matches_of_num.exact_match_count.should == 1
|
|
2349
|
-
end
|
|
2350
|
-
builder.calculate_matches_for((num * 100) + 5).tap do |matches_of_num|
|
|
2351
|
-
matches_of_num.potential_match_count.should == 0
|
|
2352
|
-
matches_of_num.exact_match_count.should == 1
|
|
2353
|
-
end
|
|
2354
|
-
end
|
|
2355
|
-
end
|
|
2356
|
-
|
|
2357
|
-
it "numeric literals that don't match but ultimately would" do
|
|
2358
|
-
builder.tap do |link|
|
|
2359
|
-
link.nineninenine 999
|
|
2360
|
-
link.shouldnt_match 4444
|
|
2361
|
-
end
|
|
2362
|
-
builder.calculate_matches_for(9).potential_match_count.should == 1
|
|
2363
|
-
end
|
|
2364
|
-
|
|
2365
|
-
it "three fixnums that obviously don't conflict" do
|
|
2366
|
-
builder.tap do |link|
|
|
2367
|
-
link.one 1
|
|
2368
|
-
link.two 2
|
|
2369
|
-
link.three 3
|
|
2370
|
-
end
|
|
2371
|
-
[[1,2,3,4,'#'], [1,1,1,0,0]].transpose.each do |(input,expected_matches)|
|
|
2372
|
-
matches = builder.calculate_matches_for input
|
|
2373
|
-
matches.exact_match_count.should be expected_matches
|
|
2374
|
-
end
|
|
2375
|
-
end
|
|
2376
|
-
|
|
2377
|
-
it "numerical digits mixed with special digits" do
|
|
2378
|
-
builder.tap do |link|
|
|
2379
|
-
link.one '5*11#3'
|
|
2380
|
-
link.two '5***'
|
|
2381
|
-
link.three '###'
|
|
2382
|
-
end
|
|
2383
|
-
|
|
2384
|
-
builder_should_match_with_these_quantities_of_calculated_matches \
|
|
2385
|
-
'5' => { :potential_match_count => 2, :exact_match_count => 0 },
|
|
2386
|
-
'*' => { :potential_match_count => 0, :exact_match_count => 0 },
|
|
2387
|
-
'5**' => { :potential_match_count => 1, :exact_match_count => 0 },
|
|
2388
|
-
'5*1' => { :potential_match_count => 1, :exact_match_count => 0 },
|
|
2389
|
-
'5*11#3' => { :potential_match_count => 0, :exact_match_count => 1 },
|
|
2390
|
-
'5*11#4' => { :potential_match_count => 0, :exact_match_count => 0 },
|
|
2391
|
-
'5***' => { :potential_match_count => 0, :exact_match_count => 1 },
|
|
2392
|
-
'###' => { :potential_match_count => 0, :exact_match_count => 1 },
|
|
2393
|
-
'##*' => { :potential_match_count => 0, :exact_match_count => 0 }
|
|
2394
|
-
|
|
2395
|
-
end
|
|
2396
|
-
|
|
2397
|
-
it 'a Fixnum exact match conflicting with a Range that would ultimately match' do
|
|
2398
|
-
builder.tap do |link|
|
|
2399
|
-
link.single_digit 1
|
|
2400
|
-
link.range 100..200
|
|
2401
|
-
end
|
|
2402
|
-
matches = builder.calculate_matches_for 1
|
|
2403
|
-
matches.potential_match_count.should == 100
|
|
2404
|
-
end
|
|
2405
|
-
|
|
2406
|
-
end
|
|
2407
|
-
|
|
2408
|
-
describe 'say_digits command' do
|
|
2409
|
-
include DialplanCommandTestHelpers
|
|
2410
|
-
it 'Can execute the saydigits application using say_digits' do
|
|
2411
|
-
digits = "12345"
|
|
2412
|
-
pbx_should_respond_with_success
|
|
2413
|
-
mock_call.say_digits digits
|
|
2414
|
-
pbx_was_asked_to_execute "saydigits", digits
|
|
2415
|
-
end
|
|
2416
|
-
|
|
2417
|
-
it 'Digits that include pound, star, and minus are considered valid' do
|
|
2418
|
-
digits = "1#2*3-4"
|
|
2419
|
-
mock_call.should_receive(:execute).once.with("saydigits", digits)
|
|
2420
|
-
mock_call.say_digits digits
|
|
2421
|
-
end
|
|
2422
|
-
|
|
2423
|
-
it 'Cannot pass non-integers into say_digits. Will raise an ArgumentError' do
|
|
2424
|
-
the_following_code {
|
|
2425
|
-
mock_call.say_digits 'abc'
|
|
2426
|
-
}.should raise_error(ArgumentError)
|
|
2427
|
-
|
|
2428
|
-
the_following_code {
|
|
2429
|
-
mock_call.say_digits '1.20'
|
|
2430
|
-
}.should raise_error(ArgumentError)
|
|
2431
|
-
end
|
|
2432
|
-
|
|
2433
|
-
it 'Digits that start with a 0 are considered valid and parsed properly' do
|
|
2434
|
-
digits = "0123"
|
|
2435
|
-
mock_call.should_receive(:execute).once.with("saydigits", digits)
|
|
2436
|
-
mock_call.say_digits digits
|
|
2437
|
-
end
|
|
2438
|
-
|
|
2439
|
-
end
|
|
2440
|
-
|
|
2441
|
-
describe 'the enable_feature command' do
|
|
2442
|
-
|
|
2443
|
-
include DialplanCommandTestHelpers
|
|
2444
|
-
|
|
2445
|
-
it 'it should fetch the variable for DYNAMIC_FEATURES at first' do
|
|
2446
|
-
mock_call.should_receive(:variable).once.with("DYNAMIC_FEATURES").and_throw :got_variable
|
|
2447
|
-
should_throw :got_variable do
|
|
2448
|
-
mock_call.enable_feature :foobar
|
|
2449
|
-
end
|
|
2450
|
-
end
|
|
2451
|
-
|
|
2452
|
-
it 'should check Adhearsion::VoIP::Asterisk::Commands::DYNAMIC_FEATURE_EXTENSIONS mapping for configuration setters' do
|
|
2453
|
-
feature_name = :attended_transfer
|
|
2454
|
-
|
|
2455
|
-
assertion = lambda do |arg|
|
|
2456
|
-
arg.should == :this_is_the_right_arg
|
|
2457
|
-
throw :inside_assertion!
|
|
2458
|
-
end
|
|
2459
|
-
|
|
2460
|
-
# I had to do this ugly hack because of a bug in Flexmock which prevented me from mocking out Hash#[] :(
|
|
2461
|
-
old_hash_feature_extension = Adhearsion::VoIP::Asterisk::Commands::DYNAMIC_FEATURE_EXTENSIONS[feature_name]
|
|
2462
|
-
begin
|
|
2463
|
-
Adhearsion::VoIP::Asterisk::Commands::DYNAMIC_FEATURE_EXTENSIONS[feature_name] = assertion
|
|
2464
|
-
# </uglyhack>
|
|
2465
|
-
should_throw :inside_assertion! do
|
|
2466
|
-
mock_call.enable_feature(feature_name, :this_is_the_right_arg)
|
|
2467
|
-
end
|
|
2468
|
-
ensure
|
|
2469
|
-
Adhearsion::VoIP::Asterisk::Commands::DYNAMIC_FEATURE_EXTENSIONS[feature_name] = old_hash_feature_extension
|
|
2470
|
-
end
|
|
2471
|
-
end
|
|
2472
|
-
|
|
2473
|
-
it 'should separate enabled features with a "#"' do
|
|
2474
|
-
mock_call.should_receive(:variable).once.with("DYNAMIC_FEATURES").and_return("one")
|
|
2475
|
-
mock_call.should_receive(:variable).once.with("DYNAMIC_FEATURES" => 'one#bar')
|
|
2476
|
-
mock_call.enable_feature "bar"
|
|
2477
|
-
end
|
|
2478
|
-
|
|
2479
|
-
it 'should not add duplicate enabled dynamic features' do
|
|
2480
|
-
mock_call.should_receive(:variable).once.and_return('eins#zwei')
|
|
2481
|
-
mock_call.enable_feature "eins"
|
|
2482
|
-
end
|
|
2483
|
-
|
|
2484
|
-
it 'should raise an ArgumentError if optional options are given when DYNAMIC_FEATURE_EXTENSIONS does not have a key for the feature name' do
|
|
2485
|
-
the_following_code {
|
|
2486
|
-
mock_call.enable_feature :this_is_not_recognized, :these_features => "are not going to be recognized"
|
|
2487
|
-
}.should raise_error ArgumentError
|
|
2488
|
-
end
|
|
2489
|
-
|
|
2490
|
-
it 'enabling :attended_transfer should actually enable the atxfer feature' do
|
|
2491
|
-
mock_call.should_receive(:variable).once.with("DYNAMIC_FEATURES").and_return ''
|
|
2492
|
-
mock_call.should_receive(:variable).once.with("DYNAMIC_FEATURES" => 'atxfer')
|
|
2493
|
-
mock_call.enable_feature :attended_transfer
|
|
2494
|
-
end
|
|
2495
|
-
|
|
2496
|
-
it 'the :context optional option when enabling :attended_transfer should set the TRANSFER_CONTEXT variable to the String supplied as a Hash value' do
|
|
2497
|
-
context_name = "direct_dial"
|
|
2498
|
-
mock_call.should_receive(:variable).once.with("DYNAMIC_FEATURES").and_return ''
|
|
2499
|
-
mock_call.should_receive(:variable).once.with("DYNAMIC_FEATURES" => 'atxfer')
|
|
2500
|
-
mock_call.should_receive(:variable).once.with("TRANSFER_CONTEXT" => context_name)
|
|
2501
|
-
mock_call.enable_feature :attended_transfer, :context => context_name
|
|
2502
|
-
end
|
|
2503
|
-
|
|
2504
|
-
it 'enabling :attended_transfer should not add a duplicate if atxfer has been enabled, but it should still set the TRANSFER_CONTEXT variable' do
|
|
2505
|
-
context_name = 'blah'
|
|
2506
|
-
mock_call.should_receive(:variable).once.with('DYNAMIC_FEATURES').and_return 'atxfer'
|
|
2507
|
-
mock_call.should_receive(:variable).once.with('TRANSFER_CONTEXT' => context_name)
|
|
2508
|
-
mock_call.enable_feature :attended_transfer, :context => context_name
|
|
2509
|
-
end
|
|
2510
|
-
|
|
2511
|
-
end
|
|
2512
|
-
|
|
2513
|
-
describe 'the disable_feature command' do
|
|
2514
|
-
|
|
2515
|
-
include DialplanCommandTestHelpers
|
|
2516
|
-
|
|
2517
|
-
it "should properly remove the feature from the DYNAMIC_FEATURES variable" do
|
|
2518
|
-
mock_call.should_receive(:variable).once.with('DYNAMIC_FEATURES').and_return 'foobar#qaz'
|
|
2519
|
-
mock_call.should_receive(:variable).once.with('DYNAMIC_FEATURES' => 'qaz')
|
|
2520
|
-
mock_call.disable_feature "foobar"
|
|
2521
|
-
end
|
|
2522
|
-
|
|
2523
|
-
it "should not re-set the variable if the feature wasn't enabled in the first place" do
|
|
2524
|
-
mock_call.should_receive(:variable).once.with('DYNAMIC_FEATURES').and_return 'atxfer'
|
|
2525
|
-
mock_call.should_receive(:variable).never
|
|
2526
|
-
mock_call.disable_feature "jay"
|
|
2527
|
-
end
|
|
2528
|
-
|
|
2529
|
-
end
|
|
2530
|
-
|
|
2531
|
-
describe 'jump_to command' do
|
|
2532
|
-
|
|
2533
|
-
include DialplanCommandTestHelpers
|
|
2534
|
-
|
|
2535
|
-
it 'when given a DialplanContextProc as the only argument, it should raise a ControlPassingException with that as the target' do
|
|
2536
|
-
# Having to do this ugly hack because I can't do anything with the exception once I set up an expectation with it normally.
|
|
2537
|
-
dialplan_context = Adhearsion::DialPlan::DialplanContextProc.new("my_context") {}
|
|
2538
|
-
should_throw :finishing_the_rescue_block do
|
|
2539
|
-
begin
|
|
2540
|
-
mock_call.jump_to dialplan_context
|
|
2541
|
-
rescue Adhearsion::VoIP::DSL::Dialplan::ControlPassingException => cpe
|
|
2542
|
-
cpe.target.should be dialplan_context
|
|
2543
|
-
throw :finishing_the_rescue_block
|
|
2544
|
-
end
|
|
2545
|
-
end
|
|
2546
|
-
end
|
|
2547
|
-
|
|
2548
|
-
it 'when given a String, it should perform a lookup of the context name' do
|
|
2549
|
-
context_name = 'cool_context'
|
|
2550
|
-
mock_call.should_receive(context_name).once.and_throw :found_context!
|
|
2551
|
-
should_throw :found_context! do
|
|
2552
|
-
mock_call.jump_to context_name
|
|
2553
|
-
end
|
|
2554
|
-
end
|
|
2555
|
-
|
|
2556
|
-
it 'when given a Symbol, it should perform a lookup of the context name' do
|
|
2557
|
-
context_name = :cool_context
|
|
2558
|
-
mock_call.should_receive(context_name).once.and_throw :found_context!
|
|
2559
|
-
should_throw :found_context! do
|
|
2560
|
-
mock_call.jump_to context_name
|
|
2561
|
-
end
|
|
2562
|
-
end
|
|
2563
|
-
|
|
2564
|
-
it "a clearly invalid context name should raise a ContextNotFoundException" do
|
|
2565
|
-
bad_context_name = ' ZOMGS this is A REALLY! STUPID context name . wtf were you thinking?!'
|
|
2566
|
-
the_following_code {
|
|
2567
|
-
mock_call.jump_to bad_context_name
|
|
2568
|
-
}.should raise_error Adhearsion::VoIP::DSL::Dialplan::ContextNotFoundException
|
|
2569
|
-
end
|
|
2570
|
-
|
|
2571
|
-
it 'when given an :extension override, the new value should be boxed in a PhoneNumber' do
|
|
2572
|
-
my_context = Adhearsion::DialPlan::DialplanContextProc.new("my_context") {}
|
|
2573
|
-
begin
|
|
2574
|
-
mock_call.jump_to my_context, :extension => 1337
|
|
2575
|
-
rescue Adhearsion::VoIP::DSL::Dialplan::ControlPassingException
|
|
2576
|
-
# Eating this exception
|
|
2577
|
-
end
|
|
2578
|
-
mock_call.extension.__real_num.should == 1337
|
|
2579
|
-
end
|
|
2580
|
-
|
|
2581
|
-
it 'other overrides should be simply metadef()d' do
|
|
2582
|
-
test_context = Adhearsion::DialPlan::DialplanContextProc.new("test_context") {}
|
|
2583
|
-
begin
|
|
2584
|
-
mock_call.jump_to test_context, :caller_id => 1_444_555_6666
|
|
2585
|
-
rescue Adhearsion::VoIP::DSL::Dialplan::ControlPassingException
|
|
2586
|
-
# Eating this exception
|
|
2587
|
-
end
|
|
2588
|
-
mock_call.caller_id.should == 1_444_555_6666
|
|
2589
|
-
end
|
|
2590
|
-
|
|
2591
|
-
end
|
|
2592
|
-
|
|
2593
|
-
describe "get variable command" do
|
|
2594
|
-
include DialplanCommandTestHelpers
|
|
2595
|
-
|
|
2596
|
-
it "Getting a variable that isn't set returns nothing" do
|
|
2597
|
-
pbx_should_respond_with "200 result=0"
|
|
2598
|
-
mock_call.get_variable('OMGURFACE').should be nil
|
|
2599
|
-
pbx_should_have_been_sent 'GET VARIABLE "OMGURFACE"'
|
|
2600
|
-
end
|
|
2601
|
-
|
|
2602
|
-
it 'An empty variable should return an empty String' do
|
|
2603
|
-
pbx_should_respond_with_value ""
|
|
2604
|
-
mock_call.get_variable('kablamm').should == ""
|
|
2605
|
-
pbx_should_have_been_sent 'GET VARIABLE "kablamm"'
|
|
2606
|
-
end
|
|
2607
|
-
|
|
2608
|
-
it "Getting a variable that is set returns its value" do
|
|
2609
|
-
unique_id = "1192470850.1"
|
|
2610
|
-
pbx_should_respond_with_value unique_id
|
|
2611
|
-
variable_value_returned = mock_call.get_variable('UNIQUEID')
|
|
2612
|
-
variable_value_returned.should == unique_id
|
|
2613
|
-
pbx_should_have_been_sent 'GET VARIABLE "UNIQUEID"'
|
|
2614
|
-
end
|
|
2615
|
-
end
|
|
2616
|
-
|
|
2617
|
-
describe "duration_of command" do
|
|
2618
|
-
include DialplanCommandTestHelpers
|
|
2619
|
-
|
|
2620
|
-
it "Duration of must take a block" do
|
|
2621
|
-
the_following_code {
|
|
2622
|
-
mock_call.duration_of
|
|
2623
|
-
}.should raise_error(LocalJumpError)
|
|
2624
|
-
end
|
|
2625
|
-
|
|
2626
|
-
it "Passed block to duration of is actually executed" do
|
|
2627
|
-
the_following_code {
|
|
2628
|
-
mock_call.duration_of {
|
|
2629
|
-
throw :inside_duration_of
|
|
2630
|
-
}
|
|
2631
|
-
}.should throw_symbol :inside_duration_of
|
|
2632
|
-
end
|
|
2633
|
-
|
|
2634
|
-
it "Duration of block is returned" do
|
|
2635
|
-
start_time = Time.parse('9:25:00')
|
|
2636
|
-
end_time = Time.parse('9:25:05')
|
|
2637
|
-
expected_duration = end_time - start_time
|
|
2638
|
-
|
|
2639
|
-
flexmock(Time).should_receive(:now).twice.and_return(start_time, end_time)
|
|
2640
|
-
duration = mock_call.duration_of {
|
|
2641
|
-
# This doesn't matter
|
|
2642
|
-
}
|
|
2643
|
-
|
|
2644
|
-
duration.should == expected_duration
|
|
2645
|
-
end
|
|
2646
|
-
end
|
|
2647
|
-
|
|
2648
|
-
describe "Dial command" do
|
|
2649
|
-
include DialplanCommandTestHelpers
|
|
2650
|
-
|
|
2651
|
-
it "should set the caller id if the caller_id option is specified" do
|
|
2652
|
-
does_not_read_data_back
|
|
2653
|
-
mock_call.should_receive(:set_caller_id_number).once
|
|
2654
|
-
mock_call.dial 123, :caller_id => "1234678901"
|
|
2655
|
-
pbx_should_have_been_sent 'EXEC Dial "123"|""|""'
|
|
2656
|
-
end
|
|
2657
|
-
|
|
2658
|
-
it 'should raise an exception when unknown hash key arguments are given to it' do
|
|
2659
|
-
the_following_code {
|
|
2660
|
-
mock_call.dial 123, :asjndfhasndfahsbdfbhasbdfhabsd => "asbdfhabshdfbajhshfbajsf"
|
|
2661
|
-
}.should raise_error ArgumentError
|
|
2662
|
-
end
|
|
2663
|
-
|
|
2664
|
-
it 'should set the caller ID name when given the :name hash key argument' do
|
|
2665
|
-
does_not_read_data_back
|
|
2666
|
-
name = "Jay Phillips"
|
|
2667
|
-
mock_call.should_receive(:set_caller_id_name).once.with(name)
|
|
2668
|
-
mock_call.dial "BlahBlahBlah", :name => name
|
|
2669
|
-
pbx_should_have_been_sent 'EXEC Dial "BlahBlahBlah"|""|""'
|
|
2670
|
-
end
|
|
2671
|
-
|
|
2672
|
-
it "should raise an exception when a non-numerical caller_id is specified" do
|
|
2673
|
-
the_following_code {
|
|
2674
|
-
mock_call.dial 911, :caller_id => "zomgz"
|
|
2675
|
-
}.should raise_error ArgumentError
|
|
2676
|
-
end
|
|
2677
|
-
|
|
2678
|
-
it "should not raise an exception when a caller_id is specified in E.164 format (with '+' sign)" do
|
|
2679
|
-
the_following_code {
|
|
2680
|
-
mock_call.dial 911, :caller_id => "+123456789"
|
|
2681
|
-
}.should_not raise_error ArgumentError
|
|
2682
|
-
pbx_should_have_been_sent 'SET VARIABLE "CALLERID(num)" "+123456789"'
|
|
2683
|
-
end
|
|
2684
|
-
|
|
2685
|
-
it 'should pass the value of the :confirm key to dial_macro_option_compiler()' do
|
|
2686
|
-
does_not_read_data_back
|
|
2687
|
-
value_of_confirm_key = {:play => "ohai", :timeout => 30}
|
|
2688
|
-
mock_call.should_receive(:dial_macro_option_compiler).once.with value_of_confirm_key
|
|
2689
|
-
mock_call.dial 123, :confirm => value_of_confirm_key
|
|
2690
|
-
pbx_should_have_been_sent 'EXEC Dial "123"|""|""'
|
|
2691
|
-
end
|
|
2692
|
-
|
|
2693
|
-
it "should add the return value of dial_macro_option_compiler to the :options key's value given to the dial command" do
|
|
2694
|
-
channel = "SIP/1337"
|
|
2695
|
-
macro_arg = "THISSHOULDGETPASSEDTOASTERISK"
|
|
2696
|
-
timeout = 10
|
|
2697
|
-
options = 'hH'
|
|
2698
|
-
|
|
2699
|
-
mock_call.should_receive(:dial_macro_option_compiler).once.and_return macro_arg
|
|
2700
|
-
mock_call.should_receive(:execute).with('Dial', channel, timeout, options + macro_arg)
|
|
2701
|
-
mock_call.dial channel, :for => timeout, :confirm => true, :options => options
|
|
2702
|
-
end
|
|
2703
|
-
|
|
2704
|
-
it 'should add the return value of dial_macro_option_compiler to the options field when NO :options are given' do
|
|
2705
|
-
channel = "SIP/1337"
|
|
2706
|
-
macro_arg = "THISSHOULDGETPASSEDTOASTERISK"
|
|
2707
|
-
timeout = 10
|
|
2708
|
-
options = 'hH'
|
|
2709
|
-
|
|
2710
|
-
mock_call.should_receive(:dial_macro_option_compiler).once.and_return macro_arg
|
|
2711
|
-
mock_call.should_receive(:execute).with('Dial', channel, timeout, options + macro_arg)
|
|
2712
|
-
mock_call.dial channel, :for => timeout, :confirm => true, :options => options
|
|
2713
|
-
end
|
|
2714
|
-
|
|
2715
|
-
end
|
|
2716
|
-
|
|
2717
|
-
describe "The Dial command's :confirm option setting builder" do
|
|
2718
|
-
|
|
2719
|
-
include DialplanCommandTestHelpers
|
|
2720
|
-
|
|
2721
|
-
attr_reader :formatter
|
|
2722
|
-
before :each do
|
|
2723
|
-
@formatter = mock_call.method :dial_macro_option_compiler
|
|
2724
|
-
end
|
|
2725
|
-
|
|
2726
|
-
it 'should allow passing in the :confirm named argument with true' do
|
|
2727
|
-
the_following_code {
|
|
2728
|
-
formatter.call true
|
|
2729
|
-
}.should_not raise_error ArgumentError
|
|
2730
|
-
end
|
|
2731
|
-
|
|
2732
|
-
it 'should separate :play options with "++"' do
|
|
2733
|
-
sound_files = *1..10
|
|
2734
|
-
formatter.call(:play => sound_files).should include sound_files.join('++')
|
|
2735
|
-
end
|
|
2736
|
-
|
|
2737
|
-
it 'should raise an ArgumentError if an invalid Hash key is given' do
|
|
2738
|
-
the_following_code {
|
|
2739
|
-
formatter.call :this_symbol_is_not_valid => 123
|
|
2740
|
-
}.should raise_error ArgumentError
|
|
2741
|
-
end
|
|
2742
|
-
|
|
2743
|
-
it "should raise an ArgumentError if the argument's class is not recognized" do
|
|
2744
|
-
the_following_code {
|
|
2745
|
-
formatter.call Time.now # Time is an example strange case
|
|
2746
|
-
}.should raise_error ArgumentError
|
|
2747
|
-
end
|
|
2748
|
-
|
|
2749
|
-
it 'should return the contents within a M() Dial argument' do
|
|
2750
|
-
formatter.call(true).should =~ /^M\(.+\)$/
|
|
2751
|
-
end
|
|
2752
|
-
|
|
2753
|
-
it 'should replace the default macro name when given the :macro options' do
|
|
2754
|
-
macro_name = "ivegotalovelybunchofcoconuts"
|
|
2755
|
-
formatter.call(:macro => macro_name).starts_with?("M(#{macro_name}").should be true
|
|
2756
|
-
end
|
|
2757
|
-
|
|
2758
|
-
it 'should allow a symbol macro name' do
|
|
2759
|
-
the_following_code {
|
|
2760
|
-
formatter.call(:macro => :foo)
|
|
2761
|
-
}.should_not raise_error ArgumentError
|
|
2762
|
-
end
|
|
2763
|
-
|
|
2764
|
-
it 'should only allow alphanumeric and underscores in the macro name' do
|
|
2765
|
-
bad_options = ["this has a space", "foo,bar", 'exists?', 'x^z', '', "!&@&*^!@"]
|
|
2766
|
-
bad_options.each do |bad_option|
|
|
2767
|
-
the_following_code {
|
|
2768
|
-
formatter.call(:macro => bad_option)
|
|
2769
|
-
}.should raise_error ArgumentError
|
|
2770
|
-
end
|
|
2771
|
-
end
|
|
2772
|
-
|
|
2773
|
-
it 'should confirm :timeout => :none to 0' do
|
|
2774
|
-
formatter.call(:timeout => :none).should include "timeout:0"
|
|
2775
|
-
end
|
|
2776
|
-
|
|
2777
|
-
it 'should separate the macro name and the arguments with a caret (^)' do
|
|
2778
|
-
formatter.call(:macro => "jay").should =~ /M\(jay\^.+/
|
|
2779
|
-
end
|
|
2780
|
-
|
|
2781
|
-
it 'should raise an ArgumentError if a caret existed anywhere in the resulting String' do
|
|
2782
|
-
# FIXME: Duplicate hash key
|
|
2783
|
-
bad_options = [{:play => "foo^bar", :key => "^", :play => ["hello-world", 'lol^cats']}]
|
|
2784
|
-
bad_options.each do |bad_option|
|
|
2785
|
-
the_following_code {
|
|
2786
|
-
formatter.call(bad_option)
|
|
2787
|
-
}.should raise_error ArgumentError
|
|
2788
|
-
end
|
|
2789
|
-
end
|
|
2790
|
-
|
|
2791
|
-
it 'should raise an ArgumentError if the :key is not [0-9#*]' do
|
|
2792
|
-
bad_options = %w[& A $ @ . )]
|
|
2793
|
-
bad_options.each do |bad_option|
|
|
2794
|
-
the_following_code {
|
|
2795
|
-
formatter.call :key => bad_option
|
|
2796
|
-
}.should raise_error ArgumentError
|
|
2797
|
-
end
|
|
2798
|
-
end
|
|
2799
|
-
|
|
2800
|
-
it 'should raise an ArgumentError if the key is longer than one digit' do
|
|
2801
|
-
the_following_code {
|
|
2802
|
-
formatter.call :key => "55"
|
|
2803
|
-
}.should raise_error ArgumentError
|
|
2804
|
-
end
|
|
2805
|
-
|
|
2806
|
-
it 'should raise an ArgumentError if the timeout is not numeric and not :none' do
|
|
2807
|
-
bad_options = [:nonee, Time.now, method(:inspect)]
|
|
2808
|
-
bad_options.each do |bad_option|
|
|
2809
|
-
the_following_code {
|
|
2810
|
-
formatter.call bad_option
|
|
2811
|
-
}.should raise_error ArgumentError
|
|
2812
|
-
end
|
|
2813
|
-
end
|
|
2814
|
-
|
|
2815
|
-
it 'should support passing a String argument as a timeout' do
|
|
2816
|
-
the_following_code {
|
|
2817
|
-
formatter.call :timeout => "123"
|
|
2818
|
-
}.should_not raise_error ArgumentError
|
|
2819
|
-
end
|
|
2820
|
-
|
|
2821
|
-
it 'should raise an ArgumentError if given a Float' do
|
|
2822
|
-
the_following_code {
|
|
2823
|
-
formatter.call :timeout => 100.0012
|
|
2824
|
-
}.should raise_error ArgumentError
|
|
2825
|
-
end
|
|
2826
|
-
|
|
2827
|
-
it 'should allow passing a ActiveSupport::Duration to :timeout' do
|
|
2828
|
-
the_following_code {
|
|
2829
|
-
formatter.call :timeout => 3.minutes
|
|
2830
|
-
}.should_not raise_error ArgumentError
|
|
2831
|
-
end
|
|
2832
|
-
|
|
2833
|
-
end
|
|
2834
|
-
|
|
2835
|
-
describe 'the dtmf command' do
|
|
2836
|
-
|
|
2837
|
-
include DialplanCommandTestHelpers
|
|
2838
|
-
|
|
2839
|
-
it 'should send the proper AGI command' do
|
|
2840
|
-
does_not_read_data_back
|
|
2841
|
-
digits = '8404#4*'
|
|
2842
|
-
mock_call.dtmf digits
|
|
2843
|
-
pbx_should_have_been_sent "EXEC SendDTMF \"#{digits}\""
|
|
2844
|
-
end
|
|
2845
|
-
end
|
|
2846
|
-
|
|
2847
|
-
describe "the last_dial_status command and family" do
|
|
2848
|
-
|
|
2849
|
-
include DialplanCommandTestHelpers
|
|
2850
|
-
|
|
2851
|
-
it 'should convert common DIALSTATUS variables to their appropriate symbols' do
|
|
2852
|
-
mock_call.should_receive(:variable).with("DIALSTATUS").once.and_return('ANSWER')
|
|
2853
|
-
mock_call.last_dial_status.should be :answered
|
|
2854
|
-
|
|
2855
|
-
mock_call.should_receive(:variable).with("DIALSTATUS").once.and_return('CONGESTION')
|
|
2856
|
-
mock_call.last_dial_status.should be :congested
|
|
2857
|
-
|
|
2858
|
-
mock_call.should_receive(:variable).once.with("DIALSTATUS").and_return("BUSY")
|
|
2859
|
-
mock_call.last_dial_status.should be :busy
|
|
2860
|
-
|
|
2861
|
-
mock_call.should_receive(:variable).once.with("DIALSTATUS").and_return("CANCEL")
|
|
2862
|
-
mock_call.last_dial_status.should be :cancelled
|
|
2863
|
-
|
|
2864
|
-
mock_call.should_receive(:variable).once.with("DIALSTATUS").and_return("NOANSWER")
|
|
2865
|
-
mock_call.last_dial_status.should be :unanswered
|
|
2866
|
-
|
|
2867
|
-
mock_call.should_receive(:variable).once.with("DIALSTATUS").and_return("CHANUNAVAIL")
|
|
2868
|
-
mock_call.last_dial_status.should be :channel_unavailable
|
|
2869
|
-
|
|
2870
|
-
mock_call.should_receive(:variable).once.with("DIALSTATUS").and_return("THISISNOTVALID")
|
|
2871
|
-
mock_call.last_dial_status.should be :unknown
|
|
2872
|
-
end
|
|
2873
|
-
|
|
2874
|
-
it 'last_dial_successful? should return true if last_dial_status == :answered' do
|
|
2875
|
-
mock_call.should_receive(:variable).with("DIALSTATUS").once.and_return('ANSWER')
|
|
2876
|
-
mock_call.last_dial_successful?.should be true
|
|
2877
|
-
|
|
2878
|
-
mock_call.should_receive(:variable).with("DIALSTATUS").once.and_return('CHANUNAVAIL')
|
|
2879
|
-
mock_call.last_dial_successful?.should be false
|
|
2880
|
-
end
|
|
2881
|
-
|
|
2882
|
-
it 'last_dial_unsuccessful? should be the opposite of last_dial_successful?' do
|
|
2883
|
-
mock_call.should_receive(:variable).with("DIALSTATUS").once.and_return('ANSWER')
|
|
2884
|
-
mock_call.last_dial_unsuccessful?.should be false
|
|
2885
|
-
|
|
2886
|
-
mock_call.should_receive(:variable).with("DIALSTATUS").once.and_return('CHANUNAVAIL')
|
|
2887
|
-
mock_call.last_dial_unsuccessful?.should be true
|
|
2888
|
-
end
|
|
2889
|
-
|
|
2890
|
-
it 'last_dial_status should not blow up if variable() returns nil. it should return :cancelled' do
|
|
2891
|
-
the_following_code {
|
|
2892
|
-
mock_call.should_receive(:variable).once.with("DIALSTATUS").and_return nil
|
|
2893
|
-
mock_call.last_dial_status.should be :cancelled
|
|
2894
|
-
|
|
2895
|
-
mock_call.should_receive(:variable).once.with("DIALSTATUS").and_return nil
|
|
2896
|
-
mock_call.last_dial_successful?.should be false
|
|
2897
|
-
}.should_not raise_error
|
|
2898
|
-
end
|
|
2899
|
-
|
|
2900
|
-
end
|
|
2901
|
-
|
|
2902
|
-
describe "set_caller_id_number command" do
|
|
2903
|
-
include DialplanCommandTestHelpers
|
|
2904
|
-
|
|
2905
|
-
it "should encapsulate the number with quotes" do
|
|
2906
|
-
caller_id = "14445556666"
|
|
2907
|
-
mock_call.should_receive(:raw_response).once.with(%(SET VARIABLE "CALLERID(num)" "#{caller_id}")).and_return true
|
|
2908
|
-
mock_call.send(:set_caller_id_number, caller_id)
|
|
2909
|
-
end
|
|
2910
|
-
end
|
|
2911
|
-
|
|
2912
|
-
describe 'set_caller_id_name command' do
|
|
2913
|
-
include DialplanCommandTestHelpers
|
|
2914
|
-
|
|
2915
|
-
it "should wrap the name in quotes" do
|
|
2916
|
-
name = "Jay Phillips"
|
|
2917
|
-
mock_call.should_receive(:raw_response).once.with(%(SET VARIABLE "CALLERID(name)" "#{name}")).and_return true
|
|
2918
|
-
mock_call.send(:set_caller_id_name, name)
|
|
2919
|
-
end
|
|
2920
|
-
end
|
|
2921
|
-
|
|
2922
|
-
describe "speak command" do
|
|
2923
|
-
include DialplanCommandTestHelpers
|
|
2924
|
-
|
|
2925
|
-
before :all do
|
|
2926
|
-
@speech_engines = Adhearsion::VoIP::Asterisk::Commands::SpeechEngines
|
|
2927
|
-
end
|
|
2928
|
-
|
|
2929
|
-
it "executes the command SpeechEngine gives it based on the engine name" do
|
|
2930
|
-
pbx_should_respond_with_success
|
|
2931
|
-
flexmock(@speech_engines).should_receive(:cepstral).once
|
|
2932
|
-
mock_call.speak "Spoken text doesn't matter", :engine => :cepstral
|
|
2933
|
-
end
|
|
2934
|
-
|
|
2935
|
-
it "raises an InvalidSpeechEngine exception when the engine is 'none'" do
|
|
2936
|
-
the_following_code {
|
|
2937
|
-
mock_call.speak("o hai!", :engine => :none)
|
|
2938
|
-
}.should raise_error @speech_engines::InvalidSpeechEngine
|
|
2939
|
-
end
|
|
2940
|
-
|
|
2941
|
-
it "should default its engine to :none" do
|
|
2942
|
-
the_following_code {
|
|
2943
|
-
flexmock(@speech_engines).should_receive(:none).once.
|
|
2944
|
-
and_raise(@speech_engines::InvalidSpeechEngine)
|
|
2945
|
-
mock_call.speak "ruby ruby ruby ruby!"
|
|
2946
|
-
}.should raise_error @speech_engines::InvalidSpeechEngine
|
|
2947
|
-
end
|
|
2948
|
-
|
|
2949
|
-
it 'should default to a configured TTS engine' do
|
|
2950
|
-
Adhearsion::Configuration.configure {|c| c.asterisk.speech_engine = :unimrcp }
|
|
2951
|
-
flexmock(@speech_engines).should_receive(:unimrcp).once
|
|
2952
|
-
mock_call.speak 'What say you, sir?'
|
|
2953
|
-
end
|
|
2954
|
-
|
|
2955
|
-
it 'should allow the caller to override the default configured TTS engine' do
|
|
2956
|
-
Adhearsion::Configuration.configure {|c| c.asterisk.speech_engine = :unimrcp }
|
|
2957
|
-
flexmock(@speech_engines).should_receive(:cepstral).once
|
|
2958
|
-
mock_call.speak 'What say you now, sir?', :engine => :cepstral
|
|
2959
|
-
end
|
|
2960
|
-
|
|
2961
|
-
it 'should default to uninterruptible TTS rendering' do
|
|
2962
|
-
flexmock(@speech_engines).should_receive(:cepstral).once.with(mock_call, 'hello', {:interruptible => false})
|
|
2963
|
-
mock_call.speak 'hello', :engine => :cepstral
|
|
2964
|
-
end
|
|
2965
|
-
|
|
2966
|
-
it 'should allow setting TTS rendering interruptible' do
|
|
2967
|
-
flexmock(@speech_engines).should_receive(:cepstral).once.with(mock_call, 'hello', {:interruptible => true})
|
|
2968
|
-
mock_call.speak 'hello', :engine => :cepstral, :interruptible => true
|
|
2969
|
-
end
|
|
2970
|
-
|
|
2971
|
-
it "should stringify the text" do
|
|
2972
|
-
flexmock(@speech_engines).should_receive(:cepstral).once.with(mock_call, 'hello', {:interruptible => false})
|
|
2973
|
-
mock_call.speak :hello, :engine => :cepstral
|
|
2974
|
-
end
|
|
2975
|
-
|
|
2976
|
-
context "with the engine :cepstral" do
|
|
2977
|
-
it "should execute Swift"do
|
|
2978
|
-
pbx_should_respond_with_value 0
|
|
2979
|
-
mock_call.should_receive(:execute).with('Swift', 'hello')
|
|
2980
|
-
@speech_engines.cepstral(mock_call, 'hello')
|
|
2981
|
-
@output.read.should == "GET VARIABLE \"SWIFT_DTMF\"\n"
|
|
2982
|
-
end
|
|
2983
|
-
|
|
2984
|
-
it "should properly escape commas in the TTS string" do
|
|
2985
|
-
pbx_should_respond_with_value 0
|
|
2986
|
-
mock_call.should_receive(:execute).with('Swift', 'Once\, a long\, long time ago\, ...')
|
|
2987
|
-
@speech_engines.cepstral(mock_call, 'Once, a long, long time ago, ...')
|
|
2988
|
-
@output.read.should == "GET VARIABLE \"SWIFT_DTMF\"\n"
|
|
2989
|
-
end
|
|
2990
|
-
|
|
2991
|
-
it "should properly escape double-quotes (for XML) in the TTS string" do
|
|
2992
|
-
mock_call.should_receive(:raw_response).once.with('EXEC MRCPSynth "<speak xmlns=\\\\\"http://www.w3.org/2001/10/synthesis\\\\\" version=\\\\\"1.0\\\\\" xml:lang=\\\\\"en-US\\\\\"> <voice name=\\\\\"Paul\\\\\"> <prosody rate=\\\\\"1.0\\\\\">Howdy, stranger. How are you today?</prosody> </voice> </speak>"').and_return pbx_success_response
|
|
2993
|
-
@speech_engines.unimrcp(mock_call, '<speak xmlns="http://www.w3.org/2001/10/synthesis" version="1.0" xml:lang="en-US"> <voice name="Paul"> <prosody rate="1.0">Howdy, stranger. How are you today?</prosody> </voice> </speak>')
|
|
2994
|
-
end
|
|
2995
|
-
|
|
2996
|
-
context "with barge in digits set" do
|
|
2997
|
-
it "should return the digit when :interruptible = true" do
|
|
2998
|
-
mock_call.should_receive(:execute).once.with('Swift', 'hello', 1, 1).and_return pbx_success_response
|
|
2999
|
-
mock_call.should_receive(:get_variable).once.with('SWIFT_DTMF').and_return ?1
|
|
3000
|
-
@speech_engines.cepstral(mock_call, 'hello', :interruptible => true).should == ?1
|
|
3001
|
-
end
|
|
3002
|
-
end
|
|
3003
|
-
end
|
|
3004
|
-
|
|
3005
|
-
context "with the engine :unimrcp" do
|
|
3006
|
-
it "should execute MRCPSynth" do
|
|
3007
|
-
pbx_should_respond_with_success
|
|
3008
|
-
mock_call.should_receive(:execute).with('MRCPSynth', 'hello').once.and_return pbx_success_response
|
|
3009
|
-
@speech_engines.unimrcp(mock_call, 'hello')
|
|
3010
|
-
end
|
|
3011
|
-
|
|
3012
|
-
context "with barge in digits set" do
|
|
3013
|
-
it "should pass the i option for MRCPSynth" do
|
|
3014
|
-
mock_call.should_receive(:execute).with('MRCPSynth', 'hello', 'i=any').once.and_return pbx_result_response 0
|
|
3015
|
-
@speech_engines.unimrcp(mock_call, 'hello', :interrupt_digits => 'any')
|
|
3016
|
-
end
|
|
3017
|
-
end
|
|
3018
|
-
end
|
|
3019
|
-
|
|
3020
|
-
context "with the engine :tropo" do
|
|
3021
|
-
it "should execute tropo" do
|
|
3022
|
-
pbx_should_respond_with_success
|
|
3023
|
-
response = '200 result=' + {:interpretation => '1'}.to_json
|
|
3024
|
-
mock_call.should_receive(:raw_response).with(/Ask/i, 'hello').once.and_return response
|
|
3025
|
-
@speech_engines.tropo(mock_call, 'hello').should == "1"
|
|
3026
|
-
end
|
|
3027
|
-
|
|
3028
|
-
context "with :interruptible set to false"do
|
|
3029
|
-
it "should pass the :bargein => false option for Tropo Ask" do
|
|
3030
|
-
response = '200 result=' + {:interpretation => '1'}.to_json
|
|
3031
|
-
mock_call.should_receive(:raw_response).with(/Ask/i, 'hello', {:bargein => false}.to_json).once.and_return response
|
|
3032
|
-
@speech_engines.tropo(mock_call, 'hello', :interruptible => false)
|
|
3033
|
-
end
|
|
3034
|
-
end
|
|
3035
|
-
end
|
|
3036
|
-
|
|
3037
|
-
it "properly escapes spoken text" do
|
|
3038
|
-
pending 'What are the escaping needs?'
|
|
3039
|
-
end
|
|
3040
|
-
end
|
|
3041
|
-
|
|
3042
|
-
describe 'The join command' do
|
|
3043
|
-
|
|
3044
|
-
include DialplanCommandTestHelpers
|
|
3045
|
-
|
|
3046
|
-
it "should pass the 'd' flag when no options are given" do
|
|
3047
|
-
conference_id = "123"
|
|
3048
|
-
mock_call.should_receive(:execute).once.with("MeetMe", conference_id, "d", nil)
|
|
3049
|
-
mock_call.join conference_id
|
|
3050
|
-
end
|
|
3051
|
-
|
|
3052
|
-
it "should pass through any given flags with 'd' appended to it if necessary" do
|
|
3053
|
-
conference_id, flags = "1000", "zomgs"
|
|
3054
|
-
mock_call.should_receive(:execute).once.with("MeetMe", conference_id, flags + "d", nil)
|
|
3055
|
-
mock_call.join conference_id, :options => flags
|
|
3056
|
-
end
|
|
3057
|
-
|
|
3058
|
-
it "should NOT pass the 'd' flag when requiring static conferences" do
|
|
3059
|
-
conference_id, options = "1000", {:use_static_conf => true}
|
|
3060
|
-
mock_call.should_receive(:execute).once.with("MeetMe", conference_id, "", nil)
|
|
3061
|
-
mock_call.join conference_id, options
|
|
3062
|
-
end
|
|
3063
|
-
|
|
3064
|
-
it "should raise an ArgumentError when the pin is not numerical" do
|
|
3065
|
-
the_following_code {
|
|
3066
|
-
mock_call.should_receive(:execute).never
|
|
3067
|
-
mock_call.join 3333, :pin => "letters are bad, mkay?!1"
|
|
3068
|
-
}.should raise_error ArgumentError
|
|
3069
|
-
end
|
|
3070
|
-
|
|
3071
|
-
it "should strip out illegal characters from a conference name" do
|
|
3072
|
-
bizarre_conference_name = "a- bc!d&&e--`"
|
|
3073
|
-
normal_conference_name = "abcde"
|
|
3074
|
-
mock_call.should_receive(:execute).twice.with("MeetMe", normal_conference_name, "d", nil)
|
|
3075
|
-
|
|
3076
|
-
mock_call.join bizarre_conference_name
|
|
3077
|
-
mock_call.join normal_conference_name
|
|
3078
|
-
end
|
|
3079
|
-
|
|
3080
|
-
it "should allow textual conference names" do
|
|
3081
|
-
the_following_code {
|
|
3082
|
-
mock_call.should_receive(:execute).once.with_any_args
|
|
3083
|
-
mock_call.join "david bowie's pants"
|
|
3084
|
-
}.should_not raise_error
|
|
3085
|
-
end
|
|
3086
|
-
|
|
3087
|
-
end
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
describe 'the DialPlan::ConfirmationManager' do
|
|
3091
|
-
|
|
3092
|
-
include ConfirmationManagerTestHelper
|
|
3093
|
-
include DialplanCommandTestHelpers
|
|
3094
|
-
|
|
3095
|
-
attr_reader :example_encoded_hash, :example_encoded_hash_without_macro_name
|
|
3096
|
-
before :each do
|
|
3097
|
-
@example_encoded_hash_without_macro_name = 'timeout:20!play:foo-bar++qaz_qwerty.gsm!key:#'
|
|
3098
|
-
@example_encoded_hash = 'confirm!' + @example_encoded_hash_without_macro_name
|
|
3099
|
-
end
|
|
3100
|
-
|
|
3101
|
-
it '::decode_hash() should convert the String of key/value escaped pairs into a Hash with Symbol keys when the macro name is not given' do
|
|
3102
|
-
Adhearsion::DialPlan::ConfirmationManager.decode_hash(example_encoded_hash).should ==
|
|
3103
|
-
{:timeout => 20, :play => ['foo-bar', 'qaz_qwerty.gsm'], :key => '#'}
|
|
3104
|
-
end
|
|
3105
|
-
|
|
3106
|
-
it '::decode_hash() should convert the String of key/value escaped pairs into a Hash with Symbol keys when the macro name is not given' do
|
|
3107
|
-
Adhearsion::DialPlan::ConfirmationManager.decode_hash(example_encoded_hash_without_macro_name).should ==
|
|
3108
|
-
{:timeout => 20, :play => ['foo-bar', 'qaz_qwerty.gsm'], :key => '#'}
|
|
3109
|
-
end
|
|
3110
|
-
|
|
3111
|
-
it '::decode_hash() should split the sound files in the :play key to an array by splitting by "++"' do
|
|
3112
|
-
decoded_sound_files = Adhearsion::DialPlan::ConfirmationManager.decode_hash(example_encoded_hash)[:play]
|
|
3113
|
-
decoded_sound_files.should be_a_kind_of Array
|
|
3114
|
-
decoded_sound_files.size.should == 2
|
|
3115
|
-
end
|
|
3116
|
-
|
|
3117
|
-
it 'a call to a party which is acknowledged with the proper key during the call to interruptible_play' do
|
|
3118
|
-
variables = {:timeout => 20, :play => ['foo-bar', 'qaz_qwerty.gsm'], :key => '#', :macro => 'confirmer'}
|
|
3119
|
-
encoded_variables = {:network_script => encode_hash(variables)}
|
|
3120
|
-
io_mock = StringIO.new
|
|
3121
|
-
|
|
3122
|
-
mock_call.should_receive(:originating_voip_platform).once.and_return :asterisk
|
|
3123
|
-
mock_call.should_receive(:variables).once.and_return encoded_variables
|
|
3124
|
-
|
|
3125
|
-
sound_files = variables[:play]
|
|
3126
|
-
|
|
3127
|
-
manager = Adhearsion::DialPlan::ConfirmationManager.new(mock_call)
|
|
3128
|
-
|
|
3129
|
-
flexstub(manager).should_receive(:result_digit_from).and_return ?0.ord
|
|
3130
|
-
flexstub(manager).should_receive(:raw_response).and_return nil
|
|
3131
|
-
|
|
3132
|
-
flexmock(manager).should_receive(:answer).once
|
|
3133
|
-
flexmock(manager).should_receive(:interruptible_play).once.with(*sound_files).and_return '#'
|
|
3134
|
-
|
|
3135
|
-
manager.handle
|
|
3136
|
-
end
|
|
3137
|
-
|
|
3138
|
-
it 'when an timeout is encountered, it should set the MACRO_RESULT variable to CONTINUE' do
|
|
3139
|
-
variables = {:timeout => 20, :play => ['foo-bar', 'qaz_qwerty.gsm'], :key => '#', :macro => 'confirmer'}
|
|
3140
|
-
encoded_variables = {:network_script => encode_hash(variables)}
|
|
3141
|
-
io_mock = StringIO.new
|
|
3142
|
-
|
|
3143
|
-
mock_call.should_receive(:originating_voip_platform).once.and_return :asterisk
|
|
3144
|
-
mock_call.should_receive(:variables).once.and_return encoded_variables
|
|
3145
|
-
|
|
3146
|
-
sound_files = variables[:play]
|
|
3147
|
-
|
|
3148
|
-
manager = Adhearsion::DialPlan::ConfirmationManager.new(mock_call)
|
|
3149
|
-
|
|
3150
|
-
flexstub(manager).should_receive(:result_digit_from).and_return ?0.ord
|
|
3151
|
-
flexstub(manager).should_receive(:raw_response).and_return nil
|
|
3152
|
-
|
|
3153
|
-
flexmock(manager).should_receive(:answer).once
|
|
3154
|
-
flexmock(manager).should_receive(:interruptible_play).once.with(*sound_files).and_return nil
|
|
3155
|
-
flexmock(manager).should_receive(:wait_for_digit).once.with(20).and_return nil
|
|
3156
|
-
|
|
3157
|
-
flexmock(manager).should_receive(:variable).once.with("MACRO_RESULT" => 'CONTINUE')
|
|
3158
|
-
|
|
3159
|
-
manager.handle
|
|
3160
|
-
end
|
|
3161
|
-
|
|
3162
|
-
it 'should wait the :timeout number of seconds if no digit was received when playing the files and continue when the right key is pressed' do
|
|
3163
|
-
variables = {:timeout => 20, :play => ['foo-bar', 'qaz_qwerty.gsm'], :key => '#', :macro => 'confirmer'}
|
|
3164
|
-
encoded_variables = {:network_script => encode_hash(variables)}
|
|
3165
|
-
io_mock = StringIO.new
|
|
3166
|
-
|
|
3167
|
-
mock_call.should_receive(:originating_voip_platform).once.and_return :asterisk
|
|
3168
|
-
mock_call.should_receive(:variables).once.and_return encoded_variables
|
|
3169
|
-
|
|
3170
|
-
sound_files = variables[:play]
|
|
3171
|
-
|
|
3172
|
-
manager = Adhearsion::DialPlan::ConfirmationManager.new(mock_call)
|
|
3173
|
-
|
|
3174
|
-
flexstub(manager).should_receive(:result_digit_from).and_return ?0.ord
|
|
3175
|
-
flexstub(manager).should_receive(:raw_response).and_return nil
|
|
3176
|
-
|
|
3177
|
-
flexmock(manager).should_receive(:answer).once
|
|
3178
|
-
flexmock(manager).should_receive(:interruptible_play).once.with(*sound_files).and_return nil
|
|
3179
|
-
flexmock(manager).should_receive(:wait_for_digit).once.with(20).and_return '#'
|
|
3180
|
-
|
|
3181
|
-
manager.handle
|
|
3182
|
-
end
|
|
3183
|
-
|
|
3184
|
-
it 'should restart playback if the key received was not recognized' do
|
|
3185
|
-
variables = {:timeout => 20, :play => ['foo-bar', 'qaz_qwerty.gsm'], :key => '2', :macro => 'confirmer'}
|
|
3186
|
-
encoded_variables = {:network_script => encode_hash(variables)}
|
|
3187
|
-
io_mock = StringIO.new
|
|
3188
|
-
|
|
3189
|
-
mock_call.should_receive(:originating_voip_platform).once.and_return :asterisk
|
|
3190
|
-
mock_call.should_receive(:variables).once.and_return encoded_variables
|
|
3191
|
-
|
|
3192
|
-
sound_files = variables[:play]
|
|
3193
|
-
|
|
3194
|
-
manager = Adhearsion::DialPlan::ConfirmationManager.new(mock_call)
|
|
3195
|
-
|
|
3196
|
-
flexstub(manager).should_receive(:result_digit_from).and_return ?0.ord
|
|
3197
|
-
flexstub(manager).should_receive(:raw_response).and_return nil
|
|
3198
|
-
|
|
3199
|
-
flexmock(manager).should_receive(:answer).once
|
|
3200
|
-
flexmock(manager).should_receive(:interruptible_play).once.with(*sound_files).and_return '3' # not :key
|
|
3201
|
-
flexmock(manager).should_receive(:interruptible_play).once.with(*sound_files).and_return '#' # not :key
|
|
3202
|
-
flexmock(manager).should_receive(:interruptible_play).once.with(*sound_files).and_return '1' # not :key
|
|
3203
|
-
flexmock(manager).should_receive(:interruptible_play).once.with(*sound_files).and_return '2' # matches :key
|
|
3204
|
-
|
|
3205
|
-
flexmock(manager).should_receive(:wait_for_digit).never # We never let it get to the point where it may timeout
|
|
3206
|
-
flexmock(manager).should_receive(:variable).never # We succeed by not setting the MACRO_RESULT variable
|
|
3207
|
-
|
|
3208
|
-
manager.handle
|
|
3209
|
-
end
|
|
3210
|
-
|
|
3211
|
-
end
|
|
3212
|
-
|
|
3213
|
-
describe 'say_phonetic command' do
|
|
3214
|
-
include DialplanCommandTestHelpers
|
|
3215
|
-
it 'Can execute the sayphonetic application using say_phonetic' do
|
|
3216
|
-
text = 'Say This'
|
|
3217
|
-
mock_call.should_receive(:execute).once.with("sayphonetic", text)
|
|
3218
|
-
mock_call.say_phonetic text
|
|
3219
|
-
end
|
|
3220
|
-
|
|
3221
|
-
it 'Can use special characters with say_phonetic' do
|
|
3222
|
-
text = '*Say This!*'
|
|
3223
|
-
mock_call.should_receive(:execute).once.with("sayphonetic", text)
|
|
3224
|
-
mock_call.say_phonetic text
|
|
3225
|
-
end
|
|
3226
|
-
end
|
|
3227
|
-
|
|
3228
|
-
describe 'say_chars command' do
|
|
3229
|
-
include DialplanCommandTestHelpers
|
|
3230
|
-
it 'Can execute the sayalpha application using say_chars' do
|
|
3231
|
-
text = 'ha124d9'
|
|
3232
|
-
mock_call.should_receive(:execute).once.with("sayalpha", text)
|
|
3233
|
-
mock_call.say_chars text
|
|
3234
|
-
end
|
|
3235
|
-
|
|
3236
|
-
it 'Can use special characters with say_chars' do
|
|
3237
|
-
text = "1a2.#"
|
|
3238
|
-
mock_call.should_receive(:execute).once.with("sayalpha", text)
|
|
3239
|
-
mock_call.say_chars text
|
|
3240
|
-
end
|
|
3241
|
-
end
|