adhearsion 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. data/.gitignore +10 -0
  2. data/CHANGELOG +8 -0
  3. data/README.markdown +33 -0
  4. data/Rakefile +28 -68
  5. data/adhearsion.gemspec +19 -133
  6. data/app_generators/ahn/templates/Gemfile +0 -4
  7. data/app_generators/ahn/templates/components/disabled/restful_rpc/spec/restful_rpc_spec.rb +4 -16
  8. data/lib/adhearsion/cli.rb +17 -0
  9. data/lib/adhearsion/component_manager/component_tester.rb +1 -3
  10. data/lib/adhearsion/component_manager/spec_framework.rb +4 -10
  11. data/lib/adhearsion/foundation/object.rb +10 -0
  12. data/lib/adhearsion/version.rb +1 -1
  13. data/spec/ahn_command_spec.rb +284 -0
  14. data/spec/component_manager_spec.rb +292 -0
  15. data/spec/constants_spec.rb +8 -0
  16. data/spec/drb_spec.rb +65 -0
  17. data/spec/fixtures/dialplan.rb +3 -0
  18. data/spec/foundation/event_socket_spec.rb +168 -0
  19. data/spec/host_definitions_spec.rb +79 -0
  20. data/spec/initialization_spec.rb +163 -0
  21. data/spec/initializer/configuration_spec.rb +270 -0
  22. data/spec/initializer/loading_spec.rb +149 -0
  23. data/spec/initializer/paths_spec.rb +74 -0
  24. data/spec/logging_spec.rb +86 -0
  25. data/spec/relationship_properties_spec.rb +54 -0
  26. data/spec/silence.rb +10 -0
  27. data/spec/spec_helper.rb +101 -0
  28. data/spec/voip/asterisk/agi_server_spec.rb +473 -0
  29. data/spec/voip/asterisk/ami/ami_spec.rb +549 -0
  30. data/spec/voip/asterisk/ami/lexer/ami_fixtures.yml +30 -0
  31. data/spec/voip/asterisk/ami/lexer/lexer_story +291 -0
  32. data/spec/voip/asterisk/ami/lexer/lexer_story.rb +241 -0
  33. data/spec/voip/asterisk/ami/lexer/story_helper.rb +124 -0
  34. data/spec/voip/asterisk/ami/old_tests.rb +204 -0
  35. data/spec/voip/asterisk/ami/super_manager/super_manager_story +25 -0
  36. data/spec/voip/asterisk/ami/super_manager/super_manager_story.rb +15 -0
  37. data/spec/voip/asterisk/ami/super_manager/super_manager_story_helper.rb +5 -0
  38. data/spec/voip/asterisk/commands_spec.rb +2179 -0
  39. data/spec/voip/asterisk/config_file_generators/agents_spec.rb +251 -0
  40. data/spec/voip/asterisk/config_file_generators/queues_spec.rb +323 -0
  41. data/spec/voip/asterisk/config_file_generators/voicemail_spec.rb +306 -0
  42. data/spec/voip/asterisk/config_manager_spec.rb +127 -0
  43. data/spec/voip/asterisk/menu_command/calculated_match_spec.rb +109 -0
  44. data/spec/voip/asterisk/menu_command/matchers_spec.rb +97 -0
  45. data/spec/voip/call_routing_spec.rb +125 -0
  46. data/spec/voip/dialplan_manager_spec.rb +468 -0
  47. data/spec/voip/dsl/dialing_dsl_spec.rb +270 -0
  48. data/spec/voip/dsl/dispatcher_spec.rb +82 -0
  49. data/spec/voip/dsl/dispatcher_spec_helper.rb +45 -0
  50. data/spec/voip/dsl/parser_spec.rb +69 -0
  51. data/spec/voip/freeswitch/basic_connection_manager_spec.rb +39 -0
  52. data/spec/voip/freeswitch/inbound_connection_manager_spec.rb +39 -0
  53. data/spec/voip/freeswitch/oes_server_spec.rb +9 -0
  54. data/spec/voip/numerical_string_spec.rb +61 -0
  55. data/spec/voip/phone_number_spec.rb +45 -0
  56. data/theatre-spec/dsl_examples/dynamic_stomp.rb +7 -0
  57. data/theatre-spec/dsl_examples/simple_before_call.rb +7 -0
  58. data/theatre-spec/dsl_spec.rb +43 -0
  59. data/theatre-spec/invocation_spec.rb +167 -0
  60. data/theatre-spec/namespace_spec.rb +125 -0
  61. data/theatre-spec/spec_helper.rb +37 -0
  62. data/theatre-spec/spec_helper_spec.rb +28 -0
  63. data/theatre-spec/theatre_class_spec.rb +150 -0
  64. 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