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.
- data/CHANGELOG +8 -2
- data/EVENTS +11 -0
- data/Rakefile +92 -26
- data/adhearsion.gemspec +131 -23
- data/app_generators/ahn/ahn_generator.rb +21 -7
- data/app_generators/ahn/templates/.ahnrc +10 -4
- data/app_generators/ahn/templates/Rakefile +7 -2
- data/app_generators/ahn/templates/components/ami_remote/ami_remote.rb +15 -0
- data/app_generators/ahn/templates/components/disabled/HOW_TO_ENABLE +7 -0
- data/app_generators/ahn/templates/components/disabled/stomp_gateway/README.markdown +47 -0
- data/app_generators/ahn/templates/components/disabled/stomp_gateway/config.yml +12 -0
- data/app_generators/ahn/templates/components/disabled/stomp_gateway/stomp_gateway.rb +34 -0
- data/app_generators/ahn/templates/components/simon_game/{lib/simon_game.rb → simon_game.rb} +14 -19
- data/app_generators/ahn/templates/config/startup.rb +3 -6
- data/app_generators/ahn/templates/dialplan.rb +2 -3
- data/app_generators/ahn/templates/events.rb +32 -6
- data/bin/jahn +10 -0
- data/examples/asterisk_manager_interface/standalone.rb +51 -0
- data/lib/adhearsion/cli.rb +140 -23
- data/lib/adhearsion/component_manager/component_tester.rb +55 -0
- data/lib/adhearsion/component_manager/spec_framework.rb +24 -0
- data/lib/adhearsion/component_manager.rb +169 -238
- data/lib/adhearsion/events_support.rb +59 -237
- data/lib/adhearsion/{core_extensions → foundation}/all.rb +0 -0
- data/lib/adhearsion/{blank_slate.rb → foundation/blank_slate.rb} +0 -0
- data/lib/adhearsion/{core_extensions → foundation}/custom_daemonizer.rb +0 -0
- data/lib/adhearsion/foundation/event_socket.rb +203 -0
- data/lib/adhearsion/foundation/future_resource.rb +36 -0
- data/lib/adhearsion/{core_extensions → foundation}/global.rb +0 -0
- data/lib/adhearsion/{core_extensions → foundation}/metaprogramming.rb +0 -0
- data/lib/adhearsion/foundation/numeric.rb +13 -0
- data/lib/adhearsion/foundation/pseudo_guid.rb +10 -0
- data/lib/adhearsion/{core_extensions → foundation}/relationship_properties.rb +2 -0
- data/lib/adhearsion/foundation/string.rb +26 -0
- data/lib/adhearsion/foundation/synchronized_hash.rb +96 -0
- data/lib/adhearsion/{core_extensions → foundation}/thread_safety.rb +0 -0
- data/lib/adhearsion/host_definitions.rb +5 -1
- data/lib/adhearsion/initializer/asterisk.rb +33 -11
- data/lib/adhearsion/initializer/configuration.rb +58 -6
- data/lib/adhearsion/initializer/database.rb +3 -46
- data/lib/adhearsion/initializer/drb.rb +9 -3
- data/lib/adhearsion/initializer/freeswitch.rb +3 -3
- data/lib/adhearsion/initializer/rails.rb +1 -1
- data/lib/adhearsion/initializer.rb +213 -87
- data/lib/adhearsion/tasks/deprecations.rb +59 -0
- data/lib/adhearsion/tasks.rb +2 -1
- data/lib/adhearsion/version.rb +3 -3
- data/lib/adhearsion/voip/asterisk/agi_server.rb +6 -6
- data/lib/adhearsion/voip/asterisk/commands.rb +100 -2
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rb +1754 -0
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rl.rb +286 -0
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_messages.rb +78 -0
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_protocol_lexer_machine.rl +87 -0
- data/lib/adhearsion/voip/asterisk/manager_interface.rb +562 -0
- data/lib/adhearsion/voip/asterisk/super_manager.rb +19 -0
- data/lib/adhearsion/voip/asterisk.rb +1 -8
- data/lib/adhearsion/voip/call.rb +5 -1
- data/lib/adhearsion/voip/dial_plan.rb +74 -61
- data/lib/adhearsion/voip/dsl/dialing_dsl.rb +1 -1
- data/lib/adhearsion/voip/dsl/dialplan/parser.rb +2 -6
- data/lib/adhearsion/voip/dsl/numerical_string.rb +2 -2
- data/lib/adhearsion/voip/freeswitch/oes_server.rb +2 -2
- data/lib/adhearsion.rb +16 -11
- data/lib/theatre/README.markdown +64 -0
- data/lib/theatre/callback_definition_loader.rb +84 -0
- data/lib/theatre/guid.rb +23 -0
- data/lib/theatre/invocation.rb +121 -0
- data/lib/theatre/namespace_manager.rb +153 -0
- data/lib/theatre/version.rb +2 -0
- data/lib/theatre.rb +151 -0
- metadata +60 -147
- data/Manifest.txt +0 -151
- data/README.txt +0 -5
- data/ahn_generators/component/USAGE +0 -5
- data/ahn_generators/component/component_generator.rb +0 -57
- data/ahn_generators/component/templates/configuration.rb +0 -0
- data/ahn_generators/component/templates/lib/lib.rb.erb +0 -3
- data/ahn_generators/component/templates/test/test.rb.erb +0 -12
- data/ahn_generators/component/templates/test/test_helper.rb +0 -14
- data/app_generators/ahn/templates/components/simon_game/configuration.rb +0 -0
- data/app_generators/ahn/templates/components/simon_game/test/test_helper.rb +0 -14
- data/app_generators/ahn/templates/components/simon_game/test/test_simon_game.rb +0 -31
- data/lib/adhearsion/core_extensions/array.rb +0 -0
- data/lib/adhearsion/core_extensions/guid.rb +0 -5
- data/lib/adhearsion/core_extensions/hash.rb +0 -0
- data/lib/adhearsion/core_extensions/numeric.rb +0 -4
- data/lib/adhearsion/core_extensions/proc.rb +0 -0
- data/lib/adhearsion/core_extensions/pseudo_uuid.rb +0 -11
- data/lib/adhearsion/core_extensions/publishable.rb +0 -73
- data/lib/adhearsion/core_extensions/string.rb +0 -26
- data/lib/adhearsion/core_extensions/thread.rb +0 -13
- data/lib/adhearsion/core_extensions/time.rb +0 -0
- data/lib/adhearsion/distributed/gateways/dbus_gateway.rb +0 -0
- data/lib/adhearsion/distributed/gateways/osa_gateway.rb +0 -0
- data/lib/adhearsion/distributed/gateways/rest_gateway.rb +0 -9
- data/lib/adhearsion/distributed/gateways/soap_gateway.rb +0 -9
- data/lib/adhearsion/distributed/gateways/xmlrpc_gateway.rb +0 -9
- data/lib/adhearsion/distributed/peer_finder.rb +0 -0
- data/lib/adhearsion/distributed/remote_cli.rb +0 -0
- data/lib/adhearsion/hooks.rb +0 -57
- data/lib/adhearsion/initializer/paths.rb +0 -55
- data/lib/adhearsion/voip/asterisk/ami/actions.rb +0 -238
- data/lib/adhearsion/voip/asterisk/ami/machine.rb +0 -871
- data/lib/adhearsion/voip/asterisk/ami/machine.rl +0 -109
- data/lib/adhearsion/voip/asterisk/ami/parser.rb +0 -262
- data/lib/adhearsion/voip/asterisk/ami.rb +0 -147
- data/spec/fixtures/dialplan.rb +0 -3
- data/spec/initializer/test_configuration.rb +0 -267
- data/spec/initializer/test_loading.rb +0 -162
- data/spec/initializer/test_paths.rb +0 -43
- data/spec/sample.rb +0 -9
- data/spec/silence.rb +0 -10
- data/spec/test_ahn_command.rb +0 -149
- data/spec/test_code_quality.rb +0 -87
- data/spec/test_component_manager.rb +0 -97
- data/spec/test_constants.rb +0 -8
- data/spec/test_drb.rb +0 -104
- data/spec/test_events.rb +0 -136
- data/spec/test_helper.rb +0 -106
- data/spec/test_hooks.rb +0 -15
- data/spec/test_host_definitions.rb +0 -79
- data/spec/test_initialization.rb +0 -124
- data/spec/test_logging.rb +0 -80
- data/spec/test_relationship_properties.rb +0 -54
- data/spec/voip/asterisk/ami_response_definitions.rb +0 -23
- data/spec/voip/asterisk/config_file_generators/test_agents.rb +0 -253
- data/spec/voip/asterisk/config_file_generators/test_queues.rb +0 -325
- data/spec/voip/asterisk/config_file_generators/test_voicemail.rb +0 -306
- data/spec/voip/asterisk/menu_command/test_calculated_match.rb +0 -111
- data/spec/voip/asterisk/menu_command/test_matchers.rb +0 -98
- data/spec/voip/asterisk/mock_ami_server.rb +0 -176
- data/spec/voip/asterisk/test_agi_server.rb +0 -453
- data/spec/voip/asterisk/test_ami.rb +0 -227
- data/spec/voip/asterisk/test_commands.rb +0 -2006
- data/spec/voip/asterisk/test_config_manager.rb +0 -129
- data/spec/voip/dsl/dispatcher_spec_helper.rb +0 -45
- data/spec/voip/dsl/test_dialing_dsl.rb +0 -268
- data/spec/voip/dsl/test_dispatcher.rb +0 -82
- data/spec/voip/dsl/test_parser.rb +0 -87
- data/spec/voip/freeswitch/test_basic_connection_manager.rb +0 -39
- data/spec/voip/freeswitch/test_inbound_connection_manager.rb +0 -39
- data/spec/voip/freeswitch/test_oes_server.rb +0 -9
- data/spec/voip/test_call_routing.rb +0 -127
- data/spec/voip/test_dialplan_manager.rb +0 -442
- data/spec/voip/test_numerical_string.rb +0 -48
- data/spec/voip/test_phone_number.rb +0 -36
- data/test/test_ahn_generator.rb +0 -59
- data/test/test_component_generator.rb +0 -52
- 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
|
-
}
|