sevenscale-adhearsion 0.7.1003 → 0.8.0

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 (149) hide show
  1. data/CHANGELOG +8 -2
  2. data/EVENTS +11 -0
  3. data/Rakefile +92 -26
  4. data/adhearsion.gemspec +131 -23
  5. data/app_generators/ahn/ahn_generator.rb +21 -7
  6. data/app_generators/ahn/templates/.ahnrc +10 -4
  7. data/app_generators/ahn/templates/Rakefile +7 -2
  8. data/app_generators/ahn/templates/components/ami_remote/ami_remote.rb +15 -0
  9. data/app_generators/ahn/templates/components/disabled/HOW_TO_ENABLE +7 -0
  10. data/app_generators/ahn/templates/components/disabled/stomp_gateway/README.markdown +47 -0
  11. data/app_generators/ahn/templates/components/disabled/stomp_gateway/config.yml +12 -0
  12. data/app_generators/ahn/templates/components/disabled/stomp_gateway/stomp_gateway.rb +34 -0
  13. data/app_generators/ahn/templates/components/simon_game/{lib/simon_game.rb → simon_game.rb} +14 -19
  14. data/app_generators/ahn/templates/config/startup.rb +3 -6
  15. data/app_generators/ahn/templates/dialplan.rb +2 -3
  16. data/app_generators/ahn/templates/events.rb +32 -6
  17. data/bin/jahn +10 -0
  18. data/examples/asterisk_manager_interface/standalone.rb +51 -0
  19. data/lib/adhearsion/cli.rb +140 -23
  20. data/lib/adhearsion/component_manager/component_tester.rb +55 -0
  21. data/lib/adhearsion/component_manager/spec_framework.rb +24 -0
  22. data/lib/adhearsion/component_manager.rb +169 -238
  23. data/lib/adhearsion/events_support.rb +59 -237
  24. data/lib/adhearsion/{core_extensions → foundation}/all.rb +0 -0
  25. data/lib/adhearsion/{blank_slate.rb → foundation/blank_slate.rb} +0 -0
  26. data/lib/adhearsion/{core_extensions → foundation}/custom_daemonizer.rb +0 -0
  27. data/lib/adhearsion/foundation/event_socket.rb +203 -0
  28. data/lib/adhearsion/foundation/future_resource.rb +36 -0
  29. data/lib/adhearsion/{core_extensions → foundation}/global.rb +0 -0
  30. data/lib/adhearsion/{core_extensions → foundation}/metaprogramming.rb +0 -0
  31. data/lib/adhearsion/foundation/numeric.rb +13 -0
  32. data/lib/adhearsion/foundation/pseudo_guid.rb +10 -0
  33. data/lib/adhearsion/{core_extensions → foundation}/relationship_properties.rb +2 -0
  34. data/lib/adhearsion/foundation/string.rb +26 -0
  35. data/lib/adhearsion/foundation/synchronized_hash.rb +96 -0
  36. data/lib/adhearsion/{core_extensions → foundation}/thread_safety.rb +0 -0
  37. data/lib/adhearsion/host_definitions.rb +5 -1
  38. data/lib/adhearsion/initializer/asterisk.rb +33 -11
  39. data/lib/adhearsion/initializer/configuration.rb +58 -6
  40. data/lib/adhearsion/initializer/database.rb +3 -46
  41. data/lib/adhearsion/initializer/drb.rb +9 -3
  42. data/lib/adhearsion/initializer/freeswitch.rb +3 -3
  43. data/lib/adhearsion/initializer/rails.rb +1 -1
  44. data/lib/adhearsion/initializer.rb +213 -87
  45. data/lib/adhearsion/tasks/deprecations.rb +59 -0
  46. data/lib/adhearsion/tasks.rb +2 -1
  47. data/lib/adhearsion/version.rb +3 -3
  48. data/lib/adhearsion/voip/asterisk/agi_server.rb +6 -6
  49. data/lib/adhearsion/voip/asterisk/commands.rb +100 -2
  50. data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rb +1754 -0
  51. data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rl.rb +286 -0
  52. data/lib/adhearsion/voip/asterisk/manager_interface/ami_messages.rb +78 -0
  53. data/lib/adhearsion/voip/asterisk/manager_interface/ami_protocol_lexer_machine.rl +87 -0
  54. data/lib/adhearsion/voip/asterisk/manager_interface.rb +562 -0
  55. data/lib/adhearsion/voip/asterisk/super_manager.rb +19 -0
  56. data/lib/adhearsion/voip/asterisk.rb +1 -8
  57. data/lib/adhearsion/voip/call.rb +5 -1
  58. data/lib/adhearsion/voip/dial_plan.rb +74 -61
  59. data/lib/adhearsion/voip/dsl/dialing_dsl.rb +1 -1
  60. data/lib/adhearsion/voip/dsl/dialplan/parser.rb +2 -6
  61. data/lib/adhearsion/voip/dsl/numerical_string.rb +2 -2
  62. data/lib/adhearsion/voip/freeswitch/oes_server.rb +2 -2
  63. data/lib/adhearsion.rb +16 -11
  64. data/lib/theatre/README.markdown +64 -0
  65. data/lib/theatre/callback_definition_loader.rb +84 -0
  66. data/lib/theatre/guid.rb +23 -0
  67. data/lib/theatre/invocation.rb +121 -0
  68. data/lib/theatre/namespace_manager.rb +153 -0
  69. data/lib/theatre/version.rb +2 -0
  70. data/lib/theatre.rb +151 -0
  71. metadata +60 -147
  72. data/Manifest.txt +0 -151
  73. data/README.txt +0 -5
  74. data/ahn_generators/component/USAGE +0 -5
  75. data/ahn_generators/component/component_generator.rb +0 -57
  76. data/ahn_generators/component/templates/configuration.rb +0 -0
  77. data/ahn_generators/component/templates/lib/lib.rb.erb +0 -3
  78. data/ahn_generators/component/templates/test/test.rb.erb +0 -12
  79. data/ahn_generators/component/templates/test/test_helper.rb +0 -14
  80. data/app_generators/ahn/templates/components/simon_game/configuration.rb +0 -0
  81. data/app_generators/ahn/templates/components/simon_game/test/test_helper.rb +0 -14
  82. data/app_generators/ahn/templates/components/simon_game/test/test_simon_game.rb +0 -31
  83. data/lib/adhearsion/core_extensions/array.rb +0 -0
  84. data/lib/adhearsion/core_extensions/guid.rb +0 -5
  85. data/lib/adhearsion/core_extensions/hash.rb +0 -0
  86. data/lib/adhearsion/core_extensions/numeric.rb +0 -4
  87. data/lib/adhearsion/core_extensions/proc.rb +0 -0
  88. data/lib/adhearsion/core_extensions/pseudo_uuid.rb +0 -11
  89. data/lib/adhearsion/core_extensions/publishable.rb +0 -73
  90. data/lib/adhearsion/core_extensions/string.rb +0 -26
  91. data/lib/adhearsion/core_extensions/thread.rb +0 -13
  92. data/lib/adhearsion/core_extensions/time.rb +0 -0
  93. data/lib/adhearsion/distributed/gateways/dbus_gateway.rb +0 -0
  94. data/lib/adhearsion/distributed/gateways/osa_gateway.rb +0 -0
  95. data/lib/adhearsion/distributed/gateways/rest_gateway.rb +0 -9
  96. data/lib/adhearsion/distributed/gateways/soap_gateway.rb +0 -9
  97. data/lib/adhearsion/distributed/gateways/xmlrpc_gateway.rb +0 -9
  98. data/lib/adhearsion/distributed/peer_finder.rb +0 -0
  99. data/lib/adhearsion/distributed/remote_cli.rb +0 -0
  100. data/lib/adhearsion/hooks.rb +0 -57
  101. data/lib/adhearsion/initializer/paths.rb +0 -55
  102. data/lib/adhearsion/voip/asterisk/ami/actions.rb +0 -238
  103. data/lib/adhearsion/voip/asterisk/ami/machine.rb +0 -871
  104. data/lib/adhearsion/voip/asterisk/ami/machine.rl +0 -109
  105. data/lib/adhearsion/voip/asterisk/ami/parser.rb +0 -262
  106. data/lib/adhearsion/voip/asterisk/ami.rb +0 -147
  107. data/spec/fixtures/dialplan.rb +0 -3
  108. data/spec/initializer/test_configuration.rb +0 -267
  109. data/spec/initializer/test_loading.rb +0 -162
  110. data/spec/initializer/test_paths.rb +0 -43
  111. data/spec/sample.rb +0 -9
  112. data/spec/silence.rb +0 -10
  113. data/spec/test_ahn_command.rb +0 -149
  114. data/spec/test_code_quality.rb +0 -87
  115. data/spec/test_component_manager.rb +0 -97
  116. data/spec/test_constants.rb +0 -8
  117. data/spec/test_drb.rb +0 -104
  118. data/spec/test_events.rb +0 -136
  119. data/spec/test_helper.rb +0 -106
  120. data/spec/test_hooks.rb +0 -15
  121. data/spec/test_host_definitions.rb +0 -79
  122. data/spec/test_initialization.rb +0 -124
  123. data/spec/test_logging.rb +0 -80
  124. data/spec/test_relationship_properties.rb +0 -54
  125. data/spec/voip/asterisk/ami_response_definitions.rb +0 -23
  126. data/spec/voip/asterisk/config_file_generators/test_agents.rb +0 -253
  127. data/spec/voip/asterisk/config_file_generators/test_queues.rb +0 -325
  128. data/spec/voip/asterisk/config_file_generators/test_voicemail.rb +0 -306
  129. data/spec/voip/asterisk/menu_command/test_calculated_match.rb +0 -111
  130. data/spec/voip/asterisk/menu_command/test_matchers.rb +0 -98
  131. data/spec/voip/asterisk/mock_ami_server.rb +0 -176
  132. data/spec/voip/asterisk/test_agi_server.rb +0 -453
  133. data/spec/voip/asterisk/test_ami.rb +0 -227
  134. data/spec/voip/asterisk/test_commands.rb +0 -2006
  135. data/spec/voip/asterisk/test_config_manager.rb +0 -129
  136. data/spec/voip/dsl/dispatcher_spec_helper.rb +0 -45
  137. data/spec/voip/dsl/test_dialing_dsl.rb +0 -268
  138. data/spec/voip/dsl/test_dispatcher.rb +0 -82
  139. data/spec/voip/dsl/test_parser.rb +0 -87
  140. data/spec/voip/freeswitch/test_basic_connection_manager.rb +0 -39
  141. data/spec/voip/freeswitch/test_inbound_connection_manager.rb +0 -39
  142. data/spec/voip/freeswitch/test_oes_server.rb +0 -9
  143. data/spec/voip/test_call_routing.rb +0 -127
  144. data/spec/voip/test_dialplan_manager.rb +0 -442
  145. data/spec/voip/test_numerical_string.rb +0 -48
  146. data/spec/voip/test_phone_number.rb +0 -36
  147. data/test/test_ahn_generator.rb +0 -59
  148. data/test/test_component_generator.rb +0 -52
  149. data/test/test_generator_helper.rb +0 -20
@@ -1,453 +0,0 @@
1
- require File.dirname(__FILE__) + "/../../test_helper"
2
- require 'adhearsion/voip/asterisk'
3
-
4
- context "The AGI server's serve() method" do
5
-
6
- include AgiServerTestHelper
7
-
8
- attr_reader :server_class, :server
9
- before :each do
10
- @server_class = Adhearsion::VoIP::Asterisk::AGI::Server::RubyServer
11
- @server = @server_class.new(:port,:host)
12
- end
13
-
14
- test 'should instantiate a new Call with the IO object it receives' do
15
- stub_before_call_hooks!
16
- io_mock = flexmock "Mock IO object that's passed to the serve() method"
17
- call_mock = flexmock "A Call mock that's returned by Adhearsion#receive_call_from", :variable => {}
18
- flexstub(server_class).should_receive(:ahn_log)
19
- the_following_code {
20
- flexmock(Adhearsion).should_receive(:receive_call_from).once.with(io_mock).and_throw :created_call!
21
- server.serve(io_mock)
22
- }.should.throw :created_call!
23
- end
24
-
25
- test 'should hand the call off to a new Manager if the request is agi://IP_ADDRESS_HERE' do
26
- stub_before_call_hooks!
27
- call_mock = flexmock 'A new mock call that will be passed to the manager', :variables => {}, :unique_identifier => "X"
28
-
29
- flexmock(Adhearsion).should_receive(:receive_call_from).once.and_return call_mock
30
- manager_mock = flexmock 'a mock dialplan manager'
31
- manager_mock.should_receive(:handle).once.with(call_mock)
32
- flexmock(Adhearsion::DialPlan::Manager).should_receive(:new).once.and_return manager_mock
33
- server.serve(nil)
34
- end
35
-
36
- test 'should hand off a call to a ConfirmationManager if the request begins with confirm!' do
37
- confirm_options = Adhearsion::DialPlan::ConfirmationManager.encode_hash_for_dial_macro_argument :timeout => 20, :key => "#"
38
- call_mock = flexmock "a call that has network_script as a variable", :variables => {:network_script => "confirm!#{confirm_options[/^M\(\^?(.+)\)$/,1]}"}, :unique_identifier => "X"
39
- manager_mock = flexmock 'a mock ConfirmationManager'
40
-
41
- the_following_code {
42
- flexstub(Adhearsion).should_receive(:receive_call_from).once.and_return(call_mock)
43
- flexmock(Adhearsion::DialPlan::ConfirmationManager).should_receive(:confirmation_call?).once.with(call_mock).and_return true
44
- flexmock(Adhearsion::DialPlan::ConfirmationManager).should_receive(:handle).once.with(call_mock).and_throw :handled_call!
45
- server.serve(nil)
46
- }.should.throw :handled_call!
47
- end
48
-
49
- test 'calling the serve() method invokes any BeforeCall hooks' do
50
- flexmock(Adhearsion::Hooks::BeforeCall).should_receive(:trigger_hooks).once.and_throw :before_call_hooks_executed
51
- assert_throws :before_call_hooks_executed do
52
- server.serve nil
53
- end
54
- end
55
-
56
- test 'should execute the OnHungupCall hooks when a HungupExtensionCallException is raised' do
57
- call_mock = flexmock 'a bogus call', :hungup_call? => true, :variables => {:extension => "h"}, :unique_identifier => "X"
58
- mock_env = flexmock "A mock execution environment which gets passed along in the HungupExtensionCallException"
59
-
60
- stub_confirmation_manager!
61
- flexstub(Adhearsion).should_receive(:receive_call_from).once.and_return(call_mock)
62
- flexmock(Adhearsion::DialPlan::Manager).should_receive(:handle).once.and_raise Adhearsion::HungupExtensionCallException.new(mock_env)
63
- flexmock(Adhearsion::Hooks::OnHungupCall).should_receive(:trigger_hooks).once.with(mock_env).and_throw :hungup_call
64
-
65
- the_following_code { server.serve nil }.should.throw :hungup_call
66
- end
67
-
68
- test 'should execute the OnFailedCall hooks when a FailedExtensionCallException is raised' do
69
- call_mock = flexmock 'a bogus call', :failed_call? => true, :variables => {:extension => "failed"}, :unique_identifier => "X"
70
- mock_env = flexmock "A mock execution environment which gets passed along in the HungupExtensionCallException", :failed_reason => "does not matter"
71
-
72
- server = Adhearsion::VoIP::Asterisk::AGI::Server::RubyServer.new :port, :host
73
-
74
- flexmock(Adhearsion).should_receive(:receive_call_from).once.and_return(call_mock)
75
- flexmock(Adhearsion::DialPlan::Manager).should_receive(:handle).once.and_raise Adhearsion::FailedExtensionCallException.new(mock_env)
76
- flexmock(Adhearsion::Hooks::OnFailedCall).should_receive(:trigger_hooks).once.with(mock_env).and_throw :failed_call
77
- the_following_code { server.serve nil }.should.throw :failed_call
78
- end
79
-
80
- end
81
-
82
- context "Active Calls" do
83
- include CallVariableTestHelper
84
- attr_accessor :typical_call
85
-
86
- before do
87
- @mock_io = StringIO.new
88
- @typical_call = Adhearsion::Call.new(@mock_io, typical_call_variables_hash)
89
- end
90
-
91
- after do
92
- Adhearsion::active_calls.clear!
93
- end
94
-
95
- test 'A Call object can be instantiated with a hash of attributes' do
96
- the_following_code {
97
- Adhearsion::Call.new(@mock_io, {})
98
- }.should.not.raise
99
- end
100
-
101
- test 'Attributes passed into initialization of call object are accessible as attributes on the object' do
102
- Adhearsion::Call.new(@mock_io, {:channel => typical_call_variables_hash[:channel]}).channel.should == typical_call_variables_hash[:channel]
103
- end
104
-
105
- test 'Attributes passed into initialization of call object are accessible in the variables() Hash' do
106
- Adhearsion::Call.new(@mock_io, typical_call_variables_hash).variables.should.equal typical_call_variables_hash
107
- end
108
-
109
- test 'Can add a call to the active calls list' do
110
- Adhearsion.active_calls.should.not.be.any
111
- Adhearsion.active_calls << typical_call
112
- Adhearsion.active_calls.size.should == 1
113
- end
114
-
115
- test 'A hungup call removes itself from the active calls' do
116
- mock_io = flexmock typical_call_variable_io
117
- mock_io.should_receive(:close).once
118
-
119
- size_before = Adhearsion.active_calls.size
120
-
121
- call = Adhearsion.receive_call_from mock_io
122
- Adhearsion.active_calls.size.should.be > size_before
123
- call.hangup!
124
- Adhearsion.active_calls.size.should == size_before
125
- end
126
-
127
- test 'Can find active call by unique ID' do
128
- Adhearsion.active_calls << typical_call
129
- assert_not_nil Adhearsion.active_calls.find(typical_call_variables_hash[:channel])
130
- end
131
-
132
- test 'A call can store the IO associated with the PBX/switch connection' do
133
- Adhearsion::Call.new(@mock_io, {}).should.respond_to(:io)
134
- end
135
-
136
- test 'A call can be instantiated given a PBX/switch IO' do
137
- call = Adhearsion::Call.receive_from(typical_call_variable_io)
138
- call.should.be.kind_of(Adhearsion::Call)
139
- call.channel.should == typical_call_variables_hash[:channel]
140
- end
141
-
142
- test 'A call with an extension of "t" raises a UselessCallException' do
143
- the_following_code {
144
- Adhearsion::Call.new(@mock_io, typical_call_variables_hash.merge(:extension => 't'))
145
- }.should.raise(Adhearsion::UselessCallException)
146
- end
147
-
148
- test 'Can create a call and add it via a top-level method on the Adhearsion module' do
149
- assert !Adhearsion.active_calls.any?
150
- call = Adhearsion.receive_call_from(typical_call_variable_io)
151
- call.should.be.kind_of(Adhearsion::Call)
152
- Adhearsion.active_calls.size.should == 1
153
- end
154
-
155
- test 'A call can identify its originating voip platform' do
156
- call = Adhearsion::receive_call_from(typical_call_variable_io)
157
- call.originating_voip_platform.should.equal(:asterisk)
158
- end
159
-
160
- end
161
-
162
- context 'A new Call object' do
163
-
164
- include CallVariableTestHelper
165
-
166
- test "it should have an @inbox object that's a synchronized Queue" do
167
- new_call = Adhearsion::Call.new(nil, {})
168
- new_call.inbox.should.be.kind_of Queue
169
- new_call.should.respond_to :<<
170
- end
171
-
172
- test 'the unique_identifier() method should return the :channel variable for :asterisk calls' do
173
- variables = typical_call_variables_hash
174
- new_call = Adhearsion::Call.new(nil, typical_call_variables_hash)
175
- flexmock(new_call).should_receive(:originating_voip_platform).and_return :asterisk
176
- new_call.unique_identifier.should == variables[:channel]
177
- end
178
-
179
- test "Call#define_singleton_accessor_with_pair should define a singleton method, not a class method" do
180
- control = Adhearsion::Call.new(nil, {})
181
- experiment = Adhearsion::Call.new(nil, {})
182
-
183
- experiment.send(:define_singleton_accessor_with_pair, "ohai", 123)
184
- experiment.should.respond_to "ohai"
185
- control.should.not.respond_to "ohai"
186
- end
187
-
188
- end
189
-
190
- context 'the Calls collection' do
191
-
192
- include CallVariableTestHelper
193
-
194
- test 'the #<< method should add a Call to the Hash with its unique_id' do
195
- id = rand
196
- collection = Adhearsion::Calls.new
197
- call = Adhearsion::Call.new(nil, {})
198
- flexmock(call).should_receive(:unique_identifier).and_return id
199
- collection << call
200
- hash = collection.instance_variable_get("@calls")
201
- hash.should.not.be.empty
202
- hash[id].should.equal call
203
- end
204
-
205
- test '#size should return the size of the Hash' do
206
- collection = Adhearsion::Calls.new
207
- collection.size.should.equal 0
208
- collection << Adhearsion::Call.new(nil, {})
209
- collection.size.should.equal 1
210
- end
211
-
212
- test '#remove_inactive_call should delete the call in the Hash' do
213
- collection = Adhearsion::Calls.new
214
-
215
- number_of_calls = 10
216
- unique_ids = Array.new(number_of_calls) { rand }
217
- calls = unique_ids.map { |id| Adhearsion::Call.new(nil, {:uniqueid => id}) }
218
- calls.each { |call| collection << call }
219
-
220
- deleted_call = calls[number_of_calls / 2]
221
- collection.remove_inactive_call deleted_call
222
- collection.size.should.equal number_of_calls - 1
223
- end
224
-
225
- test '#find_by_unique_id should pull the Call from the Hash using the unique_id' do
226
- id = rand
227
- call_database = flexmock "a mock Hash in which calls are stored"
228
- call_database.should_receive(:[]).once.with(id)
229
- collection = Adhearsion::Calls.new
230
- flexmock(collection).should_receive(:calls).once.and_return(call_database)
231
- collection.find(id)
232
- end
233
-
234
- end
235
-
236
- context 'Typical call variable parsing with typical data that has no special treatment' do
237
- include CallVariableTestHelper
238
- attr_reader :variables, :io
239
-
240
- setup do
241
- @io = typical_call_variable_io
242
- @variables = parsed_call_variables_from(io)
243
- end
244
-
245
- # test "listing all variable names" do
246
- # parser.variable_names.map(&:to_s).sort.should == typical_call_variables_hash.keys.map(&:to_s).sort
247
- # end
248
-
249
- test "extracts call variables into a Hash" do
250
- assert variables.kind_of?(Hash)
251
- end
252
-
253
- test "extracting and converting variables and their values to a hash" do
254
- variables.should == typical_call_variables_hash
255
- end
256
- end
257
-
258
- context 'Call variable parsing with data that is treated specially' do
259
- include CallVariableTestHelper
260
- test "callington is renamed to type_of_calling_number" do
261
- variables = parsed_call_variables_from typical_call_variable_io
262
- variables[:type_of_calling_number].should == :unknown
263
- variables.has_key?(:callington).should == false
264
- end
265
- test "normalizes the context to be a valid Ruby method name"
266
- test "value of 'no' converts to false" do
267
- merged_hash_with_call_variables(:no_var => "no")[:no_var].should.equal(false)
268
- end
269
- test "value of 'yes' converts to true"
270
- test "value of 'unknown' converts to nil"
271
- test 'separate_line_into_key_value_pair parses values with spaces in them' do
272
- key, value = Adhearsion::Call::Variables::Parser.separate_line_into_key_value_pair("foo: My Name")
273
- value.should == 'My Name'
274
- end
275
- end
276
-
277
- context 'Typical call variable line parsing with a typical line that is not treated specially' do
278
- include CallVariableTestHelper
279
- attr_reader :parser, :line
280
-
281
- setup do
282
- @line = 'agi_channel: SIP/marcel-b58046e0'
283
- @key, @value = Adhearsion::Call::Variables::Parser.separate_line_into_key_value_pair line
284
- end
285
-
286
- test "raw name is extracted correctly" do
287
- @key.should == 'agi_channel'
288
- end
289
-
290
- test "raw value is extracted correctly" do
291
- @value.should == 'SIP/marcel-b58046e0'
292
- end
293
- end
294
-
295
- context 'Call variable line parsing with a line that is treated specially' do
296
- include CallVariableTestHelper
297
- attr_reader :key, :value, :line
298
-
299
- setup do
300
- @line = 'agi_request: agi://10.0.0.152'
301
- @key, @value = Adhearsion::Call::Variables::Parser.separate_line_into_key_value_pair line
302
- end
303
-
304
- test "splits out name and value correctly even if the value contains a semicolon (i.e. the same character that is used as the name/value separators)" do
305
- @key.should == 'agi_request'
306
- @value.should == 'agi://10.0.0.152'
307
- end
308
-
309
- end
310
-
311
- context "Extracting the query from the request URI" do
312
- include CallVariableTestHelper
313
- attr_reader :parser
314
-
315
- setup do
316
- # We don't want this Call::Variables::Parser to call parse because we only care about handling the request
317
- # variable which we mock here.
318
- @parser = Adhearsion::Call::Variables::Parser.new(StringIO.new('This argument does not matter'))
319
- end
320
-
321
- test "an empty hash is returned if there is no query string" do
322
- parsed_call_variables_with_query('').should == {}
323
- end
324
-
325
- test "a key and value for parameter is returned when there is one query string parameter" do
326
- parsed_call_variables_with_query('?foo=bar').should == {'foo' => 'bar'}
327
- end
328
-
329
- test "both key/value pairs are returned when there are a pair of query string parameters" do
330
- parsed_call_variables_with_query('?foo=bar&baz=quux').should == {'foo' => 'bar', 'baz' => 'quux'}
331
- end
332
-
333
- test "all key/value pairs are returned when there are more than a pair of query string parameters" do
334
- parsed_call_variables_with_query('?foo=bar&baz=quux&name=marcel').should == {'foo' => 'bar', 'baz' => 'quux', 'name' => 'marcel'}
335
- end
336
-
337
- end
338
-
339
- BEGIN {
340
- module CallVariableTestHelper
341
- def parsed_call_variables_from(io)
342
- Adhearsion::Call::Variables::Parser.parse(io).variables
343
- end
344
-
345
- def coerce_call_variables(variables)
346
- Adhearsion::Call::Variables::Parser.coerce_variables(variables)
347
- end
348
-
349
- def merged_hash_with_call_variables(new_hash)
350
- call_variables_with_new_query = typical_call_variables_hash.merge new_hash
351
- coerce_call_variables call_variables_with_new_query
352
- end
353
-
354
- def parsed_call_variables_with_query(query_string)
355
- request_string = "agi://10.0.0.0/#{query_string}"
356
- merged_hash_with_call_variables({:request => request_string})[:query]
357
- end
358
-
359
- def typical_call_variable_io
360
- StringIO.new(typical_call_variable_section)
361
- end
362
-
363
- def typical_call_variable_section
364
- <<-VARIABLES
365
- agi_network: yes
366
- agi_request: agi://10.0.0.152/monkey?foo=bar&qaz=qwerty
367
- agi_channel: SIP/marcel-b58046e0
368
- agi_language: en
369
- agi_type: SIP
370
- agi_uniqueid: 1191245124.16
371
- agi_callerid: 011441234567899
372
- agi_calleridname: unknown
373
- agi_callingpres: 0
374
- agi_callingani2: 0
375
- agi_callington: 0
376
- agi_callingtns: 0
377
- agi_dnid: 911
378
- agi_rdnis: unknown
379
- agi_context: adhearsion
380
- agi_extension: 911
381
- agi_priority: 1
382
- agi_enhanced: 0.0
383
- agi_accountcode:
384
-
385
- VARIABLES
386
- end
387
-
388
- # TODO:
389
- # - "unknown" should be converted to nil
390
- # - "yes" or "no" should be converted to true or false
391
- # - numbers beginning with a 0 MUST be converted to a NumericalString
392
- # - Look up why there are so many zeroes. They're likely reprentative of some PRI definition.
393
-
394
- def typical_call_variables_hash
395
- uncoerced_variable_map = expected_uncoerced_variable_map
396
-
397
- uncoerced_variable_map[:request] = URI.parse(uncoerced_variable_map[:request])
398
- uncoerced_variable_map[:extension] = 911 # Adhearsion::VoIP::DSL::PhoneNumber.new(uncoerced_variable_map[:extension]) #
399
- uncoerced_variable_map[:callerid] = Adhearsion::VoIP::DSL::NumericalString.new(uncoerced_variable_map[:callerid])
400
-
401
- uncoerced_variable_map[:network] = true
402
- uncoerced_variable_map[:calleridname] = nil
403
- uncoerced_variable_map[:callingpres] = 0
404
- uncoerced_variable_map[:callingani2] = 0
405
- uncoerced_variable_map[:callingtns] = 0
406
- uncoerced_variable_map[:dnid] = 911
407
- uncoerced_variable_map[:rdnis] = nil
408
- uncoerced_variable_map[:priority] = 1
409
- uncoerced_variable_map[:enhanced] = 0.0
410
- uncoerced_variable_map[:uniqueid] = 1191245124.16
411
-
412
- uncoerced_variable_map[:type_of_calling_number] = Adhearsion::VoIP::Constants::Q931_TYPE_OF_NUMBER[uncoerced_variable_map.delete(:callington).to_i]
413
-
414
- coerced_variable_map = uncoerced_variable_map
415
- coerced_variable_map[:query] = {"foo" => "bar", "qaz" => "qwerty"}
416
- coerced_variable_map[:foo] = 'bar'
417
- coerced_variable_map[:qaz] = 'qwerty'
418
- coerced_variable_map
419
- end
420
-
421
- def expected_uncoerced_variable_map
422
- {:network => 'yes',
423
- :request => 'agi://10.0.0.152/monkey?foo=bar&qaz=qwerty',
424
- :channel => 'SIP/marcel-b58046e0',
425
- :language => 'en',
426
- :type => 'SIP',
427
- :uniqueid => '1191245124.16',
428
- :callerid => '011441234567899',
429
- :calleridname => 'unknown',
430
- :callingpres => '0',
431
- :callingani2 => '0',
432
- :callington => '0',
433
- :callingtns => '0',
434
- :dnid => '911',
435
- :rdnis => 'unknown',
436
- :context => 'adhearsion',
437
- :extension => '911',
438
- :priority => '1',
439
- :enhanced => '0.0',
440
- :accountcode => ''}
441
- end
442
- end
443
-
444
- module AgiServerTestHelper
445
- def stub_before_call_hooks!
446
- flexstub(Adhearsion::Hooks::BeforeCall).should_receive :trigger_hooks
447
- end
448
-
449
- def stub_confirmation_manager!
450
- flexstub(Adhearsion::DialPlan::ConfirmationManager).should_receive(:confirmation_call?).and_return false
451
- end
452
- end
453
- }
@@ -1,227 +0,0 @@
1
- require File.dirname(__FILE__) + "/../../test_helper"
2
- require File.dirname(__FILE__) + "/mock_ami_server"
3
-
4
- require 'adhearsion'
5
- require 'adhearsion/voip/asterisk/ami'
6
-
7
- context "Connecting via AMI" do
8
- test "should raise an exception if the password was invalid" do
9
- host, port = "localhost", 5038
10
- ami = Adhearsion::VoIP::Asterisk::AMI.new "admin", "bad_password", "localhost", :port => port
11
-
12
- ami_server = AmiServer.new
13
- flexmock(TCPSocket).should_receive(:new).once.with(host, port).and_return(ami_server)
14
- flexmock(IO).should_receive(:select).at_least.once.with([ami_server], nil, nil, 1.0).and_return(true)
15
-
16
- the_following_code do
17
- ami.connect!
18
- end.should.raise Adhearsion::VoIP::Asterisk::AMI::AuthenticationFailedException
19
- ami.disconnect!
20
- end
21
-
22
- test "should discover its own permissions and make them available as connection attributes"
23
-
24
- # TODO: DRY up the following two specs
25
- test "should start a new thread if events are enabled" do
26
- host, port = "localhost", 5038
27
- ami = Adhearsion::VoIP::Asterisk::AMI.new "admin", "password", "localhost", :port => port, :events => true
28
-
29
- ami_server = AmiServer.new
30
- flexmock(TCPSocket).should_receive(:new).once.with(host, port).and_return(ami_server)
31
- flexmock(IO).should_receive(:select).at_least.once.with([ami_server], nil, nil, 1.0).and_return(true)
32
-
33
- ami.connect!
34
- ami.instance_eval { meta_eval { attr_accessor :event_thread } }
35
- ami.event_thread.should.be.a.kind_of Thread
36
- ami.disconnect!
37
- end
38
-
39
- test "should find the Asterisk version when connecting" do
40
- host, port = "localhost", 5038
41
- ami = Adhearsion::VoIP::Asterisk::AMI.new "admin", "password", "localhost", :port => port
42
-
43
- ami_server = AmiServer.new
44
- flexmock(TCPSocket).should_receive(:new).once.with(host, port).and_return(ami_server)
45
- flexmock(IO).should_receive(:select).at_least.once.with([ami_server], nil, nil, 1.0).and_return(true)
46
-
47
- ami.connect!
48
- ami.version.should == "1.0"
49
- ami.disconnect!
50
- end
51
- end
52
-
53
- context "The AMI command interface" do
54
- before do
55
- host, port = "localhost", 5038
56
- @ami = Adhearsion::VoIP::Asterisk::AMI.new "admin", "password", host, :port => port, :events => false
57
-
58
- ami_server = AmiServer.new
59
- flexmock(TCPSocket).should_receive(:new).once.with(host, port).and_return(ami_server)
60
- flexmock(IO).should_receive(:select).at_least.once.with([ami_server], nil, nil, 1.0).and_return(true)
61
-
62
- @ami.connect!
63
- end
64
-
65
- after do
66
- @ami.disconnect!
67
- end
68
-
69
- test "should respond to an immediate command" do
70
- resp = @ami.queues
71
- resp[0][:raw].should.be.a.kind_of String
72
- end
73
-
74
- test "should respond to a follows command" do
75
- resp = @ami.command :Command => "show channels"
76
- resp[0][:raw].should.be.a.kind_of String
77
- end
78
-
79
- test "should respond to a DBGet for a non-existent key with an exception" do
80
- the_following_code do
81
- resp = @ami.dbget :Family => "none", :Key => "somekey"
82
- end.should.raise Adhearsion::VoIP::Asterisk::AMI::ActionError
83
- end
84
-
85
- test "should respond to a DBGet for a key with an event" do
86
- resp = @ami.dbput :Family => "none", :Key => "somekey", :Val => 5
87
- resp = @ami.dbget :Family => "none", :Key => "somekey"
88
- resp[0]['Val'].should == "5"
89
- end
90
-
91
- test "should respond to a command that generates follows event(s)" do
92
- resp = @ami.queuestatus
93
- resp[0]['Queue'].should == "default"
94
- end
95
-
96
- test "should show usage for an improper follows command" do
97
- resp = @ami.command :Command => "meetme list"
98
- resp[0][:raw].should.be.a.kind_of String
99
- end
100
-
101
- test "should respond to a synchronous originate"
102
- test "should respond to an asynchronous originate"
103
-
104
- test "should define events() as a private method to prevent turning events on or off" do
105
- @ami.private_methods.include?("events").should.equal true
106
- end
107
-
108
- test "should raise an exception when Asterisk doesn't recognize a command" do
109
- the_following_code {
110
- @ami.this_command_does_not_exist_kthx
111
- }.should.raise Adhearsion::VoIP::Asterisk::AMI::ActionError
112
-
113
- end
114
-
115
- end
116
-
117
- context 'AMI#originate' do
118
- include AmiCommandTestHelper
119
- test "should pass the arguments to execute_ami_command! with the options given" do
120
- ami = new_ami_instance
121
- options = { :channel => "ohai_lolz", :application => "Echo" }
122
- flexmock(ami).should_receive(:execute_ami_command!).with(:originate, options).once
123
- ami.originate options
124
- end
125
-
126
- test "should rename the :caller_id Hash key to :callerid" do
127
- ami, caller_id = new_ami_instance, "Jay"
128
- options = { :channel => "ohai_lolz", :application => "Echo"}
129
- flexmock(ami).should_receive(:execute_ami_command!).with(:originate, options.merge(:callerid => caller_id)).once
130
- ami.originate options.merge(:caller_id => caller_id)
131
- end
132
-
133
- end
134
-
135
- context 'AMI#call_and_exec' do
136
- include AmiCommandTestHelper
137
- test "should execute originate properly with the minimum arguments" do
138
- number, app = "12224446666", "Echo"
139
-
140
- ami = flexmock new_ami_instance
141
- ami.should_receive(:originate).once.with(:channel => number, :application => app).and_return true
142
- ami.call_and_exec number, app
143
- end
144
-
145
- end
146
-
147
- context 'AMI#introduce' do
148
-
149
- include AmiCommandTestHelper
150
-
151
- test "should execute origiante properly (when :caller_id and :options aren't specified)" do
152
- caller, callee, caller_id = "SIP/12224446666@trunk", "SIP/12224447777@trunk", "Jay Phillips"
153
-
154
- correct_args = {:application => "Dial", :channel => caller, :data => callee, :caller_id => "Jay"}
155
- ami = flexmock new_ami_instance
156
- ami.should_receive(:originate).once.with(correct_args).and_return(true)
157
- ami.introduce caller, callee, :caller_id => "Jay"
158
- end
159
-
160
- end
161
-
162
- context "The manager proxy" do
163
- before do
164
- host, port = "localhost", 5038
165
- @ami = Adhearsion::VoIP::Asterisk::AMI.new "admin", "password", "localhost", :port => port, :events => false
166
-
167
- ami_server = AmiServer.new
168
- flexmock(TCPSocket).should_receive(:new).once.with(host, port).and_return(ami_server)
169
- flexmock(IO).should_receive(:select).at_least.once.with([ami_server], nil, nil, 1.0).and_return(true)
170
-
171
- @ami.connect!
172
- @door = DRb.start_service "druby://127.0.0.1:9050", Adhearsion::DrbDoor.instance
173
- end
174
-
175
- test "should accept a command" do
176
- client = DRbObject.new nil, DRb.uri
177
- client.proxy.ping
178
- end
179
-
180
- after do
181
- DRb.stop_service
182
- @ami.disconnect!
183
- end
184
- end
185
-
186
- context "The command-sending interface" do
187
- test "should raise an exception if permission was denied"
188
- test "should allow variables to be specified as a Hash"
189
- end
190
-
191
- context "Sent arbitrary AMI commands" do
192
-
193
- test "should allow a convenient way of parsing by event name"
194
- test "should return Hash arguments"
195
-
196
- test "should recognize its subclasses"
197
- test "should send events to all of its subclasses"
198
- test "should catch action names with method_missing() and format them properly"
199
-
200
- test "should raise an exception if permission was denied"
201
- end
202
-
203
- context "AMI Packets" do
204
- test "A Packet should not be an error" do
205
- Adhearsion::VoIP::Asterisk::AMI::Packet.new.error?.should.be false
206
- end
207
- test "An ErrorPacket should be an error" do
208
- Adhearsion::VoIP::Asterisk::AMI::ErrorPacket.new.error?.should.be true
209
- end
210
- end
211
-
212
- context "The event parser" do
213
- test "should parse the the YAML-like format "
214
- test "should allow a Hash to specify multiple matches"
215
- end
216
-
217
- BEGIN {
218
- module AmiCommandTestHelper
219
- def new_ami_instance
220
- # TODO. mock everything out here
221
- returning Adhearsion::VoIP::Asterisk::AMI.new("user","pass") do |ami|
222
- flexmock(ami).should_receive(:connect!).and_return(true)
223
- end
224
- end
225
-
226
- end
227
- }