eric-adhearsion 0.7.999
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +3 -0
- data/LICENSE +456 -0
- data/Manifest.txt +149 -0
- data/README.txt +6 -0
- data/Rakefile +48 -0
- data/ahn_generators/component/USAGE +5 -0
- data/ahn_generators/component/component_generator.rb +57 -0
- data/ahn_generators/component/templates/configuration.rb +0 -0
- data/ahn_generators/component/templates/lib/lib.rb.erb +3 -0
- data/ahn_generators/component/templates/test/test.rb.erb +12 -0
- data/ahn_generators/component/templates/test/test_helper.rb +14 -0
- data/app_generators/ahn/USAGE +5 -0
- data/app_generators/ahn/ahn_generator.rb +76 -0
- data/app_generators/ahn/templates/.ahnrc +12 -0
- data/app_generators/ahn/templates/README +8 -0
- data/app_generators/ahn/templates/Rakefile +3 -0
- data/app_generators/ahn/templates/components/simon_game/configuration.rb +0 -0
- data/app_generators/ahn/templates/components/simon_game/lib/simon_game.rb +61 -0
- data/app_generators/ahn/templates/components/simon_game/test/test_helper.rb +14 -0
- data/app_generators/ahn/templates/components/simon_game/test/test_simon_game.rb +31 -0
- data/app_generators/ahn/templates/config/startup.rb +53 -0
- data/app_generators/ahn/templates/dialplan.rb +4 -0
- data/bin/ahn +28 -0
- data/bin/ahnctl +68 -0
- data/bin/jahn +32 -0
- data/lib/adhearsion/blank_slate.rb +5 -0
- data/lib/adhearsion/cli.rb +106 -0
- data/lib/adhearsion/component_manager.rb +277 -0
- data/lib/adhearsion/core_extensions/all.rb +9 -0
- data/lib/adhearsion/core_extensions/array.rb +0 -0
- data/lib/adhearsion/core_extensions/custom_daemonizer.rb +45 -0
- data/lib/adhearsion/core_extensions/global.rb +1 -0
- data/lib/adhearsion/core_extensions/guid.rb +5 -0
- data/lib/adhearsion/core_extensions/hash.rb +0 -0
- data/lib/adhearsion/core_extensions/metaprogramming.rb +17 -0
- data/lib/adhearsion/core_extensions/numeric.rb +4 -0
- data/lib/adhearsion/core_extensions/proc.rb +0 -0
- data/lib/adhearsion/core_extensions/pseudo_uuid.rb +11 -0
- data/lib/adhearsion/core_extensions/publishable.rb +73 -0
- data/lib/adhearsion/core_extensions/relationship_properties.rb +40 -0
- data/lib/adhearsion/core_extensions/string.rb +26 -0
- data/lib/adhearsion/core_extensions/thread.rb +13 -0
- data/lib/adhearsion/core_extensions/thread_safety.rb +7 -0
- data/lib/adhearsion/core_extensions/time.rb +0 -0
- data/lib/adhearsion/distributed/gateways/dbus_gateway.rb +0 -0
- data/lib/adhearsion/distributed/gateways/osa_gateway.rb +0 -0
- data/lib/adhearsion/distributed/gateways/rest_gateway.rb +9 -0
- data/lib/adhearsion/distributed/gateways/soap_gateway.rb +9 -0
- data/lib/adhearsion/distributed/gateways/xmlrpc_gateway.rb +9 -0
- data/lib/adhearsion/distributed/peer_finder.rb +0 -0
- data/lib/adhearsion/distributed/remote_cli.rb +0 -0
- data/lib/adhearsion/hooks.rb +57 -0
- data/lib/adhearsion/host_definitions.rb +63 -0
- data/lib/adhearsion/initializer/asterisk.rb +59 -0
- data/lib/adhearsion/initializer/configuration.rb +202 -0
- data/lib/adhearsion/initializer/database.rb +92 -0
- data/lib/adhearsion/initializer/drb.rb +25 -0
- data/lib/adhearsion/initializer/freeswitch.rb +22 -0
- data/lib/adhearsion/initializer/paths.rb +55 -0
- data/lib/adhearsion/initializer/rails.rb +40 -0
- data/lib/adhearsion/initializer.rb +217 -0
- data/lib/adhearsion/logging.rb +92 -0
- data/lib/adhearsion/services/scheduler.rb +5 -0
- data/lib/adhearsion/tasks/database.rb +5 -0
- data/lib/adhearsion/tasks/generating.rb +20 -0
- data/lib/adhearsion/tasks/lint.rb +4 -0
- data/lib/adhearsion/tasks/testing.rb +37 -0
- data/lib/adhearsion/tasks.rb +15 -0
- data/lib/adhearsion/version.rb +9 -0
- data/lib/adhearsion/voip/asterisk/agi_server.rb +78 -0
- data/lib/adhearsion/voip/asterisk/ami/actions.rb +238 -0
- data/lib/adhearsion/voip/asterisk/ami/machine.rb +871 -0
- data/lib/adhearsion/voip/asterisk/ami/machine.rl +109 -0
- data/lib/adhearsion/voip/asterisk/ami/parser.rb +262 -0
- data/lib/adhearsion/voip/asterisk/ami.rb +147 -0
- data/lib/adhearsion/voip/asterisk/commands.rb +1182 -0
- data/lib/adhearsion/voip/asterisk/config_generators/agents.conf.rb +140 -0
- data/lib/adhearsion/voip/asterisk/config_generators/config_generator.rb +101 -0
- data/lib/adhearsion/voip/asterisk/config_generators/queues.conf.rb +250 -0
- data/lib/adhearsion/voip/asterisk/config_generators/voicemail.conf.rb +240 -0
- data/lib/adhearsion/voip/asterisk/config_manager.rb +71 -0
- data/lib/adhearsion/voip/asterisk/special_dial_plan_managers.rb +80 -0
- data/lib/adhearsion/voip/asterisk.rb +4 -0
- data/lib/adhearsion/voip/call.rb +391 -0
- data/lib/adhearsion/voip/call_routing.rb +64 -0
- data/lib/adhearsion/voip/commands.rb +9 -0
- data/lib/adhearsion/voip/constants.rb +39 -0
- data/lib/adhearsion/voip/conveniences.rb +18 -0
- data/lib/adhearsion/voip/dial_plan.rb +205 -0
- data/lib/adhearsion/voip/dsl/dialing_dsl/dialing_dsl_monkey_patches.rb +37 -0
- data/lib/adhearsion/voip/dsl/dialing_dsl.rb +151 -0
- data/lib/adhearsion/voip/dsl/dialplan/control_passing_exception.rb +27 -0
- data/lib/adhearsion/voip/dsl/dialplan/dispatcher.rb +124 -0
- data/lib/adhearsion/voip/dsl/dialplan/parser.rb +75 -0
- data/lib/adhearsion/voip/dsl/dialplan/thread_mixin.rb +16 -0
- data/lib/adhearsion/voip/dsl/numerical_string.rb +117 -0
- data/lib/adhearsion/voip/freeswitch/basic_connection_manager.rb +48 -0
- data/lib/adhearsion/voip/freeswitch/event_handler.rb +58 -0
- data/lib/adhearsion/voip/freeswitch/freeswitch_dialplan_command_factory.rb +129 -0
- data/lib/adhearsion/voip/freeswitch/inbound_connection_manager.rb +38 -0
- data/lib/adhearsion/voip/freeswitch/oes_server.rb +195 -0
- data/lib/adhearsion/voip/menu_state_machine/calculated_match.rb +80 -0
- data/lib/adhearsion/voip/menu_state_machine/matchers.rb +123 -0
- data/lib/adhearsion/voip/menu_state_machine/menu_builder.rb +58 -0
- data/lib/adhearsion/voip/menu_state_machine/menu_class.rb +149 -0
- data/lib/adhearsion.rb +31 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/spec/fixtures/dialplan.rb +3 -0
- data/spec/initializer/test_configuration.rb +267 -0
- data/spec/initializer/test_loading.rb +162 -0
- data/spec/initializer/test_paths.rb +43 -0
- data/spec/silence.rb +10 -0
- data/spec/test_ahn_command.rb +149 -0
- data/spec/test_code_quality.rb +87 -0
- data/spec/test_component_manager.rb +97 -0
- data/spec/test_constants.rb +8 -0
- data/spec/test_drb.rb +104 -0
- data/spec/test_helper.rb +94 -0
- data/spec/test_hooks.rb +37 -0
- data/spec/test_host_definitions.rb +79 -0
- data/spec/test_initialization.rb +105 -0
- data/spec/test_logging.rb +80 -0
- data/spec/test_relationship_properties.rb +54 -0
- data/spec/voip/asterisk/ami_response_definitions.rb +23 -0
- data/spec/voip/asterisk/config_file_generators/test_agents.rb +253 -0
- data/spec/voip/asterisk/config_file_generators/test_queues.rb +325 -0
- data/spec/voip/asterisk/config_file_generators/test_voicemail.rb +306 -0
- data/spec/voip/asterisk/menu_command/test_calculated_match.rb +111 -0
- data/spec/voip/asterisk/menu_command/test_matchers.rb +98 -0
- data/spec/voip/asterisk/mock_ami_server.rb +176 -0
- data/spec/voip/asterisk/test_agi_server.rb +451 -0
- data/spec/voip/asterisk/test_ami.rb +227 -0
- data/spec/voip/asterisk/test_commands.rb +2006 -0
- data/spec/voip/asterisk/test_config_manager.rb +129 -0
- data/spec/voip/dsl/dispatcher_spec_helper.rb +45 -0
- data/spec/voip/dsl/test_dialing_dsl.rb +268 -0
- data/spec/voip/dsl/test_dispatcher.rb +82 -0
- data/spec/voip/dsl/test_parser.rb +87 -0
- data/spec/voip/freeswitch/test_basic_connection_manager.rb +39 -0
- data/spec/voip/freeswitch/test_inbound_connection_manager.rb +39 -0
- data/spec/voip/freeswitch/test_oes_server.rb +9 -0
- data/spec/voip/test_call_routing.rb +127 -0
- data/spec/voip/test_dialplan_manager.rb +372 -0
- data/spec/voip/test_numerical_string.rb +48 -0
- data/spec/voip/test_phone_number.rb +36 -0
- data/test/test_ahn_generator.rb +59 -0
- data/test/test_component_generator.rb +52 -0
- data/test/test_generator_helper.rb +20 -0
- metadata +254 -0
@@ -0,0 +1,129 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../../test_helper"
|
2
|
+
require 'adhearsion/voip/asterisk/config_manager'
|
3
|
+
|
4
|
+
context "The configuration file parser behavior" do
|
5
|
+
|
6
|
+
include ConfigurationManagerTestHelper
|
7
|
+
|
8
|
+
test "should expose a sections array" do
|
9
|
+
manager = mock_config_manager
|
10
|
+
manager.sections.map(&:first).should.equal(["jicksta", "picard"])
|
11
|
+
end
|
12
|
+
|
13
|
+
test "should ignore comments" do
|
14
|
+
context_names = %w(monkey data)
|
15
|
+
tested_key_name, tested_key_value_before_comment = "bar", "baz"
|
16
|
+
manager = mock_config_manager_for <<-CONFIG
|
17
|
+
[monkey]
|
18
|
+
#{tested_key_name}=#{tested_key_value_before_comment};thiscommentshouldnotbehere
|
19
|
+
asdf=fdsa
|
20
|
+
;[data]
|
21
|
+
;ignored=asdf
|
22
|
+
CONFIG
|
23
|
+
manager.sections.map(&:first).should.equal [context_names.first]
|
24
|
+
manager[context_names.first].size.should.equal 2
|
25
|
+
manager[context_names.first][tested_key_name].should.equal tested_key_value_before_comment
|
26
|
+
end
|
27
|
+
|
28
|
+
test "should match context names with dashes and underscores" do
|
29
|
+
context_names = %w"foo-bar qaz_b-a-z"
|
30
|
+
definition_string = <<-CONFIG
|
31
|
+
[#{context_names.first}]
|
32
|
+
platypus=no
|
33
|
+
zebra=no
|
34
|
+
crappyconfig=yes
|
35
|
+
|
36
|
+
[#{context_names.last}]
|
37
|
+
callerid="Jay Phillips" <133>
|
38
|
+
CONFIG
|
39
|
+
mock_config_manager_for(definition_string).sections.map(&:first).should.equal context_names
|
40
|
+
end
|
41
|
+
|
42
|
+
test "should strip whitespace around keys and values" do
|
43
|
+
section_name = "hey-there-hot-momma"
|
44
|
+
tested_key_name, tested_key_value_before_comment = "bar", "i heart white space. SIKE!"
|
45
|
+
config_manager = mock_config_manager_for <<-CONFIG
|
46
|
+
\t[#{section_name}]
|
47
|
+
|
48
|
+
thereis = a lot of whitespace after these
|
49
|
+
|
50
|
+
#{tested_key_name} = \t\t\t #{tested_key_value_before_comment}
|
51
|
+
|
52
|
+
CONFIG
|
53
|
+
config_manager[section_name][tested_key_name].should.equal tested_key_value_before_comment
|
54
|
+
end
|
55
|
+
|
56
|
+
test "should return a Hash of properties when searching for an existing section" do
|
57
|
+
result = mock_config_manager["jicksta"]
|
58
|
+
result.should.be.kind_of Hash
|
59
|
+
result.size.should.equal 3
|
60
|
+
end
|
61
|
+
|
62
|
+
test "should return nil when searching for a non-existant section" do
|
63
|
+
mock_config_manager["i-so-dont-exist-dude"].should.be.nil
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
context "The configuration file writer" do
|
69
|
+
|
70
|
+
include ConfigurationManagerTestHelper
|
71
|
+
|
72
|
+
attr_reader :config_manager
|
73
|
+
|
74
|
+
setup do
|
75
|
+
@config_manager = mock_config_manager
|
76
|
+
end
|
77
|
+
|
78
|
+
test "should remove an old section when replacing it" do
|
79
|
+
config_manager.delete_section "picard"
|
80
|
+
config_manager.sections.map(&:first).should.equal ["jicksta"]
|
81
|
+
end
|
82
|
+
|
83
|
+
test "should add a new section to the end" do
|
84
|
+
section_name = "wittynamehere"
|
85
|
+
config_manager.new_section(section_name, :type => "friend",
|
86
|
+
:witty => "yes",
|
87
|
+
:shaken => "yes",
|
88
|
+
:stirred => "no")
|
89
|
+
new_section = config_manager.sections.last
|
90
|
+
new_section.first.should.equal section_name
|
91
|
+
new_section.last.size.should.equal 4
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context "The configuration file generator" do
|
96
|
+
end
|
97
|
+
|
98
|
+
BEGIN {
|
99
|
+
module ConfigurationManagerTestHelper
|
100
|
+
|
101
|
+
def mock_config_manager
|
102
|
+
mock_config_manager_for sample_standard_config
|
103
|
+
end
|
104
|
+
|
105
|
+
def mock_config_manager_for(config_string)
|
106
|
+
returning new_config_manager_with("bogus filename") do |manager|
|
107
|
+
flexmock(manager).should_receive(:execute).and_return(config_string)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def new_config_manager_with(filename)
|
112
|
+
Adhearsion::VoIP::Asterisk::ConfigurationManager.new(filename)
|
113
|
+
end
|
114
|
+
|
115
|
+
def sample_standard_config
|
116
|
+
<<-CONFIG
|
117
|
+
[jicksta]
|
118
|
+
foo=bar
|
119
|
+
qaz=qwerty
|
120
|
+
baz=zxcvb
|
121
|
+
[picard]
|
122
|
+
type=friend
|
123
|
+
insecure=very
|
124
|
+
host=dynamic
|
125
|
+
secret=blargh
|
126
|
+
CONFIG
|
127
|
+
end
|
128
|
+
end
|
129
|
+
}
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../test_helper'
|
2
|
+
|
3
|
+
require 'adhearsion/voip/dsl/dialplan/dispatcher'
|
4
|
+
|
5
|
+
module StandardDispatcherBehavior
|
6
|
+
def xtest_standard_dispatcher_behavior
|
7
|
+
#"This test looks bogus. Not finished? Let's not check in failing specs ever if we can help it."
|
8
|
+
returned_event_command = Adhearsion::VoIP::DSL::Dialplan::EventCommand.new "ilikesexypants"
|
9
|
+
linking_event_command = Adhearsion::VoIP::DSL::Dialplan::EventCommand.new "ihavesexypants" do
|
10
|
+
returned_event_command
|
11
|
+
end
|
12
|
+
|
13
|
+
dispatcher = @dispatcher_class.new MyFactory
|
14
|
+
dispatcher.should_receive(:dispatch!).with(linking_event_command, returned_event_command).and_return(linking_event_command, returned_event_command)
|
15
|
+
# returned_event_command.should_receive(:command_block).and_return nil
|
16
|
+
dispatcher.dispatch! linking_event_command
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class NilDispatcher < Adhearsion::VoIP::DSL::Dialplan::CommandDispatcher
|
21
|
+
def dispatch!(string)
|
22
|
+
# Would send it off to the PBX here (or prepend something to the String)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class EvalDispatcher < Adhearsion::VoIP::DSL::Dialplan::CommandDispatcher
|
27
|
+
def dispatch!(event)
|
28
|
+
eval event.app.to_s
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class MyFactory
|
33
|
+
|
34
|
+
def initialize(context)
|
35
|
+
@context = context
|
36
|
+
end
|
37
|
+
|
38
|
+
def sequence
|
39
|
+
all = []
|
40
|
+
EventCommand.new("2", :response => Numeric) do |response|
|
41
|
+
all << response
|
42
|
+
all.size > 3 ? all : nil
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,268 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../test_helper'
|
2
|
+
require 'adhearsion/voip/dsl/dialing_dsl'
|
3
|
+
|
4
|
+
# Keep the monkey patches in a module and load that into Regexp
|
5
|
+
# eigenclasses during a before(:all) block?
|
6
|
+
|
7
|
+
describe "RouteRule Regexp assembling" do
|
8
|
+
|
9
|
+
test "should compile two Regexps" do
|
10
|
+
first, last = /jay/, /phillips/
|
11
|
+
r = first | last
|
12
|
+
r.patterns.should == [first, last]
|
13
|
+
end
|
14
|
+
|
15
|
+
test "should compile three or more Regexps" do
|
16
|
+
first, second, third = /lorem/, /ipsum/, /dolar/
|
17
|
+
r = first | second | third
|
18
|
+
r.patterns.should == [first, second, third]
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "RouteRule assembling with one provider definition" do
|
24
|
+
|
25
|
+
before :each do
|
26
|
+
@provider = Adhearsion::VoIP::DSL::DialingDSL::ProviderDefinition.new(:icanhascheezburger?)
|
27
|
+
end
|
28
|
+
|
29
|
+
test "should store one pattern properly" do
|
30
|
+
pattern = /lorem/
|
31
|
+
route = pattern >> @provider
|
32
|
+
route.patterns.should == [pattern]
|
33
|
+
end
|
34
|
+
|
35
|
+
test "should store three patterns properly" do
|
36
|
+
first, second, third = /lorem/, /ipsum/, /dolar/
|
37
|
+
route = first | second | third >> @provider
|
38
|
+
route.patterns.should == [first, second, third]
|
39
|
+
route.providers.should == [@provider]
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "RouteRule assembling with multiple patterns and multiple provider definitions" do
|
45
|
+
|
46
|
+
before:each do
|
47
|
+
1.upto 3 do |i|
|
48
|
+
instance_variable_set "@prov_#{i}",
|
49
|
+
Adhearsion::VoIP::DSL::DialingDSL::ProviderDefinition.new("prov_#{i}")
|
50
|
+
instance_variable_set "@pattern_#{i}", /^#{i * 100}$/
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
test "should store the patterns properly" do
|
55
|
+
route_1 = @pattern_1 | @pattern_2 | @pattern_3 >> @prov_1 >> @prov_2 >> @prov_3
|
56
|
+
route_1.patterns.should == [@pattern_1, @pattern_2, @pattern_3]
|
57
|
+
|
58
|
+
route_2 = @pattern_2 | @pattern_3 | @pattern_1 >> @prov_3 >> @prov_2 >> @prov_1
|
59
|
+
route_2.patterns.should == [@pattern_2, @pattern_3, @pattern_1]
|
60
|
+
end
|
61
|
+
|
62
|
+
test "should store the providers properly" do
|
63
|
+
route_1 = @pattern_1 | @pattern_2 | @pattern_3 >> @prov_1 >> @prov_2 >> @prov_3
|
64
|
+
route_1.providers.should == [@prov_1, @prov_2, @prov_3]
|
65
|
+
|
66
|
+
route_2 = @pattern_2 | @pattern_3 | @pattern_1 >> @prov_3 >> @prov_2 >> @prov_1
|
67
|
+
route_2.patterns.should == [@pattern_2, @pattern_3, @pattern_1]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "The DialingDSL class internals" do
|
72
|
+
|
73
|
+
test "should allow Asterisk-like patterns" do
|
74
|
+
Adhearsion::VoIP::DSL::DialingDSL.class_eval do
|
75
|
+
_('23XX')
|
76
|
+
end.should.be.instance_of Regexp
|
77
|
+
end
|
78
|
+
|
79
|
+
test "should define all of the VoIP constants" do
|
80
|
+
lambda do
|
81
|
+
Adhearsion::VoIP::Constants.constants.each do |constant|
|
82
|
+
eval "Adhearsion::VoIP::DSL::DialingDSL::#{constant}"
|
83
|
+
end
|
84
|
+
end.should.not.raise NameError
|
85
|
+
end
|
86
|
+
|
87
|
+
# test "should define a DUNDI constant"
|
88
|
+
|
89
|
+
test "should synchronize access to the trunking information for Thread safety"
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "The provider DSL's 'provider' macro" do
|
94
|
+
|
95
|
+
test "should make the providers available in the order they were received" do
|
96
|
+
provider_holder = Class.new Adhearsion::VoIP::DSL::DialingDSL
|
97
|
+
provider_holder.class_eval do
|
98
|
+
provider(:tweedledee) {}
|
99
|
+
provider(:tweedledum) {}
|
100
|
+
end
|
101
|
+
provider_holder.providers.map { |x| x.name }.should == [:tweedledee, :tweedledum]
|
102
|
+
end
|
103
|
+
test "should define a singleton method for the provider name given" do
|
104
|
+
Class.new(Adhearsion::VoIP::DSL::DialingDSL).class_eval do
|
105
|
+
class_variable_get(:@@providers).size.should == 0
|
106
|
+
|
107
|
+
provider(:icanhascheezburger?) {}
|
108
|
+
|
109
|
+
should.respond_to(:icanhascheezburger?)
|
110
|
+
class_variable_get(:@@providers).size.should == 1
|
111
|
+
end
|
112
|
+
end
|
113
|
+
test "should not define a class-wide method for the provider name given" do
|
114
|
+
Class.new(Adhearsion::VoIP::DSL::DialingDSL).class_eval do
|
115
|
+
provider(:icanhascheezburger?) {}
|
116
|
+
end
|
117
|
+
Adhearsion::VoIP::DSL::DialingDSL.class_eval do
|
118
|
+
class_variable_defined?(:@@providers).should == false
|
119
|
+
should.not.respond_to(:icanhascheezburger?)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
test "should yield a ProviderDefinition object" do
|
123
|
+
possible_provider_definition = nil
|
124
|
+
Class.new(Adhearsion::VoIP::DSL::DialingDSL).class_eval do
|
125
|
+
provider(:blah) { |pd| possible_provider_definition = pd }
|
126
|
+
end
|
127
|
+
possible_provider_definition.should.be.a.kind_of(Adhearsion::VoIP::DSL::DialingDSL::ProviderDefinition)
|
128
|
+
end
|
129
|
+
test "should raise an error when no block is given" do
|
130
|
+
the_following_code do
|
131
|
+
Class.new(Adhearsion::VoIP::DSL::DialingDSL).class_eval do
|
132
|
+
provider :explode
|
133
|
+
end
|
134
|
+
end.should.raise ArgumentError
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
describe "The provider DSL's monkey patches to Regexp" do
|
139
|
+
test "should return a RouteRule when using Regexp#| with another Regexp" do
|
140
|
+
(// | //).should.be.a.kind_of(Adhearsion::VoIP::DSL::DialingDSL::RouteRule)
|
141
|
+
end
|
142
|
+
test "should return a RouteRule when chaining three Regexp's with the | operator" do
|
143
|
+
(// | // | //).should.be.a.kind_of(Adhearsion::VoIP::DSL::DialingDSL::RouteRule)
|
144
|
+
end
|
145
|
+
test "should return a RouteRule when Regexp#| is given a RouteRule" do
|
146
|
+
route_rule = Adhearsion::VoIP::DSL::DialingDSL::RouteRule.new :patterns => //
|
147
|
+
(// | route_rule).should.be.a.kind_of(Adhearsion::VoIP::DSL::DialingDSL::RouteRule)
|
148
|
+
end
|
149
|
+
test "should return a RouteRule when Regexp#>> is given a ProviderDefinition" do
|
150
|
+
(/1/ >> Adhearsion::VoIP::DSL::DialingDSL::ProviderDefinition.new(:foo)).
|
151
|
+
should.be.a.kind_of(Adhearsion::VoIP::DSL::DialingDSL::RouteRule)
|
152
|
+
end
|
153
|
+
test "should return a RouteRule when Regexp#>>() receives a ProviderDefinition" do
|
154
|
+
definition = Adhearsion::VoIP::DSL::DialingDSL::ProviderDefinition.new(:london)
|
155
|
+
(/foo/ >> definition).should.be.a.kind_of(Adhearsion::VoIP::DSL::DialingDSL::RouteRule)
|
156
|
+
end
|
157
|
+
test "should raise an exception when Regexp#| receives something other than a RouteRule" do
|
158
|
+
bad_args = [ 0..100, 20, 45.55, {}, [] ]
|
159
|
+
bad_args.each do |arg|
|
160
|
+
the_following_code { /foo/ | arg }.should.raise ArgumentError
|
161
|
+
end
|
162
|
+
end
|
163
|
+
test "should raise an exception when Regexp#>>() receives anything other than a ProviderDefintion or RouteRule" do
|
164
|
+
bad_args = [ 0..100, 20, 45.55, {}, [] ]
|
165
|
+
bad_args.each do |arg|
|
166
|
+
the_following_code { /foo/ >> arg }.should.raise ArgumentError
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
describe "A RouteRule" do
|
172
|
+
test "should expose chained ProviderDefinitions properly" do
|
173
|
+
one, two, three = definitions = %w"foo bar qaz".map do |name|
|
174
|
+
Adhearsion::VoIP::DSL::DialingDSL::ProviderDefinition.new name
|
175
|
+
end
|
176
|
+
route = /^911$/ >> one >> two >> three
|
177
|
+
route.should.be.kind_of(Adhearsion::VoIP::DSL::DialingDSL::RouteRule)
|
178
|
+
route.providers.should == definitions
|
179
|
+
end
|
180
|
+
test "should define attr_readers for providers and patterns" do
|
181
|
+
route = Adhearsion::VoIP::DSL::DialingDSL::RouteRule.new
|
182
|
+
route.should.respond_to(:patterns)
|
183
|
+
route.should.respond_to(:providers)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
describe "The provider order modifiers" do
|
188
|
+
disabled_test "should support randomizing trunks" do
|
189
|
+
dsl = Class.new Adhearsion::VoIP::DSL::DialingDSL
|
190
|
+
dsl.class_eval do
|
191
|
+
provider(:l33thost) {}
|
192
|
+
provider(:h4xxhost) {}
|
193
|
+
route /\d+\*548/ >> random(l33thost, h4xxhost)
|
194
|
+
end
|
195
|
+
dsl.routes.first.provider_definitions.first.should.be.a.kind_of(
|
196
|
+
Adhearsion::VoIP::DSL::DialingDSL::RandomRouteRule
|
197
|
+
)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
describe "The provider DSL's 'route' builder" do
|
202
|
+
test "should register routes in the order received" do
|
203
|
+
dsl = Class.new Adhearsion::VoIP::DSL::DialingDSL
|
204
|
+
dsl.class_eval do
|
205
|
+
provider(:kewlphone) {}
|
206
|
+
[/1?4445556666/, /123/, /\d+\*548/].each do |r|
|
207
|
+
route r >> kewlphone
|
208
|
+
end
|
209
|
+
end
|
210
|
+
dsl.routes.map { |x| x.patterns }.flatten.should == [/1?4445556666/, /123/, /\d+\*548/]
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
describe "A ProviderDefinition" do
|
215
|
+
test "should store any arbitrary property" do
|
216
|
+
definition = Adhearsion::VoIP::DSL::DialingDSL::ProviderDefinition.new :foo
|
217
|
+
definition.qaz = :something
|
218
|
+
definition.qaz.should == :something
|
219
|
+
end
|
220
|
+
test "should define a >>() method" do
|
221
|
+
Adhearsion::VoIP::DSL::DialingDSL::ProviderDefinition.new(:arghh).should.respond_to(:>>)
|
222
|
+
end
|
223
|
+
|
224
|
+
test "should format numbers properly" do
|
225
|
+
definition = Adhearsion::VoIP::DSL::DialingDSL::ProviderDefinition.new(:arghh)
|
226
|
+
definition.protocol = "SIP"
|
227
|
+
definition.format_number_for_platform("14445556666", :asterisk).should == "SIP/arghh/14445556666"
|
228
|
+
definition.protocol = "SCCP"
|
229
|
+
definition.format_number_for_platform("16663331111", :asterisk).should == "SCCP/arghh/16663331111"
|
230
|
+
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
describe "Routing with the interpreted route definitions" do
|
235
|
+
test "should use the first matching regular expression" do
|
236
|
+
dsl = Class.new Adhearsion::VoIP::DSL::DialingDSL
|
237
|
+
dsl.class_eval do
|
238
|
+
provider(:bad) {}
|
239
|
+
provider(:good) {}
|
240
|
+
route /^111$/ | /^222$/ | /^333$/ >> good >> bad
|
241
|
+
end
|
242
|
+
|
243
|
+
found = dsl.calculate_routes_for(333)
|
244
|
+
|
245
|
+
assert_equal 1, found.size
|
246
|
+
found.first.size.should.equal 2
|
247
|
+
end
|
248
|
+
|
249
|
+
end
|
250
|
+
|
251
|
+
# @example = Class.new Adhearsion::VoIP::DSL::DialingDSL
|
252
|
+
# @example.class_eval do
|
253
|
+
#
|
254
|
+
# provider:kewlphone do |trunk|
|
255
|
+
# trunk.protocol :sip
|
256
|
+
# trunk.host "voip.nufone.com"
|
257
|
+
# trunk.username "phonedude"
|
258
|
+
# trunk.password "secret"
|
259
|
+
# trunk.enters :internal
|
260
|
+
# end
|
261
|
+
#
|
262
|
+
# route US_NUMBER | US_LOCAL_NUMBER >> voip_ms >> nufone
|
263
|
+
#
|
264
|
+
# route INTL_NUMBER >> random(voip_ms, nufone)
|
265
|
+
#
|
266
|
+
# # route _('NXX') >> DUNDI
|
267
|
+
#
|
268
|
+
# end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/dispatcher_spec_helper'
|
2
|
+
require 'adhearsion/voip/dsl/dialplan/dispatcher'
|
3
|
+
|
4
|
+
|
5
|
+
describe "A EventCommand" do
|
6
|
+
|
7
|
+
test "should allow a block that's set to response_block()" do
|
8
|
+
block = lambda {}
|
9
|
+
cmd = Adhearsion::VoIP::DSL::Dialplan::EventCommand.new "foo", &block
|
10
|
+
cmd.response_block.should.equal(block)
|
11
|
+
end
|
12
|
+
|
13
|
+
test "should return specified return type with returns()" do
|
14
|
+
return_type = Numeric
|
15
|
+
cmd = Adhearsion::VoIP::DSL::Dialplan::EventCommand.new "foo", :returns => return_type
|
16
|
+
cmd.returns.should.equal(return_type)
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "The abstract CommandDispatcher" do
|
22
|
+
|
23
|
+
test "should make an attribute reader for context()" do
|
24
|
+
context = "foo"
|
25
|
+
d = Adhearsion::VoIP::DSL::Dialplan::CommandDispatcher.new String, context
|
26
|
+
d.context.should.equal(context)
|
27
|
+
end
|
28
|
+
|
29
|
+
test "should instantiate a new instance of the specified factory" do
|
30
|
+
d = Adhearsion::VoIP::DSL::Dialplan::CommandDispatcher.new Hash
|
31
|
+
d.factory.should.be.kind_of(Hash)
|
32
|
+
end
|
33
|
+
|
34
|
+
test "should pass the context to the factory when instantiating it" do
|
35
|
+
context = "shazbot"
|
36
|
+
klass = flexmock "a class that has one argument in its constructor"
|
37
|
+
klass.should_receive(:new).with(context)
|
38
|
+
d = Adhearsion::VoIP::DSL::Dialplan::CommandDispatcher.new klass, context
|
39
|
+
end
|
40
|
+
|
41
|
+
test "should not allow calling dispatch!() directly" do
|
42
|
+
dispatcher = Adhearsion::VoIP::DSL::Dialplan::CommandDispatcher.new MyFactory
|
43
|
+
lambda do
|
44
|
+
dispatcher.dispatch! nil
|
45
|
+
end.should.raise(NotImplementedError)
|
46
|
+
end
|
47
|
+
|
48
|
+
test "should pass a method and any args onto its CommandFactory" do
|
49
|
+
|
50
|
+
weird_args = [1, 2, ["foo", nil], Object.new, 12.3..13.4]
|
51
|
+
|
52
|
+
bogus_command = Adhearsion::VoIP::DSL::Dialplan::EventCommand.new "123"
|
53
|
+
|
54
|
+
dispatcher = NilDispatcher.new MyFactory
|
55
|
+
flexmock(dispatcher.factory).should_receive(:monkey).with(*weird_args).and_return bogus_command
|
56
|
+
dispatcher.monkey(*weird_args)
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
test "should continue executing response_blocks until nil is returned" do
|
61
|
+
actual_executions, target_executions = 0, 5
|
62
|
+
response = Adhearsion::VoIP::DSL::Dialplan::EventCommand.new "1" do |response|
|
63
|
+
if response > target_executions
|
64
|
+
nil
|
65
|
+
else
|
66
|
+
actual_executions += 1
|
67
|
+
Adhearsion::VoIP::DSL::Dialplan::EventCommand.new(response + 1)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
mock_factory_class = Class.new do
|
71
|
+
def initialize(*args)
|
72
|
+
end
|
73
|
+
def testplz
|
74
|
+
response
|
75
|
+
end
|
76
|
+
end
|
77
|
+
dispatcher = EvalDispatcher.new(mock_factory_class)
|
78
|
+
flexmock(dispatcher.factory).should_receive(:testplz).and_return(response)
|
79
|
+
dispatcher.testplz
|
80
|
+
actual_executions.should.equal(target_executions)
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../test_helper'
|
2
|
+
|
3
|
+
require 'adhearsion/voip/dsl/dialplan/parser'
|
4
|
+
|
5
|
+
describe "The Adhearsion VoIP dialplan parser" do
|
6
|
+
|
7
|
+
test "should return a list of dialplans properly from dialplan code" do
|
8
|
+
file = "foobar.rb"
|
9
|
+
flexmock(Adhearsion::Paths).should_receive(:manager_for?).and_return true
|
10
|
+
flexmock(Adhearsion::VoIP::DSL::Dialplan::DialplanParser).
|
11
|
+
should_receive(:all_dialplans).and_return [file]
|
12
|
+
|
13
|
+
flexmock(File).should_receive(:exists?).with(file).and_return true
|
14
|
+
flexmock(File).should_receive(:read).once.with(file).and_return <<-DIALPLAN
|
15
|
+
internal {
|
16
|
+
play "hello-world"
|
17
|
+
}
|
18
|
+
monkeys {
|
19
|
+
play "tt-monkeys"
|
20
|
+
}
|
21
|
+
DIALPLAN
|
22
|
+
contexts = Adhearsion::VoIP::DSL::Dialplan::DialplanParser.get_contexts
|
23
|
+
contexts.keys.size.should.equal(2)
|
24
|
+
contexts.keys.should.include(:internal)
|
25
|
+
contexts.keys.should.include(:monkeys)
|
26
|
+
contexts.each_pair do |context, struct|
|
27
|
+
struct.should.be.kind_of(OpenStruct)
|
28
|
+
%w"file name block".each do |method|
|
29
|
+
struct.should.respond_to(method)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
test "should raise an error when no dialplan paths were in the .ahnrc file" do
|
35
|
+
lambda do
|
36
|
+
# Not loading it here is the same as it not existing in the "paths" sub-Hash
|
37
|
+
Adhearsion::Paths.manager_for?("dialplans").once.and_return false
|
38
|
+
Adhearsion::VoIP::DSL::Dialplan::DialplanParser.get_contexts
|
39
|
+
end.should.raise NoMethodError
|
40
|
+
end
|
41
|
+
|
42
|
+
test "should warn() when no dialplan files exist but return an empty Hash" #do
|
43
|
+
# Adhearsion::Paths.should_receive(:manager_for?).with("dialplans").and_return true
|
44
|
+
# Adhearsion::Paths.
|
45
|
+
# Adhearsion::Logging::LoggingMethods.should_receive(:warn)
|
46
|
+
#
|
47
|
+
# end
|
48
|
+
|
49
|
+
test "should warn() when no contexts were found but return an empty Hash" do
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "The Adhearsion VoIP dialplan interpreter" do
|
56
|
+
|
57
|
+
test "should make dialplan contexts available within the context's block" do
|
58
|
+
file = "contexts_from_code_helper_pseudo_dialplan.rb"
|
59
|
+
flexmock(Adhearsion::Paths).should_receive(:manager_for?).once.with("dialplans").and_return true
|
60
|
+
flexmock(Adhearsion::VoIP::DSL::Dialplan::DialplanParser).
|
61
|
+
should_receive(:all_dialplans).and_return [file]
|
62
|
+
|
63
|
+
flexmock(File).should_receive(:exists?).with(file).and_return true
|
64
|
+
flexmock(File).should_receive(:read).with(file).and_return "foo { cool_method }"
|
65
|
+
|
66
|
+
contexts = Adhearsion::VoIP::DSL::Dialplan::DialplanParser.get_contexts
|
67
|
+
|
68
|
+
contexts.each_pair do |name, struct|
|
69
|
+
contexts.meta_def(name) { struct.code }
|
70
|
+
end
|
71
|
+
|
72
|
+
# Simulate incoming request
|
73
|
+
contexts = contexts.clone
|
74
|
+
|
75
|
+
call_variables = { "callerid" => "14445556666", "context" => "foo" }
|
76
|
+
|
77
|
+
call_variables.each_pair do |key, value|
|
78
|
+
contexts.meta_def(key) { value }
|
79
|
+
contexts.instance_variable_set "@#{key}", value
|
80
|
+
end
|
81
|
+
|
82
|
+
# TODO
|
83
|
+
# dispatcher = DSL::Dialplan::CommandDispatcher.new
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../../test_helper"
|
2
|
+
require 'adhearsion/voip/freeswitch/basic_connection_manager'
|
3
|
+
|
4
|
+
include Adhearsion::VoIP::FreeSwitch
|
5
|
+
|
6
|
+
context "FreeSwitch BasicConnectionManager" do
|
7
|
+
attr_reader :manager, :io
|
8
|
+
setup do
|
9
|
+
@io = StringIO.new
|
10
|
+
@manager = BasicConnectionManager.new io
|
11
|
+
end
|
12
|
+
|
13
|
+
test "<<() should add two newlines" do
|
14
|
+
manager << "foobar"
|
15
|
+
io.string.should == "foobar\n\n"
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
context "FreeSwitch BasicConnectionManager's header parser" do
|
21
|
+
test "YAML-like headers are read properly" do
|
22
|
+
header = {
|
23
|
+
"Foo-Bar" => "bar",
|
24
|
+
"Qaz-Monkey-Charlie-Zebra" => "qwerty"
|
25
|
+
}
|
26
|
+
|
27
|
+
string_header = header.inject("") do |string, (key, value)|
|
28
|
+
string + "#{key}: #{value}\n"
|
29
|
+
end
|
30
|
+
|
31
|
+
string_header << "\n"
|
32
|
+
|
33
|
+
manager = BasicConnectionManager.new StringIO.new(string_header)
|
34
|
+
manager.get_raw_header.should == string_header.strip
|
35
|
+
|
36
|
+
manager = BasicConnectionManager.new StringIO.new(string_header)
|
37
|
+
manager.get_header.should == header
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../../test_helper"
|
2
|
+
require 'adhearsion/voip/freeswitch/inbound_connection_manager'
|
3
|
+
include Adhearsion::VoIP::FreeSwitch
|
4
|
+
|
5
|
+
context "A FreeSwitch InboundConnectionManager" do
|
6
|
+
|
7
|
+
test "authenticatating with the given password" do
|
8
|
+
manager = InboundConnectionManager.new io_mock
|
9
|
+
manager.login password
|
10
|
+
end
|
11
|
+
|
12
|
+
test "a hash is accepted when creating a new InboundConnectionManager" do
|
13
|
+
host, port = "myhost.mydomain", 31337
|
14
|
+
|
15
|
+
flexmock(TCPSocket).should_receive(:new).once.with(host, port).and_return io_mock
|
16
|
+
|
17
|
+
InboundConnectionManager.new :host => host, :port => port, :pass => password
|
18
|
+
end
|
19
|
+
|
20
|
+
test "an IO is accepted when creating a new InboundConnectionManager"
|
21
|
+
|
22
|
+
private
|
23
|
+
def io_mock
|
24
|
+
@io_mock ||=
|
25
|
+
begin
|
26
|
+
io_mock = StringIO.new
|
27
|
+
flexmock(io_mock) do |io|
|
28
|
+
io.should_receive(:write).with("auth #{password}\n\n")
|
29
|
+
io.should_receive(:gets).and_return "connection: kthnx\n",
|
30
|
+
"\n", "login: +OK\n", "\n"
|
31
|
+
end
|
32
|
+
io_mock
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def password
|
37
|
+
"supersecret"
|
38
|
+
end
|
39
|
+
end
|