eric-adhearsion 0.7.999

Sign up to get free protection for your applications and to get access to all the features.
Files changed (150) hide show
  1. data/CHANGELOG +3 -0
  2. data/LICENSE +456 -0
  3. data/Manifest.txt +149 -0
  4. data/README.txt +6 -0
  5. data/Rakefile +48 -0
  6. data/ahn_generators/component/USAGE +5 -0
  7. data/ahn_generators/component/component_generator.rb +57 -0
  8. data/ahn_generators/component/templates/configuration.rb +0 -0
  9. data/ahn_generators/component/templates/lib/lib.rb.erb +3 -0
  10. data/ahn_generators/component/templates/test/test.rb.erb +12 -0
  11. data/ahn_generators/component/templates/test/test_helper.rb +14 -0
  12. data/app_generators/ahn/USAGE +5 -0
  13. data/app_generators/ahn/ahn_generator.rb +76 -0
  14. data/app_generators/ahn/templates/.ahnrc +12 -0
  15. data/app_generators/ahn/templates/README +8 -0
  16. data/app_generators/ahn/templates/Rakefile +3 -0
  17. data/app_generators/ahn/templates/components/simon_game/configuration.rb +0 -0
  18. data/app_generators/ahn/templates/components/simon_game/lib/simon_game.rb +61 -0
  19. data/app_generators/ahn/templates/components/simon_game/test/test_helper.rb +14 -0
  20. data/app_generators/ahn/templates/components/simon_game/test/test_simon_game.rb +31 -0
  21. data/app_generators/ahn/templates/config/startup.rb +53 -0
  22. data/app_generators/ahn/templates/dialplan.rb +4 -0
  23. data/bin/ahn +28 -0
  24. data/bin/ahnctl +68 -0
  25. data/bin/jahn +32 -0
  26. data/lib/adhearsion/blank_slate.rb +5 -0
  27. data/lib/adhearsion/cli.rb +106 -0
  28. data/lib/adhearsion/component_manager.rb +277 -0
  29. data/lib/adhearsion/core_extensions/all.rb +9 -0
  30. data/lib/adhearsion/core_extensions/array.rb +0 -0
  31. data/lib/adhearsion/core_extensions/custom_daemonizer.rb +45 -0
  32. data/lib/adhearsion/core_extensions/global.rb +1 -0
  33. data/lib/adhearsion/core_extensions/guid.rb +5 -0
  34. data/lib/adhearsion/core_extensions/hash.rb +0 -0
  35. data/lib/adhearsion/core_extensions/metaprogramming.rb +17 -0
  36. data/lib/adhearsion/core_extensions/numeric.rb +4 -0
  37. data/lib/adhearsion/core_extensions/proc.rb +0 -0
  38. data/lib/adhearsion/core_extensions/pseudo_uuid.rb +11 -0
  39. data/lib/adhearsion/core_extensions/publishable.rb +73 -0
  40. data/lib/adhearsion/core_extensions/relationship_properties.rb +40 -0
  41. data/lib/adhearsion/core_extensions/string.rb +26 -0
  42. data/lib/adhearsion/core_extensions/thread.rb +13 -0
  43. data/lib/adhearsion/core_extensions/thread_safety.rb +7 -0
  44. data/lib/adhearsion/core_extensions/time.rb +0 -0
  45. data/lib/adhearsion/distributed/gateways/dbus_gateway.rb +0 -0
  46. data/lib/adhearsion/distributed/gateways/osa_gateway.rb +0 -0
  47. data/lib/adhearsion/distributed/gateways/rest_gateway.rb +9 -0
  48. data/lib/adhearsion/distributed/gateways/soap_gateway.rb +9 -0
  49. data/lib/adhearsion/distributed/gateways/xmlrpc_gateway.rb +9 -0
  50. data/lib/adhearsion/distributed/peer_finder.rb +0 -0
  51. data/lib/adhearsion/distributed/remote_cli.rb +0 -0
  52. data/lib/adhearsion/hooks.rb +57 -0
  53. data/lib/adhearsion/host_definitions.rb +63 -0
  54. data/lib/adhearsion/initializer/asterisk.rb +59 -0
  55. data/lib/adhearsion/initializer/configuration.rb +202 -0
  56. data/lib/adhearsion/initializer/database.rb +92 -0
  57. data/lib/adhearsion/initializer/drb.rb +25 -0
  58. data/lib/adhearsion/initializer/freeswitch.rb +22 -0
  59. data/lib/adhearsion/initializer/paths.rb +55 -0
  60. data/lib/adhearsion/initializer/rails.rb +40 -0
  61. data/lib/adhearsion/initializer.rb +217 -0
  62. data/lib/adhearsion/logging.rb +92 -0
  63. data/lib/adhearsion/services/scheduler.rb +5 -0
  64. data/lib/adhearsion/tasks/database.rb +5 -0
  65. data/lib/adhearsion/tasks/generating.rb +20 -0
  66. data/lib/adhearsion/tasks/lint.rb +4 -0
  67. data/lib/adhearsion/tasks/testing.rb +37 -0
  68. data/lib/adhearsion/tasks.rb +15 -0
  69. data/lib/adhearsion/version.rb +9 -0
  70. data/lib/adhearsion/voip/asterisk/agi_server.rb +78 -0
  71. data/lib/adhearsion/voip/asterisk/ami/actions.rb +238 -0
  72. data/lib/adhearsion/voip/asterisk/ami/machine.rb +871 -0
  73. data/lib/adhearsion/voip/asterisk/ami/machine.rl +109 -0
  74. data/lib/adhearsion/voip/asterisk/ami/parser.rb +262 -0
  75. data/lib/adhearsion/voip/asterisk/ami.rb +147 -0
  76. data/lib/adhearsion/voip/asterisk/commands.rb +1182 -0
  77. data/lib/adhearsion/voip/asterisk/config_generators/agents.conf.rb +140 -0
  78. data/lib/adhearsion/voip/asterisk/config_generators/config_generator.rb +101 -0
  79. data/lib/adhearsion/voip/asterisk/config_generators/queues.conf.rb +250 -0
  80. data/lib/adhearsion/voip/asterisk/config_generators/voicemail.conf.rb +240 -0
  81. data/lib/adhearsion/voip/asterisk/config_manager.rb +71 -0
  82. data/lib/adhearsion/voip/asterisk/special_dial_plan_managers.rb +80 -0
  83. data/lib/adhearsion/voip/asterisk.rb +4 -0
  84. data/lib/adhearsion/voip/call.rb +391 -0
  85. data/lib/adhearsion/voip/call_routing.rb +64 -0
  86. data/lib/adhearsion/voip/commands.rb +9 -0
  87. data/lib/adhearsion/voip/constants.rb +39 -0
  88. data/lib/adhearsion/voip/conveniences.rb +18 -0
  89. data/lib/adhearsion/voip/dial_plan.rb +205 -0
  90. data/lib/adhearsion/voip/dsl/dialing_dsl/dialing_dsl_monkey_patches.rb +37 -0
  91. data/lib/adhearsion/voip/dsl/dialing_dsl.rb +151 -0
  92. data/lib/adhearsion/voip/dsl/dialplan/control_passing_exception.rb +27 -0
  93. data/lib/adhearsion/voip/dsl/dialplan/dispatcher.rb +124 -0
  94. data/lib/adhearsion/voip/dsl/dialplan/parser.rb +75 -0
  95. data/lib/adhearsion/voip/dsl/dialplan/thread_mixin.rb +16 -0
  96. data/lib/adhearsion/voip/dsl/numerical_string.rb +117 -0
  97. data/lib/adhearsion/voip/freeswitch/basic_connection_manager.rb +48 -0
  98. data/lib/adhearsion/voip/freeswitch/event_handler.rb +58 -0
  99. data/lib/adhearsion/voip/freeswitch/freeswitch_dialplan_command_factory.rb +129 -0
  100. data/lib/adhearsion/voip/freeswitch/inbound_connection_manager.rb +38 -0
  101. data/lib/adhearsion/voip/freeswitch/oes_server.rb +195 -0
  102. data/lib/adhearsion/voip/menu_state_machine/calculated_match.rb +80 -0
  103. data/lib/adhearsion/voip/menu_state_machine/matchers.rb +123 -0
  104. data/lib/adhearsion/voip/menu_state_machine/menu_builder.rb +58 -0
  105. data/lib/adhearsion/voip/menu_state_machine/menu_class.rb +149 -0
  106. data/lib/adhearsion.rb +31 -0
  107. data/script/destroy +14 -0
  108. data/script/generate +14 -0
  109. data/spec/fixtures/dialplan.rb +3 -0
  110. data/spec/initializer/test_configuration.rb +267 -0
  111. data/spec/initializer/test_loading.rb +162 -0
  112. data/spec/initializer/test_paths.rb +43 -0
  113. data/spec/silence.rb +10 -0
  114. data/spec/test_ahn_command.rb +149 -0
  115. data/spec/test_code_quality.rb +87 -0
  116. data/spec/test_component_manager.rb +97 -0
  117. data/spec/test_constants.rb +8 -0
  118. data/spec/test_drb.rb +104 -0
  119. data/spec/test_helper.rb +94 -0
  120. data/spec/test_hooks.rb +37 -0
  121. data/spec/test_host_definitions.rb +79 -0
  122. data/spec/test_initialization.rb +105 -0
  123. data/spec/test_logging.rb +80 -0
  124. data/spec/test_relationship_properties.rb +54 -0
  125. data/spec/voip/asterisk/ami_response_definitions.rb +23 -0
  126. data/spec/voip/asterisk/config_file_generators/test_agents.rb +253 -0
  127. data/spec/voip/asterisk/config_file_generators/test_queues.rb +325 -0
  128. data/spec/voip/asterisk/config_file_generators/test_voicemail.rb +306 -0
  129. data/spec/voip/asterisk/menu_command/test_calculated_match.rb +111 -0
  130. data/spec/voip/asterisk/menu_command/test_matchers.rb +98 -0
  131. data/spec/voip/asterisk/mock_ami_server.rb +176 -0
  132. data/spec/voip/asterisk/test_agi_server.rb +451 -0
  133. data/spec/voip/asterisk/test_ami.rb +227 -0
  134. data/spec/voip/asterisk/test_commands.rb +2006 -0
  135. data/spec/voip/asterisk/test_config_manager.rb +129 -0
  136. data/spec/voip/dsl/dispatcher_spec_helper.rb +45 -0
  137. data/spec/voip/dsl/test_dialing_dsl.rb +268 -0
  138. data/spec/voip/dsl/test_dispatcher.rb +82 -0
  139. data/spec/voip/dsl/test_parser.rb +87 -0
  140. data/spec/voip/freeswitch/test_basic_connection_manager.rb +39 -0
  141. data/spec/voip/freeswitch/test_inbound_connection_manager.rb +39 -0
  142. data/spec/voip/freeswitch/test_oes_server.rb +9 -0
  143. data/spec/voip/test_call_routing.rb +127 -0
  144. data/spec/voip/test_dialplan_manager.rb +372 -0
  145. data/spec/voip/test_numerical_string.rb +48 -0
  146. data/spec/voip/test_phone_number.rb +36 -0
  147. data/test/test_ahn_generator.rb +59 -0
  148. data/test/test_component_generator.rb +52 -0
  149. data/test/test_generator_helper.rb +20 -0
  150. 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