adhearsion 2.0.0.alpha2 → 2.0.0.alpha3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. data/.gitignore +16 -14
  2. data/CHANGELOG.md +17 -1
  3. data/adhearsion.gemspec +14 -13
  4. data/features/cli_basic.feature +30 -0
  5. data/features/cli_create.feature +24 -0
  6. data/features/cli_daemon.feature +21 -0
  7. data/features/cli_generate.feature +9 -0
  8. data/features/cli_start.feature +33 -0
  9. data/features/cli_stop.feature +38 -0
  10. data/features/controller_generator.feature +19 -0
  11. data/features/plugin_generator.feature +55 -0
  12. data/lib/adhearsion.rb +5 -1
  13. data/lib/adhearsion/call.rb +57 -51
  14. data/lib/adhearsion/call_controller.rb +4 -20
  15. data/lib/adhearsion/call_controller/dial.rb +34 -4
  16. data/lib/adhearsion/calls.rb +4 -1
  17. data/lib/adhearsion/cli_commands.rb +31 -6
  18. data/lib/adhearsion/configuration.rb +2 -6
  19. data/lib/adhearsion/console.rb +56 -17
  20. data/lib/adhearsion/generators.rb +53 -2
  21. data/lib/adhearsion/generators/app/app_generator.rb +2 -24
  22. data/lib/adhearsion/generators/app/templates/config/adhearsion.rb +1 -1
  23. data/lib/adhearsion/generators/controller/controller_generator.rb +18 -0
  24. data/lib/adhearsion/generators/controller/templates/lib/controller.rb +4 -0
  25. data/lib/adhearsion/generators/controller/templates/spec/controller_spec.rb +3 -0
  26. data/lib/adhearsion/generators/generator.rb +77 -0
  27. data/lib/adhearsion/generators/plugin/plugin_generator.rb +33 -0
  28. data/lib/adhearsion/generators/plugin/templates/.gitignore +9 -0
  29. data/lib/adhearsion/generators/plugin/templates/Gemfile.tt +4 -0
  30. data/lib/adhearsion/generators/plugin/templates/README.md.tt +2 -0
  31. data/lib/adhearsion/generators/plugin/templates/Rakefile.tt +1 -0
  32. data/lib/adhearsion/generators/plugin/templates/lib/plugin-template.rb.tt +5 -0
  33. data/lib/adhearsion/generators/plugin/templates/lib/plugin-template/controller_methods.rb.tt +10 -0
  34. data/lib/adhearsion/generators/plugin/templates/lib/plugin-template/plugin.rb.tt +29 -0
  35. data/lib/adhearsion/generators/plugin/templates/lib/plugin-template/version.rb.tt +3 -0
  36. data/lib/adhearsion/generators/plugin/templates/plugin-template.gemspec.tt +35 -0
  37. data/lib/adhearsion/generators/plugin/templates/spec/plugin-template/controller_methods_spec.rb.tt +26 -0
  38. data/lib/adhearsion/generators/plugin/templates/spec/spec_helper.rb.tt +13 -0
  39. data/lib/adhearsion/initializer.rb +14 -22
  40. data/lib/adhearsion/logging.rb +25 -16
  41. data/lib/adhearsion/outbound_call.rb +3 -3
  42. data/lib/adhearsion/plugin.rb +14 -0
  43. data/lib/adhearsion/punchblock_plugin.rb +6 -1
  44. data/lib/adhearsion/punchblock_plugin/initializer.rb +8 -8
  45. data/lib/adhearsion/tasks/configuration.rb +1 -1
  46. data/lib/adhearsion/version.rb +1 -1
  47. data/spec/adhearsion/call_controller/dial_spec.rb +108 -17
  48. data/spec/adhearsion/call_controller_spec.rb +7 -64
  49. data/spec/adhearsion/call_spec.rb +48 -29
  50. data/spec/adhearsion/calls_spec.rb +7 -0
  51. data/spec/adhearsion/configuration_spec.rb +14 -14
  52. data/spec/adhearsion/console_spec.rb +124 -4
  53. data/spec/adhearsion/generators_spec.rb +17 -0
  54. data/spec/adhearsion/initializer_spec.rb +22 -18
  55. data/spec/adhearsion/logging_spec.rb +78 -48
  56. data/spec/adhearsion/outbound_call_spec.rb +6 -15
  57. data/spec/adhearsion/plugin_spec.rb +18 -0
  58. data/spec/adhearsion/process_spec.rb +10 -1
  59. data/spec/adhearsion/punchblock_plugin/initializer_spec.rb +8 -6
  60. data/spec/spec_helper.rb +5 -2
  61. data/spec/support/call_controller_test_helpers.rb +1 -1
  62. data/spec/support/initializer_stubs.rb +1 -1
  63. metadata +106 -66
  64. data/features/cli.feature +0 -108
  65. data/lib/adhearsion/initializer/logging.rb +0 -33
  66. data/spec/adhearsion/initializer/logging_spec.rb +0 -55
@@ -41,14 +41,14 @@ module Adhearsion
41
41
 
42
42
  write_and_await_response(Punchblock::Command::Dial.new(options), wait_timeout).tap do |dial_command|
43
43
  @dial_command = dial_command
44
- Adhearsion.active_calls << self
44
+ Adhearsion.active_calls << current_actor
45
45
  end
46
46
  end
47
47
 
48
48
  def run_router
49
49
  catching_standard_errors do
50
- dispatcher = Adhearsion.router.handle self
51
- dispatcher.call self
50
+ dispatcher = Adhearsion.router.handle current_actor
51
+ dispatcher.call current_actor
52
52
  end
53
53
  end
54
54
 
@@ -105,6 +105,20 @@ module Adhearsion
105
105
  end
106
106
  end
107
107
 
108
+ ##
109
+ # Register generator classes
110
+ #
111
+ # @example
112
+ # FooBar = Class.new Adhearsion::Plugin do
113
+ # generators :'my_plugin:foo_generator' => FooGenerator
114
+ # end
115
+ #
116
+ def generators(mapping)
117
+ mapping.each_pair do |name, klass|
118
+ Generators.add_generator name, klass
119
+ end
120
+ end
121
+
108
122
  def subclasses
109
123
  @subclasses ||= []
110
124
  end
@@ -23,11 +23,16 @@ module Adhearsion
23
23
  end
24
24
 
25
25
  init :punchblock do
26
- Initializer.start
26
+ Initializer.init
27
+ end
28
+
29
+ run :punchblock do
30
+ Initializer.run
27
31
  end
28
32
 
29
33
  class << self
30
34
  delegate :client, :to => Initializer
35
+ delegate :connection, :to => Initializer
31
36
 
32
37
  def validate_number(value)
33
38
  return 1.0/0.0 if ["Infinity", 1.0/0.0].include? value
@@ -1,12 +1,12 @@
1
1
  module Adhearsion
2
2
  class PunchblockPlugin
3
3
  class Initializer
4
- cattr_accessor :config, :client, :dispatcher, :attempts
4
+ cattr_accessor :config, :client, :connection, :dispatcher, :attempts
5
5
 
6
6
  self.attempts = 0
7
7
 
8
8
  class << self
9
- def start
9
+ def init
10
10
  self.config = Adhearsion.config[:punchblock]
11
11
  connection_class = case (self.config.platform || :xmpp)
12
12
  when :xmpp
@@ -25,7 +25,7 @@ module Adhearsion
25
25
  :mixers_domain => self.config.mixers_domain
26
26
  }
27
27
 
28
- connection = connection_class.new connection_options
28
+ self.connection = connection_class.new connection_options
29
29
  self.client = ::Punchblock::Client.new :connection => connection
30
30
 
31
31
  # Tell the Punchblock connection that we are ready to process calls.
@@ -65,7 +65,9 @@ module Adhearsion
65
65
  Events.punchblock proc { |e| e.respond_to?(:call_id) }, :call_id do |event|
66
66
  dispatch_call_event event
67
67
  end
68
+ end
68
69
 
70
+ def run
69
71
  connect
70
72
  end
71
73
 
@@ -119,6 +121,7 @@ module Adhearsion
119
121
  when :booting, :rejecting
120
122
  call.reject :decline
121
123
  when :running
124
+ call.accept
122
125
  dispatcher = Adhearsion.router.handle call
123
126
  dispatcher.call call
124
127
  else
@@ -129,11 +132,8 @@ module Adhearsion
129
132
 
130
133
  def dispatch_call_event(event, latch = nil)
131
134
  if call = Adhearsion.active_calls.find(event.call_id)
132
- logger.debug "Event received for call #{call.id}: #{event.inspect}"
133
- Thread.new do
134
- call << event
135
- latch.countdown! if latch
136
- end
135
+ call.deliver_message! event
136
+ latch.countdown! if latch
137
137
  else
138
138
  logger.error "Event received for inactive call #{event.call_id}: #{event.inspect}"
139
139
  end
@@ -1,6 +1,6 @@
1
1
  namespace :config do
2
2
  desc "Show configuration values; accepts a parameter: [nil|platform|<plugin-name>|all]"
3
- task :show, :name, :needs => :environment do |t, args|
3
+ task :show, [:name] => [:environment] do |t, args|
4
4
  name = args.name.nil? ? :all : args.name.to_sym
5
5
  puts "\nAdhearsion.config do |config|\n\n"
6
6
  puts Adhearsion.config.description name, :show_values => true
@@ -1,5 +1,5 @@
1
1
  module Adhearsion #:nodoc:
2
- VERSION = '2.0.0.alpha2'
2
+ VERSION = '2.0.0.alpha3'
3
3
 
4
4
  class PkgVersion
5
5
  include Comparable
@@ -6,11 +6,11 @@ module Adhearsion
6
6
  include CallControllerTestHelpers
7
7
 
8
8
  let(:to) { 'sip:foo@bar.com' }
9
- let(:other_call_id) { rand }
9
+ let(:other_call_id) { new_uuid }
10
10
  let(:other_mock_call) { flexmock OutboundCall.new, :id => other_call_id }
11
11
 
12
12
  let(:second_to) { 'sip:baz@bar.com' }
13
- let(:second_other_call_id) { rand }
13
+ let(:second_other_call_id) { new_uuid }
14
14
  let(:second_other_mock_call) { flexmock OutboundCall.new, :id => second_other_call_id }
15
15
 
16
16
  let(:mock_end) { flexmock Punchblock::Event::End.new, :reason => :hangup }
@@ -18,26 +18,26 @@ module Adhearsion
18
18
 
19
19
  let(:latch) { CountDownLatch.new 1 }
20
20
 
21
- def mock_dial
22
- flexmock(OutboundCall).new_instances.should_receive(:dial).and_return true
23
- end
24
-
25
21
  describe "#dial" do
26
- it "should create a new call and return it" do
27
- mock_dial
28
- t = Thread.new do
29
- subject.dial(to, {}, latch).should be_a OutboundCall
22
+ it "should dial the call to the correct endpoint and return it" do
23
+ other_mock_call
24
+ flexmock(OutboundCall).should_receive(:new).and_return other_mock_call
25
+ flexmock(other_mock_call).should_receive(:dial).with(to, :from => 'foo').once
26
+ dial_thread = Thread.new do
27
+ subject.dial(to, :from => 'foo').should be_a OutboundCall
30
28
  end
31
- latch.countdown!
32
- t.join
29
+ sleep 0.1
30
+ other_mock_call << mock_end
31
+ dial_thread.join.should be_true
33
32
  end
34
33
 
35
- it "should dial the call to the correct endpoint" do
34
+ it "should default the caller ID to that of the original call" do
36
35
  other_mock_call
36
+ flexmock call, :from => 'sip:foo@bar.com'
37
37
  flexmock(OutboundCall).should_receive(:new).and_return other_mock_call
38
- flexmock(other_mock_call).should_receive(:dial).with(to, :from => 'foo').once
38
+ flexmock(other_mock_call).should_receive(:dial).with(to, :from => 'sip:foo@bar.com').once
39
39
  dial_thread = Thread.new do
40
- subject.dial to, :from => 'foo'
40
+ subject.dial to
41
41
  end
42
42
  sleep 0.1
43
43
  other_mock_call << mock_end
@@ -49,6 +49,7 @@ module Adhearsion
49
49
  other_mock_call
50
50
 
51
51
  flexmock(other_mock_call).should_receive(:dial).once
52
+ flexmock(other_mock_call).should_receive(:hangup).once
52
53
  flexmock(OutboundCall).should_receive(:new).and_return other_mock_call
53
54
 
54
55
  latch = CountDownLatch.new 1
@@ -65,11 +66,33 @@ module Adhearsion
65
66
  latch.wait(1).should be_true
66
67
  end
67
68
 
69
+ it "unblocks the original controller if the original call ends" do
70
+ other_mock_call
71
+
72
+ flexmock(other_mock_call).should_receive(:dial).once
73
+ flexmock(other_mock_call).should_receive(:hangup).once
74
+ flexmock(OutboundCall).should_receive(:new).and_return other_mock_call
75
+
76
+ latch = CountDownLatch.new 1
77
+
78
+ Thread.new do
79
+ subject.dial to
80
+ latch.countdown!
81
+ end
82
+
83
+ latch.wait(1).should be_false
84
+
85
+ call << mock_end
86
+
87
+ latch.wait(1).should be_true
88
+ end
89
+
68
90
  it "joins the new call to the existing one on answer" do
69
91
  other_mock_call
70
92
 
71
93
  flexmock(other_mock_call).should_receive(:dial).once
72
94
  flexmock(other_mock_call).should_receive(:join).once.with(call)
95
+ flexmock(other_mock_call).should_receive(:hangup).once
73
96
  flexmock(OutboundCall).should_receive(:new).and_return other_mock_call
74
97
 
75
98
  latch = CountDownLatch.new 1
@@ -86,6 +109,29 @@ module Adhearsion
86
109
 
87
110
  latch.wait(1).should be_true
88
111
  end
112
+
113
+ it "hangs up the new call when the dial unblocks" do
114
+ other_mock_call
115
+
116
+ flexmock(other_mock_call).should_receive(:dial).once
117
+ flexmock(other_mock_call).should_receive(:join).once.with(call)
118
+ flexmock(other_mock_call).should_receive(:hangup).once
119
+ flexmock(OutboundCall).should_receive(:new).and_return other_mock_call
120
+
121
+ latch = CountDownLatch.new 1
122
+
123
+ Thread.new do
124
+ subject.dial to
125
+ latch.countdown!
126
+ end
127
+
128
+ latch.wait(1).should be_false
129
+
130
+ other_mock_call << mock_answered
131
+ call << mock_end
132
+
133
+ latch.wait(1).should be_true
134
+ end
89
135
  end
90
136
 
91
137
  describe "with multiple third parties specified" do
@@ -95,10 +141,11 @@ module Adhearsion
95
141
 
96
142
  flexmock(other_mock_call).should_receive(:dial).once
97
143
  flexmock(other_mock_call).should_receive(:join).once.with(call)
98
- flexmock(other_mock_call).should_receive(:hangup!).never
144
+ flexmock(other_mock_call).should_receive(:hangup).once
99
145
 
100
146
  flexmock(second_other_mock_call).should_receive(:dial).once
101
- flexmock(second_other_mock_call).should_receive(:hangup!).once
147
+ flexmock(second_other_mock_call).should_receive(:join).never
148
+ flexmock(second_other_mock_call).should_receive(:hangup).twice
102
149
 
103
150
  flexmock(OutboundCall).should_receive(:new).and_return other_mock_call, second_other_mock_call
104
151
  latch = CountDownLatch.new 1
@@ -114,6 +161,49 @@ module Adhearsion
114
161
  other_mock_call << mock_answered
115
162
  other_mock_call << mock_end
116
163
 
164
+ latch.wait(1).should be_false
165
+
166
+ second_other_mock_call << mock_end
167
+
168
+ latch.wait(2).should be_true
169
+
170
+ t.join
171
+ calls = t.value
172
+ calls.should have(2).calls
173
+ calls.each { |c| c.should be_a OutboundCall }
174
+ end
175
+
176
+ it "unblocks when the joined call unjoins, allowing it to proceed further" do
177
+ other_mock_call
178
+ second_other_mock_call
179
+
180
+ flexmock(other_mock_call).should_receive(:dial).once
181
+ flexmock(other_mock_call).should_receive(:join).once.with(call)
182
+ flexmock(other_mock_call).should_receive(:hangup).once
183
+
184
+ flexmock(second_other_mock_call).should_receive(:dial).once
185
+ flexmock(second_other_mock_call).should_receive(:join).never
186
+ flexmock(second_other_mock_call).should_receive(:hangup).twice
187
+
188
+ flexmock(OutboundCall).should_receive(:new).and_return other_mock_call, second_other_mock_call
189
+ latch = CountDownLatch.new 1
190
+
191
+ t = Thread.new do
192
+ calls = subject.dial [to, second_to]
193
+ latch.countdown!
194
+ calls
195
+ end
196
+
197
+ latch.wait(1).should be_false
198
+
199
+ other_mock_call << mock_answered
200
+ other_mock_call << Punchblock::Event::Unjoined.new(:other_call_id => call.id)
201
+ other_mock_call << mock_end
202
+
203
+ latch.wait(1).should be_false
204
+
205
+ second_other_mock_call << mock_end
206
+
117
207
  latch.wait(2).should be_true
118
208
 
119
209
  t.join
@@ -130,6 +220,7 @@ module Adhearsion
130
220
  other_mock_call
131
221
 
132
222
  flexmock(other_mock_call).should_receive(:dial).once
223
+ flexmock(other_mock_call).should_receive(:hangup).once
133
224
  flexmock(OutboundCall).should_receive(:new).and_return other_mock_call
134
225
 
135
226
  latch = CountDownLatch.new 1
@@ -29,41 +29,7 @@ module Adhearsion
29
29
  describe "execution on a call" do
30
30
  before do
31
31
  flexmock subject, :execute_component_and_await_completion => nil
32
- flexmock call, :write_and_await_response => nil
33
- end
34
-
35
- context "when auto-accept is enabled" do
36
- before do
37
- Adhearsion.config.platform.automatically_accept_incoming_calls = true
38
- end
39
-
40
- it "should accept the call" do
41
- subject.should_receive(:accept).once.ordered
42
- subject.should_receive(:run).once.ordered
43
- subject.execute!
44
- end
45
-
46
- context "and accept is skipped" do
47
- before { subject.skip_accept! }
48
-
49
- it "should not accept the call" do
50
- subject.should_receive(:accept).never
51
- subject.should_receive(:run).once
52
- subject.execute!
53
- end
54
- end
55
- end
56
-
57
- context "when auto-accept is disabled" do
58
- before do
59
- Adhearsion.config.platform.automatically_accept_incoming_calls = false
60
- end
61
-
62
- it "should not accept the call" do
63
- subject.should_receive(:accept).never
64
- subject.should_receive(:run).once
65
- subject.execute!
66
- end
32
+ flexmock call.wrapped_object, :write_and_await_response => nil
67
33
  end
68
34
 
69
35
  it "catches Hangup exceptions and logs the hangup" do
@@ -137,9 +103,8 @@ module Adhearsion
137
103
 
138
104
  before do
139
105
  flexmock subject, :execute_component_and_await_completion => nil
140
- flexmock call, :write_and_await_response => nil
106
+ flexmock call.wrapped_object, :write_and_await_response => nil
141
107
  flexmock(Events).should_receive(:trigger).with(:exception, Exception).never
142
- Adhearsion.config.platform.automatically_accept_incoming_calls = true
143
108
  end
144
109
 
145
110
  it "should invoke another controller before returning to the current controller" do
@@ -155,12 +120,6 @@ module Adhearsion
155
120
  subject.execute!
156
121
  end
157
122
 
158
- it "should not attempt to accept the call again" do
159
- call.should_receive(:accept).once
160
-
161
- subject.execute!
162
- end
163
-
164
123
  it "should allow the outer controller to cease execution and handle remote hangups" do
165
124
  subject[:second_controller] = SecondControllerWithRemoteHangup
166
125
 
@@ -195,11 +154,10 @@ module Adhearsion
195
154
  subject { PassController.new call }
196
155
 
197
156
  before do
198
- flexmock(call).should_receive(:write_and_await_response).and_return nil
157
+ flexmock(call.wrapped_object).should_receive(:write_and_await_response).and_return nil
199
158
  flexmock subject, :execute_component_and_await_completion => nil
200
159
  flexmock(SecondController).new_instances.should_receive(:md_check).once.with :foo => 'bar'
201
160
  flexmock(Events).should_receive(:trigger).with(:exception, Exception).never
202
- Adhearsion.config.platform.automatically_accept_incoming_calls = true
203
161
  end
204
162
 
205
163
  let(:latch) { CountDownLatch.new 1 }
@@ -208,18 +166,12 @@ module Adhearsion
208
166
  subject.should_receive(:before).once.ordered
209
167
  call.should_receive(:answer).once.ordered
210
168
  subject.should_receive(:after).never.ordered
211
- call.should_receive(:hangup!).once.ordered
169
+ call.wrapped_object.should_receive(:hangup).once.ordered
212
170
 
213
171
  call.execute_controller subject, latch
214
172
  latch.wait(1).should be_true
215
173
  end
216
174
 
217
- it "should not attempt to accept the call again" do
218
- call.should_receive(:accept).once
219
-
220
- CallController.exec subject
221
- end
222
-
223
175
  it "should execute after_call callbacks before passing control" do
224
176
  subject.should_receive(:before).once.ordered
225
177
  subject.should_receive(:foobar).once.ordered
@@ -296,13 +248,6 @@ module Adhearsion
296
248
  end
297
249
  end
298
250
 
299
- describe '#accept' do
300
- it "should delegate to the call" do
301
- flexmock(call).should_receive(:accept).once.with(:foo)
302
- subject.accept :foo
303
- end
304
- end
305
-
306
251
  describe '#answer' do
307
252
  it "should delegate to the call" do
308
253
  flexmock(call).should_receive(:answer).once.with(:foo)
@@ -319,7 +264,7 @@ module Adhearsion
319
264
 
320
265
  describe '#hangup' do
321
266
  it "should delegate to the call" do
322
- flexmock(call).should_receive(:hangup!).once.with(:foo)
267
+ flexmock(call).should_receive(:hangup).once.with(:foo)
323
268
  subject.hangup :foo
324
269
  end
325
270
  end
@@ -378,13 +323,11 @@ describe ExampleCallController do
378
323
 
379
324
  before do
380
325
  flexmock subject, :execute_component_and_await_completion => nil
381
- flexmock call, :write_and_await_response => nil
382
- Adhearsion.config.platform.automatically_accept_incoming_calls = true
326
+ flexmock call.wrapped_object, :write_and_await_response => nil
383
327
  end
384
328
 
385
- it "should execute the before_call callbacks before accepting the call" do
329
+ it "should execute the before_call callbacks before processing the call" do
386
330
  subject.should_receive(:setup_models).twice.ordered
387
- subject.should_receive(:accept).once.ordered
388
331
  subject.should_receive(:join_to_conference).once.ordered
389
332
  subject.execute!
390
333
  end