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.
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