eric-adhearsion 0.7.999 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (150) hide show
  1. data/CHANGELOG +8 -2
  2. data/EVENTS +11 -0
  3. data/Rakefile +96 -24
  4. data/adhearsion.gemspec +148 -0
  5. data/app_generators/ahn/ahn_generator.rb +24 -9
  6. data/app_generators/ahn/templates/.ahnrc +25 -3
  7. data/app_generators/ahn/templates/Rakefile +22 -2
  8. data/app_generators/ahn/templates/components/ami_remote/ami_remote.rb +15 -0
  9. data/app_generators/ahn/templates/components/disabled/HOW_TO_ENABLE +7 -0
  10. data/app_generators/ahn/templates/components/disabled/stomp_gateway/README.markdown +47 -0
  11. data/app_generators/ahn/templates/components/disabled/stomp_gateway/config.yml +12 -0
  12. data/app_generators/ahn/templates/components/disabled/stomp_gateway/stomp_gateway.rb +34 -0
  13. data/app_generators/ahn/templates/components/simon_game/{lib/simon_game.rb → simon_game.rb} +14 -19
  14. data/app_generators/ahn/templates/config/startup.rb +3 -6
  15. data/app_generators/ahn/templates/dialplan.rb +2 -3
  16. data/app_generators/ahn/templates/events.rb +32 -0
  17. data/bin/jahn +10 -0
  18. data/examples/asterisk_manager_interface/standalone.rb +51 -0
  19. data/lib/adhearsion.rb +17 -11
  20. data/lib/adhearsion/cli.rb +141 -24
  21. data/lib/adhearsion/component_manager.rb +169 -238
  22. data/lib/adhearsion/component_manager/component_tester.rb +55 -0
  23. data/lib/adhearsion/component_manager/spec_framework.rb +24 -0
  24. data/lib/adhearsion/events_support.rb +84 -0
  25. data/lib/adhearsion/{core_extensions → foundation}/all.rb +0 -0
  26. data/lib/adhearsion/{blank_slate.rb → foundation/blank_slate.rb} +0 -0
  27. data/lib/adhearsion/{core_extensions → foundation}/custom_daemonizer.rb +0 -0
  28. data/lib/adhearsion/foundation/event_socket.rb +203 -0
  29. data/lib/adhearsion/foundation/future_resource.rb +36 -0
  30. data/lib/adhearsion/{core_extensions → foundation}/global.rb +0 -0
  31. data/lib/adhearsion/{core_extensions → foundation}/metaprogramming.rb +0 -0
  32. data/lib/adhearsion/foundation/numeric.rb +13 -0
  33. data/lib/adhearsion/foundation/pseudo_guid.rb +10 -0
  34. data/lib/adhearsion/{core_extensions → foundation}/relationship_properties.rb +2 -0
  35. data/lib/adhearsion/foundation/string.rb +26 -0
  36. data/lib/adhearsion/foundation/synchronized_hash.rb +96 -0
  37. data/lib/adhearsion/{core_extensions → foundation}/thread_safety.rb +0 -0
  38. data/lib/adhearsion/host_definitions.rb +5 -1
  39. data/lib/adhearsion/initializer.rb +229 -73
  40. data/lib/adhearsion/initializer/asterisk.rb +33 -11
  41. data/lib/adhearsion/initializer/configuration.rb +58 -6
  42. data/lib/adhearsion/initializer/database.rb +3 -46
  43. data/lib/adhearsion/initializer/drb.rb +9 -3
  44. data/lib/adhearsion/initializer/freeswitch.rb +3 -3
  45. data/lib/adhearsion/initializer/rails.rb +1 -1
  46. data/lib/adhearsion/tasks.rb +2 -1
  47. data/lib/adhearsion/tasks/deprecations.rb +59 -0
  48. data/lib/adhearsion/version.rb +3 -3
  49. data/lib/adhearsion/voip/asterisk.rb +2 -2
  50. data/lib/adhearsion/voip/asterisk/agi_server.rb +9 -6
  51. data/lib/adhearsion/voip/asterisk/commands.rb +106 -4
  52. data/lib/adhearsion/voip/asterisk/manager_interface.rb +562 -0
  53. data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rb +1754 -0
  54. data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rl.rb +286 -0
  55. data/lib/adhearsion/voip/asterisk/manager_interface/ami_messages.rb +78 -0
  56. data/lib/adhearsion/voip/asterisk/manager_interface/ami_protocol_lexer_machine.rl +87 -0
  57. data/lib/adhearsion/voip/asterisk/super_manager.rb +19 -0
  58. data/lib/adhearsion/voip/call.rb +51 -2
  59. data/lib/adhearsion/voip/dial_plan.rb +74 -61
  60. data/lib/adhearsion/voip/dsl/dialing_dsl.rb +1 -1
  61. data/lib/adhearsion/voip/dsl/dialplan/parser.rb +2 -6
  62. data/lib/adhearsion/voip/dsl/numerical_string.rb +2 -2
  63. data/lib/adhearsion/voip/freeswitch/oes_server.rb +2 -2
  64. data/lib/theatre.rb +151 -0
  65. data/lib/theatre/README.markdown +64 -0
  66. data/lib/theatre/callback_definition_loader.rb +84 -0
  67. data/lib/theatre/guid.rb +23 -0
  68. data/lib/theatre/invocation.rb +121 -0
  69. data/lib/theatre/namespace_manager.rb +153 -0
  70. data/lib/theatre/version.rb +2 -0
  71. metadata +63 -138
  72. data/Manifest.txt +0 -149
  73. data/README.txt +0 -6
  74. data/ahn_generators/component/USAGE +0 -5
  75. data/ahn_generators/component/component_generator.rb +0 -57
  76. data/ahn_generators/component/templates/configuration.rb +0 -0
  77. data/ahn_generators/component/templates/lib/lib.rb.erb +0 -3
  78. data/ahn_generators/component/templates/test/test.rb.erb +0 -12
  79. data/ahn_generators/component/templates/test/test_helper.rb +0 -14
  80. data/app_generators/ahn/templates/components/simon_game/configuration.rb +0 -0
  81. data/app_generators/ahn/templates/components/simon_game/test/test_helper.rb +0 -14
  82. data/app_generators/ahn/templates/components/simon_game/test/test_simon_game.rb +0 -31
  83. data/lib/adhearsion/core_extensions/array.rb +0 -0
  84. data/lib/adhearsion/core_extensions/guid.rb +0 -5
  85. data/lib/adhearsion/core_extensions/hash.rb +0 -0
  86. data/lib/adhearsion/core_extensions/numeric.rb +0 -4
  87. data/lib/adhearsion/core_extensions/proc.rb +0 -0
  88. data/lib/adhearsion/core_extensions/pseudo_uuid.rb +0 -11
  89. data/lib/adhearsion/core_extensions/publishable.rb +0 -73
  90. data/lib/adhearsion/core_extensions/string.rb +0 -26
  91. data/lib/adhearsion/core_extensions/thread.rb +0 -13
  92. data/lib/adhearsion/core_extensions/time.rb +0 -0
  93. data/lib/adhearsion/distributed/gateways/dbus_gateway.rb +0 -0
  94. data/lib/adhearsion/distributed/gateways/osa_gateway.rb +0 -0
  95. data/lib/adhearsion/distributed/gateways/rest_gateway.rb +0 -9
  96. data/lib/adhearsion/distributed/gateways/soap_gateway.rb +0 -9
  97. data/lib/adhearsion/distributed/gateways/xmlrpc_gateway.rb +0 -9
  98. data/lib/adhearsion/distributed/peer_finder.rb +0 -0
  99. data/lib/adhearsion/distributed/remote_cli.rb +0 -0
  100. data/lib/adhearsion/hooks.rb +0 -57
  101. data/lib/adhearsion/initializer/paths.rb +0 -55
  102. data/lib/adhearsion/services/scheduler.rb +0 -5
  103. data/lib/adhearsion/voip/asterisk/ami.rb +0 -147
  104. data/lib/adhearsion/voip/asterisk/ami/actions.rb +0 -238
  105. data/lib/adhearsion/voip/asterisk/ami/machine.rb +0 -871
  106. data/lib/adhearsion/voip/asterisk/ami/machine.rl +0 -109
  107. data/lib/adhearsion/voip/asterisk/ami/parser.rb +0 -262
  108. data/script/destroy +0 -14
  109. data/script/generate +0 -14
  110. data/spec/fixtures/dialplan.rb +0 -3
  111. data/spec/initializer/test_configuration.rb +0 -267
  112. data/spec/initializer/test_loading.rb +0 -162
  113. data/spec/initializer/test_paths.rb +0 -43
  114. data/spec/silence.rb +0 -10
  115. data/spec/test_ahn_command.rb +0 -149
  116. data/spec/test_code_quality.rb +0 -87
  117. data/spec/test_component_manager.rb +0 -97
  118. data/spec/test_constants.rb +0 -8
  119. data/spec/test_drb.rb +0 -104
  120. data/spec/test_helper.rb +0 -94
  121. data/spec/test_hooks.rb +0 -37
  122. data/spec/test_host_definitions.rb +0 -79
  123. data/spec/test_initialization.rb +0 -105
  124. data/spec/test_logging.rb +0 -80
  125. data/spec/test_relationship_properties.rb +0 -54
  126. data/spec/voip/asterisk/ami_response_definitions.rb +0 -23
  127. data/spec/voip/asterisk/config_file_generators/test_agents.rb +0 -253
  128. data/spec/voip/asterisk/config_file_generators/test_queues.rb +0 -325
  129. data/spec/voip/asterisk/config_file_generators/test_voicemail.rb +0 -306
  130. data/spec/voip/asterisk/menu_command/test_calculated_match.rb +0 -111
  131. data/spec/voip/asterisk/menu_command/test_matchers.rb +0 -98
  132. data/spec/voip/asterisk/mock_ami_server.rb +0 -176
  133. data/spec/voip/asterisk/test_agi_server.rb +0 -451
  134. data/spec/voip/asterisk/test_ami.rb +0 -227
  135. data/spec/voip/asterisk/test_commands.rb +0 -2006
  136. data/spec/voip/asterisk/test_config_manager.rb +0 -129
  137. data/spec/voip/dsl/dispatcher_spec_helper.rb +0 -45
  138. data/spec/voip/dsl/test_dialing_dsl.rb +0 -268
  139. data/spec/voip/dsl/test_dispatcher.rb +0 -82
  140. data/spec/voip/dsl/test_parser.rb +0 -87
  141. data/spec/voip/freeswitch/test_basic_connection_manager.rb +0 -39
  142. data/spec/voip/freeswitch/test_inbound_connection_manager.rb +0 -39
  143. data/spec/voip/freeswitch/test_oes_server.rb +0 -9
  144. data/spec/voip/test_call_routing.rb +0 -127
  145. data/spec/voip/test_dialplan_manager.rb +0 -372
  146. data/spec/voip/test_numerical_string.rb +0 -48
  147. data/spec/voip/test_phone_number.rb +0 -36
  148. data/test/test_ahn_generator.rb +0 -59
  149. data/test/test_component_generator.rb +0 -52
  150. data/test/test_generator_helper.rb +0 -20
@@ -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
- }
@@ -1,2006 +0,0 @@
1
- require File.dirname(__FILE__) + "/../../test_helper"
2
- require 'adhearsion/voip/menu_state_machine/menu_class'
3
- require 'adhearsion/voip/menu_state_machine/menu_builder'
4
-
5
- context 'Asterisk VoIP Commands' do
6
- include DialplanCommandTestHelpers
7
-
8
- test "a call can write back to the PBX" do
9
- message = 'oh hai'
10
- mock_call.write message
11
- pbx_should_have_been_sent message
12
- end
13
- end
14
- context 'hangup command' do
15
- include DialplanCommandTestHelpers
16
-
17
- test "hanging up a call succesfully writes HANGUP back to the PBX and a success resopnse is returned" do
18
- pbx_should_respond_with_success
19
- response = mock_call.hangup
20
- pbx_should_have_been_sent 'HANGUP'
21
- response.should.equal pbx_success_response
22
- end
23
- end
24
-
25
- context 'interruptable_play command' do
26
-
27
- include DialplanCommandTestHelpers
28
-
29
- test 'should return a string for the digit that was pressed' do
30
- digits = [?0, ?1, ?#, ?*, ?9]
31
- file = "file_doesnt_matter"
32
- digits.each { |digit| pbx_should_respond_with_success digit }
33
- digits.map { |digit| mock_call.send(:interruptable_play, file) }.should == digits.map(&:chr)
34
- end
35
-
36
- test "should return nil if no digit was pressed" do
37
- pbx_should_respond_with_success 0
38
- mock_call.send(:interruptable_play, 'foobar').should.equal nil
39
- end
40
-
41
- test "should play a series of files, stopping the series when a digit is played" do
42
- stubbed_keypad_input = [0, 0, ?3]
43
- stubbed_keypad_input.each do |digit|
44
- pbx_should_respond_with_success digit
45
- end
46
-
47
- files = (100..105).map(&:to_s)
48
- mock_call.send(:interruptable_play, *files).should == '3'
49
- end
50
-
51
- end
52
-
53
- context 'wait_for_digit command' do
54
-
55
- include DialplanCommandTestHelpers
56
-
57
- test 'should return a string for the digit that was pressed' do
58
- digits = [?0, ?1, ?#, ?*, ?9]
59
- digits.each { |digit| pbx_should_respond_with_success digit }
60
- digits.map { |digit| mock_call.send(:wait_for_digit) }.should == digits.map(&:chr)
61
- end
62
-
63
- test "the timeout given must be converted to milliseconds" do
64
- pbx_should_respond_with_success 0
65
- mock_call.send(:wait_for_digit, 1)
66
- output.messages.first.ends_with?('1000').should.equal true
67
- end
68
- end
69
-
70
- context 'answer' do
71
- include DialplanCommandTestHelpers
72
-
73
- test 'should send ANSWER over the AGI socket' do
74
- mock_call.answer
75
- pbx_should_have_been_sent 'ANSWER'
76
- end
77
-
78
- end
79
-
80
- context 'execute' do
81
- include DialplanCommandTestHelpers
82
-
83
- test 'execute writes exec and app name to the PBX' do
84
- pbx_should_respond_with_success
85
- assert_success mock_call.execute(:foo)
86
- pbx_should_have_been_sent 'EXEC foo '
87
- end
88
-
89
- test 'execute returns false if the command was not executed successfully by the PBX' do
90
- pbx_should_respond_with_failure
91
- assert !mock_call.execute(:foo), "execute should have failed"
92
- end
93
-
94
- test 'execute can accept arguments after the app name which get translated into pipe-delimited arguments to the PBX' do
95
- pbx_should_respond_with_success
96
- mock_call.execute :foo, 'bar', 'baz', 'hi'
97
- pbx_should_have_been_sent 'EXEC foo bar|baz|hi'
98
- end
99
- end
100
-
101
- context 'play command' do
102
- include DialplanCommandTestHelpers
103
-
104
- test 'passing a single string to play results in the playback application being executed with that file name on the PBX' do
105
- pbx_should_respond_with_success
106
- audio_file = "cents-per-minute"
107
- mock_call.play audio_file
108
- pbx_was_asked_to_play audio_file
109
- end
110
-
111
- test 'multiple strings can be passed to play, causing multiple playback commands to be issued' do
112
- 2.times do
113
- pbx_should_respond_with_success
114
- end
115
- audio_files = ["cents-per-minute", 'o-hai']
116
- mock_call.play(*audio_files)
117
- pbx_was_asked_to_play(*audio_files)
118
- end
119
-
120
- test 'If a number is passed to play(), the saynumber application is executed with the number as an argument' do
121
- pbx_should_respond_with_success
122
- mock_call.play 123
123
- pbx_was_asked_to_play_number(123)
124
- end
125
-
126
- test 'if a string representation of a number is passed to play(), the saynumber application is executed with the number as an argument' do
127
- pbx_should_respond_with_success
128
- mock_call.play '123'
129
- pbx_was_asked_to_play_number(123)
130
- end
131
-
132
- test 'If a Time is passed to play(), the SayUnixTime application will be executed with the time since the UNIX epoch in seconds as an argument' do
133
- time = Time.parse("12/5/2000")
134
- pbx_should_respond_with_success
135
- mock_call.play time
136
- pbx_was_asked_to_play_time(time.to_i)
137
- end
138
-
139
- disabled_test 'If a string matching dollars and (optionally) cents is passed to play(), a series of command will be executed to read the dollar amount' do
140
- #TODO: I think we should not have this be part of play(). Too much functionality in one method. Too much overloading. When we want to support multiple
141
- # currencies, it'll be completely unwieldy. I'd suggest play_currency as a separate method. - Chad
142
- end
143
- end
144
-
145
- context 'input command' do
146
-
147
- include DialplanCommandTestHelpers
148
-
149
- # pbx_should_respond_with_successful_background_response
150
- # pbx_should_respond_with_a_wait_for_digit_timeout
151
-
152
- test 'should raise an error when the number of digits expected is -1 (this is deprecated behavior)' do
153
- the_following_code {
154
- mock_call.input(-1)
155
- }.should.raise ArgumentError
156
- end
157
-
158
- test 'input() calls wait_for_digit the specified number of times (when no sound files are given)' do
159
- # mock_call.should_receive(:interruptable_play).never
160
- mock_call.should_receive(:wait_for_digit).times(4).and_return('1', '2', '3', '4')
161
- mock_call.input(4).should == '1234'
162
- end
163
-
164
- test 'should execute wait_for_digit if no digit is pressed during interruptable_play' do
165
- sound_files = %w[one two three]
166
- mock_call.should_receive(:interruptable_play).once.with(*sound_files).and_return nil
167
- mock_call.should_receive(:wait_for_digit).once.and_throw :digit_request
168
- should_throw(:digit_request) { mock_call.input(10, :play => sound_files) }
169
- end
170
-
171
- test 'should default the :accept_key to "#" when unlimited digits are to be collected' do
172
- mock_call.should_receive(:wait_for_digit).times(2).and_return '*', '#'
173
- mock_call.input.should == '*'
174
- end
175
-
176
- test 'should raise an exception when unlimited digits are to be collected and :accept_key => false' do
177
- the_following_code {
178
- mock_call.input(:accept_key => false)
179
- }.should.raise ArgumentError
180
- end
181
-
182
- test 'when :accept_key is false and input() is collecting a finite number of digits, it should allow all DTMFs' do
183
- all_digits = %w[0 1 2 3 # * 4 5 6 7 8 9]
184
- mock_call.should_receive(:wait_for_digit).times(all_digits.size).and_return(*all_digits)
185
- the_following_code {
186
- mock_call.input(all_digits.size, :accept_key => false)
187
- }.should.not.raise ArgumentError
188
- end
189
-
190
- test 'passes wait_for_digit the :timeout option when one is given' do
191
- mock_call.should_receive(:interruptable_play).never
192
- mock_call.should_receive(:wait_for_digit).twice.and_return '1', '2'
193
- mock_call.input(2, :timeout => 1.minute).should == '12'
194
- end
195
-
196
- test 'executes interruptable_play() with all of the files given to :play' do
197
- sound_files = %w[foo bar qaz]
198
- mock_call.should_receive(:interruptable_play).once.with(*sound_files).and_return '#'
199
- mock_call.should_receive(:wait_for_digit).once.and_return '*'
200
- mock_call.input(2, :play => sound_files).should == '#*'
201
- end
202
-
203
- test 'pressing the terminating key before any other digits returns an empty string' do
204
- mock_call.should_receive(:wait_for_digit).once.and_return '*'
205
- mock_call.input(:accept_key => '*').should == ''
206
- end
207
-
208
- test 'should execute wait_for_digit first if no sound files are given' do
209
- mock_call.should_receive(:interruptable_play).never
210
- mock_call.should_receive(:wait_for_digit).once.and_throw :digit_request
211
- should_throw(:digit_request) { mock_call.input(1) }
212
- end
213
-
214
- test "Input timing out when digits are pressed returns only the collected digits" do
215
- mock_call.should_receive(:wait_for_digit).twice.and_return '5', nil
216
- mock_call.input(9, :timeout => 1.day).should == '5'
217
- end
218
-
219
- end
220
-
221
- context "The variable() command" do
222
-
223
- include DialplanCommandTestHelpers
224
-
225
- test "should call set_variable for every Hash-key argument given" do
226
- args = [:ohai, "ur_home_erly"]
227
- mock_call.should_receive(:set_variable).once.with(*args)
228
- mock_call.variable Hash[*args]
229
- end
230
-
231
- test "should call set_variable for every Hash-key argument given" do
232
- many_args = { :a => :b, :c => :d, :e => :f, :g => :h}
233
- mock_call.should_receive(:set_variable).times(many_args.size)
234
- mock_call.variable many_args
235
- end
236
-
237
- test "should call get_variable for every String given" do
238
- variables = ["foo", "bar", :qaz, :qwerty, :baz]
239
- variables.each do |var|
240
- mock_call.should_receive(:get_variable).once.with(var).and_return("X")
241
- end
242
- mock_call.variable(*variables)
243
- end
244
-
245
- test "should NOT return an Array when just one arg is given" do
246
- mock_call.should_receive(:get_variable).once.and_return "lol"
247
- mock_call.variable(:foo).should.not.be.kind_of Array
248
- end
249
-
250
- test "should raise an ArgumentError when a Hash and normal args are given" do
251
- the_following_code {
252
- mock_call.variable 5,4,3,2,1, :foo => :bar
253
- }.should.raise ArgumentError
254
- end
255
-
256
- end
257
-
258
- context "the set_variable method" do
259
-
260
- include DialplanCommandTestHelpers
261
-
262
- test "variables and values are properly quoted" do
263
- mock_call.should_receive(:raw_response).once.with 'SET VARIABLE foo "i can \\" has ruby?"'
264
- mock_call.set_variable 'foo', 'i can " has ruby?'
265
- end
266
-
267
- test "to_s() is effectively called on both the key and the value" do
268
- mock_call.should_receive(:raw_response).once.with 'SET VARIABLE QAZ "QWERTY"'
269
- mock_call.set_variable :QAZ, :QWERTY
270
- end
271
-
272
- end
273
-
274
- context 'the voicemail command' do
275
-
276
- include DialplanCommandTestHelpers
277
-
278
- test 'should not send the context name when none is given' do
279
- mailbox_number = 123
280
- mock_call.should_receive(:execute).once.with('voicemail', 123, '').and_throw :sent_voicemail!
281
- should_throw(:sent_voicemail!) { mock_call.voicemail 123 }
282
- end
283
-
284
- test 'should send the context name when one is given' do
285
- mailbox_number, context_name = 333, 'doesntmatter'
286
- mock_call.should_receive(:execute).once.with('voicemail', "#{mailbox_number}@#{context_name}", '').and_throw :sent_voicemail!
287
- should_throw(:sent_voicemail!) { mock_call.voicemail(context_name => mailbox_number) }
288
- end
289
-
290
- test 'should pass in the s option if :skip => true' do
291
- mailbox_number = '012'
292
- mock_call.should_receive(:execute).once.with('voicemail', mailbox_number, 's').and_throw :sent_voicemail!
293
- should_throw(:sent_voicemail!) { mock_call.voicemail(mailbox_number, :skip => true) }
294
- end
295
-
296
- test 'should combine mailbox numbers with the context name given when both are given' do
297
- context = "lolcats"
298
- mailboxes = [1,2,3,4,5]
299
- mailboxes_with_context = mailboxes.map { |mailbox| "#{mailbox}@#{context}"}
300
- mock_call.should_receive(:execute).once.with('voicemail', mailboxes_with_context.join('&'), '')
301
- mock_call.voicemail context => mailboxes
302
- end
303
-
304
- test 'should raise an argument error if the mailbox number is not numerical' do
305
- the_following_code {
306
- mock_call.voicemail :foo => "bar"
307
- }.should.raise ArgumentError
308
- end
309
-
310
- test 'should raise an argument error if too many arguments are supplied' do
311
- the_following_code {
312
- mock_call.voicemail "wtfisthisargument", :context_name => 123, :greeting => :busy
313
- }.should.raise ArgumentError
314
- end
315
-
316
- test 'should raise an ArgumentError if multiple context names are given' do
317
- the_following_code {
318
- mock_call.voicemail :one => [1,2,3], :two => [11,22,33]
319
- }.should.raise ArgumentError
320
- end
321
-
322
- test "should raise an ArgumentError when the :greeting value isn't recognized" do
323
- the_following_code {
324
- mock_call.voicemail :context_name => 123, :greeting => :zomgz
325
- }.should.raise ArgumentError
326
- end
327
-
328
- test 'should pass in the u option if :greeting => :unavailable' do
329
- mailbox_number = '776'
330
- mock_call.should_receive(:execute).once.with('voicemail', mailbox_number, 'u').and_throw :sent_voicemail!
331
- should_throw(:sent_voicemail!) { mock_call.voicemail(mailbox_number, :greeting => :unavailable) }
332
- end
333
-
334
- test 'should pass in both the skip and greeting options if both are supplied' do
335
- mailbox_number = '4'
336
- mock_call.should_receive(:execute).once.with('voicemail', mailbox_number, 'u').and_throw :sent_voicemail!
337
- should_throw(:sent_voicemail!) { mock_call.voicemail(mailbox_number, :greeting => :unavailable) }
338
- end
339
-
340
- test 'should raise an ArgumentError if mailbox_number is blank?()' do
341
- the_following_code {
342
- mock_call.voicemail ''
343
- }.should.raise ArgumentError
344
-
345
- the_following_code {
346
- mock_call.voicemail nil
347
- }.should.raise ArgumentError
348
- end
349
-
350
- test 'should pass in the b option if :gretting => :busy' do
351
- mailbox_number = '1'
352
- mock_call.should_receive(:execute).once.with('voicemail', mailbox_number, 'b').and_throw :sent_voicemail!
353
- should_throw(:sent_voicemail!) { mock_call.voicemail(mailbox_number, :greeting => :busy) }
354
- end
355
-
356
- test 'should return true if VMSTATUS == "SUCCESS"' do
357
- mock_call.should_receive(:execute).once
358
- mock_call.should_receive(:variable).once.with('VMSTATUS').and_return "SUCCESS"
359
- mock_call.voicemail(3).should.equal true
360
- end
361
-
362
- test 'should return false if VMSTATUS == "USEREXIT"' do
363
- mock_call.should_receive(:execute).once
364
- mock_call.should_receive(:variable).once.with('VMSTATUS').and_return "USEREXIT"
365
- mock_call.voicemail(2).should.equal false
366
- end
367
-
368
- test 'should return nil if VMSTATUS == "FAILED"' do
369
- mock_call.should_receive(:execute).once
370
- mock_call.should_receive(:variable).once.with('VMSTATUS').and_return "FAILED"
371
- mock_call.voicemail(2).should.equal nil
372
- end
373
-
374
- end
375
-
376
- context 'The voicemail_main command' do
377
-
378
- include DialplanCommandTestHelpers
379
-
380
- test "should not pass in the context or the delimiting @ sign if you don't supply one"
381
-
382
- test "the :folder Hash key argument should wrap the value in a()" do
383
- folder = "foobar"
384
- mailbox = 81
385
- mock_call.should_receive(:execute).once.with("VoiceMailMain", "#{mailbox}","a(#{folder})")
386
- mock_call.voicemail_main :mailbox => mailbox, :folder => folder
387
- end
388
-
389
- test ':authenticate should pass in the "s" option if given false' do
390
- mailbox = 333
391
- mock_call.should_receive(:execute).once.with("VoiceMailMain", "#{mailbox}","s")
392
- mock_call.voicemail_main :mailbox => mailbox, :authenticate => false
393
- end
394
-
395
- test ':authenticate should pass in the s option if given false' do
396
- mailbox = 55
397
- mock_call.should_receive(:execute).once.with("VoiceMailMain", "#{mailbox}")
398
- mock_call.voicemail_main :mailbox => mailbox, :authenticate => true
399
- end
400
-
401
- test 'should not pass any flags only a mailbox is given' do
402
- mailbox = "1"
403
- mock_call.should_receive(:execute).once.with("VoiceMailMain", "#{mailbox}")
404
- mock_call.voicemail_main :mailbox => mailbox
405
- end
406
-
407
- test 'when given no mailbox or context an empty string should be passed to execute as the first argument' do
408
- mock_call.should_receive(:execute).once.with("VoiceMailMain", "", "s")
409
- mock_call.voicemail_main :authenticate => false
410
- end
411
-
412
- test 'should properly concatenate the options when given multiple ones' do
413
- folder = "ohai"
414
- mailbox = 9999
415
- mock_call.should_receive(:execute).once.with("VoiceMailMain", "#{mailbox}", "sa(#{folder})")
416
- mock_call.voicemail_main :mailbox => mailbox, :authenticate => false, :folder => folder
417
- end
418
-
419
- test 'should not require any arguments' do
420
- mock_call.should_receive(:execute).once.with("VoiceMailMain")
421
- mock_call.voicemail_main
422
- end
423
-
424
- test 'should pass in the "@context_name" part in if a :context is given and no mailbox is given' do
425
- context_name = "icanhascheezburger"
426
- mock_call.should_receive(:execute).once.with("VoiceMailMain", "@#{context_name}")
427
- mock_call.voicemail_main :context => context_name
428
- end
429
-
430
- test "should raise an exception if the folder has a space or malformed characters in it" do
431
- ["i has a space", "exclaim!", ",", ""].each do |bad_folder_name|
432
- the_following_code {
433
- mock_call.voicemail_main :mailbox => 123, :folder => bad_folder_name
434
- }.should.raise ArgumentError
435
- end
436
- end
437
-
438
- end
439
-
440
- context 'the check_voicemail command' do
441
-
442
- include DialplanCommandTestHelpers
443
-
444
- test "should simply execute voicemail_main with no arguments after warning" do
445
- flexmock(ahn_log.agi).should_receive(:warn).once.with(String)
446
- mock_call.should_receive(:voicemail_main).once.and_return :mocked_out
447
- mock_call.check_voicemail.should.equal :mocked_out
448
- end
449
-
450
- end
451
-
452
-
453
- context "The queue management abstractions" do
454
-
455
- include DialplanCommandTestHelpers
456
-
457
- test 'should not create separate objects for queues with basically the same name' do
458
- mock_call.queue('foo').should.equal mock_call.queue('foo')
459
- mock_call.queue('bar').should.equal mock_call.queue(:bar)
460
- end
461
-
462
- test "queue() should return an instance of QueueProxy" do
463
- mock_call.queue("foobar").should.be.kind_of Adhearsion::VoIP::Asterisk::Commands::QueueProxy
464
- end
465
-
466
- test "a QueueProxy should respond to join!(), members()" do
467
- %w[join! agents].each do |method|
468
- mock_call.queue('foobar').should.respond_to(method)
469
- end
470
- end
471
-
472
- test 'a QueueProxy should return a QueueAgentsListProxy when members() is called' do
473
- mock_call.queue('foobar').agents.should.be.kind_of(Adhearsion::VoIP::Asterisk::Commands::QueueProxy::QueueAgentsListProxy)
474
- end
475
-
476
- test 'join! should properly join a queue' do
477
- mock_call.should_receive(:execute).once.with("queue", "foobaz", "", '', '', '')
478
- mock_call.should_receive(:get_variable).once.with("QUEUESTATUS").and_return "FULL"
479
- mock_call.queue("foobaz").join!
480
- end
481
-
482
- test 'should return a symbol representing the result of joining the queue' do
483
- mock_call.should_receive(:get_variable).once.with("QUEUESTATUS").and_return "TIMEOUT"
484
- mock_call.queue('monkey').join!.should.equal :timeout
485
- end
486
-
487
- test 'should join a queue with a timeout properly' do
488
- mock_call.should_receive(:execute).once.with("queue", "foobaz", "", '', '', '60')
489
- mock_call.should_receive(:get_variable).once.with("QUEUESTATUS").and_return "JOINEMPTY"
490
- mock_call.queue("foobaz").join! :timeout => 1.minute
491
- end
492
-
493
- test 'should join a queue with an announcement file properly' do
494
- mock_call.should_receive(:execute).once.with("queue", "roflcopter", "", '', '', '5')
495
- mock_call.should_receive(:get_variable).once.with("QUEUESTATUS").and_return "JOINEMPTY"
496
- mock_call.queue("roflcopter").join! :timeout => 5
497
- end
498
-
499
- test 'should join a queue with allow_transfer properly' do
500
- mock_call.should_receive(:execute).once.with("queue", "roflcopter", "Tt", '', '', '')
501
- mock_call.should_receive(:get_variable).once.with("QUEUESTATUS").and_return "JOINEMPTY"
502
- mock_call.queue("roflcopter").join! :allow_transfer => :everyone
503
-
504
- mock_call.should_receive(:execute).once.with("queue", "roflcopter", "T", '', '', '')
505
- mock_call.should_receive(:get_variable).once.with("QUEUESTATUS").and_return "JOINEMPTY"
506
- mock_call.queue("roflcopter").join! :allow_transfer => :caller
507
-
508
- mock_call.should_receive(:execute).once.with("queue", "roflcopter", "t", '', '', '')
509
- mock_call.should_receive(:get_variable).once.with("QUEUESTATUS").and_return "JOINEMPTY"
510
- mock_call.queue("roflcopter").join! :allow_transfer => :agent
511
- end
512
-
513
- test 'should join a queue with allow_hangup properly' do
514
- mock_call.should_receive(:execute).once.with("queue", "roflcopter", "Hh", '', '', '')
515
- mock_call.should_receive(:get_variable).once.with("QUEUESTATUS").and_return "JOINEMPTY"
516
- mock_call.queue("roflcopter").join! :allow_hangup => :everyone
517
-
518
- mock_call.should_receive(:execute).once.with("queue", "roflcopter", "H", '', '', '')
519
- mock_call.should_receive(:get_variable).once.with("QUEUESTATUS").and_return "JOINEMPTY"
520
- mock_call.queue("roflcopter").join! :allow_hangup => :caller
521
-
522
- mock_call.should_receive(:execute).once.with("queue", "roflcopter", "h", '', '', '')
523
- mock_call.should_receive(:get_variable).once.with("QUEUESTATUS").and_return "JOINEMPTY"
524
- mock_call.queue("roflcopter").join! :allow_hangup => :agent
525
- end
526
-
527
- test 'should join a queue properly with the :play argument' do
528
- mock_call.should_receive(:execute).once.with("queue", "roflcopter", "r", '', '', '')
529
- mock_call.should_receive(:get_variable).once.with("QUEUESTATUS").and_return "JOINEMPTY"
530
- mock_call.queue("roflcopter").join! :play => :ringing
531
-
532
- mock_call.should_receive(:execute).once.with("queue", "roflcopter", "", '', '', '')
533
- mock_call.should_receive(:get_variable).once.with("QUEUESTATUS").and_return "JOINEMPTY"
534
- mock_call.queue("roflcopter").join! :play => :music
535
- end
536
-
537
- test 'joining a queue with many options specified' do
538
- mock_call.should_receive(:execute).once.with("queue", "q", "rtHh", '', '', '120')
539
- mock_call.should_receive(:get_variable).once.with("QUEUESTATUS").and_return "JOINEMPTY"
540
- mock_call.queue('q').join! :allow_transfer => :agent, :timeout => 2.minutes,
541
- :play => :ringing, :allow_hangup => :everyone
542
- end
543
-
544
- test 'join!() should raise an ArgumentError when unrecognized Hash key arguments are given' do
545
- the_following_code {
546
- mock_call.queue('iwearmysunglassesatnight').join! :misspelled => true
547
- }.should.raise ArgumentError
548
- end
549
-
550
- test 'should fetch the members with the name given to queue()' do
551
- mock_call.should_receive(:variable).once.with("QUEUE_MEMBER_COUNT(jay)").and_return 5
552
- mock_call.queue('jay').agents.size.should.equal 5
553
- end
554
-
555
- test 'should not fetch a QUEUE_MEMBER_COUNT each time count() is called when caching is enabled' do
556
- mock_call.should_receive(:variable).once.with("QUEUE_MEMBER_COUNT(sales)").and_return 0
557
- 10.times do
558
- mock_call.queue('sales').agents(:cache => true).size
559
- end
560
- end
561
-
562
- test 'should raise an argument error if the members() method receives an unrecognized symbol' do
563
- the_following_code {
564
- mock_call.queue('foobarz').agents(:cached => true) # common typo
565
- }.should.raise ArgumentError
566
- end
567
-
568
- test 'when fetching agents, it should properly split by the supported delimiters' do
569
- queue_name = "doesnt_matter"
570
- mock_call.should_receive(:get_variable).with("QUEUE_MEMBER_LIST(#{queue_name})").and_return('Agent/007,Agent/003,Zap/2')
571
- mock_call.queue(queue_name).agents(:cache => true).to_a.size.should.equal 3
572
- end
573
-
574
- test 'when fetching agents, each array index should be an instance of AgentProxy' do
575
- queue_name = 'doesnt_matter'
576
- mock_call.should_receive(:get_variable).with("QUEUE_MEMBER_LIST(#{queue_name})").and_return('Agent/007,Agent/003,Zap/2')
577
- agents = mock_call.queue(queue_name).agents(:cache => true).to_a
578
- agents.size.should > 0
579
- agents.each do |agent|
580
- agent.should.be.kind_of Adhearsion::VoIP::Asterisk::Commands::QueueProxy::AgentProxy
581
- end
582
- end
583
-
584
- test 'should properly retrieve metadata for an AgentProxy instance' do
585
- agent_id, metadata_name = '22', 'status'
586
- mock_env = flexmock "a mock ExecutionEnvironment"
587
- mock_queue = flexmock "a queue that references our mock ExecutionEnvironment", :environment => mock_env, :name => "doesntmatter"
588
- mock_env.should_receive(:variable).once.with("AGENT(#{agent_id}:#{metadata_name})")
589
- agent = Adhearsion::VoIP::Asterisk::Commands::QueueProxy::AgentProxy.new("Agent/#{agent_id}", mock_queue)
590
- agent.send(:agent_metadata, metadata_name)
591
- end
592
-
593
- test 'AgentProxy#logged_in? should return true if the "state" of an agent == LOGGEDIN' do
594
- mock_env = flexmock "a mock ExecutionEnvironment"
595
- mock_queue = flexmock "a queue that references our mock ExecutionEnvironment", :environment => mock_env, :name => "doesntmatter"
596
-
597
- agent = Adhearsion::VoIP::Asterisk::Commands::QueueProxy::AgentProxy.new('Agent/123', mock_queue)
598
- flexmock(agent).should_receive(:agent_metadata).once.with('status').and_return 'LOGGEDIN'
599
- agent.should.be.logged_in
600
-
601
- flexmock(agent).should_receive(:agent_metadata).once.with('status').and_return 'LOGGEDOUT'
602
- agent.should.not.be.logged_in
603
- end
604
-
605
- test 'the AgentProxy should populate its own "id" property to the numerical ID of the "interface" with which it was constructed' do
606
- mock_queue = flexmock :name => "doesntmatter"
607
- id = '123'
608
-
609
- agent = Adhearsion::VoIP::Asterisk::Commands::QueueProxy::AgentProxy.new("Agent/#{id}", mock_queue)
610
- agent.id.should.equal id
611
-
612
- agent = Adhearsion::VoIP::Asterisk::Commands::QueueProxy::AgentProxy.new(id, mock_queue)
613
- agent.id.should == id
614
- end
615
-
616
- test 'QueueAgentsListProxy#<<() should new the channel driver given as the argument to the system' do
617
- queue_name, agent_channel = "metasyntacticvariablesftw", "Agent/123"
618
- pbx_should_respond_with_value "ADDED"
619
- mock_call.should_receive('execute').once.with("AddQueueMember", queue_name, agent_channel, "", "", "")
620
- mock_call.queue(queue_name).agents.new agent_channel
621
- end
622
-
623
- test 'when a queue agent is dynamically added and the queue does not exist, a QueueDoesNotExistError should be raised' do
624
- mock_call.should_receive(:get_variable).once.with('AQMSTATUS').and_return('NOSUCHQUEUE')
625
- the_following_code {
626
- mock_call.queue('this_should_not_exist').agents.new 'Agent/911'
627
- }.should.raise Adhearsion::VoIP::Asterisk::Commands::QueueProxy::QueueDoesNotExistError
628
- end
629
-
630
- test 'when a queue agent is dynamiaclly added and the adding was successful, true should be returned' do
631
- mock_call.should_receive(:get_variable).once.with("AQMSTATUS").and_return("ADDED")
632
- mock_call.should_receive(:execute).once.with("AddQueueMember", "lalala", "Agent/007", "", "", "")
633
- return_value = mock_call.queue('lalala').agents.new "Agent/007"
634
- return_value.should.equal true
635
- end
636
-
637
- test 'should raise an argument when an unrecognized key is given to add()' do
638
- the_following_code {
639
- mock_call.queue('q').agents.new :foo => "bar"
640
- }.should.raise ArgumentError
641
- end
642
-
643
- test 'should execute AddQueueMember with the penalty properly' do
644
- queue_name = 'name_does_not_matter'
645
- mock_call.should_receive(:execute).once.with('AddQueueMember', queue_name, '', 10, '', '')
646
- mock_call.should_receive(:get_variable).once.with('AQMSTATUS').and_return('ADDED')
647
- mock_call.queue(queue_name).agents.new :penalty => 10
648
- end
649
-
650
- test 'should execute AddQueueMember properly when the name is given' do
651
- queue_name, agent_name = 'name_does_not_matter', 'Jay Phillips'
652
- mock_call.should_receive(:execute).once.with('AddQueueMember', queue_name, '', '', '', agent_name)
653
- mock_call.should_receive(:get_variable).once.with('AQMSTATUS').and_return('ADDED')
654
- mock_call.queue(queue_name).agents.new :name => agent_name
655
- end
656
-
657
- test 'should execute AddQueueMember properly when the name, penalty, and interface is given' do
658
- queue_name, agent_name, interface, penalty = 'name_does_not_matter', 'Jay Phillips', 'Agent/007', 4
659
- mock_call.should_receive(:execute).once.with('AddQueueMember', queue_name, interface, penalty, '', agent_name)
660
- mock_call.should_receive(:get_variable).once.with('AQMSTATUS').and_return('ADDED')
661
- mock_call.queue(queue_name).agents.new interface, :name => agent_name, :penalty => penalty
662
- end
663
-
664
- test 'should return a correct boolean for exists?()' do
665
- mock_call.should_receive(:execute).once.with("RemoveQueueMember", "kablamm", "SIP/AdhearsionQueueExistenceCheck")
666
- mock_call.should_receive(:get_variable).once.with("RQMSTATUS").and_return "NOTINQUEUE"
667
- mock_call.queue("kablamm").exists?.should.equal true
668
-
669
- mock_call.should_receive(:execute).once.with("RemoveQueueMember", "monkey", "SIP/AdhearsionQueueExistenceCheck")
670
- mock_call.should_receive(:get_variable).once.with("RQMSTATUS").and_return "NOSUCHQUEUE"
671
- mock_call.queue("monkey").exists?.should.equal false
672
- end
673
-
674
- test 'should pause an agent properly from a certain queue' do
675
- mock_call.should_receive(:get_variable).once.with("QUEUE_MEMBER_LIST(lolcats)").and_return "Agent/007,Agent/008"
676
- mock_call.should_receive(:get_variable).once.with("PQMSTATUS").and_return "PAUSED"
677
-
678
- agents = mock_call.queue('lolcats').agents :cache => true
679
- agents.last.pause!.should.equal true
680
- end
681
-
682
- test 'should pause an agent properly from a certain queue and return false when the agent did not exist' do
683
- mock_call.should_receive(:get_variable).once.with("QUEUE_MEMBER_LIST(lolcats)").and_return "Agent/007,Agent/008"
684
- mock_call.should_receive(:get_variable).once.with("PQMSTATUS").and_return "NOTFOUND"
685
- mock_call.should_receive(:execute).once.with("PauseQueueMember", 'lolcats', "Agent/008")
686
-
687
- agents = mock_call.queue('lolcats').agents :cache => true
688
- agents.last.pause!.should.equal false
689
- end
690
-
691
- test 'should pause an agent globally properly' do
692
- mock_call.should_receive(:get_variable).once.with("QUEUE_MEMBER_LIST(family)").and_return "Agent/Jay"
693
- mock_call.should_receive(:get_variable).once.with("PQMSTATUS").and_return "PAUSED"
694
- mock_call.should_receive(:execute).once.with("PauseQueueMember", nil, "Agent/Jay")
695
-
696
- mock_call.queue('family').agents.first.pause! :everywhere => true
697
- end
698
-
699
- test 'should unpause an agent properly' do
700
- queue_name = "name with spaces"
701
- mock_call.should_receive(:get_variable).once.with("QUEUE_MEMBER_LIST(#{queue_name})").and_return "Agent/Jay"
702
- mock_call.should_receive(:get_variable).once.with("UPQMSTATUS").and_return "UNPAUSED"
703
- mock_call.should_receive(:execute).once.with("UnpauseQueueMember", queue_name, "Agent/Jay")
704
-
705
- mock_call.queue(queue_name).agents.first.unpause!.should.equal true
706
- end
707
-
708
- test 'should unpause an agent globally properly' do
709
- mock_call.should_receive(:get_variable).once.with("QUEUE_MEMBER_LIST(FOO)").and_return "Agent/Tom"
710
- mock_call.should_receive(:get_variable).once.with("UPQMSTATUS").and_return "UNPAUSED"
711
- mock_call.should_receive(:execute).once.with("UnpauseQueueMember", nil, "Agent/Tom")
712
-
713
- mock_call.queue('FOO').agents.first.unpause!(:everywhere => true).should.equal true
714
- end
715
-
716
- test 'waiting_count for a queue that does exist' do
717
- mock_call.should_receive(:get_variable).once.with("QUEUE_WAITING_COUNT(q)").and_return "50"
718
- flexmock(mock_call.queue('q')).should_receive(:exists?).once.and_return true
719
- mock_call.queue('q').waiting_count.should.equal 50
720
- end
721
-
722
- test 'waiting_count for a queue that does not exist' do
723
- the_following_code {
724
- flexmock(mock_call.queue('q')).should_receive(:exists?).once.and_return false
725
- mock_call.queue('q').waiting_count
726
- }.should.raise Adhearsion::VoIP::Asterisk::Commands::QueueProxy::QueueDoesNotExistError
727
- end
728
-
729
- test 'empty? should call waiting_count' do
730
- queue = mock_call.queue 'testing_empty'
731
- flexmock(queue).should_receive(:waiting_count).once.and_return 0
732
- queue.should.be.empty
733
-
734
- queue = mock_call.queue 'testing_empty'
735
- flexmock(queue).should_receive(:waiting_count).once.and_return 99
736
- queue.should.not.be.empty
737
- end
738
-
739
- test 'any? should call waiting_count' do
740
- queue = mock_call.queue 'testing_empty'
741
- flexmock(queue).should_receive(:waiting_count).once.and_return 0
742
- queue.any?.should.equal false
743
-
744
- queue = mock_call.queue 'testing_empty'
745
- flexmock(queue).should_receive(:waiting_count).once.and_return 99
746
- queue.any?.should.equal true
747
- end
748
-
749
- test 'should remove an agent properly' do
750
- mock_call.should_receive(:get_variable).once.with("QUEUE_MEMBER_LIST(FOO)").and_return "Agent/Tom"
751
- mock_call.should_receive(:execute).once.with('RemoveQueueMember', 'FOO', 'Agent/Tom')
752
- mock_call.should_receive(:get_variable).once.with("RQMSTATUS").and_return "REMOVED"
753
- mock_call.queue('FOO').agents.first.remove!.should.equal true
754
- end
755
-
756
- test 'should remove an agent properly' do
757
- mock_call.should_receive(:get_variable).once.with("QUEUE_MEMBER_LIST(FOO)").and_return "Agent/Tom"
758
- mock_call.should_receive(:execute).once.with('RemoveQueueMember', 'FOO', 'Agent/Tom')
759
- mock_call.should_receive(:get_variable).once.with("RQMSTATUS").and_return "NOTINQUEUE"
760
- mock_call.queue('FOO').agents.first.remove!.should.equal false
761
- end
762
-
763
- test "should raise a QueueDoesNotExistError when removing an agent from a queue that doesn't exist" do
764
- mock_call.should_receive(:get_variable).once.with("QUEUE_MEMBER_LIST(cool_people)").and_return "Agent/ZeroCool"
765
- mock_call.should_receive(:execute).once.with("RemoveQueueMember", "cool_people", "Agent/ZeroCool")
766
- mock_call.should_receive(:get_variable).once.with("RQMSTATUS").and_return "NOSUCHQUEUE"
767
- the_following_code {
768
- mock_call.queue("cool_people").agents.first.remove!
769
- }.should.raise Adhearsion::VoIP::Asterisk::Commands::QueueProxy::QueueDoesNotExistError
770
- end
771
-
772
- test "should log an agent in properly with no agent id given" do
773
- mock_call.should_receive(:execute).once.with('AgentLogin', nil, 's')
774
- mock_call.queue('barrel_o_agents').agents.login!
775
- end
776
-
777
- test 'should remove "Agent/" before the agent ID given if necessary when logging an agent in' do
778
- mock_call.should_receive(:execute).once.with('AgentLogin', '007', 's')
779
- mock_call.queue('barrel_o_agents').agents.login! 'Agent/007'
780
-
781
- mock_call.should_receive(:execute).once.with('AgentLogin', '007', 's')
782
- mock_call.queue('barrel_o_agents').agents.login! '007'
783
- end
784
-
785
- test 'should add an agent silently properly' do
786
- mock_call.should_receive(:execute).once.with('AgentLogin', '007', '')
787
- mock_call.queue('barrel_o_agents').agents.login! 'Agent/007', :silent => false
788
-
789
- mock_call.should_receive(:execute).once.with('AgentLogin', '008', 's')
790
- mock_call.queue('barrel_o_agents').agents.login! 'Agent/008', :silent => true
791
- end
792
-
793
- test 'logging an agent in should raise an ArgumentError is unrecognized arguments are given' do
794
- the_following_code {
795
- mock_call.queue('ohai').agents.login! 1,2,3,4,5
796
- }.should.raise ArgumentError
797
-
798
- the_following_code {
799
- mock_call.queue('lols').agents.login! 1337, :sssssilent => false
800
- }.should.raise ArgumentError
801
-
802
- the_following_code {
803
- mock_call.queue('qwerty').agents.login! 777, 6,5,4,3,2,1, :wee => :wee
804
- }.should.raise ArgumentError
805
- end
806
-
807
- end
808
-
809
- context 'the menu() method' do
810
-
811
- include DialplanCommandTestHelpers
812
-
813
- test "should instantiate a new Menu object with only the Hash given as menu() options" do
814
- args = [1,2,3,4,5, {:timeout => 1.year, :tries => (1.0/0.0)}]
815
-
816
- flexmock(Adhearsion::VoIP::Menu).should_receive(:new).once.
817
- with(args.last).and_throw(:instantiating_menu!)
818
-
819
- should_throw(:instantiating_menu!) { mock_call.menu(*args) }
820
- end
821
-
822
- test "should jump to a context when a timeout is encountered and there is at least one exact match" do
823
- pbx_should_respond_with_successful_background_response ?5
824
- pbx_should_respond_with_successful_background_response ?4
825
- pbx_should_respond_with_a_wait_for_digit_timeout
826
-
827
- context_named_main = Adhearsion::DialPlan::DialplanContextProc.new(:main) { throw :inside_main! }
828
- context_named_other = Adhearsion::DialPlan::DialplanContextProc.new(:other) { throw :inside_other! }
829
- flexmock(mock_call).should_receive(:main).once.and_return(context_named_main)
830
- flexmock(mock_call).should_receive(:other).never
831
-
832
- should_pass_control_to_a_context_that_throws :inside_main! do
833
- mock_call.menu do |link|
834
- link.main 54
835
- link.other 543
836
- end
837
- end
838
- end
839
-
840
- test "when the 'extension' variable is changed, it should be an instance of PhoneNumber" do
841
- pbx_should_respond_with_successful_background_response ?5
842
- foobar_context = Adhearsion::DialPlan::DialplanContextProc.new(:foobar) { throw :foobar! }
843
- mock_call.should_receive(:foobar).once.and_return foobar_context
844
- should_pass_control_to_a_context_that_throws :foobar! do
845
- mock_call.menu do |link|
846
- link.foobar 5
847
- end
848
- end
849
- 5.should === mock_call.extension
850
- mock_call.extension.__real_string.should == "5"
851
- end
852
-
853
- end
854
-
855
- context 'the Menu class' do
856
-
857
- include DialplanCommandTestHelpers
858
-
859
- test "should yield a MenuBuilder when instantiated" do
860
- lambda {
861
- Adhearsion::VoIP::Menu.new do |block_argument|
862
- block_argument.should.be.kind_of Adhearsion::VoIP::MenuBuilder
863
- throw :inside_block
864
- end
865
- }.should.throw :inside_block
866
- end
867
-
868
- test "should invoke wait_for_digit instead of interruptable_play when no sound files are given" do
869
- mock_call.should_receive(:wait_for_digit).once.with(5).and_return '#'
870
- mock_call.menu { |link| link.does_not_match 3 }
871
- end
872
-
873
- test 'should invoke interruptable_play when sound files are given only for the first digit' do
874
- sound_files = %w[i like big butts and i cannot lie]
875
- timeout = 1337
876
-
877
- mock_call.should_receive(:interruptable_play).once.with(*sound_files).and_return nil
878
- mock_call.should_receive(:wait_for_digit).once.with(timeout).and_return nil
879
-
880
- mock_call.menu(sound_files, :timeout => timeout) { |link| link.qwerty 12345 }
881
- end
882
-
883
- test 'if the call to interruptable_play receives a timeout, it should execute wait_for_digit with the timeout given' do
884
- sound_files = %w[i like big butts and i cannot lie]
885
- timeout = 987
886
-
887
- mock_call.should_receive(:interruptable_play).once.with(*sound_files).and_return nil
888
- mock_call.should_receive(:wait_for_digit).with(timeout).and_return
889
-
890
- mock_call.menu(sound_files, :timeout => timeout) { |link| link.foobar 911 }
891
- end
892
-
893
- test "should work when no files are given to be played and a timeout is reached on the first digit" do
894
- timeout = 12
895
- [:on_premature_timeout, :on_failure].each do |usage_case|
896
- should_throw :got_here! do
897
- mock_call.should_receive(:wait_for_digit).once.with(timeout).and_return nil # Simulates timeout
898
- mock_call.menu :timeout => timeout do |link|
899
- link.foobar 0
900
- link.__send__(usage_case) { throw :got_here! }
901
- end
902
- end
903
- end
904
- end
905
-
906
- test "should default the timeout to five seconds" do
907
- pbx_should_respond_with_successful_background_response ?2
908
- pbx_should_respond_with_a_wait_for_digit_timeout
909
-
910
- mock_call.should_receive(:wait_for_digit).once.with(5).and_return nil
911
- mock_call.menu { |link| link.foobar 22 }
912
- end
913
-
914
- test "when matches fail due to timeouts, the menu should repeat :tries times" do
915
- tries, times_timed_out = 10, 0
916
-
917
- tries.times do
918
- pbx_should_respond_with_successful_background_response ?4
919
- pbx_should_respond_with_successful_background_response ?0
920
- pbx_should_respond_with_a_wait_for_digit_timeout
921
- end
922
-
923
- should_throw :inside_failure_callback do
924
- mock_call.menu :tries => tries do |link|
925
- link.pattern_longer_than_our_test_input 400
926
- link.on_premature_timeout { times_timed_out += 1 }
927
- link.on_invalid { raise "should never get here!" }
928
- link.on_failure { throw :inside_failure_callback }
929
- end
930
- end
931
- times_timed_out.should.equal tries
932
- end
933
-
934
- test "when matches fail due to invalid input, the menu should repeat :tries times" do
935
- tries = 10
936
- times_invalid = 0
937
-
938
- tries.times do
939
- pbx_should_respond_with_successful_background_response ?0
940
- end
941
-
942
- should_throw :inside_failure_callback do
943
- mock_call.menu :tries => tries do |link|
944
- link.be_leet 1337
945
- link.on_premature_timeout { raise "should never get here!" }
946
- link.on_invalid { times_invalid += 1 }
947
- link.on_failure { throw :inside_failure_callback }
948
- end
949
- end
950
- times_invalid.should.equal tries
951
- end
952
-
953
- test "invoke on_invalid callback when an invalid extension was entered" do
954
- pbx_should_respond_with_successful_background_response ?5
955
- pbx_should_respond_with_successful_background_response ?5
956
- pbx_should_respond_with_successful_background_response ?5
957
- should_throw :inside_invalid_callback do
958
- mock_call.menu do |link|
959
- link.onetwothree 123
960
- link.on_invalid { throw :inside_invalid_callback }
961
- end
962
- end
963
- end
964
-
965
- test "invoke on_premature_timeout when a timeout is encountered" do
966
- pbx_should_respond_with_successful_background_response ?9
967
- pbx_should_respond_with_a_wait_for_digit_timeout
968
-
969
- should_throw :inside_timeout do
970
- mock_call.menu :timeout => 1 do |link|
971
- link.something 999
972
- link.on_premature_timeout { throw :inside_timeout }
973
- end
974
- end
975
- end
976
-
977
- end
978
-
979
- context "the Menu class's high-level judgment" do
980
-
981
- include DialplanCommandTestHelpers
982
-
983
- test "should match things in ambiguous ranges properly" do
984
- pbx_should_respond_with_successful_background_response ?1
985
- pbx_should_respond_with_successful_background_response ?1
986
- pbx_should_respond_with_successful_background_response ?1
987
- pbx_should_respond_with_a_wait_for_digit_timeout
988
-
989
- main_context = Adhearsion::DialPlan::DialplanContextProc.new(:main) { throw :got_here! }
990
- mock_call.should_receive(:main).and_return main_context
991
-
992
- should_pass_control_to_a_context_that_throws :got_here! do
993
- mock_call.menu do |link|
994
- link.blah 1
995
- link.main 11..11111
996
- end
997
- end
998
- 111.should === mock_call.extension
999
- end
1000
-
1001
- test 'should match things in a range when there are many other non-matching patterns' do
1002
- pbx_should_respond_with_successful_background_response ?9
1003
- pbx_should_respond_with_successful_background_response ?9
1004
- pbx_should_respond_with_successful_background_response ?5
1005
-
1006
- conferences_context = Adhearsion::DialPlan::DialplanContextProc.new(:conferences) { throw :got_here! }
1007
- mock_call.should_receive(:conferences).and_return conferences_context
1008
-
1009
- should_pass_control_to_a_context_that_throws :got_here! do
1010
- mock_call.menu do |link|
1011
- link.sales 1
1012
- link.tech_support 2
1013
- link.finance 3
1014
- link.conferences 900..999
1015
- end
1016
- end
1017
- end
1018
-
1019
- end
1020
-
1021
- context 'the MenuBuilder' do
1022
-
1023
- include MenuBuilderTestHelper
1024
-
1025
- attr_reader :builder
1026
- before:each do
1027
- @builder = Adhearsion::VoIP::MenuBuilder.new
1028
- end
1029
-
1030
- test "should convert each pattern given to it into a MatchCalculator instance" do
1031
- returning builder do |link|
1032
- link.foo 1,2,3
1033
- link.bar "4", "5", 6
1034
- end
1035
-
1036
- builder.weighted_match_calculators.size.should.equal 6
1037
- builder.weighted_match_calculators.each do |match_calculator|
1038
- match_calculator.should.be.kind_of Adhearsion::VoIP::MatchCalculator
1039
- end
1040
- end
1041
-
1042
- test "conflicting ranges" do
1043
- returning builder do |link|
1044
- link.hundreds 100...200
1045
- link.thousands 1_000...2_000
1046
- link.tenthousands 10_000...20_000
1047
- end
1048
-
1049
- builder_should_match_with_these_quantities_of_calculated_matches \
1050
- 1 => { :exact_match_count => 0, :potential_match_count => 11100 },
1051
- 10 => { :exact_match_count => 0, :potential_match_count => 1110 },
1052
- 100 => { :exact_match_count => 1, :potential_match_count => 110 },
1053
- 1_000 => { :exact_match_count => 1, :potential_match_count => 10 },
1054
- 10_000 => { :exact_match_count => 1, :potential_match_count => 0 },
1055
- 100_000 => { :exact_match_count => 0, :potential_match_count => 0 }
1056
-
1057
- end
1058
-
1059
- test 'a String query ran against multiple Numeric patterns and a range' do
1060
- returning builder do |link|
1061
- link.sales 1
1062
- link.tech_support 2
1063
- link.finance 3
1064
- link.conferences 900..999
1065
- end
1066
- match = builder.calculate_matches_for "995"
1067
- require 'pp'
1068
- # pp match
1069
- match.should.not.be.potential_match
1070
- match.should.be.exact_match
1071
- match.actual_exact_matches.should == ["995"]
1072
- end
1073
-
1074
- test "multiple patterns given at once" do
1075
- returning builder do |link|
1076
- link.multiple_patterns 1,2,3,4,5,6,7,8,9
1077
- link.multiple_patterns 100..199, 200..299, 300..399, 400..499, 500..599,
1078
- 600..699, 700..799, 800..899, 900..999
1079
- end
1080
- 1.upto 9 do |num|
1081
- returning builder.calculate_matches_for(num) do |matches_of_num|
1082
- matches_of_num.potential_match_count.should.equal 100
1083
- matches_of_num.exact_match_count.should.equal 1
1084
- end
1085
- returning builder.calculate_matches_for((num * 100) + 5) do |matches_of_num|
1086
- matches_of_num.potential_match_count.should.equal 0
1087
- matches_of_num.exact_match_count.should.equal 1
1088
- end
1089
- end
1090
- end
1091
-
1092
- test "numeric literals that don't match but ultimately would" do
1093
- returning builder do |link|
1094
- link.nineninenine 999
1095
- link.shouldnt_match 4444
1096
- end
1097
- builder.calculate_matches_for(9).potential_match_count.should.equal 1
1098
- end
1099
-
1100
- test "three fixnums that obviously don't conflict" do
1101
- returning builder do |link|
1102
- link.one 1
1103
- link.two 2
1104
- link.three 3
1105
- end
1106
- [[1,2,3,4,'#'], [1,1,1,0,0]].transpose.each do |(input,expected_matches)|
1107
- matches = builder.calculate_matches_for input
1108
- matches.exact_match_count.should.equal expected_matches
1109
- end
1110
- end
1111
-
1112
- test "numerical digits mixed with special digits" do
1113
- returning builder do |link|
1114
- link.one '5*11#3'
1115
- link.two '5***'
1116
- link.three '###'
1117
- end
1118
-
1119
- builder_should_match_with_these_quantities_of_calculated_matches \
1120
- '5' => { :potential_match_count => 2, :exact_match_count => 0 },
1121
- '*' => { :potential_match_count => 0, :exact_match_count => 0 },
1122
- '5**' => { :potential_match_count => 1, :exact_match_count => 0 },
1123
- '5*1' => { :potential_match_count => 1, :exact_match_count => 0 },
1124
- '5*11#3' => { :potential_match_count => 0, :exact_match_count => 1 },
1125
- '5*11#4' => { :potential_match_count => 0, :exact_match_count => 0 },
1126
- '5***' => { :potential_match_count => 0, :exact_match_count => 1 },
1127
- '###' => { :potential_match_count => 0, :exact_match_count => 1 },
1128
- '##*' => { :potential_match_count => 0, :exact_match_count => 0 }
1129
-
1130
- end
1131
-
1132
- test 'a Fixnum exact match conflicting with a Range that would ultimately match' do
1133
- returning builder do |link|
1134
- link.single_digit 1
1135
- link.range 100..200
1136
- end
1137
- matches = builder.calculate_matches_for 1
1138
- matches.potential_match_count.should.equal 100
1139
- end
1140
-
1141
- end
1142
-
1143
- context 'say_digits command' do
1144
- include DialplanCommandTestHelpers
1145
- test 'Can execute the saydigits application using say_digits' do
1146
- digits = "12345"
1147
- pbx_should_respond_with_success
1148
- mock_call.say_digits digits
1149
- pbx_was_asked_to_execute "saydigits", digits
1150
- end
1151
-
1152
- test 'Cannot pass non-integers into say_digits. Will raise an ArgumentError' do
1153
- the_following_code {
1154
- mock_call.say_digits 'abc'
1155
- }.should.raise(ArgumentError)
1156
-
1157
- the_following_code {
1158
- mock_call.say_digits '1.20'
1159
- }.should.raise(ArgumentError)
1160
- end
1161
-
1162
- test 'Digits that start with a 0 are considered valid and parsed properly' do
1163
- digits = "0123"
1164
- mock_call.should_receive(:execute).once.with("saydigits", digits)
1165
- mock_call.say_digits digits
1166
- end
1167
-
1168
- end
1169
-
1170
- context 'the enable_feature command' do
1171
-
1172
- include DialplanCommandTestHelpers
1173
-
1174
- test 'it should fetch the variable for DYNAMIC_FEATURES at first' do
1175
- mock_call.should_receive(:variable).once.with("DYNAMIC_FEATURES").and_throw :got_variable
1176
- should_throw :got_variable do
1177
- mock_call.enable_feature :foobar
1178
- end
1179
- end
1180
-
1181
- test 'should check Adhearsion::VoIP::Asterisk::Commands::DYNAMIC_FEATURE_EXTENSIONS mapping for configuration setters' do
1182
- feature_name = :attended_transfer
1183
-
1184
- assertion = lambda do |arg|
1185
- arg.should.equal :this_is_the_right_arg
1186
- throw :inside_assertion!
1187
- end
1188
-
1189
- # I had to do this ugly hack because of a bug in Flexmock which prevented me from mocking out Hash#[] :(
1190
- old_hash_feature_extension = Adhearsion::VoIP::Asterisk::Commands::DYNAMIC_FEATURE_EXTENSIONS[feature_name]
1191
- begin
1192
- Adhearsion::VoIP::Asterisk::Commands::DYNAMIC_FEATURE_EXTENSIONS[feature_name] = assertion
1193
- # </uglyhack>
1194
- should_throw :inside_assertion! do
1195
- mock_call.enable_feature(feature_name, :this_is_the_right_arg)
1196
- end
1197
- ensure
1198
- Adhearsion::VoIP::Asterisk::Commands::DYNAMIC_FEATURE_EXTENSIONS[feature_name] = old_hash_feature_extension
1199
- end
1200
- end
1201
-
1202
- test 'should separate enabled features with a "#"' do
1203
- mock_call.should_receive(:variable).once.with("DYNAMIC_FEATURES").and_return("one")
1204
- mock_call.should_receive(:variable).once.with("DYNAMIC_FEATURES" => 'one#bar')
1205
- mock_call.enable_feature "bar"
1206
- end
1207
-
1208
- test 'should not add duplicate enabled dynamic features' do
1209
- mock_call.should_receive(:variable).once.and_return('eins#zwei')
1210
- mock_call.enable_feature "eins"
1211
- end
1212
-
1213
- test 'should raise an ArgumentError if optional options are given when DYNAMIC_FEATURE_EXTENSIONS does not have a key for the feature name' do
1214
- the_following_code {
1215
- mock_call.enable_feature :this_is_not_recognized, :these_features => "are not going to be recognized"
1216
- }.should.raise ArgumentError
1217
- end
1218
-
1219
- test 'enabling :attended_transfer should actually enable the atxfer feature' do
1220
- mock_call.should_receive(:variable).once.with("DYNAMIC_FEATURES").and_return ''
1221
- mock_call.should_receive(:variable).once.with("DYNAMIC_FEATURES" => 'atxfer')
1222
- mock_call.enable_feature :attended_transfer
1223
- end
1224
-
1225
- test 'the :context optional option when enabling :attended_transfer should set the TRANSFER_CONTEXT variable to the String supplied as a Hash value' do
1226
- context_name = "direct_dial"
1227
- mock_call.should_receive(:variable).once.with("DYNAMIC_FEATURES").and_return ''
1228
- mock_call.should_receive(:variable).once.with("DYNAMIC_FEATURES" => 'atxfer')
1229
- mock_call.should_receive(:variable).once.with("TRANSFER_CONTEXT" => context_name)
1230
- mock_call.enable_feature :attended_transfer, :context => context_name
1231
- end
1232
-
1233
- test 'enabling :attended_transfer should not add a duplicate if atxfer has been enabled, but it should still set the TRANSFER_CONTEXT variable' do
1234
- context_name = 'blah'
1235
- mock_call.should_receive(:variable).once.with('DYNAMIC_FEATURES').and_return 'atxfer'
1236
- mock_call.should_receive(:variable).once.with('TRANSFER_CONTEXT' => context_name)
1237
- mock_call.enable_feature :attended_transfer, :context => context_name
1238
- end
1239
-
1240
- end
1241
-
1242
- context 'the disable_feature command' do
1243
-
1244
- include DialplanCommandTestHelpers
1245
-
1246
- test "should properly remove the feature from the DYNAMIC_FEATURES variable" do
1247
- mock_call.should_receive(:variable).once.with('DYNAMIC_FEATURES').and_return 'foobar#qaz'
1248
- mock_call.should_receive(:variable).once.with('DYNAMIC_FEATURES' => 'qaz')
1249
- mock_call.disable_feature "foobar"
1250
- end
1251
-
1252
- test "should not re-set the variable if the feature wasn't enabled in the first place" do
1253
- mock_call.should_receive(:variable).once.with('DYNAMIC_FEATURES').and_return 'atxfer'
1254
- mock_call.should_receive(:variable).never
1255
- mock_call.disable_feature "jay"
1256
- end
1257
-
1258
- end
1259
-
1260
- context 'jump_to command' do
1261
-
1262
- include DialplanCommandTestHelpers
1263
-
1264
- test 'when given a DialplanContextProc as the only argument, it should raise a ControlPassingException with that as the target' do
1265
- # Having to do this ugly hack because I can't do anything with the exception once I set up an expectation with it normally.
1266
- dialplan_context = Adhearsion::DialPlan::DialplanContextProc.new("my_context") {}
1267
- should_throw :finishing_the_rescue_block do
1268
- begin
1269
- mock_call.jump_to dialplan_context
1270
- rescue Adhearsion::VoIP::DSL::Dialplan::ControlPassingException => cpe
1271
- cpe.target.should.equal dialplan_context
1272
- throw :finishing_the_rescue_block
1273
- end
1274
- end
1275
- end
1276
-
1277
- test 'when given a String, it should perform a lookup of the context name' do
1278
- context_name = 'cool_context'
1279
- mock_call.should_receive(context_name).once.and_throw :found_context!
1280
- should_throw :found_context! do
1281
- mock_call.jump_to context_name
1282
- end
1283
- end
1284
-
1285
- test 'when given a Symbol, it should perform a lookup of the context name' do
1286
- context_name = :cool_context
1287
- mock_call.should_receive(context_name).once.and_throw :found_context!
1288
- should_throw :found_context! do
1289
- mock_call.jump_to context_name
1290
- end
1291
- end
1292
-
1293
- test "a clearly invalid context name should raise a ContextNotFoundException" do
1294
- bad_context_name = ' ZOMGS this is A REALLY! STUPID context name . wtf were you thinking?!'
1295
- the_following_code {
1296
- mock_call.jump_to bad_context_name
1297
- }.should.raise Adhearsion::VoIP::DSL::Dialplan::ContextNotFoundException
1298
- end
1299
-
1300
- test 'when given an :extension override, the new value should be boxed in a PhoneNumber' do
1301
- my_context = Adhearsion::DialPlan::DialplanContextProc.new("my_context") {}
1302
- begin
1303
- mock_call.jump_to my_context, :extension => 1337
1304
- rescue Adhearsion::VoIP::DSL::Dialplan::ControlPassingException
1305
- # Eating this exception
1306
- end
1307
- mock_call.extension.__real_num.should.equal 1337
1308
- end
1309
-
1310
- test 'other overrides should be simply metadef()d' do
1311
- test_context = Adhearsion::DialPlan::DialplanContextProc.new("test_context") {}
1312
- begin
1313
- mock_call.jump_to test_context, :caller_id => 1_444_555_6666
1314
- rescue Adhearsion::VoIP::DSL::Dialplan::ControlPassingException
1315
- # Eating this exception
1316
- end
1317
- mock_call.caller_id.should.equal 1_444_555_6666
1318
- end
1319
-
1320
- end
1321
-
1322
- context "get variable command" do
1323
- include DialplanCommandTestHelpers
1324
-
1325
- test "Getting a variable that isn't set returns nothing" do
1326
- pbx_should_respond_with "200 result=0"
1327
- assert !mock_call.get_variable('OMGURFACE')
1328
- end
1329
-
1330
- test 'An empty variable should return an empty String' do
1331
- pbx_should_respond_with_value ""
1332
- mock_call.get_variable('kablamm').should == ""
1333
- end
1334
-
1335
- test "Getting a variable that is set returns its value" do
1336
- unique_id = "1192470850.1"
1337
- pbx_should_respond_with_value unique_id
1338
- variable_value_returned = mock_call.get_variable('UNIQUEID')
1339
- variable_value_returned.should.equal unique_id
1340
- end
1341
- end
1342
-
1343
- context "duration_of command" do
1344
- include DialplanCommandTestHelpers
1345
-
1346
- test "Duration of must take a block" do
1347
- the_following_code {
1348
- mock_call.duration_of
1349
- }.should.raise(LocalJumpError)
1350
- end
1351
-
1352
- test "Passed block to duration of is actually executed" do
1353
- the_following_code {
1354
- mock_call.duration_of {
1355
- throw :inside_duration_of
1356
- }
1357
- }.should.throw :inside_duration_of
1358
- end
1359
-
1360
- test "Duration of block is returned" do
1361
- start_time = Time.parse('9:25:00')
1362
- end_time = Time.parse('9:25:05')
1363
- expected_duration = end_time - start_time
1364
-
1365
- flexmock(Time).should_receive(:now).twice.and_return(start_time, end_time)
1366
- duration = mock_call.duration_of {
1367
- # This doesn't matter
1368
- }
1369
-
1370
- duration.should.equal expected_duration
1371
- end
1372
- end
1373
-
1374
- context "Dial command" do
1375
- include DialplanCommandTestHelpers
1376
-
1377
- test "should set the caller id if the caller_id option is specified" do
1378
- mock_call.should_receive(:set_caller_id_number).once
1379
- mock_call.dial 123, :caller_id => "1234678901"
1380
- end
1381
-
1382
- test 'should raise an exception when unknown hash key arguments are given to it' do
1383
- the_following_code {
1384
- mock_call.dial 123, :asjndfhasndfahsbdfbhasbdfhabsd => "asbdfhabshdfbajhshfbajsf"
1385
- }.should.raise ArgumentError
1386
- end
1387
-
1388
- test 'should set the caller ID name when given the :name hash key argument' do
1389
- name = "Jay Phillips"
1390
- mock_call.should_receive(:set_caller_id_name).once.with(name)
1391
- mock_call.dial "BlahBlahBlah", :name => name
1392
- end
1393
-
1394
- test "should raise an exception when a non-numerical caller_id is specified" do
1395
- the_following_code {
1396
- mock_call.dial 911, :caller_id => "zomgz"
1397
- }.should.raise ArgumentError
1398
- end
1399
-
1400
- test 'should pass the value of the :confirm key to dial_macro_option_compiler()' do
1401
- value_of_confirm_key = {:play => "ohai", :timeout => 30}
1402
- mock_call.should_receive(:dial_macro_option_compiler).once.with value_of_confirm_key
1403
- mock_call.dial 123, :confirm => value_of_confirm_key
1404
- end
1405
-
1406
- test "should add the return value of dial_macro_option_compiler to the :options key's value given to the dial command" do
1407
- channel = "SIP/1337"
1408
- macro_arg = "THISSHOULDGETPASSEDTOASTERISK"
1409
- timeout = 10
1410
- options = 'hH'
1411
-
1412
- mock_call.should_receive(:dial_macro_option_compiler).once.and_return macro_arg
1413
- mock_call.should_receive(:execute).with('Dial', channel, timeout, options + macro_arg)
1414
- mock_call.dial channel, :for => timeout, :confirm => true, :options => options
1415
- end
1416
-
1417
- test 'should add the return value of dial_macro_option_compiler to the options field when NO :options are given' do
1418
- channel = "SIP/1337"
1419
- macro_arg = "THISSHOULDGETPASSEDTOASTERISK"
1420
- timeout = 10
1421
- options = 'hH'
1422
-
1423
- mock_call.should_receive(:dial_macro_option_compiler).once.and_return macro_arg
1424
- mock_call.should_receive(:execute).with('Dial', channel, timeout, options + macro_arg)
1425
- mock_call.dial channel, :for => timeout, :confirm => true, :options => options
1426
- end
1427
-
1428
- end
1429
-
1430
- context "The Dial command's :confirm option setting builder" do
1431
-
1432
- include DialplanCommandTestHelpers
1433
-
1434
- attr_reader :formatter
1435
- before :each do
1436
- @formatter = mock_call.method :dial_macro_option_compiler
1437
- end
1438
-
1439
- test 'should allow passing in the :confirm named argument with true' do
1440
- the_following_code {
1441
- formatter.call true
1442
- }.should.not.raise ArgumentError
1443
- end
1444
-
1445
- test 'should separate :play options with "++"' do
1446
- sound_files = *1..10
1447
- formatter.call(:play => sound_files).should.include sound_files.join('++')
1448
- end
1449
-
1450
- test 'should raise an ArgumentError if an invalid Hash key is given' do
1451
- the_following_code {
1452
- formatter.call :this_symbol_is_not_valid => 123
1453
- }.should.raise ArgumentError
1454
- end
1455
-
1456
- test "should raise an ArgumentError if the argument's class is not recognized" do
1457
- the_following_code {
1458
- formatter.call Time.now # Time is an example strange case
1459
- }.should.raise ArgumentError
1460
- end
1461
-
1462
- test 'should return the contents within a M() Dial argument' do
1463
- formatter.call(true).should =~ /^M\(.+\)$/
1464
- end
1465
-
1466
- test 'should replace the default macro name when given the :macro options' do
1467
- macro_name = "ivegotalovelybunchofcoconuts"
1468
- formatter.call(:macro => macro_name).starts_with?("M(#{macro_name}").should.equal true
1469
- end
1470
-
1471
- test 'should allow a symbol macro name' do
1472
- the_following_code {
1473
- formatter.call(:macro => :foo)
1474
- }.should.not.raise ArgumentError
1475
- end
1476
-
1477
- test 'should only allow alphanumeric and underscores in the macro name' do
1478
- bad_options = ["this has a space", "foo,bar", 'exists?', 'x^z', '', "!&@&*^!@"]
1479
- bad_options.each do |bad_option|
1480
- the_following_code {
1481
- formatter.call(:macro => bad_option)
1482
- }.should.raise ArgumentError
1483
- end
1484
- end
1485
-
1486
- test 'should confirm :timeout => :none to 0' do
1487
- formatter.call(:timeout => :none).should.include "timeout:0"
1488
- end
1489
-
1490
- test 'should separate the macro name and the arguments with a caret (^)' do
1491
- formatter.call(:macro => "jay").should =~ /M\(jay\^.+/
1492
- end
1493
-
1494
- test 'should raise an ArgumentError if a caret existed anywhere in the resulting String' do
1495
- bad_options = [{:play => "foo^bar", :key => "^", :play => ["hello-world", 'lol^cats']}]
1496
- bad_options.each do |bad_option|
1497
- the_following_code {
1498
- formatter.call(bad_option)
1499
- }.should.raise ArgumentError
1500
- end
1501
- end
1502
-
1503
- test 'should raise an ArgumentError if the :key is not [0-9#*]' do
1504
- bad_options = %w[& A $ @ . )]
1505
- bad_options.each do |bad_option|
1506
- the_following_code {
1507
- formatter.call :key => bad_option
1508
- }.should.raise ArgumentError
1509
- end
1510
- end
1511
-
1512
- test 'should raise an ArgumentError if the key is longer than one digit' do
1513
- the_following_code {
1514
- formatter.call :key => "55"
1515
- }.should.raise ArgumentError
1516
- end
1517
-
1518
- test 'should raise an ArgumentError if the timeout is not numeric and not :none' do
1519
- bad_options = [:nonee, Time.now, method(:inspect)]
1520
- bad_options.each do |bad_option|
1521
- the_following_code {
1522
- formatter.call bad_option
1523
- }.should.raise ArgumentError
1524
- end
1525
- end
1526
-
1527
- test 'should support passing a String argument as a timeout' do
1528
- the_following_code {
1529
- formatter.call :timeout => "123"
1530
- }.should.not.raise ArgumentError
1531
- end
1532
-
1533
- test 'should raise an ArgumentError if given a Float' do
1534
- the_following_code {
1535
- formatter.call :timeout => 100.0012
1536
- }.should.raise ArgumentError
1537
- end
1538
-
1539
- test 'should allow passing a ActiveSupport::Duration to :timeout' do
1540
- the_following_code {
1541
- formatter.call :timeout => 3.minutes
1542
- }.should.not.raise ArgumentError
1543
- end
1544
-
1545
- end
1546
-
1547
- context 'the dtmf command' do
1548
-
1549
- include DialplanCommandTestHelpers
1550
-
1551
- test 'should send the proper AGI command' do
1552
- digits = '8404#4*'
1553
- mock_call.dtmf digits
1554
- pbx_should_have_been_sent "EXEC SendDTMF #{digits}"
1555
- end
1556
- end
1557
-
1558
- context "the last_dial_status command and family" do
1559
-
1560
- include DialplanCommandTestHelpers
1561
-
1562
- test 'should convert common DIALSTATUS variables to their appropriate symbols' do
1563
- mock_call.should_receive(:variable).with("DIALSTATUS").once.and_return('ANSWER')
1564
- mock_call.last_dial_status.should.equal :answered
1565
-
1566
- mock_call.should_receive(:variable).with("DIALSTATUS").once.and_return('CONGESTION')
1567
- mock_call.last_dial_status.should.equal :congested
1568
-
1569
- mock_call.should_receive(:variable).once.with("DIALSTATUS").and_return("BUSY")
1570
- mock_call.last_dial_status.should.equal:busy
1571
-
1572
- mock_call.should_receive(:variable).once.with("DIALSTATUS").and_return("CANCEL")
1573
- mock_call.last_dial_status.should.equal :cancelled
1574
-
1575
- mock_call.should_receive(:variable).once.with("DIALSTATUS").and_return("NOANSWER")
1576
- mock_call.last_dial_status.should.equal :unanswered
1577
-
1578
- mock_call.should_receive(:variable).once.with("DIALSTATUS").and_return("CHANUNAVAIL")
1579
- mock_call.last_dial_status.should.equal :channel_unavailable
1580
-
1581
- mock_call.should_receive(:variable).once.with("DIALSTATUS").and_return("THISISNOTVALID")
1582
- mock_call.last_dial_status.should.equal :unknown
1583
- end
1584
-
1585
- test 'last_dial_successful? should return true if last_dial_status == :answered' do
1586
- mock_call.should_receive(:variable).with("DIALSTATUS").once.and_return('ANSWER')
1587
- mock_call.last_dial_successful?.should.equal true
1588
-
1589
- mock_call.should_receive(:variable).with("DIALSTATUS").once.and_return('CHANUNAVAIL')
1590
- mock_call.last_dial_successful?.should.equal false
1591
- end
1592
-
1593
- test 'last_dial_unsuccessful? should be the opposite of last_dial_successful?' do
1594
- mock_call.should_receive(:variable).with("DIALSTATUS").once.and_return('ANSWER')
1595
- mock_call.last_dial_unsuccessful?.should.equal false
1596
-
1597
- mock_call.should_receive(:variable).with("DIALSTATUS").once.and_return('CHANUNAVAIL')
1598
- mock_call.last_dial_unsuccessful?.should.equal true
1599
- end
1600
-
1601
- test 'last_dial_status should not blow up if variable() returns nil. it should return :cancelled' do
1602
- the_following_code {
1603
- mock_call.should_receive(:variable).once.with("DIALSTATUS").and_return nil
1604
- mock_call.last_dial_status.should.equal :cancelled
1605
-
1606
- mock_call.should_receive(:variable).once.with("DIALSTATUS").and_return nil
1607
- mock_call.last_dial_successful?.should.equal false
1608
- }.should.not.raise
1609
- end
1610
-
1611
- end
1612
-
1613
- context "set_caller_id_number command" do
1614
- include DialplanCommandTestHelpers
1615
-
1616
- test "should encapsulate the number with quotes" do
1617
- caller_id = "14445556666"
1618
- mock_call.should_receive(:raw_response).once.with(%(SET CALLERID "#{caller_id}")).and_return true
1619
- mock_call.send(:set_caller_id_number, caller_id)
1620
- end
1621
- end
1622
-
1623
- context 'set_caller_id_name command' do
1624
- include DialplanCommandTestHelpers
1625
-
1626
- test "should wrap the name in quotes" do
1627
- name = "Jay Phillips"
1628
- mock_call.should_receive(:raw_response).once.with(%(SET VARIABLE CALLERID(name) "#{name}")).and_return true
1629
- mock_call.send(:set_caller_id_name, name)
1630
- end
1631
- end
1632
-
1633
- context "record command" do
1634
- include DialplanCommandTestHelpers
1635
-
1636
- test "executes the command SpeechEngine gives it based on the engine name" do
1637
- mock_speak_command = "returned command doesn't matter"
1638
- flexmock(Adhearsion::VoIP::Asterisk::Commands::SpeechEngines).should_receive(:cepstral).
1639
- once.and_return(mock_speak_command)
1640
- mock_call.should_receive(:execute).once.with(mock_speak_command)
1641
- mock_call.speak "Spoken text doesn't matter", :cepstral
1642
- end
1643
-
1644
- test "raises an InvalidSpeechEngine exception when the engine is 'none'" do
1645
- the_following_code {
1646
- mock_call.speak("o hai!", :none)
1647
- }.should.raise Adhearsion::VoIP::Asterisk::Commands::SpeechEngines::InvalidSpeechEngine
1648
- end
1649
-
1650
- test "should default its engine to :none" do
1651
- the_following_code {
1652
- flexmock(Adhearsion::VoIP::Asterisk::Commands::SpeechEngines).should_receive(:none).once.
1653
- and_raise(Adhearsion::VoIP::Asterisk::Commands::SpeechEngines::InvalidSpeechEngine)
1654
- mock_call.speak "ruby ruby ruby ruby!"
1655
- }.should.raise Adhearsion::VoIP::Asterisk::Commands::SpeechEngines::InvalidSpeechEngine
1656
- end
1657
-
1658
- test "Properly escapes spoken text" # TODO: What are the escaping needs?
1659
-
1660
- end
1661
-
1662
- context 'The join command' do
1663
-
1664
- include DialplanCommandTestHelpers
1665
-
1666
- test "should pass the 'd' flag when no options are given" do
1667
- conference_id = "123"
1668
- mock_call.should_receive(:execute).once.with("MeetMe", conference_id, "d", nil)
1669
- mock_call.join conference_id
1670
- end
1671
-
1672
- test "should pass through any given flags with 'd' appended to it if necessary" do
1673
- conference_id, flags = "1000", "zomgs"
1674
- mock_call.should_receive(:execute).once.with("MeetMe", conference_id, flags + "d", nil)
1675
- mock_call.join conference_id, :options => flags
1676
- end
1677
-
1678
- test "should raise an ArgumentError when the pin is not numerical" do
1679
- the_following_code {
1680
- mock_call.should_receive(:execute).never
1681
- mock_call.join 3333, :pin => "letters are bad, mkay?!1"
1682
- }.should.raise ArgumentError
1683
- end
1684
-
1685
- test "should strip out illegal characters from a conference name" do
1686
- bizarre_conference_name = "a- bc!d&&e--`"
1687
- normal_conference_name = "abcde"
1688
- mock_call.should_receive(:execute).twice.with("MeetMe", normal_conference_name, "d", nil)
1689
-
1690
- mock_call.join bizarre_conference_name
1691
- mock_call.join normal_conference_name
1692
- end
1693
-
1694
- test "should allow textual conference names" do
1695
- the_following_code {
1696
- mock_call.should_receive(:execute).once.with_any_args
1697
- mock_call.join "david bowie's pants"
1698
- }.should.not.raise
1699
- end
1700
-
1701
- end
1702
-
1703
-
1704
- context 'the DialPlan::ConfirmationManager' do
1705
-
1706
- include ConfirmationManagerTestHelper
1707
- include DialplanCommandTestHelpers
1708
-
1709
- attr_reader :example_encoded_hash, :example_encoded_hash_without_macro_name
1710
- before :each do
1711
- @example_encoded_hash_without_macro_name = 'timeout:20!play:foo-bar++qaz_qwerty.gsm!key:#'
1712
- @example_encoded_hash = 'confirm!' + @example_encoded_hash_without_macro_name
1713
- end
1714
-
1715
- test '::decode_hash() should convert the String of key/value escaped pairs into a Hash with Symbol keys when the macro name is not given' do
1716
- Adhearsion::DialPlan::ConfirmationManager.decode_hash(example_encoded_hash).should ==
1717
- {:timeout => 20, :play => ['foo-bar', 'qaz_qwerty.gsm'], :key => '#'}
1718
- end
1719
-
1720
- test '::decode_hash() should convert the String of key/value escaped pairs into a Hash with Symbol keys when the macro name is not given' do
1721
- Adhearsion::DialPlan::ConfirmationManager.decode_hash(example_encoded_hash_without_macro_name).should ==
1722
- {:timeout => 20, :play => ['foo-bar', 'qaz_qwerty.gsm'], :key => '#'}
1723
- end
1724
-
1725
- test '::decode_hash() should split the sound files in the :play key to an array by splitting by "++"' do
1726
- decoded_sound_files = Adhearsion::DialPlan::ConfirmationManager.decode_hash(example_encoded_hash)[:play]
1727
- decoded_sound_files.should.be.kind_of Array
1728
- decoded_sound_files.size.should.equal 2
1729
- end
1730
-
1731
- test 'a call to a party which is acknowledged with the proper key during the call to interruptable_play' do
1732
- variables = {:timeout => 20, :play => ['foo-bar', 'qaz_qwerty.gsm'], :key => '#', :macro => 'confirmer'}
1733
- encoded_variables = {:network_script => encode_hash(variables)}
1734
- io_mock = StringIO.new
1735
-
1736
- mock_call.should_receive(:originating_voip_platform).once.and_return :asterisk
1737
- mock_call.should_receive(:variables).once.and_return encoded_variables
1738
-
1739
- sound_files = variables[:play]
1740
-
1741
- manager = Adhearsion::DialPlan::ConfirmationManager.new(mock_call)
1742
-
1743
- flexstub(manager).should_receive(:result_digit_from).and_return ?0
1744
- flexstub(manager).should_receive(:raw_response).and_return nil
1745
-
1746
- flexmock(manager).should_receive(:answer).once
1747
- flexmock(manager).should_receive(:interruptable_play).once.with(*sound_files).and_return '#'
1748
-
1749
- manager.handle
1750
- end
1751
-
1752
- test 'when an timeout is encountered, it should set the MACRO_RESULT variable to CONTINUE' do
1753
- variables = {:timeout => 20, :play => ['foo-bar', 'qaz_qwerty.gsm'], :key => '#', :macro => 'confirmer'}
1754
- encoded_variables = {:network_script => encode_hash(variables)}
1755
- io_mock = StringIO.new
1756
-
1757
- mock_call.should_receive(:originating_voip_platform).once.and_return :asterisk
1758
- mock_call.should_receive(:variables).once.and_return encoded_variables
1759
-
1760
- sound_files = variables[:play]
1761
-
1762
- manager = Adhearsion::DialPlan::ConfirmationManager.new(mock_call)
1763
-
1764
- flexstub(manager).should_receive(:result_digit_from).and_return ?0
1765
- flexstub(manager).should_receive(:raw_response).and_return nil
1766
-
1767
- flexmock(manager).should_receive(:answer).once
1768
- flexmock(manager).should_receive(:interruptable_play).once.with(*sound_files).and_return nil
1769
- flexmock(manager).should_receive(:wait_for_digit).once.with(20).and_return nil
1770
-
1771
- flexmock(manager).should_receive(:variable).once.with("MACRO_RESULT" => 'CONTINUE')
1772
-
1773
- manager.handle
1774
- end
1775
-
1776
- test 'should wait the :timeout number of seconds if no digit was received when playing the files and continue when the right key is pressed' do
1777
- variables = {:timeout => 20, :play => ['foo-bar', 'qaz_qwerty.gsm'], :key => '#', :macro => 'confirmer'}
1778
- encoded_variables = {:network_script => encode_hash(variables)}
1779
- io_mock = StringIO.new
1780
-
1781
- mock_call.should_receive(:originating_voip_platform).once.and_return :asterisk
1782
- mock_call.should_receive(:variables).once.and_return encoded_variables
1783
-
1784
- sound_files = variables[:play]
1785
-
1786
- manager = Adhearsion::DialPlan::ConfirmationManager.new(mock_call)
1787
-
1788
- flexstub(manager).should_receive(:result_digit_from).and_return ?0
1789
- flexstub(manager).should_receive(:raw_response).and_return nil
1790
-
1791
- flexmock(manager).should_receive(:answer).once
1792
- flexmock(manager).should_receive(:interruptable_play).once.with(*sound_files).and_return nil
1793
- flexmock(manager).should_receive(:wait_for_digit).once.with(20).and_return '#'
1794
-
1795
- manager.handle
1796
- end
1797
-
1798
- test 'should restart playback if the key received was not recognized' do
1799
- variables = {:timeout => 20, :play => ['foo-bar', 'qaz_qwerty.gsm'], :key => '2', :macro => 'confirmer'}
1800
- encoded_variables = {:network_script => encode_hash(variables)}
1801
- io_mock = StringIO.new
1802
-
1803
- mock_call.should_receive(:originating_voip_platform).once.and_return :asterisk
1804
- mock_call.should_receive(:variables).once.and_return encoded_variables
1805
-
1806
- sound_files = variables[:play]
1807
-
1808
- manager = Adhearsion::DialPlan::ConfirmationManager.new(mock_call)
1809
-
1810
- flexstub(manager).should_receive(:result_digit_from).and_return ?0
1811
- flexstub(manager).should_receive(:raw_response).and_return nil
1812
-
1813
- flexmock(manager).should_receive(:answer).once
1814
- flexmock(manager).should_receive(:interruptable_play).once.with(*sound_files).and_return '3' # not :key
1815
- flexmock(manager).should_receive(:interruptable_play).once.with(*sound_files).and_return '#' # not :key
1816
- flexmock(manager).should_receive(:interruptable_play).once.with(*sound_files).and_return '1' # not :key
1817
- flexmock(manager).should_receive(:interruptable_play).once.with(*sound_files).and_return '2' # matches :key
1818
-
1819
- flexmock(manager).should_receive(:wait_for_digit).never # We never let it get to the point where it may timeout
1820
- flexmock(manager).should_receive(:variable).never # We succeed by not setting the MACRO_RESULT variable
1821
-
1822
- manager.handle
1823
- end
1824
-
1825
- end
1826
-
1827
- BEGIN {
1828
- module DialplanCommandTestHelpers
1829
- def self.included(test_case)
1830
- test_case.send(:attr_reader, :mock_call, :input, :output)
1831
-
1832
- test_case.before do
1833
- @input = MockSocket.new
1834
- @output = MockSocket.new
1835
- @mock_call = Object.new
1836
- @mock_call.metaclass.send(:attr_reader, :call)
1837
- mock_call.extend(Adhearsion::VoIP::Asterisk::Commands)
1838
- flexmock(mock_call) do |call|
1839
- call.should_receive(:from_pbx).and_return(input)
1840
- call.should_receive(:to_pbx).and_return(output)
1841
- end
1842
- end
1843
- end
1844
-
1845
- class MockSocket
1846
-
1847
- def print(message)
1848
- messages << message
1849
- end
1850
-
1851
- def read
1852
- messages.shift
1853
- end
1854
-
1855
- def gets
1856
- read
1857
- end
1858
-
1859
- def messages
1860
- @messages ||= []
1861
- end
1862
- end
1863
-
1864
-
1865
- private
1866
-
1867
- def should_pass_control_to_a_context_that_throws(symbol, &block)
1868
- did_the_rescue_block_get_executed = false
1869
- begin
1870
- yield
1871
- rescue Adhearsion::VoIP::DSL::Dialplan::ControlPassingException => cpe
1872
- did_the_rescue_block_get_executed = true
1873
- cpe.target.should.throw symbol
1874
- rescue => e
1875
- did_the_rescue_block_get_executed = true
1876
- raise e
1877
- ensure
1878
- did_the_rescue_block_get_executed.should.be true
1879
- end
1880
- end
1881
-
1882
- def should_throw(sym=nil,&block)
1883
- block.should.throw(*[sym].compact)
1884
- end
1885
-
1886
- def mock_route_calculation_with(*definitions)
1887
- flexmock(Adhearsion::VoIP::DSL::DialingDSL).should_receive(:calculate_routes_for).and_return(definitions)
1888
- end
1889
-
1890
- def pbx_should_have_been_sent(message)
1891
- output.gets.should.equal message
1892
- end
1893
-
1894
- def pbx_should_respond_with(message)
1895
- input.print message
1896
- end
1897
-
1898
- def pbx_should_respond_with_digits(string_of_digits)
1899
- pbx_should_respond_with "200 result=#{string_of_digits}"
1900
- end
1901
-
1902
- def pbx_should_respond_with_digits_and_timeout(string_of_digits)
1903
- pbx_should_respond_with "200 result=#{string_of_digits} (timeout)"
1904
- end
1905
-
1906
- def pbx_should_respond_to_timeout(timeout)
1907
- pbx_should_respond_with "200 result=#{timeout}"
1908
- end
1909
-
1910
- def pbx_should_respond_with_value(value)
1911
- pbx_should_respond_with "200 result=1 (#{value})"
1912
- end
1913
-
1914
- def pbx_should_respond_with_success(success_code = nil)
1915
- pbx_should_respond_with pbx_success_response(success_code)
1916
- end
1917
-
1918
- def pbx_should_respond_with_failure(failure_code = nil)
1919
- pbx_should_respond_with(pbx_failure_response(failure_code))
1920
- end
1921
-
1922
- def pbx_should_respond_with_successful_background_response(digit=0)
1923
- pbx_should_respond_with_success digit.kind_of?(String) ? digit[0] : digit
1924
- end
1925
-
1926
- def pbx_should_respond_with_a_wait_for_digit_timeout
1927
- pbx_should_respond_with_successful_background_response 0
1928
- end
1929
-
1930
- def pbx_success_response(success_code = nil)
1931
- "200 result=#{success_code || default_success_code}"
1932
- end
1933
-
1934
- def default_success_code
1935
- '1'
1936
- end
1937
-
1938
- def pbx_failure_response(failure_code = nil)
1939
- "200 result=#{failure_code || default_failure_code}"
1940
- end
1941
-
1942
- def default_failure_code
1943
- '0'
1944
- end
1945
-
1946
- def output_stream_matches(pattern)
1947
- assert_match(pattern, output.gets)
1948
- end
1949
-
1950
- module OutputStreamMatchers
1951
- def pbx_was_asked_to_play(*audio_files)
1952
- audio_files.each do |audio_file|
1953
- output_stream_matches(/playback #{audio_file}/)
1954
- end
1955
- end
1956
-
1957
- def pbx_was_asked_to_play_number(number)
1958
- output_stream_matches(/saynumber #{number}/)
1959
- end
1960
-
1961
- def pbx_was_asked_to_play_time(number)
1962
- output_stream_matches(/sayunixtime #{number}/)
1963
- end
1964
-
1965
- def pbx_was_asked_to_execute(application, *options)
1966
- output_stream_matches(/exec saydigits #{options.join('|')}/i)
1967
- end
1968
- end
1969
- include OutputStreamMatchers
1970
-
1971
- def assert_success(response)
1972
- response.should.equal pbx_success_response
1973
- end
1974
-
1975
- end
1976
-
1977
-
1978
- module MenuBuilderTestHelper
1979
- def builder_should_match_with_these_quantities_of_calculated_matches(checks)
1980
- checks.each do |check,hash|
1981
- hash.each_pair do |method_name,intended_quantity|
1982
- message = "There were supposed to be #{intended_quantity} #{method_name.to_s.humanize} calculated."
1983
- builder.calculate_matches_for(check).send(method_name).
1984
- should.messaging(message).equal(intended_quantity)
1985
- end
1986
- end
1987
- end
1988
- end
1989
-
1990
- module MenuTestHelper
1991
-
1992
- def pbx_should_send_digits(*digits)
1993
- digits.each do |digit|
1994
- digit = nil if digit == :timeout
1995
- mock_call.should_receive(:interruptable_play).once.and_return(digit)
1996
- end
1997
- end
1998
- end
1999
-
2000
- module ConfirmationManagerTestHelper
2001
- def encode_hash(hash)
2002
- Adhearsion::DialPlan::ConfirmationManager.encode_hash_for_dial_macro_argument(hash)
2003
- end
2004
- end
2005
-
2006
- }