adhearsion 1.2.6 → 2.0.0.alpha1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (236) hide show
  1. data/.gitignore +17 -10
  2. data/CHANGELOG.md +273 -0
  3. data/Gemfile +1 -1
  4. data/Guardfile +17 -0
  5. data/README.markdown +61 -9
  6. data/Rakefile +16 -48
  7. data/adhearsion.gemspec +21 -7
  8. data/bin/ahn +3 -1
  9. data/cucumber.yml +4 -0
  10. data/features/app_generator.feature +42 -0
  11. data/features/cli.feature +108 -0
  12. data/features/step_definitions/app_generator_steps.rb +6 -0
  13. data/features/step_definitions/cli_steps.rb +74 -0
  14. data/features/support/aruba_helper.rb +22 -0
  15. data/features/support/env.rb +37 -0
  16. data/features/support/utils.rb +8 -0
  17. data/lib/adhearsion.rb +85 -41
  18. data/lib/adhearsion/call.rb +176 -0
  19. data/lib/adhearsion/call_controller.rb +134 -0
  20. data/lib/adhearsion/call_controller/dial.rb +70 -0
  21. data/lib/adhearsion/call_controller/input.rb +173 -0
  22. data/lib/adhearsion/call_controller/menu.rb +124 -0
  23. data/lib/adhearsion/call_controller/output.rb +267 -0
  24. data/lib/adhearsion/call_controller/record.rb +42 -0
  25. data/lib/adhearsion/call_controller/utility.rb +60 -0
  26. data/lib/adhearsion/calls.rb +81 -0
  27. data/lib/adhearsion/cli.rb +1 -3
  28. data/lib/adhearsion/cli_commands.rb +142 -0
  29. data/lib/adhearsion/configuration.rb +149 -0
  30. data/lib/adhearsion/console.rb +19 -8
  31. data/lib/adhearsion/dialplan_controller.rb +9 -0
  32. data/lib/adhearsion/events.rb +84 -0
  33. data/lib/adhearsion/foundation/all.rb +0 -7
  34. data/lib/adhearsion/foundation/custom_daemonizer.rb +4 -6
  35. data/lib/adhearsion/foundation/exception_handler.rb +9 -0
  36. data/lib/adhearsion/foundation/object.rb +26 -8
  37. data/lib/adhearsion/foundation/synchronized_hash.rb +3 -6
  38. data/lib/adhearsion/foundation/thread_safety.rb +17 -1
  39. data/lib/adhearsion/generators/app/app_generator.rb +4 -13
  40. data/lib/adhearsion/generators/app/templates/Gemfile +10 -5
  41. data/lib/adhearsion/generators/app/templates/Procfile +1 -0
  42. data/lib/adhearsion/generators/app/templates/README.md +28 -0
  43. data/lib/adhearsion/generators/app/templates/config/adhearsion.rb +41 -0
  44. data/lib/adhearsion/generators/app/templates/{components/simon_game → lib}/simon_game.rb +6 -18
  45. data/lib/adhearsion/generators/app/templates/script/ahn +2 -2
  46. data/lib/adhearsion/initializer.rb +151 -293
  47. data/lib/adhearsion/initializer/logging.rb +33 -0
  48. data/lib/adhearsion/logging.rb +65 -69
  49. data/lib/adhearsion/menu_dsl.rb +15 -0
  50. data/lib/adhearsion/menu_dsl/calculated_match.rb +39 -0
  51. data/lib/adhearsion/menu_dsl/calculated_match_collection.rb +41 -0
  52. data/lib/adhearsion/menu_dsl/fixnum_match_calculator.rb +18 -0
  53. data/lib/adhearsion/menu_dsl/match_calculator.rb +36 -0
  54. data/lib/adhearsion/{voip/menu_state_machine/menu_class.rb → menu_dsl/menu.rb} +38 -40
  55. data/lib/adhearsion/menu_dsl/menu_builder.rb +69 -0
  56. data/lib/adhearsion/menu_dsl/range_match_calculator.rb +55 -0
  57. data/lib/adhearsion/menu_dsl/string_match_calculator.rb +21 -0
  58. data/lib/adhearsion/outbound_call.rb +64 -0
  59. data/lib/adhearsion/plugin.rb +319 -0
  60. data/lib/adhearsion/plugin/collection.rb +19 -0
  61. data/lib/adhearsion/plugin/initializer.rb +37 -0
  62. data/lib/adhearsion/plugin/methods_container.rb +6 -0
  63. data/lib/adhearsion/process.rb +94 -0
  64. data/lib/adhearsion/punchblock_plugin.rb +29 -0
  65. data/lib/adhearsion/punchblock_plugin/initializer.rb +137 -0
  66. data/lib/adhearsion/router.rb +30 -0
  67. data/lib/adhearsion/router/route.rb +42 -0
  68. data/lib/adhearsion/script_ahn_loader.rb +2 -2
  69. data/lib/adhearsion/tasks.rb +14 -9
  70. data/lib/adhearsion/tasks/configuration.rb +26 -0
  71. data/lib/adhearsion/tasks/plugins.rb +17 -0
  72. data/lib/adhearsion/version.rb +8 -14
  73. data/spec/adhearsion/call_controller/dial_spec.rb +138 -0
  74. data/spec/adhearsion/call_controller/input_spec.rb +278 -0
  75. data/spec/adhearsion/call_controller/menu_spec.rb +120 -0
  76. data/spec/adhearsion/call_controller/output_spec.rb +466 -0
  77. data/spec/adhearsion/call_controller/record_spec.rb +125 -0
  78. data/spec/adhearsion/call_controller_spec.rb +395 -0
  79. data/spec/adhearsion/call_spec.rb +438 -0
  80. data/spec/adhearsion/calls_spec.rb +47 -0
  81. data/spec/adhearsion/configuration_spec.rb +308 -0
  82. data/spec/adhearsion/dialplan_controller_spec.rb +26 -0
  83. data/spec/adhearsion/events_spec.rb +112 -0
  84. data/spec/adhearsion/initializer/logging_spec.rb +58 -0
  85. data/spec/adhearsion/initializer_spec.rb +209 -122
  86. data/spec/adhearsion/logging_spec.rb +58 -47
  87. data/spec/adhearsion/menu_dsl/calculated_match_collection_spec.rb +56 -0
  88. data/spec/adhearsion/menu_dsl/calculated_match_spec.rb +57 -0
  89. data/spec/adhearsion/menu_dsl/fixnum_match_calculator_spec.rb +33 -0
  90. data/spec/adhearsion/menu_dsl/match_calculator_spec.rb +13 -0
  91. data/spec/adhearsion/menu_dsl/menu_builder_spec.rb +118 -0
  92. data/spec/adhearsion/menu_dsl/menu_spec.rb +210 -0
  93. data/spec/adhearsion/menu_dsl/range_match_calculator_spec.rb +28 -0
  94. data/spec/adhearsion/menu_dsl/string_match_calculator_spec.rb +36 -0
  95. data/spec/adhearsion/menu_dsl_spec.rb +12 -0
  96. data/spec/adhearsion/outbound_call_spec.rb +174 -0
  97. data/spec/adhearsion/plugin_spec.rb +489 -0
  98. data/spec/adhearsion/process_spec.rb +34 -0
  99. data/spec/adhearsion/punchblock_plugin/initializer_spec.rb +294 -0
  100. data/spec/adhearsion/router/route_spec.rb +99 -0
  101. data/spec/adhearsion/router_spec.rb +106 -0
  102. data/spec/adhearsion_spec.rb +46 -0
  103. data/spec/spec_helper.rb +14 -14
  104. data/spec/support/call_controller_test_helpers.rb +48 -0
  105. data/spec/support/initializer_stubs.rb +8 -13
  106. data/spec/support/punchblock_mocks.rb +6 -0
  107. metadata +255 -253
  108. data/CHANGELOG +0 -174
  109. data/bin/ahnctl +0 -68
  110. data/bin/jahn +0 -43
  111. data/examples/asterisk_manager_interface/standalone.rb +0 -51
  112. data/lib/adhearsion/commands.rb +0 -302
  113. data/lib/adhearsion/component_manager.rb +0 -278
  114. data/lib/adhearsion/component_manager/component_tester.rb +0 -54
  115. data/lib/adhearsion/component_manager/spec_framework.rb +0 -18
  116. data/lib/adhearsion/events_support.rb +0 -65
  117. data/lib/adhearsion/foundation/blank_slate.rb +0 -3
  118. data/lib/adhearsion/foundation/event_socket.rb +0 -205
  119. data/lib/adhearsion/foundation/future_resource.rb +0 -36
  120. data/lib/adhearsion/foundation/metaprogramming.rb +0 -17
  121. data/lib/adhearsion/foundation/numeric.rb +0 -13
  122. data/lib/adhearsion/foundation/pseudo_guid.rb +0 -10
  123. data/lib/adhearsion/foundation/relationship_properties.rb +0 -42
  124. data/lib/adhearsion/foundation/string.rb +0 -26
  125. data/lib/adhearsion/generators/app/templates/.ahnrc +0 -34
  126. data/lib/adhearsion/generators/app/templates/README +0 -8
  127. data/lib/adhearsion/generators/app/templates/components/ami_remote/ami_remote.rb +0 -15
  128. data/lib/adhearsion/generators/app/templates/components/disabled/HOW_TO_ENABLE +0 -7
  129. data/lib/adhearsion/generators/app/templates/components/disabled/stomp_gateway/README.markdown +0 -47
  130. data/lib/adhearsion/generators/app/templates/components/disabled/stomp_gateway/stomp_gateway.rb +0 -34
  131. data/lib/adhearsion/generators/app/templates/components/disabled/stomp_gateway/stomp_gateway.yml +0 -12
  132. data/lib/adhearsion/generators/app/templates/components/disabled/xmpp_gateway/README.markdown +0 -3
  133. data/lib/adhearsion/generators/app/templates/components/disabled/xmpp_gateway/xmpp_gateway.rb +0 -11
  134. data/lib/adhearsion/generators/app/templates/components/disabled/xmpp_gateway/xmpp_gateway.yml +0 -0
  135. data/lib/adhearsion/generators/app/templates/config/startup.rb +0 -81
  136. data/lib/adhearsion/generators/app/templates/dialplan.rb +0 -3
  137. data/lib/adhearsion/generators/app/templates/events.rb +0 -33
  138. data/lib/adhearsion/host_definitions.rb +0 -67
  139. data/lib/adhearsion/initializer/asterisk.rb +0 -86
  140. data/lib/adhearsion/initializer/configuration.rb +0 -324
  141. data/lib/adhearsion/initializer/database.rb +0 -60
  142. data/lib/adhearsion/initializer/drb.rb +0 -31
  143. data/lib/adhearsion/initializer/freeswitch.rb +0 -22
  144. data/lib/adhearsion/initializer/ldap.rb +0 -57
  145. data/lib/adhearsion/initializer/rails.rb +0 -41
  146. data/lib/adhearsion/initializer/xmpp.rb +0 -42
  147. data/lib/adhearsion/tasks/components.rb +0 -32
  148. data/lib/adhearsion/tasks/database.rb +0 -5
  149. data/lib/adhearsion/tasks/deprecations.rb +0 -59
  150. data/lib/adhearsion/tasks/generating.rb +0 -20
  151. data/lib/adhearsion/tasks/lint.rb +0 -4
  152. data/lib/adhearsion/voip/asterisk.rb +0 -4
  153. data/lib/adhearsion/voip/asterisk/agi_server.rb +0 -121
  154. data/lib/adhearsion/voip/asterisk/commands.rb +0 -1966
  155. data/lib/adhearsion/voip/asterisk/config_generators/agents.conf.rb +0 -140
  156. data/lib/adhearsion/voip/asterisk/config_generators/config_generator.rb +0 -102
  157. data/lib/adhearsion/voip/asterisk/config_generators/queues.conf.rb +0 -250
  158. data/lib/adhearsion/voip/asterisk/config_generators/voicemail.conf.rb +0 -240
  159. data/lib/adhearsion/voip/asterisk/config_manager.rb +0 -64
  160. data/lib/adhearsion/voip/asterisk/manager_interface.rb +0 -697
  161. data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rb +0 -1681
  162. data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rl.rb +0 -341
  163. data/lib/adhearsion/voip/asterisk/manager_interface/ami_messages.rb +0 -78
  164. data/lib/adhearsion/voip/asterisk/manager_interface/ami_protocol_lexer_machine.rl +0 -87
  165. data/lib/adhearsion/voip/asterisk/special_dial_plan_managers.rb +0 -80
  166. data/lib/adhearsion/voip/call.rb +0 -521
  167. data/lib/adhearsion/voip/call_routing.rb +0 -64
  168. data/lib/adhearsion/voip/commands.rb +0 -17
  169. data/lib/adhearsion/voip/constants.rb +0 -39
  170. data/lib/adhearsion/voip/conveniences.rb +0 -18
  171. data/lib/adhearsion/voip/dial_plan.rb +0 -252
  172. data/lib/adhearsion/voip/dsl/dialing_dsl.rb +0 -151
  173. data/lib/adhearsion/voip/dsl/dialing_dsl/dialing_dsl_monkey_patches.rb +0 -37
  174. data/lib/adhearsion/voip/dsl/dialplan/control_passing_exception.rb +0 -27
  175. data/lib/adhearsion/voip/dsl/dialplan/dispatcher.rb +0 -124
  176. data/lib/adhearsion/voip/dsl/dialplan/parser.rb +0 -69
  177. data/lib/adhearsion/voip/dsl/dialplan/thread_mixin.rb +0 -16
  178. data/lib/adhearsion/voip/dsl/numerical_string.rb +0 -128
  179. data/lib/adhearsion/voip/freeswitch/basic_connection_manager.rb +0 -48
  180. data/lib/adhearsion/voip/freeswitch/event_handler.rb +0 -58
  181. data/lib/adhearsion/voip/freeswitch/freeswitch_dialplan_command_factory.rb +0 -129
  182. data/lib/adhearsion/voip/freeswitch/inbound_connection_manager.rb +0 -38
  183. data/lib/adhearsion/voip/freeswitch/oes_server.rb +0 -195
  184. data/lib/adhearsion/voip/menu_state_machine/calculated_match.rb +0 -80
  185. data/lib/adhearsion/voip/menu_state_machine/matchers.rb +0 -123
  186. data/lib/adhearsion/voip/menu_state_machine/menu_builder.rb +0 -57
  187. data/lib/adhearsion/xmpp/connection.rb +0 -61
  188. data/lib/theatre.rb +0 -147
  189. data/lib/theatre/README.markdown +0 -64
  190. data/lib/theatre/callback_definition_loader.rb +0 -86
  191. data/lib/theatre/guid.rb +0 -23
  192. data/lib/theatre/invocation.rb +0 -131
  193. data/lib/theatre/namespace_manager.rb +0 -153
  194. data/lib/theatre/version.rb +0 -2
  195. data/spec/adhearsion/cli_spec.rb +0 -306
  196. data/spec/adhearsion/component_manager_spec.rb +0 -292
  197. data/spec/adhearsion/constants_spec.rb +0 -8
  198. data/spec/adhearsion/drb_spec.rb +0 -65
  199. data/spec/adhearsion/fixtures/dialplan.rb +0 -3
  200. data/spec/adhearsion/foundation/event_socket_spec.rb +0 -168
  201. data/spec/adhearsion/host_definitions_spec.rb +0 -79
  202. data/spec/adhearsion/initializer/configuration_spec.rb +0 -291
  203. data/spec/adhearsion/initializer/loading_spec.rb +0 -154
  204. data/spec/adhearsion/initializer/paths_spec.rb +0 -74
  205. data/spec/adhearsion/relationship_properties_spec.rb +0 -54
  206. data/spec/adhearsion/voip/asterisk/agi_server_spec.rb +0 -473
  207. data/spec/adhearsion/voip/asterisk/ami/ami_spec.rb +0 -550
  208. data/spec/adhearsion/voip/asterisk/ami/lexer/ami_fixtures.yml +0 -30
  209. data/spec/adhearsion/voip/asterisk/ami/lexer/lexer_story +0 -291
  210. data/spec/adhearsion/voip/asterisk/ami/lexer/lexer_story.rb +0 -241
  211. data/spec/adhearsion/voip/asterisk/ami/lexer/story_helper.rb +0 -124
  212. data/spec/adhearsion/voip/asterisk/commands_spec.rb +0 -3241
  213. data/spec/adhearsion/voip/asterisk/config_file_generators/agents_spec.rb +0 -251
  214. data/spec/adhearsion/voip/asterisk/config_file_generators/queues_spec.rb +0 -323
  215. data/spec/adhearsion/voip/asterisk/config_file_generators/voicemail_spec.rb +0 -306
  216. data/spec/adhearsion/voip/asterisk/config_manager_spec.rb +0 -127
  217. data/spec/adhearsion/voip/asterisk/menu_command/calculated_match_spec.rb +0 -109
  218. data/spec/adhearsion/voip/asterisk/menu_command/matchers_spec.rb +0 -97
  219. data/spec/adhearsion/voip/call_routing_spec.rb +0 -125
  220. data/spec/adhearsion/voip/dialplan_manager_spec.rb +0 -468
  221. data/spec/adhearsion/voip/dsl/dialing_dsl_spec.rb +0 -270
  222. data/spec/adhearsion/voip/dsl/dispatcher_spec.rb +0 -82
  223. data/spec/adhearsion/voip/dsl/dispatcher_spec_helper.rb +0 -45
  224. data/spec/adhearsion/voip/dsl/parser_spec.rb +0 -69
  225. data/spec/adhearsion/voip/freeswitch/basic_connection_manager_spec.rb +0 -39
  226. data/spec/adhearsion/voip/freeswitch/inbound_connection_manager_spec.rb +0 -39
  227. data/spec/adhearsion/voip/freeswitch/oes_server_spec.rb +0 -9
  228. data/spec/adhearsion/voip/numerical_string_spec.rb +0 -61
  229. data/spec/adhearsion/voip/phone_number_spec.rb +0 -45
  230. data/spec/support/the_following_code.rb +0 -3
  231. data/spec/theatre/dsl_examples/simple_before_call.rb +0 -7
  232. data/spec/theatre/dsl_spec.rb +0 -69
  233. data/spec/theatre/invocation_spec.rb +0 -182
  234. data/spec/theatre/namespace_spec.rb +0 -125
  235. data/spec/theatre/spec_helper_spec.rb +0 -28
  236. data/spec/theatre/theatre_class_spec.rb +0 -148
@@ -0,0 +1,438 @@
1
+ require 'spec_helper'
2
+
3
+ module Adhearsion
4
+ describe Call do
5
+ let(:headers) { nil }
6
+ let(:offer) { mock_offer nil, headers }
7
+ subject { Adhearsion::Call.new offer }
8
+
9
+ after do
10
+ Adhearsion.active_calls.clear!
11
+ end
12
+
13
+ it { should respond_to :<< }
14
+
15
+ its(:end_reason) { should == nil }
16
+ it { should be_active }
17
+
18
+ its(:commands) { should be_a Call::CommandRegistry }
19
+ its(:commands) { should be_empty }
20
+
21
+ describe "its variables" do
22
+ context "with an offer with headers" do
23
+ let(:headers) { {:x_foo => 'bar'} }
24
+ its(:variables) { should == headers }
25
+ end
26
+
27
+ context "with an offer without headers" do
28
+ let(:headers) { nil }
29
+ its(:variables) { should == {} }
30
+ end
31
+
32
+ context "without an offer" do
33
+ let(:offer) { nil }
34
+ its(:variables) { should == {} }
35
+ end
36
+ end
37
+
38
+ it '#id should return the ID from the Offer' do
39
+ offer = mock_offer
40
+ Adhearsion::Call.new(offer).id.should == offer.call_id
41
+ end
42
+
43
+ it 'should store the original offer' do
44
+ offer = mock_offer
45
+ Adhearsion::Call.new(offer).offer.should == offer
46
+ end
47
+
48
+ describe 'without an offer' do
49
+ it 'should not raise an exception' do
50
+ lambda { Adhearsion::Call.new }.should_not raise_error
51
+ end
52
+ end
53
+
54
+ it "should store the Punchblock client from the Offer" do
55
+ offer = mock_offer
56
+ client = flexmock('Client')
57
+ offer.should_receive(:client).once.and_return(client)
58
+ Adhearsion::Call.new(offer).client.should == client
59
+ end
60
+
61
+ it 'a hungup call removes itself from the active calls' do
62
+ size_before = Adhearsion.active_calls.size
63
+
64
+ call = Adhearsion.active_calls.from_offer mock_offer
65
+ Adhearsion.active_calls.size.should > size_before
66
+ call.hangup
67
+ Adhearsion.active_calls.size.should == size_before
68
+ end
69
+
70
+ it 'allows the registration of event handlers which are called when messages are delivered' do
71
+ event = flexmock 'Event'
72
+ event.should_receive(:foo?).and_return true
73
+ response = flexmock 'Response'
74
+ response.should_receive(:call).once
75
+ subject.register_event_handler(:foo?) { response.call }
76
+ subject << event
77
+ end
78
+
79
+ describe "event handlers" do
80
+ let(:response) { flexmock 'Response' }
81
+
82
+ describe "for end events" do
83
+ let :event do
84
+ Punchblock::Event::End.new.tap do |e|
85
+ flexmock e, :reason => :hangup
86
+ end
87
+ end
88
+
89
+ it "should trigger any on_end callbacks set" do
90
+ response.should_receive(:call).once.with(event)
91
+ subject.on_end { |event| response.call event }
92
+ subject << event
93
+ end
94
+ end
95
+ end
96
+
97
+ describe "#<<" do
98
+ describe "with a Punchblock End" do
99
+ let :end_event do
100
+ Punchblock::Event::End.new.tap do |e|
101
+ flexmock e, :reason => :hangup
102
+ end
103
+ end
104
+
105
+ it "should mark the call as ended" do
106
+ flexmock(subject).should_receive(:hangup).once
107
+ subject << end_event
108
+ subject.should_not be_active
109
+ end
110
+
111
+ it "should set the end reason" do
112
+ subject << end_event
113
+ subject.end_reason.should == :hangup
114
+ end
115
+
116
+ it "should instruct the command registry to terminate" do
117
+ flexmock(subject.commands).should_receive(:terminate).once
118
+ subject << end_event
119
+ end
120
+ end
121
+ end
122
+
123
+ describe "tagging a call" do
124
+ it 'with a single Symbol' do
125
+ lambda {
126
+ subject.tag :moderator
127
+ }.should_not raise_error
128
+ end
129
+
130
+ it 'with multiple Symbols' do
131
+ lambda {
132
+ subject.tag :moderator
133
+ subject.tag :female
134
+ }.should_not raise_error
135
+ end
136
+
137
+ it 'with a non-Symbol, non-String object' do
138
+ bad_objects = [123, Object.new, 888.88, nil, true, false, StringIO.new]
139
+ bad_objects.each do |bad_object|
140
+ lambda {
141
+ subject.tag bad_object
142
+ }.should raise_error ArgumentError
143
+ end
144
+ end
145
+ end
146
+
147
+ it "#remove_tag" do
148
+ subject.tag :moderator
149
+ subject.tag :female
150
+ subject.remove_tag :female
151
+ subject.tag :male
152
+ subject.tags.should == [:moderator, :male]
153
+ end
154
+
155
+ describe "#tagged_with?" do
156
+ it 'with one tag' do
157
+ subject.tag :guest
158
+ subject.tagged_with?(:guest).should be true
159
+ subject.tagged_with?(:authorized).should be false
160
+ end
161
+
162
+ it 'with many tags' do
163
+ subject.tag :customer
164
+ subject.tag :authorized
165
+ subject.tagged_with?(:customer).should be true
166
+ subject.tagged_with?(:authorized).should be true
167
+ end
168
+ end
169
+
170
+ describe "#write_command" do
171
+ let(:mock_command) { flexmock('Command') }
172
+
173
+ it "should asynchronously write the command to the Punchblock connection" do
174
+ mock_client = flexmock('Client')
175
+ flexmock(subject).should_receive(:client).once.and_return mock_client
176
+ mock_client.should_receive(:execute_command).once.with(mock_command, :call_id => subject.id).and_return true
177
+ subject.write_command mock_command
178
+ end
179
+
180
+ describe "with a hungup call" do
181
+ before do
182
+ flexmock(subject).should_receive(:active?).and_return(false)
183
+ end
184
+
185
+ it "should raise a Hangup exception" do
186
+ lambda { subject.write_command mock_command }.should raise_error(Hangup)
187
+ end
188
+
189
+ describe "if the command is a Hangup" do
190
+ let(:mock_command) { Punchblock::Command::Hangup.new }
191
+
192
+ it "should not raise a Hangup exception" do
193
+ lambda { subject.write_command mock_command }.should_not raise_error
194
+ end
195
+ end
196
+ end
197
+ end
198
+
199
+ describe '#write_and_await_response' do
200
+ let(:message) { Punchblock::Command::Accept.new }
201
+ let(:response) { :foo }
202
+
203
+ before do
204
+ flexmock(message).should_receive(:execute!).and_return true
205
+ message.response = response
206
+ end
207
+
208
+ it "writes a command to the call" do
209
+ flexmock(subject).should_receive(:write_command).once.with(message)
210
+ subject.write_and_await_response message
211
+ end
212
+
213
+ it "adds the command to the registry" do
214
+ subject.write_and_await_response message
215
+ subject.commands.should_not be_empty
216
+ end
217
+
218
+ it "blocks until a response is received" do
219
+ slow_command = Punchblock::Command::Dial.new
220
+ Thread.new do
221
+ sleep 0.5
222
+ slow_command.response = response
223
+ end
224
+ starting_time = Time.now
225
+ subject.write_and_await_response slow_command
226
+ (Time.now - starting_time).should >= 0.5
227
+ end
228
+
229
+ describe "with a successful response" do
230
+ it "returns the executed command" do
231
+ subject.write_and_await_response(message).should be message
232
+ end
233
+ end
234
+
235
+ describe "with an error response" do
236
+ let(:response) { Exception.new }
237
+
238
+ it "raises the error" do
239
+ lambda { subject.write_and_await_response message }.should raise_error Exception
240
+ end
241
+ end
242
+ end
243
+
244
+ describe "basic control commands" do
245
+ include FlexMock::ArgumentTypes
246
+
247
+ def expect_message_waiting_for_response(message)
248
+ flexmock(subject).should_receive(:write_and_await_response).once.with(message).and_return(message)
249
+ end
250
+
251
+ describe '#accept' do
252
+ describe "with no headers" do
253
+ it 'should send an Accept message' do
254
+ expect_message_waiting_for_response Punchblock::Command::Accept.new
255
+ subject.accept
256
+ end
257
+ end
258
+
259
+ describe "with headers set" do
260
+ it 'should send an Accept message with the correct headers' do
261
+ headers = {:foo => 'bar'}
262
+ expect_message_waiting_for_response Punchblock::Command::Accept.new(:headers => headers)
263
+ subject.accept headers
264
+ end
265
+ end
266
+ end
267
+
268
+ describe '#answer' do
269
+ describe "with no headers" do
270
+ it 'should send an Answer message' do
271
+ expect_message_waiting_for_response Punchblock::Command::Answer.new
272
+ subject.answer
273
+ end
274
+ end
275
+
276
+ describe "with headers set" do
277
+ it 'should send an Answer message with the correct headers' do
278
+ headers = {:foo => 'bar'}
279
+ expect_message_waiting_for_response Punchblock::Command::Answer.new(:headers => headers)
280
+ subject.answer headers
281
+ end
282
+ end
283
+ end
284
+
285
+ describe '#reject' do
286
+ describe "with a reason given" do
287
+ it 'should send a Reject message with the correct reason' do
288
+ expect_message_waiting_for_response Punchblock::Command::Reject.new(:reason => :decline)
289
+ subject.reject :decline
290
+ end
291
+ end
292
+
293
+ describe "with no reason given" do
294
+ it 'should send a Reject message with the reason busy' do
295
+ expect_message_waiting_for_response Punchblock::Command::Reject.new(:reason => :busy)
296
+ subject.reject
297
+ end
298
+ end
299
+
300
+ describe "with no headers" do
301
+ it 'should send a Reject message' do
302
+ expect_message_waiting_for_response on { |c| c.is_a?(Punchblock::Command::Reject) && c.headers_hash == {} }
303
+ subject.reject
304
+ end
305
+ end
306
+
307
+ describe "with headers set" do
308
+ it 'should send a Hangup message with the correct headers' do
309
+ headers = {:foo => 'bar'}
310
+ expect_message_waiting_for_response on { |c| c.is_a?(Punchblock::Command::Reject) && c.headers_hash == headers }
311
+ subject.reject nil, headers
312
+ end
313
+ end
314
+ end
315
+
316
+ describe "#hangup!" do
317
+ describe "if the call is not active" do
318
+ before do
319
+ flexmock(subject).should_receive(:active?).and_return false
320
+ end
321
+
322
+ it "should do nothing and return false" do
323
+ flexmock(subject).should_receive(:write_and_await_response).never
324
+ subject.hangup!.should be false
325
+ end
326
+ end
327
+
328
+ describe "if the call is active" do
329
+ it "should mark the call inactive" do
330
+ expect_message_waiting_for_response Punchblock::Command::Hangup.new
331
+ subject.hangup!
332
+ subject.should_not be_active
333
+ end
334
+
335
+ describe "with no headers" do
336
+ it 'should send a Hangup message' do
337
+ expect_message_waiting_for_response Punchblock::Command::Hangup.new
338
+ subject.hangup!
339
+ end
340
+ end
341
+
342
+ describe "with headers set" do
343
+ it 'should send a Hangup message with the correct headers' do
344
+ headers = {:foo => 'bar'}
345
+ expect_message_waiting_for_response Punchblock::Command::Hangup.new(:headers => headers)
346
+ subject.hangup! headers
347
+ end
348
+ end
349
+ end
350
+ end
351
+
352
+ describe "#join" do
353
+ let(:other_call_id) { rand }
354
+
355
+ it "should mark the call inactive" do
356
+ expect_message_waiting_for_response Punchblock::Command::Join.new :other_call_id => other_call_id
357
+ subject.join other_call_id
358
+ end
359
+ end
360
+
361
+ describe "#execute_controller" do
362
+ let(:latch) { CountDownLatch.new 1 }
363
+ let(:mock_controller) { flexmock 'CallController' }
364
+
365
+ before do
366
+ flexmock subject, :write_and_await_response => true
367
+ end
368
+
369
+ it "should call #execute on the controller instance" do
370
+ flexmock(CallController).should_receive(:exec).once.with mock_controller
371
+ subject.execute_controller mock_controller, latch
372
+ latch.wait(3).should be_true
373
+ end
374
+
375
+ it "should hangup the call after all controllers have executed" do
376
+ flexmock(CallController).should_receive(:exec).once.with mock_controller
377
+ subject.should_receive(:hangup!).once
378
+ subject.execute_controller mock_controller, latch
379
+ latch.wait(3).should be_true
380
+ end
381
+ end
382
+ end
383
+
384
+ describe Call::CommandRegistry do
385
+ subject { Call::CommandRegistry.new }
386
+
387
+ it { should be_empty }
388
+
389
+ describe "#<<" do
390
+ it "should add a command to the registry" do
391
+ subject << :foo
392
+ subject.should_not be_empty
393
+ end
394
+ end
395
+
396
+ describe "#delete" do
397
+ it "should remove a command from the registry" do
398
+ subject << :foo
399
+ subject.should_not be_empty
400
+ subject.delete :foo
401
+ subject.should be_empty
402
+ end
403
+ end
404
+
405
+ describe "#terminate" do
406
+ let :commands do
407
+ [
408
+ Punchblock::Command::Answer.new,
409
+ Punchblock::Command::Answer.new
410
+ ]
411
+ end
412
+
413
+ it "should set each command's response to an instance of Adhearsion::Hangup if it doesn't already have a response" do
414
+ finished_command = Punchblock::Command::Answer.new
415
+ finished_command.request!
416
+ finished_command.response = :foo
417
+ subject << finished_command
418
+ commands.each do |command|
419
+ command.request!
420
+ subject << command
421
+ end
422
+ subject.terminate
423
+ commands.each do |command|
424
+ command.response.should be_a Hangup
425
+ end
426
+ finished_command.response.should == :foo
427
+ end
428
+ end
429
+ end
430
+
431
+ describe Call::Registry do
432
+ it "should set a value and retrieve it" do
433
+ Adhearsion::Call::Registry[:test_value] = '123'
434
+ Adhearsion::Call::Registry[:test_value].should == '123'
435
+ end
436
+ end
437
+ end
438
+ end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+
3
+ module Adhearsion
4
+ describe Calls do
5
+ before { Adhearsion.active_calls.clear! }
6
+
7
+ let(:call) { Adhearsion::Call.new mock_offer }
8
+
9
+ it 'can create a call and add it to the active calls' do
10
+ Adhearsion.active_calls.any?.should == false
11
+ call = Adhearsion.active_calls.from_offer mock_offer
12
+ call.should be_a Adhearsion::Call
13
+ Adhearsion.active_calls.size.should == 1
14
+ end
15
+
16
+ it '#size should return the size of the collection' do
17
+ subject.size.should == 0
18
+ subject << call
19
+ subject.size.should == 1
20
+ end
21
+
22
+ it '#remove_inactive_call should delete the call in the Hash' do
23
+ number_of_calls = 10
24
+ calls = Array.new(number_of_calls) { Adhearsion::Call.new mock_offer }
25
+ calls.each { |call| subject << call }
26
+
27
+ deleted_call = calls[number_of_calls / 2]
28
+ subject.remove_inactive_call deleted_call
29
+ subject.size.should == number_of_calls - 1
30
+ end
31
+
32
+ it '#find should pull the Call from the Hash using the id' do
33
+ subject << call
34
+ subject.find(call.id).should be call
35
+ end
36
+
37
+ it "finding calls by a tag" do
38
+ calls = Array.new(3) { Adhearsion::Call.new mock_offer }
39
+ calls.each { |call| subject << call }
40
+
41
+ tagged_call = calls.last
42
+ tagged_call.tag :moderator
43
+
44
+ subject.with_tag(:moderator).should == [tagged_call]
45
+ end
46
+ end
47
+ end