sevenscale-adhearsion 0.7.1000

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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 +1186 -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 +402 -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 +453 -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,9 @@
1
+ require File.dirname(__FILE__) + "/../../test_helper"
2
+ require File.dirname(__FILE__) + "/../dsl/dispatcher_spec_helper"
3
+ require 'adhearsion/voip/freeswitch/oes_server'
4
+
5
+
6
+ describe "Adhearsion::VoIP::FreeSwitch::OesServer::OesDispatcher" do
7
+ include StandardDispatcherBehavior
8
+ setup { @dispatcher_class = Adhearsion::VoIP::FreeSwitch::OesServer::OesDispatcher }
9
+ end
@@ -0,0 +1,127 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ context "Call routing rule generation" do
4
+ include CallRoutingTestHelper
5
+
6
+ attr_reader :provider_one, :provider_two, :patterns
7
+
8
+ setup do
9
+ @provider_one = provider_named(:one)
10
+ @provider_two = provider_named(:two)
11
+ @patterns = [/pattern/, /does not/, /matter/]
12
+ end
13
+
14
+ test "specifying a single pattern routed to a single provider properly stores that pattern and its provider in the generated route rule" do
15
+ pattern = %r(does not matter)
16
+ rule = route(pattern, :to => provider_one)
17
+ rule.patterns.should.equal [pattern]
18
+ rule.providers.should.equal [provider_one]
19
+ end
20
+
21
+ test "specifying multiple patterns routed to a single provider stores all of them in the generated route rule" do
22
+ first, second, third = patterns
23
+ rule = route(first, second, third, :to => provider_one)
24
+ rule.patterns.should.equal [*patterns]
25
+ rule.providers.should.equal [provider_one]
26
+ end
27
+
28
+ test "specifying multiple patterns routed to multiple providers stores all of them in the generated route rule, listing providers in the ordered specified" do
29
+ first, second, third = patterns
30
+ rule = route(first, second, third, :to => [provider_one, provider_two])
31
+ rule.patterns.should.equal [*patterns]
32
+ rule.providers.should.equal [provider_one, provider_two]
33
+ end
34
+ end
35
+
36
+ context "Route calculation" do
37
+ include CallRoutingTestHelper
38
+ attr_reader :provider_one, :provider_two
39
+
40
+ setup do
41
+ rules.clear
42
+ @provider_one = provider_named(:one)
43
+ @provider_two = provider_named(:two)
44
+ end
45
+
46
+ test "Defining a rule adds it to the router rules" do
47
+ provider = provider_one
48
+ pattern = /123/
49
+ define_rules do
50
+ route pattern, :to => provider
51
+ end
52
+ rules.size.should.equal 1
53
+ rule = rules.first
54
+ rule.providers.should.equal [provider]
55
+ rule.patterns.should.equal [pattern]
56
+ end
57
+
58
+ test "Definiting multiple rules adds them to the router rules" do
59
+ provider_for_rule_1 = provider_one
60
+ provider_for_rule_2 = provider_two
61
+ pattern_for_rule_1 = /123/
62
+ pattern_for_rule_2 = /987/
63
+
64
+ define_rules do
65
+ route pattern_for_rule_1, :to => provider_for_rule_1
66
+ route pattern_for_rule_2, :to => provider_for_rule_2
67
+ end
68
+
69
+ rules.size.should.equal 2
70
+
71
+ rule_1 = rules.first
72
+ rule_1.providers.should.equal [provider_for_rule_1]
73
+ rule_1.patterns.should.equal [pattern_for_rule_1]
74
+
75
+ rule_2 = rules.last
76
+ rule_2.providers.should.equal [provider_for_rule_2]
77
+ rule_2.patterns.should.equal [pattern_for_rule_2]
78
+ end
79
+
80
+ test "Provider is found in the simplest case of having only one pattern and one provider" do
81
+ target_provider = provider_one
82
+ define_rules do
83
+ route /123/, :to => target_provider
84
+ end
85
+ calculate_route_for(1234).should.equal [target_provider]
86
+ end
87
+
88
+ test "Provider is found when the specified pattern matches a rule that is not the first rule" do
89
+ provider_for_rule_1 = provider_one
90
+ provider_for_rule_2 = provider_two
91
+ pattern_for_rule_1 = /123/
92
+ pattern_for_rule_2 = /987/
93
+
94
+ define_rules do
95
+ route pattern_for_rule_1, :to => provider_for_rule_1
96
+ route pattern_for_rule_2, :to => provider_for_rule_2
97
+ end
98
+
99
+ target_provider = provider_for_rule_2
100
+ calculate_route_for(9876).should.equal [target_provider]
101
+ end
102
+ end
103
+
104
+ BEGIN {
105
+ module CallRoutingTestHelper
106
+ private
107
+ def route(*args, &block)
108
+ Adhearsion::VoIP::CallRouting::Rule.new(*args, &block)
109
+ end
110
+
111
+ def provider_named(name)
112
+ Adhearsion::VoIP::DSL::DialingDSL::ProviderDefinition.new(name)
113
+ end
114
+
115
+ def define_rules(&block)
116
+ Adhearsion::VoIP::CallRouting::Router.define(&block)
117
+ end
118
+
119
+ def calculate_route_for(end_point)
120
+ Adhearsion::VoIP::CallRouting::Router.calculate_route_for(end_point)
121
+ end
122
+
123
+ def rules
124
+ Adhearsion::VoIP::CallRouting::Router.rules
125
+ end
126
+ end
127
+ }
@@ -0,0 +1,372 @@
1
+ require File.dirname(__FILE__) + "/../test_helper"
2
+ require 'adhearsion/voip/dsl/dialplan/parser'
3
+
4
+ context "Dialplan::Manager handling" do
5
+
6
+ include DialplanTestingHelper
7
+
8
+ attr_accessor :manager, :call, :context_name, :mock_context
9
+
10
+ before do
11
+ @context_name = :some_context_name
12
+ @mock_context = flexmock('a context')
13
+
14
+ hack_to_work_around_parser_coupling
15
+ mock_dial_plan_lookup_for_context_name
16
+ flexmock(Adhearsion::DialPlan::Loader).should_receive(:load_dial_plan).and_return{flexmock("loaded contexts", :contexts => nil)}
17
+ @manager = Adhearsion::DialPlan::Manager.new
18
+ @call = new_call_for_context context_name
19
+
20
+ # Sanity check context name being set
21
+ call.context.should.equal context_name
22
+ end
23
+
24
+ test "Given a Call, the manager finds the call's desired entry point/context" do
25
+ manager.entry_point_for(call).should.equal mock_context
26
+ end
27
+
28
+ test "The manager handles a call by executing the proper context" do
29
+ flexmock(Adhearsion::DialPlan::ExecutionEnvironment).new_instances.should_receive(:run).once
30
+ manager.handle(call)
31
+ end
32
+
33
+ test "should raise a NoContextError exception if the targeted context is not found" do
34
+ the_following_code {
35
+ flexmock(manager).should_receive(:entry_point_for).and_return nil
36
+ manager.handle call
37
+ }.should.raise(Adhearsion::DialPlan::Manager::NoContextError)
38
+ end
39
+
40
+ test 'should send :answer to the execution environment if Adhearsion::AHN_CONFIG.automatically_answer_incoming_calls is set' do
41
+ mock_ahn_config = flexmock 'a mock of the Adhearsion::Configuration object that is normally set when an app is initialized'
42
+ mock_ahn_config.should_receive(:automatically_answer_incoming_calls).once.and_return true
43
+ flexmock(Adhearsion::Configuration).should_receive(:new).once.and_return(mock_ahn_config)
44
+ flexmock(Adhearsion::DialPlan::ExecutionEnvironment).new_instances.should_receive(:answer).once.and_throw :answered_call!
45
+ Adhearsion::Configuration.configure
46
+ the_following_code {
47
+ manager.handle(call)
48
+ }.should.throw :answered_call!
49
+ end
50
+
51
+ test 'should not send :answer to the executuon environment if Adhearsion::AHN_CONFIG.automatically_answer_incoming_calls is NOT set' do
52
+
53
+ mock_ahn_config = flexmock 'a mock of the Adhearsion::Configuration object that is normally set when an app is initialized'
54
+ mock_ahn_config.should_receive(:automatically_answer_incoming_calls).once.and_return false
55
+
56
+ entry_point = Adhearsion::DialPlan::DialplanContextProc.new(:does_not_matter) {}
57
+ flexmock(manager).should_receive(:entry_point_for).once.with(call).and_return(entry_point)
58
+
59
+ flexmock(Adhearsion::Configuration).should_receive(:new).once.and_return(mock_ahn_config)
60
+ flexmock(Adhearsion::DialPlan::ExecutionEnvironment).new_instances.should_receive(:entry_point).and_return entry_point
61
+ flexmock(Adhearsion::DialPlan::ExecutionEnvironment).new_instances.should_receive(:answer).never
62
+ flexmock(Adhearsion::DialPlan::ExecutionEnvironment).new_instances.should_receive(:instance_eval).and_throw :doing_dialplan
63
+
64
+ Adhearsion::Configuration.configure
65
+ manager.handle(call)
66
+ end
67
+
68
+ private
69
+ def hack_to_work_around_parser_coupling
70
+ flexmock(Adhearsion::Paths).should_receive(:manager_for?).and_return(true)
71
+ flexmock(Adhearsion::VoIP::DSL::Dialplan::DialplanParser).should_receive(:all_dialplans).and_return([])
72
+ end
73
+
74
+ def mock_dial_plan_lookup_for_context_name
75
+ flexmock(Adhearsion::DialPlan).new_instances.should_receive(:lookup).with(context_name).and_return(mock_context)
76
+ end
77
+ end
78
+
79
+ context "DialPlan::Manager's handling a failed call" do
80
+
81
+ include DialplanTestingHelper
82
+
83
+ test 'should check if the call has failed and then instruct it to extract the reason from the environment' do
84
+ flexmock(Adhearsion::DialPlan::ExecutionEnvironment).new_instances.should_receive(:variable).with("REASON").once.and_return '3'
85
+ call = Adhearsion::Call.new(nil, {'extension' => "failed"})
86
+ call.should.be.failed_call
87
+ flexmock(Adhearsion::DialPlan).should_receive(:new).once.and_return flexmock("bogus DialPlan which should never be used")
88
+ begin
89
+ Adhearsion::DialPlan::Manager.handle(call)
90
+ rescue Adhearsion::FailedExtensionCallException => error
91
+ error.call.failed_reason.should == Adhearsion::Call::ASTERISK_FRAME_STATES[3]
92
+ end
93
+ end
94
+ end
95
+
96
+ context "DialPlan::Manager's handling a hungup call" do
97
+
98
+ include DialplanTestingHelper
99
+
100
+ test 'should check if the call was a hangup meta-AGI call and then raise a HangupExtensionCallException' do
101
+ call = Adhearsion::Call.new(nil, {'extension' => "h"})
102
+ call.should.be.hungup_call
103
+ flexmock(Adhearsion::DialPlan).should_receive(:new).once.and_return flexmock("bogus DialPlan which should never be used")
104
+ the_following_code {
105
+ Adhearsion::DialPlan::Manager.handle(call)
106
+ }.should.raise Adhearsion::HungupExtensionCallException
107
+ end
108
+
109
+ end
110
+
111
+ context "DialPlan" do
112
+
113
+ attr_accessor :loader, :loader_instance, :dial_plan
114
+
115
+ before do
116
+ @loader = Adhearsion::DialPlan::Loader
117
+ @loader_instance = @loader.new
118
+ flexmock(Adhearsion::DialPlan::Loader).should_receive(:load_dial_plan).once.and_return(@loader_instance)
119
+ @dial_plan = Adhearsion::DialPlan.new(Adhearsion::DialPlan::Loader)
120
+ end
121
+
122
+ test "When a dial plan is instantiated, the dialplans are loaded and stored for lookup" do
123
+ dial_plan.instance_variable_get("@entry_points").should.not.be.nil
124
+ end
125
+
126
+ test "Can look up an entry point from a dial plan" do
127
+ context_name = 'this_context_is_better_than_your_context'
128
+ loader_instance.contexts[context_name] = lambda { puts "o hai" }
129
+ dial_plan.lookup(context_name).should.not.be.nil
130
+ end
131
+ end
132
+
133
+ context "DialPlan loader" do
134
+
135
+ include DialplanTestingHelper
136
+
137
+ test "loading a single context" do
138
+ loader = load(<<-DIAL_PLAN)
139
+ one {
140
+ raise 'this block should not be evaluated'
141
+ }
142
+ DIAL_PLAN
143
+
144
+ loader.contexts.keys.size.should.equal 1
145
+ loader.contexts.keys.first.should.equal :one
146
+ end
147
+
148
+ test "loading multiple contexts loads all contexts" do
149
+ loader = load(<<-DIAL_PLAN)
150
+ one {
151
+ raise 'this block should not be evaluated'
152
+ }
153
+
154
+ two {
155
+ raise 'this other block should not be evaluated either'
156
+ }
157
+ DIAL_PLAN
158
+
159
+ loader.contexts.keys.size.should.equal 2
160
+ loader.contexts.keys.map(&:to_s).sort.should.equal %w(one two)
161
+ end
162
+
163
+ test 'loading a dialplan with a syntax error' do
164
+ the_following_code {
165
+ load "foo { &@(*!&(*@*!@^!^%@%^! }"
166
+ }.should.raise SyntaxError
167
+ end
168
+
169
+ test "loading a dial plan from a file" do
170
+ loader = nil
171
+ the_following_code {
172
+ AHN_ROOT.using_base_path(File.expand_path(File.dirname(__FILE__) + '/../fixtures')) do
173
+ loader = Adhearsion::DialPlan::Loader.load_dial_plan
174
+ end
175
+ }.should.not.raise
176
+
177
+ loader.contexts.keys.size.should.equal 1
178
+ loader.contexts.keys.first.should.equal :sample_context
179
+ end
180
+
181
+ end
182
+
183
+ context "The inbox-related dialplan methods" do
184
+
185
+ include DialplanTestingHelper
186
+
187
+ test "with_next_message should execute its block with the message from the inbox" do
188
+ mock_call = new_call_for_context :entrance
189
+ [:one, :two, :three].each { |message| mock_call.inbox << message }
190
+
191
+ dialplan = %{ entrance { with_next_message { |message| throw message } } }
192
+ executing_dialplan(:entrance => dialplan, :call => mock_call).should.throw :one
193
+ end
194
+
195
+
196
+ test "messages_waiting? should return false if the inbox is empty" do
197
+ mock_call = new_call_for_context :entrance
198
+ dialplan = %{ entrance { throw messages_waiting? ? :yes : :no } }
199
+ executing_dialplan(:entrance => dialplan, :call => mock_call).should.throw :no
200
+ end
201
+
202
+ test "messages_waiting? should return false if the inbox is not empty" do
203
+ mock_call = new_call_for_context :entrance
204
+ mock_call.inbox << Object.new
205
+ dialplan = %{ entrance { throw messages_waiting? ? :yes : :no } }
206
+ executing_dialplan(:entrance => dialplan, :call => mock_call).should.throw :yes
207
+ end
208
+
209
+ end
210
+
211
+
212
+ context "ExecutionEnvironemnt" do
213
+ attr_accessor :call, :entry_point
214
+
215
+ include DialplanTestingHelper
216
+
217
+ before do
218
+ variables = { :context => "zomgzlols", :caller_id => "Ponce de Leon" }
219
+ @call = Adhearsion::Call.new(nil, variables)
220
+ @entry_point = lambda {}
221
+ end
222
+
223
+ test "On initialization, ExecutionEnvironments extend themselves with behavior specific to the voip platform which originated the call" do
224
+ Adhearsion::DialPlan::ExecutionEnvironment.included_modules.should.not.include(Adhearsion::VoIP::Asterisk::Commands)
225
+ execution_environent = Adhearsion::DialPlan::ExecutionEnvironment.new(call, entry_point)
226
+ execution_environent.metaclass.included_modules.should.include(Adhearsion::VoIP::Asterisk::Commands)
227
+ end
228
+
229
+ test "An executed context should raise a NameError error when a missing constant is referenced" do
230
+ the_following_code do
231
+ call = new_call_for_context :context_with_missing_constant
232
+ mock_dialplan_with "context_with_missing_constant { ThisConstantDoesntExist }"
233
+ manager = new_manager_with_entry_points_loaded_from_dialplan_contexts
234
+ manager.handle call
235
+ end.should.raise NameError
236
+
237
+ end
238
+
239
+ test "should define variables accessors within itself" do
240
+ environment = Adhearsion::DialPlan::ExecutionEnvironment.new(@call, entry_point)
241
+ call.variables.should.not.be.empty
242
+ call.variables.each do |key, value|
243
+ environment.send(key).should.equal value
244
+ end
245
+ end
246
+
247
+ test "should define accessors for other contexts in the dialplan" do
248
+ call = new_call_for_context :am_not_for_kokoa!
249
+ bogus_dialplan = <<-DIALPLAN
250
+ am_not_for_kokoa! {}
251
+ icanhascheezburger? {}
252
+ these_context_names_do_not_really_matter {}
253
+ DIALPLAN
254
+
255
+ mock_dialplan_with bogus_dialplan
256
+ manager = Adhearsion::DialPlan::Manager.new
257
+ manager.dial_plan.entry_points = manager.dial_plan.loader.load_dial_plan.contexts
258
+ manager.dial_plan.entry_points.should.not.be.empty
259
+
260
+ manager.handle call
261
+
262
+ %w(these_context_names_do_not_really_matter icanhascheezburger? am_not_for_kokoa!).each do |context_name|
263
+ manager.context.respond_to?(context_name).should.equal true
264
+ end
265
+ end
266
+
267
+ end
268
+
269
+ context "Dialplan control statements" do
270
+
271
+ include DialplanTestingHelper
272
+
273
+ test "Manager should catch ControlPassingExceptions" do
274
+ dialplan = %{
275
+ foo { raise Adhearsion::VoIP::DSL::Dialplan::ControlPassingException.new(bar) }
276
+ bar {}
277
+ }
278
+ executing_dialplan(:foo => dialplan).should.not.raise
279
+ end
280
+
281
+ test "Proc#+@ should not return to its originating context" do
282
+ dialplan = %{
283
+ andere {}
284
+ zuerst {
285
+ +andere
286
+ throw :after_control_statement
287
+ }
288
+ }
289
+ executing_dialplan(:zuerst => dialplan).should.not.throw
290
+ end
291
+ test "All dialplan contexts should be available at context execution time" do
292
+ dialplan = %{
293
+ context_defined_first {
294
+ throw :i_see_it if context_defined_second
295
+ }
296
+ context_defined_second {}
297
+ }
298
+ executing_dialplan(:context_defined_first => dialplan).should.throw :i_see_it
299
+ end
300
+ test "Proc#+@ should execute the other context" do
301
+ dialplan = %{
302
+ eins {
303
+ +zwei
304
+ throw :eins
305
+ }
306
+ zwei {
307
+ throw :zwei
308
+ }
309
+ }
310
+ executing_dialplan(:eins => dialplan).should.throw :zwei
311
+ end
312
+
313
+ test "new constants should still be accessible within the dialplan" do
314
+ ::Jicksta = :Jicksta
315
+ dialplan = %{
316
+ constant_test {
317
+ Jicksta.should.equal:Jicksta
318
+ }
319
+ }
320
+ executing_dialplan(:constant_test => dialplan).should.not.raise
321
+ end
322
+
323
+ end
324
+
325
+ context "VoIP platform operations" do
326
+ test "can map a platform name to a module which holds its platform-specific operations" do
327
+ Adhearsion::VoIP::Commands.for(:asterisk).should == Adhearsion::VoIP::Asterisk::Commands
328
+ end
329
+ end
330
+
331
+ context 'ContextNameCollector' do
332
+ test '::build should raise a SyntaxError when the dialplan String contains one' do
333
+ the_following_code {
334
+ Adhearsion::DialPlan::Loader::ContextNameCollector.build "foo { ((((( *@!^*@&*^!^@ }"
335
+ }.should.raise SyntaxError
336
+ end
337
+ end
338
+
339
+ BEGIN {
340
+ module DialplanTestingHelper
341
+ def load(dial_plan_as_string)
342
+ Adhearsion::DialPlan::Loader.load(dial_plan_as_string)
343
+ end
344
+
345
+ def mock_dialplan_with(string)
346
+ flexstub(Adhearsion::DialPlan::Loader).should_receive(:read_dialplan_file).and_return(string)
347
+ end
348
+
349
+ def new_manager_with_entry_points_loaded_from_dialplan_contexts
350
+ returning Adhearsion::DialPlan::Manager.new do |manager|
351
+ manager.dial_plan.entry_points = manager.dial_plan.loader.load_dial_plan.contexts
352
+ end
353
+ end
354
+
355
+ def executing_dialplan(options)
356
+ call = options.delete(:call)
357
+ context_name = options.keys.first
358
+ dialplan = options[context_name]
359
+ call ||= new_call_for_context context_name
360
+
361
+ mock_dialplan_with dialplan
362
+ lambda do
363
+ Adhearsion::DialPlan::Manager.new.handle call
364
+ end
365
+ end
366
+
367
+ def new_call_for_context(context)
368
+ Adhearsion::Call.new(StringIO.new, :context => context)
369
+ end
370
+ end
371
+
372
+ }
@@ -0,0 +1,48 @@
1
+ require File.dirname(__FILE__) + "/../test_helper"
2
+
3
+ require 'adhearsion/voip/dsl/numerical_string'
4
+ require 'adhearsion/voip/constants'
5
+
6
+ context "A NumericalString" do
7
+ test "NumericalString should appear to be behave like a Fixnum in a case statement" do
8
+ assert 123 === numerical_string_for("123")
9
+ assert 987 === numerical_string_for("0987")
10
+ end
11
+
12
+ test "NumericalString should appear to behave like a String in a case statement" do
13
+ assert "123" === numerical_string_for("123")
14
+ assert "0987" === numerical_string_for("0987")
15
+ end
16
+
17
+ test "when compared against a Range that contains the numeric equivalent, the NumericalString is seen as a member" do
18
+ assert((100..200) === numerical_string_for("150"))
19
+ assert((100..200) === numerical_string_for("0150"))
20
+ assert !((100..200) === numerical_string_for("1000000"))
21
+ end
22
+
23
+ test "comparing against a regular expression works" do
24
+ assert %r|^\d+$| === numerical_string_for("027316287")
25
+ end
26
+
27
+ test "checking if a string representation of a number starts with a leading zero" do
28
+ with_leading_zeros = %w(01 01234 01.23 01.2)
29
+ without_leading_zeros = %w(1 1.2 0 0.0)
30
+
31
+ with_leading_zeros.each do |number|
32
+ assert numerical_string.starts_with_leading_zero?(number), number
33
+ end
34
+
35
+ without_leading_zeros.each do |number|
36
+ assert !numerical_string.starts_with_leading_zero?(number), number
37
+ end
38
+ end
39
+
40
+ private
41
+ def numerical_string
42
+ Adhearsion::VoIP::DSL::NumericalString
43
+ end
44
+
45
+ def numerical_string_for(string)
46
+ numerical_string.new(string)
47
+ end
48
+ end
@@ -0,0 +1,36 @@
1
+ require File.dirname(__FILE__) + "/../test_helper"
2
+ require 'adhearsion/voip/constants'
3
+ require 'adhearsion/voip/dsl/numerical_string'
4
+
5
+
6
+ # Use cases...
7
+ # case extension
8
+ # when US_NUMBER
9
+ # when (100..200)
10
+ # when _('12Z')
11
+ # when 123
12
+ # when "123"
13
+ # end
14
+
15
+ describe "A PhoneNumber" do
16
+
17
+ it "should have an ISN pattern-matching method" do
18
+ !! Adhearsion::VoIP::DSL::PhoneNumber.new("0115544332211").isn?.should == false
19
+ !! Adhearsion::VoIP::DSL::PhoneNumber.new("1*548").isn?.should == false
20
+ end
21
+
22
+ it "should have a US local number pattern-matching method" do
23
+ !! Adhearsion::VoIP::DSL::PhoneNumber.new("18887776665555").local_number?.should == false
24
+ !! Adhearsion::VoIP::DSL::PhoneNumber.new("18887776665555").national_number?.should == false
25
+
26
+ !! Adhearsion::VoIP::DSL::PhoneNumber.new("8887776665555").local_number?.should == false
27
+ !! Adhearsion::VoIP::DSL::PhoneNumber.new("8887776665555").national_number?.should == true
28
+
29
+ !! Adhearsion::VoIP::DSL::PhoneNumber.new("4445555").local_number?.should == true
30
+ !! Adhearsion::VoIP::DSL::PhoneNumber.new("4445555").national_number?.should == false
31
+ end
32
+
33
+ it "should convert from vanity numbers properly" do
34
+ Adhearsion::VoIP::DSL::PhoneNumber.from_vanity("1-800-FUDGEME").should == "18003834363"
35
+ end
36
+ end
@@ -0,0 +1,59 @@
1
+ require File.join(File.dirname(__FILE__), "test_generator_helper.rb")
2
+
3
+ class TestAhnGenerator < Test::Unit::TestCase
4
+ include RubiGen::GeneratorTestHelper
5
+
6
+ def setup
7
+ bare_setup
8
+ end
9
+
10
+ def teardown
11
+ bare_teardown
12
+ end
13
+
14
+ # Some generator-related assertions:
15
+ # assert_generated_file(name, &block) # block passed the file contents
16
+ # assert_directory_exists(name)
17
+ # assert_generated_class(name, &block)
18
+ # assert_generated_module(name, &block)
19
+ # assert_generated_test_for(name, &block)
20
+ # The assert_generated_(class|module|test_for) &block is passed the body of the class/module within the file
21
+ # assert_has_method(body, *methods) # check that the body has a list of methods (methods with parentheses not supported yet)
22
+ #
23
+ # Other helper methods are:
24
+ # app_root_files - put this in teardown to show files generated by the test method (e.g. p app_root_files)
25
+ # bare_setup - place this in setup method to create the APP_ROOT folder for each test
26
+ # bare_teardown - place this in teardown method to destroy the TMP_ROOT or APP_ROOT folder after each test
27
+
28
+ def test_generator_without_options
29
+ run_generator('ahn', [APP_ROOT], sources)
30
+ assert_directory_exists "components/simon_game/lib"
31
+ assert_directory_exists "components/simon_game/test"
32
+ assert_directory_exists "config"
33
+
34
+ assert_generated_file "components/simon_game/configuration.rb"
35
+ assert_generated_file "components/simon_game/lib/simon_game.rb"
36
+ assert_generated_file "components/simon_game/test/test_helper.rb"
37
+ assert_generated_file "components/simon_game/test/test_simon_game.rb"
38
+ assert_generated_file "config/startup.rb"
39
+ assert_generated_file "dialplan.rb"
40
+ assert_generated_file "README"
41
+ assert_generated_file "Rakefile"
42
+
43
+ assert_generated_class "components/simon_game/lib/simon_game" do |body|
44
+ assert_has_method body, "initialize"
45
+ assert_has_method body, "start"
46
+ assert_has_method body, "random_number"
47
+ end
48
+ end
49
+
50
+ private
51
+ def sources
52
+ [RubiGen::PathSource.new(:test, File.join(File.dirname(__FILE__),"..", generator_path))
53
+ ]
54
+ end
55
+
56
+ def generator_path
57
+ "app_generators"
58
+ end
59
+ end