adhearsion 1.0.1 → 1.0.2
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/.gitignore +10 -0
- data/CHANGELOG +8 -0
- data/README.markdown +33 -0
- data/Rakefile +28 -68
- data/adhearsion.gemspec +19 -133
- data/app_generators/ahn/templates/Gemfile +0 -4
- data/app_generators/ahn/templates/components/disabled/restful_rpc/spec/restful_rpc_spec.rb +4 -16
- data/lib/adhearsion/cli.rb +17 -0
- data/lib/adhearsion/component_manager/component_tester.rb +1 -3
- data/lib/adhearsion/component_manager/spec_framework.rb +4 -10
- data/lib/adhearsion/foundation/object.rb +10 -0
- data/lib/adhearsion/version.rb +1 -1
- data/spec/ahn_command_spec.rb +284 -0
- data/spec/component_manager_spec.rb +292 -0
- data/spec/constants_spec.rb +8 -0
- data/spec/drb_spec.rb +65 -0
- data/spec/fixtures/dialplan.rb +3 -0
- data/spec/foundation/event_socket_spec.rb +168 -0
- data/spec/host_definitions_spec.rb +79 -0
- data/spec/initialization_spec.rb +163 -0
- data/spec/initializer/configuration_spec.rb +270 -0
- data/spec/initializer/loading_spec.rb +149 -0
- data/spec/initializer/paths_spec.rb +74 -0
- data/spec/logging_spec.rb +86 -0
- data/spec/relationship_properties_spec.rb +54 -0
- data/spec/silence.rb +10 -0
- data/spec/spec_helper.rb +101 -0
- data/spec/voip/asterisk/agi_server_spec.rb +473 -0
- data/spec/voip/asterisk/ami/ami_spec.rb +549 -0
- data/spec/voip/asterisk/ami/lexer/ami_fixtures.yml +30 -0
- data/spec/voip/asterisk/ami/lexer/lexer_story +291 -0
- data/spec/voip/asterisk/ami/lexer/lexer_story.rb +241 -0
- data/spec/voip/asterisk/ami/lexer/story_helper.rb +124 -0
- data/spec/voip/asterisk/ami/old_tests.rb +204 -0
- data/spec/voip/asterisk/ami/super_manager/super_manager_story +25 -0
- data/spec/voip/asterisk/ami/super_manager/super_manager_story.rb +15 -0
- data/spec/voip/asterisk/ami/super_manager/super_manager_story_helper.rb +5 -0
- data/spec/voip/asterisk/commands_spec.rb +2179 -0
- data/spec/voip/asterisk/config_file_generators/agents_spec.rb +251 -0
- data/spec/voip/asterisk/config_file_generators/queues_spec.rb +323 -0
- data/spec/voip/asterisk/config_file_generators/voicemail_spec.rb +306 -0
- data/spec/voip/asterisk/config_manager_spec.rb +127 -0
- data/spec/voip/asterisk/menu_command/calculated_match_spec.rb +109 -0
- data/spec/voip/asterisk/menu_command/matchers_spec.rb +97 -0
- data/spec/voip/call_routing_spec.rb +125 -0
- data/spec/voip/dialplan_manager_spec.rb +468 -0
- data/spec/voip/dsl/dialing_dsl_spec.rb +270 -0
- data/spec/voip/dsl/dispatcher_spec.rb +82 -0
- data/spec/voip/dsl/dispatcher_spec_helper.rb +45 -0
- data/spec/voip/dsl/parser_spec.rb +69 -0
- data/spec/voip/freeswitch/basic_connection_manager_spec.rb +39 -0
- data/spec/voip/freeswitch/inbound_connection_manager_spec.rb +39 -0
- data/spec/voip/freeswitch/oes_server_spec.rb +9 -0
- data/spec/voip/numerical_string_spec.rb +61 -0
- data/spec/voip/phone_number_spec.rb +45 -0
- data/theatre-spec/dsl_examples/dynamic_stomp.rb +7 -0
- data/theatre-spec/dsl_examples/simple_before_call.rb +7 -0
- data/theatre-spec/dsl_spec.rb +43 -0
- data/theatre-spec/invocation_spec.rb +167 -0
- data/theatre-spec/namespace_spec.rb +125 -0
- data/theatre-spec/spec_helper.rb +37 -0
- data/theatre-spec/spec_helper_spec.rb +28 -0
- data/theatre-spec/theatre_class_spec.rb +150 -0
- metadata +171 -34
@@ -0,0 +1,549 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'adhearsion'
|
3
|
+
require 'adhearsion/voip/asterisk/manager_interface'
|
4
|
+
|
5
|
+
module ManagerInterfaceTestHelper
|
6
|
+
|
7
|
+
def mocked_queue
|
8
|
+
# This mock queue receives a ManagerInterfaceAction with <<(). Within the semantics of the OO design, this should be
|
9
|
+
# immediately picked up by the writer queue. The writer queue calls to_s on each object and passes that string to the
|
10
|
+
# event socket, blocking if it's an event with causal events.
|
11
|
+
write_queue_mock = TestableQueueMock.new
|
12
|
+
flexmock(Queue).should_receive(:new).once.and_return write_queue_mock
|
13
|
+
write_queue_mock
|
14
|
+
end
|
15
|
+
|
16
|
+
def ami_packets
|
17
|
+
OpenStruct.new.tap do |struct|
|
18
|
+
struct.fresh_socket_connection = "Asterisk Call Manager/1.0\r\nResponse: Success\r\n"+
|
19
|
+
"Message: Authentication accepted\r\n\r\n"
|
20
|
+
|
21
|
+
struct.reload_event = %{Event: ChannelReload\r\nPrivilege: system,all\r\nChannel: SIP\r\n} +
|
22
|
+
%{ReloadReason: RELOAD (Channel module reload)\r\nRegistry_Count: 1\r\nPeer_Count: 2\r\nUser_Count: 1\r\n\r\n}
|
23
|
+
|
24
|
+
struct.authentication_failed = %{Asterisk Call Manager/1.0\r\nResponse: Error\r\nMessage: Authentication failed\r\nActionID: %s\r\n\r\n}
|
25
|
+
|
26
|
+
struct.unknown_command_error = "Response: Error\r\nActionID: 2123123\r\nMessage: Invalid/unknown command\r\n\r\n"
|
27
|
+
|
28
|
+
struct.pong = "Response: Pong\r\nActionID: %s\r\n\r\n"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def new_manager_with_events
|
33
|
+
@Manager::ManagerInterface.new :host => @host, :port => @port, :events => true, :auto_reconnect => false
|
34
|
+
end
|
35
|
+
|
36
|
+
def new_manager_without_events
|
37
|
+
@Manager::ManagerInterface.new :host => @host, :port => @port, :events => false, :auto_reconnect => false
|
38
|
+
end
|
39
|
+
|
40
|
+
def new_blank_ami_response
|
41
|
+
@Manager::ManagerInterfaceResponse.new
|
42
|
+
end
|
43
|
+
|
44
|
+
def mock_for_next_created_socket
|
45
|
+
flexmock("TCPSocket").tap do |mock|
|
46
|
+
flexmock(TCPSocket).should_receive(:new).once.and_return mock
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
##
|
54
|
+
# Had to implement this class to make the Thread-based testing simpler.
|
55
|
+
#
|
56
|
+
class TestableQueueMock
|
57
|
+
|
58
|
+
attr_accessor :manager
|
59
|
+
def initialize
|
60
|
+
@shifted = []
|
61
|
+
@unshifted = []
|
62
|
+
end
|
63
|
+
|
64
|
+
def actions
|
65
|
+
@shifted + @unshifted
|
66
|
+
end
|
67
|
+
|
68
|
+
def <<(action)
|
69
|
+
@unshifted << action
|
70
|
+
@on_push.call(action) if @on_push
|
71
|
+
end
|
72
|
+
|
73
|
+
def on_push(&block)
|
74
|
+
@on_push = block
|
75
|
+
self
|
76
|
+
end
|
77
|
+
|
78
|
+
def shift
|
79
|
+
return :STOP! if actions.empty?
|
80
|
+
next_action = @unshifted.shift
|
81
|
+
@shifted << next_action
|
82
|
+
next_action
|
83
|
+
end
|
84
|
+
|
85
|
+
def received_action?(action)
|
86
|
+
actions.include?(action)
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
describe "ManagerInterface" do
|
92
|
+
|
93
|
+
include ManagerInterfaceTestHelper
|
94
|
+
|
95
|
+
before :each do
|
96
|
+
@Manager = Adhearsion::VoIP::Asterisk::Manager
|
97
|
+
@host, @port = "foobar", 9999
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should receive data and not die" do
|
101
|
+
flexmock(@Manager::ManagerInterface::ManagerInterfaceAction).new_instances.should_receive(:response).once.and_return new_blank_ami_response
|
102
|
+
|
103
|
+
mocked_queue
|
104
|
+
|
105
|
+
manager = new_manager_without_events
|
106
|
+
|
107
|
+
t = flexmock('Thread')
|
108
|
+
t.should_receive(:join)
|
109
|
+
flexmock(Thread).should_receive(:new).twice.and_yield.and_return(t)
|
110
|
+
mock_em_connection = mock_for_next_created_socket
|
111
|
+
|
112
|
+
mock_em_connection.should_receive(:readpartial).once.and_return ami_packets.fresh_socket_connection
|
113
|
+
mock_em_connection.should_receive(:readpartial).once.and_raise EOFError
|
114
|
+
|
115
|
+
flexmock(manager).should_receive(:action_message_received).once.with(@Manager::ManagerInterfaceResponse)
|
116
|
+
manager.connect!
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should use the defaults specified in DEFAULT_SETTINGS when no overrides are given" do
|
120
|
+
manager = @Manager::ManagerInterface.new
|
121
|
+
%w[host port username password events].each do |property|
|
122
|
+
manager.send(property).should ==@Manager::ManagerInterface::DEFAULT_SETTINGS[property.to_sym]
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should override the DEFAULT_SETTINGS settings with overrides given to the constructor" do
|
127
|
+
overrides = {
|
128
|
+
:host => "yayiamahost",
|
129
|
+
:port => 1337,
|
130
|
+
:username => "root",
|
131
|
+
:password => "toor",
|
132
|
+
:events => false
|
133
|
+
}
|
134
|
+
manager = @Manager::ManagerInterface.new overrides
|
135
|
+
%w[host port username password events].each do |property|
|
136
|
+
manager.send(property).should ==overrides[property.to_sym]
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should raise an ArgumentError when it's instantiated with an unrecognized named argument" do
|
141
|
+
the_following_code {
|
142
|
+
@Manager::ManagerInterface.new :ifeelsopretty => "OH SO PRETTY!"
|
143
|
+
}.should raise_error ArgumentError
|
144
|
+
end
|
145
|
+
|
146
|
+
it "a received message that matches an action ID for which we're waiting" do
|
147
|
+
action_id = "OHAILOLZ"
|
148
|
+
|
149
|
+
manager = new_manager_without_events
|
150
|
+
|
151
|
+
flexmock(@Manager::ManagerInterface::ManagerInterfaceAction).new_instances.should_receive(:action_id).once.and_return action_id
|
152
|
+
flexmock(manager).should_receive(:login_actions).once.and_return
|
153
|
+
|
154
|
+
mock_em_connection = mock_for_next_created_socket
|
155
|
+
|
156
|
+
manager.connect!
|
157
|
+
|
158
|
+
flexmock(FutureResource).new_instances.should_receive(:resource).once.and_return :THREAD_WAITING_MOCKED_OUT
|
159
|
+
flexmock(FutureResource).new_instances.should_receive(:resource=).once.with(@Manager::ManagerInterfaceResponse)
|
160
|
+
|
161
|
+
manager.send_action("ping").should be :THREAD_WAITING_MOCKED_OUT
|
162
|
+
|
163
|
+
# Avoid race where message may not yet be in the sent_messages queue
|
164
|
+
sleep(0.1)
|
165
|
+
manager.send(:instance_variable_get, :@sent_messages).has_key?(action_id).should be true
|
166
|
+
|
167
|
+
manager.send(:instance_variable_get, :@actions_connection).
|
168
|
+
send(:instance_variable_get, :@handler).
|
169
|
+
receive_data("Response: Pong\r\nActionID: #{action_id}\r\n\r\n")
|
170
|
+
|
171
|
+
manager.send(:instance_variable_get, :@sent_messages).has_key?(action_id).should be false
|
172
|
+
end
|
173
|
+
|
174
|
+
it "a received event is received by Theatre" do
|
175
|
+
flexmock(Adhearsion::Events).should_receive(:trigger).once.with(%w[asterisk manager_interface], @Manager::ManagerInterfaceEvent)
|
176
|
+
|
177
|
+
manager = new_manager_with_events
|
178
|
+
flexmock(manager).should_receive(:login_actions).once.and_return
|
179
|
+
flexmock(manager).should_receive(:login_events).once.and_return
|
180
|
+
|
181
|
+
mock_actions_connection = mock_for_next_created_socket
|
182
|
+
mock_events_connection = mock_for_next_created_socket
|
183
|
+
|
184
|
+
manager.connect!
|
185
|
+
|
186
|
+
manager.send(:instance_variable_get, :@events_connection).
|
187
|
+
send(:instance_variable_get, :@handler).
|
188
|
+
receive_data ami_packets.reload_event
|
189
|
+
end
|
190
|
+
|
191
|
+
it "an ManagerInterfaceError should be raised when the action's FutureResource is set to an ManagerInterfaceError instance" do
|
192
|
+
|
193
|
+
flexmock(FutureResource).new_instances.should_receive(:resource).once.and_return @Manager::ManagerInterfaceError.new
|
194
|
+
|
195
|
+
manager = new_manager_without_events
|
196
|
+
actions_connection = mock_for_next_created_socket
|
197
|
+
flexmock(manager).should_receive(:login_actions).once.and_return
|
198
|
+
|
199
|
+
manager.connect!
|
200
|
+
|
201
|
+
the_following_code {
|
202
|
+
manager.send_action "Foobar"
|
203
|
+
}.should raise_error @Manager::ManagerInterfaceError
|
204
|
+
|
205
|
+
end
|
206
|
+
|
207
|
+
it "an AuthenticationFailedException should be raised when the action's FutureResource is set to an ManagerInterfaceError instance" do
|
208
|
+
flexmock(FutureResource).new_instances.should_receive(:resource).once.and_return @Manager::ManagerInterfaceError.new
|
209
|
+
|
210
|
+
manager = new_manager_without_events
|
211
|
+
actions_connection = mock_for_next_created_socket
|
212
|
+
|
213
|
+
the_following_code {
|
214
|
+
manager.connect!
|
215
|
+
}.should raise_error @Manager::ManagerInterface::AuthenticationFailedException
|
216
|
+
|
217
|
+
end
|
218
|
+
|
219
|
+
# FIXME: Fix this it or nuke it.
|
220
|
+
# it "THIS TEST IS AN EXPERIMENT TO START FROM SCRATCH AND TEST WRITES GOING THROUGH THE WRITE QUEUE!" do
|
221
|
+
# # Note: this it will be cleaned up and used a reference for refactoring the other failing tests in this file.
|
222
|
+
# response = new_blank_ami_response
|
223
|
+
# flexmock(@Manager::ManagerInterface::ManagerInterfaceAction).new_instances.should_receive(:response).once.and_return response
|
224
|
+
#
|
225
|
+
# flexmock(TCPSocket).should_receive(:new).once.and_return StringIO.new
|
226
|
+
#
|
227
|
+
# write_queue_mock = mocked_queue
|
228
|
+
#
|
229
|
+
# manager = new_manager_without_events
|
230
|
+
# write_queue_mock.manager = manager
|
231
|
+
#
|
232
|
+
# manager.connect!
|
233
|
+
#
|
234
|
+
# manager.send_action "Ping"
|
235
|
+
#
|
236
|
+
# write_queue_mock.actions.size.should be 2
|
237
|
+
# write_queue_mock.actions.first.name.should =="login"
|
238
|
+
# write_queue_mock.actions.last.name.should =="ping"
|
239
|
+
# end
|
240
|
+
|
241
|
+
it "after calling connect!() with events enabled, both connections perform a login" do
|
242
|
+
response = new_blank_ami_response
|
243
|
+
|
244
|
+
flexstub(@Manager::ManagerInterface::ManagerInterfaceAction).new_instances.should_receive(:response).and_return response
|
245
|
+
|
246
|
+
# FIXME: It would be better if actions_socket blocked like the real thing...
|
247
|
+
actions_socket = StringIO.new
|
248
|
+
events_socket = StringIO.new
|
249
|
+
|
250
|
+
flexmock(TCPSocket).should_receive(:new).twice.and_return actions_socket, events_socket
|
251
|
+
|
252
|
+
write_queue_mock = mocked_queue
|
253
|
+
|
254
|
+
manager = new_manager_with_events
|
255
|
+
manager.connect!
|
256
|
+
|
257
|
+
write_queue_mock.actions.first.name.should == "login"
|
258
|
+
write_queue_mock.actions.first.headers['Events'].should == "Off"
|
259
|
+
end
|
260
|
+
|
261
|
+
it "a failed login on the actions socket raises an AuthenticationFailedException" do
|
262
|
+
manager = new_manager_with_events
|
263
|
+
|
264
|
+
mock_socket = flexmock("mock TCPSocket")
|
265
|
+
|
266
|
+
# By saying this should happen only once, we're also asserting that the events thread never does a login.
|
267
|
+
flexmock(EventSocket).should_receive(:connect).once.and_return mock_socket
|
268
|
+
|
269
|
+
login_error = @Manager::ManagerInterfaceError.new
|
270
|
+
login_error.message = "Authentication failed"
|
271
|
+
|
272
|
+
action = @Manager::ManagerInterface::ManagerInterfaceAction.new "Login", "Username" => "therestdoesntmatter"
|
273
|
+
flexmock(action).should_receive(:response).once.and_return login_error
|
274
|
+
|
275
|
+
flexmock(@Manager::ManagerInterface::ManagerInterfaceAction).should_receive(:new).once.and_return action
|
276
|
+
|
277
|
+
the_following_code {
|
278
|
+
manager.connect!
|
279
|
+
}.should raise_error @Manager::ManagerInterface::AuthenticationFailedException
|
280
|
+
|
281
|
+
end
|
282
|
+
|
283
|
+
# it "should raise an error if trying to send an action before connecting" do
|
284
|
+
# the_following_code {
|
285
|
+
# new_manager_without_events.send_action "foo"
|
286
|
+
# }.should raise_error( @Manager::ManagerInterface::NotConnectedError)
|
287
|
+
# end
|
288
|
+
|
289
|
+
it "sending an Action on the ManagerInterface should be received by the EventSocket" do
|
290
|
+
name, headers = "foobar", {"BLAH" => 1226534602.32764}
|
291
|
+
|
292
|
+
response = @Manager::ManagerInterfaceResponse.new
|
293
|
+
|
294
|
+
mock_connection = flexmock "EventSocket"
|
295
|
+
flexmock(EventSocket).should_receive(:connect).once.and_return mock_connection
|
296
|
+
|
297
|
+
action = @Manager::ManagerInterface::ManagerInterfaceAction.new(name, headers)
|
298
|
+
action.future_resource.resource = response
|
299
|
+
|
300
|
+
flexmock(@Manager::ManagerInterface::ManagerInterfaceAction).should_receive(:new).once.with(name, headers).and_return action
|
301
|
+
|
302
|
+
write_queue_mock = mocked_queue
|
303
|
+
|
304
|
+
manager = new_manager_without_events
|
305
|
+
flexmock(manager).should_receive(:login_actions).once.and_return
|
306
|
+
|
307
|
+
manager.connect!
|
308
|
+
manager.send_action(name, headers)
|
309
|
+
|
310
|
+
write_queue_mock.actions.size.should be 1
|
311
|
+
end
|
312
|
+
|
313
|
+
it 'ManagerInterface#action_error_received' do
|
314
|
+
action_id = "foobar"
|
315
|
+
|
316
|
+
error = @Manager::ManagerInterfaceError.new
|
317
|
+
error["ActionID"] = action_id
|
318
|
+
|
319
|
+
action = @Manager::ManagerInterface::ManagerInterfaceAction.new "Blah"
|
320
|
+
flexmock(action).should_receive(:action_id).and_return action_id
|
321
|
+
flexmock(action.future_resource).should_receive(:resource=).once.with(error)
|
322
|
+
manager = new_manager_without_events
|
323
|
+
|
324
|
+
flexmock(manager).should_receive(:data_for_message_received_with_action_id).once.with(action_id).and_return action
|
325
|
+
|
326
|
+
manager.action_error_received error
|
327
|
+
end
|
328
|
+
|
329
|
+
it "unsupported actions" do
|
330
|
+
@Manager::ManagerInterface::UnsupportedActionName::UNSUPPORTED_ACTION_NAMES.empty?.should_not be true
|
331
|
+
@Manager::ManagerInterface::UnsupportedActionName::UNSUPPORTED_ACTION_NAMES.each do |action_name|
|
332
|
+
manager = new_manager_without_events
|
333
|
+
the_following_code {
|
334
|
+
manager.send_action action_name
|
335
|
+
}.should raise_error @Manager::ManagerInterface::UnsupportedActionName
|
336
|
+
end
|
337
|
+
end
|
338
|
+
# FIXME: Fix this it or nuke it.
|
339
|
+
# it "normal use of Action:SIPPeers (which has causal events)" do
|
340
|
+
#
|
341
|
+
# raise "TODO"
|
342
|
+
#
|
343
|
+
# response = @Manager::ManagerInterfaceResponse.new
|
344
|
+
# response["Message"] = "Peer status list will follow"
|
345
|
+
#
|
346
|
+
# first_peer_entry = @Manager::ManagerInterfaceEvent.new "PeerEntry"
|
347
|
+
# { "Channeltype" => "SIP", "ObjectName" => "softphone", "ChanObjectType" => "peer", "IPaddress" => "-none-",
|
348
|
+
# "IPport" => "0", "Dynamic" => "yes", "Natsupport" => "no", "VideoSupport" => "no", "ACL" => "no",
|
349
|
+
# "Status" => "Unmonitored", "RealtimeDevice" => "no" }.each_pair do |key,value|
|
350
|
+
# first_peer_entry[key] = value
|
351
|
+
# end
|
352
|
+
#
|
353
|
+
# second_peer_entry = @Manager::ManagerInterfaceEvent.new "PeerEntry"
|
354
|
+
# { "Channeltype" => "SIP", "ObjectName" => "teliax", "ChanObjectType" => "peer", "IPaddress" => "74.201.8.23",
|
355
|
+
# "IPport" => "5060", "Dynamic" => "no", "Natsupport" => "yes", "VideoSupport" => "no", "ACL" => "no",
|
356
|
+
# "Status" => "OK (24 ms)", "RealtimeDevice" => "no" }.each_pair do |key, value|
|
357
|
+
# second_peer_entry[key] = value
|
358
|
+
# end
|
359
|
+
#
|
360
|
+
# ender = @Manager::ManagerInterfaceEvent.new "PeerlistComplete"
|
361
|
+
# ender["ListItems"] = "2"
|
362
|
+
#
|
363
|
+
# # flexmock(@Manager::ManagerInterface).new_instances.should_receive(:actions_connection_established).once.and_return
|
364
|
+
# # flexmock(@Manager::ManagerInterface).new_instances.should_receive(:write_loop).once.and_return
|
365
|
+
#
|
366
|
+
# manager = new_manager_without_events
|
367
|
+
#
|
368
|
+
# class << manager
|
369
|
+
# undef write_loop
|
370
|
+
# end
|
371
|
+
# action = manager.send_action "SIPPeers"
|
372
|
+
#
|
373
|
+
# manager.send(:action_message_received, response)
|
374
|
+
# manager.send(:action_message_received, first_peer_entry)
|
375
|
+
# manager.send(:action_message_received, second_peer_entry)
|
376
|
+
# manager.send(:action_message_received, ender)
|
377
|
+
#
|
378
|
+
# action.response.should be_a_kind_of Array
|
379
|
+
# action.response.size.should be 2
|
380
|
+
#
|
381
|
+
# first, second = response.response
|
382
|
+
#
|
383
|
+
# first["ObjectName"].should =="softphone"
|
384
|
+
# last["ObjectName"].should =="teliax"
|
385
|
+
# end
|
386
|
+
#
|
387
|
+
# FIXME: Fix this it or nuke it.
|
388
|
+
# it "use of Action:SIPPeers (which has causal events) which causes an error" do
|
389
|
+
#
|
390
|
+
# end
|
391
|
+
|
392
|
+
# TODO: Create the abstraction layer atop AMI with separate tests and it harness.
|
393
|
+
|
394
|
+
# TODO: Add tests which cause actions that don't reply with an action ID to raise an exception when sent
|
395
|
+
|
396
|
+
end
|
397
|
+
|
398
|
+
describe "ManagerInterface#write_loop" do
|
399
|
+
|
400
|
+
include ManagerInterfaceTestHelper
|
401
|
+
|
402
|
+
before :each do
|
403
|
+
@Manager = Adhearsion::VoIP::Asterisk::Manager
|
404
|
+
end
|
405
|
+
|
406
|
+
it "should stop when the stop instruction is sent to the write queue and return :stopped" do
|
407
|
+
flexmock(TCPSocket).should_receive(:new).once.and_return StringIO.new
|
408
|
+
flexmock(FutureResource).new_instances.should_receive(:resource).once.and_return new_blank_ami_response
|
409
|
+
|
410
|
+
mock_queue = flexmock "a mock write-Queue"
|
411
|
+
|
412
|
+
mock_queue.should_receive(:shift).once.and_return :STOP!
|
413
|
+
mock_queue.should_receive(:<<).and_return nil
|
414
|
+
|
415
|
+
flexmock(Queue).should_receive(:new).once.and_return mock_queue
|
416
|
+
|
417
|
+
manager = new_manager_without_events
|
418
|
+
manager.connect!
|
419
|
+
manager.disconnect!
|
420
|
+
end
|
421
|
+
|
422
|
+
end
|
423
|
+
|
424
|
+
describe "Class methods of ManagerInterface" do
|
425
|
+
|
426
|
+
before(:each) do
|
427
|
+
@ManagerInterface = Adhearsion::VoIP::Asterisk::Manager::ManagerInterface
|
428
|
+
end
|
429
|
+
|
430
|
+
it "the SIPPeers actions should be a causal event" do
|
431
|
+
@ManagerInterface.has_causal_events?("SIPPeers").should be true
|
432
|
+
end
|
433
|
+
|
434
|
+
it "the Queues action should not respond with an action id" do
|
435
|
+
@ManagerInterface.replies_with_action_id?("Queues").should == false
|
436
|
+
end
|
437
|
+
|
438
|
+
it "the IAXPeers action should not respond with an action id" do
|
439
|
+
# FIXME: This test relies on the side effect that earlier tests have run
|
440
|
+
# and initialized the UnsupportedActionName::UNSUPPORTED_ACTION_NAMES
|
441
|
+
# constant for an "unknown" version of Asterisk. This should be fixed
|
442
|
+
# to be more specific about which version of Asterisk is under test.
|
443
|
+
# IAXPeers is supported (with Action IDs!) since Asterisk 1.8
|
444
|
+
@ManagerInterface.replies_with_action_id?("IAXPeers").should == false
|
445
|
+
end
|
446
|
+
|
447
|
+
it "the ParkedCalls terminator event" do
|
448
|
+
@ManagerInterface.causal_event_terminator_name_for("ParkedCalls").should =="parkedcallscomplete"
|
449
|
+
@ManagerInterface.causal_event_terminator_name_for("parkedcalls").should =="parkedcallscomplete"
|
450
|
+
end
|
451
|
+
|
452
|
+
end
|
453
|
+
|
454
|
+
describe "ManagerInterfaceAction" do
|
455
|
+
|
456
|
+
before :each do
|
457
|
+
@ManagerInterface = Adhearsion::VoIP::Asterisk::Manager::ManagerInterface
|
458
|
+
end
|
459
|
+
|
460
|
+
it "should simply proxy the replies_with_action_id?() method" do
|
461
|
+
name, headers = "foobar", {"foo" => "bar"}
|
462
|
+
flexmock(@ManagerInterface).should_receive(:replies_with_action_id?).once.and_return
|
463
|
+
@ManagerInterface::ManagerInterfaceAction.new(name, headers).replies_with_action_id?
|
464
|
+
end
|
465
|
+
|
466
|
+
it "should simply proxy the has_causal_events?() method" do
|
467
|
+
name, headers = "foobar", {"foo" => "bar"}
|
468
|
+
action = @ManagerInterface::ManagerInterfaceAction.new(name, headers)
|
469
|
+
flexmock(@ManagerInterface).should_receive(:has_causal_events?).once.with(name, headers).and_return :foo
|
470
|
+
action.has_causal_events?.should be :foo
|
471
|
+
end
|
472
|
+
|
473
|
+
it "should properly convert itself into a String when additional headers are given" do
|
474
|
+
name, headers = "Hawtsawce", {"Monkey" => "Zoo"}
|
475
|
+
string = @ManagerInterface::ManagerInterfaceAction.new(name, headers).to_s
|
476
|
+
string.should =~ /^Action: Hawtsawce\r\n/i
|
477
|
+
string.should =~ /[^\n]\r\n\r\n$/
|
478
|
+
string.should =~ /^(\w+:\s*[\w-]+\r\n){3}\r\n$/
|
479
|
+
end
|
480
|
+
|
481
|
+
it "should properly convert itself into a String when no additional headers are given" do
|
482
|
+
string = @ManagerInterface::ManagerInterfaceAction.new("Ping").to_s
|
483
|
+
string.should =~ /^Action: Ping\r\nActionID: [\w-]+\r\n\r\n$/i
|
484
|
+
|
485
|
+
string = @ManagerInterface::ManagerInterfaceAction.new("ParkedCalls").to_s
|
486
|
+
string.should =~ /^Action: ParkedCalls\r\nActionID: [\w-]+\r\n\r\n$/i
|
487
|
+
end
|
488
|
+
|
489
|
+
end
|
490
|
+
|
491
|
+
describe "DelegatingAsteriskManagerInterfaceLexer" do
|
492
|
+
it "should translate the :syntax_error_encountered method call when a method_delegation_map is given" do
|
493
|
+
official_method, new_method = :syntax_error_encountered, :ohai_syntax_error!
|
494
|
+
method_argument = :testing123
|
495
|
+
mock_manager_interface = flexmock "ManagerInterface which receives callbacks"
|
496
|
+
mock_manager_interface.should_receive(new_method).once.with(method_argument).and_return
|
497
|
+
parser = Adhearsion::VoIP::Asterisk::Manager::DelegatingAsteriskManagerInterfaceLexer.new mock_manager_interface,
|
498
|
+
official_method => new_method
|
499
|
+
parser.send official_method, method_argument
|
500
|
+
end
|
501
|
+
it "should translate the :message_received method call when a method_delegation_map is given" do
|
502
|
+
official_method, new_method = :message_received, :wuzup_new_message_YO!
|
503
|
+
method_argument = :message_message_message_message
|
504
|
+
mock_manager_interface = flexmock "ManagerInterface which receives callbacks"
|
505
|
+
mock_manager_interface.should_receive(new_method).once.with(method_argument).and_return
|
506
|
+
parser = Adhearsion::VoIP::Asterisk::Manager::DelegatingAsteriskManagerInterfaceLexer.new mock_manager_interface,
|
507
|
+
official_method => new_method
|
508
|
+
parser.send official_method, method_argument
|
509
|
+
end
|
510
|
+
it "should translate the :syntax_error_encountered method call when a method_delegation_map is given" do
|
511
|
+
official_method, new_method = :error_received, :zomgs_ERROR!
|
512
|
+
method_argument = :errrrrrr
|
513
|
+
mock_manager_interface = flexmock "ManagerInterface which receives callbacks"
|
514
|
+
mock_manager_interface.should_receive(new_method).once.with(method_argument).and_return
|
515
|
+
parser = Adhearsion::VoIP::Asterisk::Manager::DelegatingAsteriskManagerInterfaceLexer.new mock_manager_interface,
|
516
|
+
official_method => new_method
|
517
|
+
parser.send official_method, method_argument
|
518
|
+
end
|
519
|
+
|
520
|
+
it "should translate all method calls when a comprehensive method_delegation_map is given" do
|
521
|
+
method_delegation_map = {
|
522
|
+
:error_received => :here_is_an_error,
|
523
|
+
:message_received => :here_is_a_message,
|
524
|
+
:syntax_error_encountered => :here_is_a_syntax_error
|
525
|
+
}
|
526
|
+
mock_manager_interface = flexmock "ManagerInterface which receives callbacks"
|
527
|
+
method_delegation_map.each_pair do |old_method,new_method|
|
528
|
+
mock_manager_interface.should_receive(new_method).once.with(old_method).and_return
|
529
|
+
end
|
530
|
+
parser = Adhearsion::VoIP::Asterisk::Manager::DelegatingAsteriskManagerInterfaceLexer.new mock_manager_interface, method_delegation_map
|
531
|
+
method_delegation_map.each_pair do |old_method, new_method|
|
532
|
+
parser.send(old_method, old_method)
|
533
|
+
end
|
534
|
+
end
|
535
|
+
end
|
536
|
+
|
537
|
+
describe "ActionManagerInterfaceConnection" do
|
538
|
+
it "should notify its associated ManagerInterface when a new message is received"
|
539
|
+
it "should notify its associated ManagerInterface when a new event is received"
|
540
|
+
it "should notify its associated ManagerInterface when a new error is received"
|
541
|
+
end
|
542
|
+
|
543
|
+
describe "EventManagerInterfaceConnection" do
|
544
|
+
it "should notify its associated ManagerInterface when a new message is received"
|
545
|
+
it "should notify its associated ManagerInterface when a new event is received"
|
546
|
+
it "should notify its associated ManagerInterface when a new error is received"
|
547
|
+
it "should stop gracefully by allowing the Queue to finish writing to the Theatre"
|
548
|
+
it "should stop forcefully by not allowing the Queue to finish writing to the Theatre"
|
549
|
+
end
|