adhearsion 2.0.0.rc3 → 2.0.0.rc4

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,13 @@
1
1
  # [develop](https://github.com/adhearsion/adhearsion)
2
2
 
3
+ # [2.0.0.rc4](https://github.com/adhearsion/adhearsion/compare/v2.0.0.rc3...v2.0.0.rc4) - [2012-03-30](https://rubygems.org/gems/adhearsion/versions/2.0.0.rc4)
4
+ * Feature: `Call#execute_controller` now takes a post-execution callback (proc)
5
+ * Feature: App generator now includes directory scaffolding for call controller specs and a sample `spec_helper.rb` which loads app config and the `lib/` directory
6
+ * Bugfix: Calls should be hung up when router executed controllers complete, not after everything executed by `Call#execute_controller`
7
+ * Bugfix: Deal with race conditions raising exceptions when hanging up calls after a controller executes
8
+ * Bugfix: Updates to new dependency APIs
9
+ * Bugfix: Ensure `Call::Hangup` exceptions are captured properly by the router and fix test synchronization
10
+
3
11
  # [2.0.0.rc3](https://github.com/adhearsion/adhearsion/compare/v2.0.0.rc2...v2.0.0.rc3) - [2012-03-23](https://rubygems.org/gems/adhearsion/versions/2.0.0.rc3)
4
12
  * Bugfix/Change: `Adhearsion::Calls` (`Adhearsion.active_calls`) now exactly mirrors the Hash API
5
13
  * Bugfix: Fix mis-use of `PlaybackError` (wrong namespace)
@@ -20,7 +20,7 @@ Gem::Specification.new do |s|
20
20
 
21
21
  # Runtime dependencies
22
22
  s.add_runtime_dependency 'bundler', [">= 1.0.10"]
23
- s.add_runtime_dependency 'punchblock', [">= 0.10.0"]
23
+ s.add_runtime_dependency 'punchblock', [">= 0.12.0"]
24
24
  s.add_runtime_dependency 'logging', [">= 1.6.1"]
25
25
  s.add_runtime_dependency 'adhearsion-loquacious', [">= 1.9.0"]
26
26
  s.add_runtime_dependency 'activesupport', [">= 3.0.10"]
@@ -10,14 +10,19 @@ Feature: Adhearsion App Generator
10
10
  | lib |
11
11
  | config |
12
12
  | script |
13
+ | spec |
14
+ | spec/call_controllers |
15
+ | spec/support |
13
16
 
14
17
  And the following files should exist:
15
18
  | .gitignore |
19
+ | .rspec |
16
20
  | config/adhearsion.rb |
17
21
  | config/environment.rb |
18
22
  | Gemfile |
19
23
  | lib/simon_game.rb |
20
24
  | script/ahn |
25
+ | spec/spec_helper.rb |
21
26
  | README.md |
22
27
  | Rakefile |
23
28
  | Procfile |
@@ -5,5 +5,11 @@ Feature: Adhearsion Ahn CLI (generate)
5
5
 
6
6
  Scenario: Listing generators
7
7
  When I run `ahn generate`
8
- Then the output should contain "Please choose a generator below."
9
- And the output should contain "controller"
8
+ Then the output should contain "Available generators:"
9
+ And the output should contain "controller [controller_name]: A call controller template. 'controller_name' should be the disired class name, either CamelCase or under_scored."
10
+ Then the output should contain "plugin [plugin_name]: A plugin template. 'plugin_name' should be the disired plugin module name, either CamelCase or under_scored."
11
+
12
+ Scenario: Generator help
13
+ When I run `ahn help generate`
14
+ Then the output should contain "controller [controller_name]: A call controller template. 'controller_name' should be the disired class name, either CamelCase or under_scored."
15
+ Then the output should contain "plugin [plugin_name]: A plugin template. 'plugin_name' should be the disired plugin module name, either CamelCase or under_scored."
@@ -43,7 +43,7 @@ module Adhearsion
43
43
  end
44
44
 
45
45
  def id
46
- offer.call_id if offer
46
+ offer.target_call_id if offer
47
47
  end
48
48
 
49
49
  def tags
@@ -90,13 +90,13 @@ module Adhearsion
90
90
  end
91
91
 
92
92
  register_event_handler Punchblock::Event::Joined do |event|
93
- target = event.other_call_id || event.mixer_name
93
+ target = event.call_id || event.mixer_name
94
94
  signal :joined, target
95
95
  throw :pass
96
96
  end
97
97
 
98
98
  register_event_handler Punchblock::Event::Unjoined do |event|
99
- target = event.other_call_id || event.mixer_name
99
+ target = event.call_id || event.mixer_name
100
100
  signal :unjoined, target
101
101
  throw :pass
102
102
  end
@@ -176,15 +176,12 @@ module Adhearsion
176
176
  def join_options_with_target(target, options = {})
177
177
  options.merge(case target
178
178
  when Call
179
- { :other_call_id => target.id }
179
+ { :call_id => target.id }
180
180
  when String
181
- { :other_call_id => target }
181
+ { :call_id => target }
182
182
  when Hash
183
183
  abort ArgumentError.new "You cannot specify both a call ID and mixer name" if target.has_key?(:call_id) && target.has_key?(:mixer_name)
184
- target.tap do |t|
185
- t[:other_call_id] = t[:call_id]
186
- t.delete :call_id
187
- end
184
+ target
188
185
  else
189
186
  abort ArgumentError.new "Don't know how to join to #{target.inspect}"
190
187
  end)
@@ -258,15 +255,15 @@ module Adhearsion
258
255
  "#<#{self.class}:#{id} #{attrs.join ', '}>"
259
256
  end
260
257
 
261
- def execute_controller(controller, latch = nil)
258
+ def execute_controller(controller, completion_callback = nil)
259
+ call = current_actor
262
260
  Thread.new do
263
261
  catching_standard_errors do
264
262
  begin
265
263
  CallController.exec controller
266
264
  ensure
267
- hangup
265
+ completion_callback.call call if completion_callback
268
266
  end
269
- latch.countdown! if latch
270
267
  end
271
268
  end.tap { |t| Adhearsion::Process.important_threads << t }
272
269
  end
@@ -69,6 +69,7 @@ module Adhearsion
69
69
  Events.trigger :exception, [e, logger]
70
70
  ensure
71
71
  after_call
72
+ logger.debug "Finished executing controller #{self.inspect}"
72
73
  end
73
74
 
74
75
  def run
@@ -145,7 +146,7 @@ module Adhearsion
145
146
  end
146
147
  block_until_resumed
147
148
  join_command = call.join target, options
148
- waiter = join_command.other_call_id || join_command.mixer_name
149
+ waiter = join_command.call_id || join_command.mixer_name
149
150
  if async
150
151
  call.wait_for_joined waiter
151
152
  else
@@ -64,7 +64,7 @@ module Adhearsion
64
64
  end
65
65
  end
66
66
 
67
- new_call.register_event_handler Punchblock::Event::Unjoined, :other_call_id => call.id do |unjoined|
67
+ new_call.register_event_handler Punchblock::Event::Unjoined, :call_id => call.id do |unjoined|
68
68
  new_call["dial_countdown_#{call.id}"] = true
69
69
  latch.countdown!
70
70
  throw :pass
@@ -3,6 +3,10 @@
3
3
  require 'fileutils'
4
4
  require 'adhearsion/script_ahn_loader'
5
5
  require 'thor'
6
+ require 'adhearsion/generators/controller/controller_generator'
7
+ require 'adhearsion/generators/plugin/plugin_generator'
8
+ Adhearsion::Generators.add_generator :controller, Adhearsion::Generators::ControllerGenerator
9
+ Adhearsion::Generators.add_generator :plugin, Adhearsion::Generators::PluginGenerator
6
10
 
7
11
  class Thor
8
12
  class Task
@@ -34,17 +38,12 @@ module Adhearsion
34
38
  Generators::AppGenerator.start
35
39
  end
36
40
 
37
- desc "generate [generator_name] arguments", "Invoke a generator"
41
+ desc "generate [generator_name] arguments", Generators.help
38
42
  def generate(generator_name = nil, *args)
39
- require 'adhearsion/generators/controller/controller_generator'
40
- Generators.add_generator :controller, Adhearsion::Generators::ControllerGenerator
41
- require 'adhearsion/generators/plugin/plugin_generator'
42
- Generators.add_generator :plugin, Adhearsion::Generators::PluginGenerator
43
-
44
43
  if generator_name
45
44
  Generators.invoke generator_name
46
45
  else
47
- Generators.help
46
+ help 'generate'
48
47
  end
49
48
  end
50
49
 
@@ -10,13 +10,12 @@ module Adhearsion
10
10
 
11
11
  # Show help message with available generators.
12
12
  def help(command = 'generate')
13
- puts "Usage: ahn #{command} GENERATOR_NAME [args] [options]"
14
- puts
15
- puts "Please choose a generator below."
16
- puts
13
+ "".tap do |h|
14
+ h << "Available generators:\n"
17
15
 
18
- mappings.each_pair do |name, klass|
19
- puts name
16
+ mappings.each_pair do |name, klass|
17
+ h << "* " << klass.desc << "\n"
18
+ end
20
19
  end
21
20
  end
22
21
 
@@ -4,13 +4,16 @@ module Adhearsion
4
4
  module Generators
5
5
  class AppGenerator < Generator
6
6
 
7
- BASEDIRS = %w( config lib script )
7
+ BASEDIRS = %w( config lib script spec )
8
+ EMPTYDIRS = %w( spec/call_controllers spec/support )
8
9
 
9
10
  def setup_project
10
11
  self.destination_root = @generator_name
11
12
  BASEDIRS.each { |dir| directory dir }
13
+ EMPTYDIRS.each { |dir| empty_directory dir }
12
14
  template "Gemfile.erb", "Gemfile"
13
15
  copy_file "gitignore", ".gitignore"
16
+ copy_file "rspec", ".rspec"
14
17
  copy_file "Procfile"
15
18
  copy_file "Rakefile"
16
19
  copy_file "README.md"
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+
3
+ ENV["AHN_ENV"] ||= 'test'
4
+ require File.expand_path("../../config/environment", __FILE__)
5
+ require 'adhearsion/rspec'
6
+ require 'rspec/autorun'
7
+
8
+ # Requires supporting ruby files with custom matchers and macros, etc,
9
+ # in spec/support/ and its subdirectories.
10
+ Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each { |f| require f }
11
+
12
+ RSpec.configure do |config|
13
+ # ## Mock Framework
14
+ #
15
+ # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
16
+ #
17
+ # config.mock_with :mocha
18
+ # config.mock_with :flexmock
19
+ # config.mock_with :rr
20
+
21
+ config.filter_run :focus => true
22
+ config.run_all_when_everything_filtered = true
23
+ end
@@ -6,6 +6,10 @@ module Adhearsion
6
6
 
7
7
  argument :controller_name, :type => :string
8
8
 
9
+ def self.short_desc
10
+ "A call controller template. 'controller_name' should be the disired class name, either CamelCase or under_scored."
11
+ end
12
+
9
13
  def create_controller
10
14
  raise Exception, "Generator commands need to be run in an Adhearsion app directory" unless ScriptAhnLoader.in_ahn_application?('.')
11
15
  self.destination_root = '.'
@@ -33,10 +33,14 @@ module Adhearsion
33
33
  @desc ||= if usage && File.exist?(usage)
34
34
  ERB.new(File.read(usage)).result(binding)
35
35
  else
36
- "Description:\n Create #{base_name.humanize.downcase} files for #{generator_name} generator."
36
+ "#{generator_name} [#{arguments.drop(2).map(&:name).join(', ')}]: #{short_desc}."
37
37
  end
38
38
  end
39
39
 
40
+ def self.short_desc
41
+ nil
42
+ end
43
+
40
44
  # Convenience method to get the namespace from the class name. It's the
41
45
  # same as Thor default except that the Generator at the end of the class
42
46
  # is removed.
@@ -6,11 +6,14 @@ module Adhearsion
6
6
 
7
7
  argument :plugin_name, :type => :string
8
8
 
9
+ def self.short_desc
10
+ "A plugin template. 'plugin_name' should be the disired plugin module name, either CamelCase or under_scored."
11
+ end
9
12
 
10
13
  def create_plugin
11
14
  @plugin_file = @plugin_name.underscore
12
15
  self.destination_root = '.'
13
-
16
+
14
17
  empty_directory @plugin_file
15
18
  empty_directory "#{@plugin_file}/lib"
16
19
  empty_directory "#{@plugin_file}/lib/#{@plugin_file}"
@@ -16,7 +16,7 @@ module Adhearsion
16
16
  end
17
17
 
18
18
  def id
19
- dial_command.call_id if dial_command
19
+ dial_command.target_call_id if dial_command
20
20
  end
21
21
 
22
22
  def client
@@ -73,7 +73,7 @@ module Adhearsion
73
73
  event.source.trigger_event_handler event
74
74
  end
75
75
 
76
- Events.punchblock proc { |e| e.respond_to?(:call_id) }, :call_id do |event|
76
+ Events.punchblock proc { |e| e.respond_to?(:target_call_id) }, :target_call_id do |event|
77
77
  dispatch_call_event event
78
78
  end
79
79
  end
@@ -150,10 +150,10 @@ module Adhearsion
150
150
  end
151
151
 
152
152
  def dispatch_call_event(event)
153
- if call = Adhearsion.active_calls[event.call_id]
153
+ if call = Adhearsion.active_calls[event.target_call_id]
154
154
  call.deliver_message! event
155
155
  else
156
- logger.error "Event received for inactive call #{event.call_id}: #{event.inspect}"
156
+ logger.error "Event received for inactive call #{event.target_call_id}: #{event.inspect}"
157
157
  end
158
158
  end
159
159
 
@@ -22,14 +22,20 @@ module Adhearsion
22
22
  end
23
23
 
24
24
  def dispatcher
25
- @dispatcher ||= lambda do |call|
25
+ @dispatcher ||= lambda do |call, callback = nil|
26
26
  controller = if target.respond_to?(:call)
27
27
  CallController.new call, &target
28
28
  else
29
29
  target.new call
30
30
  end
31
31
 
32
- call.execute_controller controller
32
+ call.execute_controller controller, lambda { |call|
33
+ begin
34
+ call.hangup
35
+ rescue Call::Hangup
36
+ end
37
+ callback.call if callback
38
+ }
33
39
  end
34
40
  end
35
41
 
@@ -0,0 +1,7 @@
1
+ # encoding: utf-8
2
+
3
+ require 'adhearsion'
4
+
5
+ initializer = Adhearsion::Initializer.new
6
+ initializer.load_lib_folder
7
+ initializer.load_config
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Adhearsion #:nodoc:
4
- VERSION = '2.0.0.rc3'
4
+ VERSION = '2.0.0.rc4'
5
5
  end
@@ -225,7 +225,7 @@ module Adhearsion
225
225
  latch.wait(1).should be_false
226
226
 
227
227
  other_mock_call << mock_answered
228
- other_mock_call << Punchblock::Event::Unjoined.new(:other_call_id => call.id)
228
+ other_mock_call << Punchblock::Event::Unjoined.new(:call_id => call.id)
229
229
 
230
230
  latch.wait(1).should be_false
231
231
 
@@ -216,16 +216,16 @@ module Adhearsion
216
216
  describe "#join" do
217
217
  it "delegates to the call, blocking first until it is allowed to execute, and unblocking when an unjoined event is received" do
218
218
  flexmock(subject).should_receive(:block_until_resumed).once.ordered
219
- flexmock(subject.call).should_receive(:join).once.with('call1', :foo => :bar).ordered.and_return Punchblock::Command::Join.new(:other_call_id => 'call1')
219
+ flexmock(subject.call).should_receive(:join).once.with('call1', :foo => :bar).ordered.and_return Punchblock::Command::Join.new(:call_id => 'call1')
220
220
  latch = CountDownLatch.new 1
221
221
  Thread.new do
222
222
  subject.join 'call1', :foo => :bar
223
223
  latch.countdown!
224
224
  end
225
225
  latch.wait(1).should be false
226
- subject.call << Punchblock::Event::Joined.new(:other_call_id => 'call1')
226
+ subject.call << Punchblock::Event::Joined.new(:call_id => 'call1')
227
227
  latch.wait(1).should be false
228
- subject.call << Punchblock::Event::Unjoined.new(:other_call_id => 'call1')
228
+ subject.call << Punchblock::Event::Unjoined.new(:call_id => 'call1')
229
229
  latch.wait(1).should be true
230
230
  end
231
231
 
@@ -249,14 +249,14 @@ module Adhearsion
249
249
  context "with :async => true" do
250
250
  it "delegates to the call, blocking first until it is allowed to execute, and unblocking when the joined event is received" do
251
251
  flexmock(subject).should_receive(:block_until_resumed).once.ordered
252
- flexmock(subject.call).should_receive(:join).once.with('call1', :foo => :bar).ordered.and_return Punchblock::Command::Join.new(:other_call_id => 'call1')
252
+ flexmock(subject.call).should_receive(:join).once.with('call1', :foo => :bar).ordered.and_return Punchblock::Command::Join.new(:call_id => 'call1')
253
253
  latch = CountDownLatch.new 1
254
254
  Thread.new do
255
255
  subject.join 'call1', :foo => :bar, :async => true
256
256
  latch.countdown!
257
257
  end
258
258
  latch.wait(1).should be false
259
- subject.call << Punchblock::Event::Joined.new(:other_call_id => 'call1')
259
+ subject.call << Punchblock::Event::Joined.new(:call_id => 'call1')
260
260
  latch.wait(1).should be true
261
261
  end
262
262
 
@@ -317,7 +317,7 @@ module Adhearsion
317
317
  let(:response) { Punchblock::Event::Complete.new }
318
318
 
319
319
  before do
320
- expect_message_waiting_for_response component
320
+ expect_message_of_type_waiting_for_response component
321
321
  component.execute!
322
322
  component.complete_event = response
323
323
  end
@@ -17,7 +17,7 @@ module Adhearsion
17
17
  let(:to) { 'sip:you@there.com' }
18
18
  let(:from) { 'sip:me@here.com' }
19
19
  let :offer do
20
- Punchblock::Event::Offer.new :call_id => call_id,
20
+ Punchblock::Event::Offer.new :target_call_id => call_id,
21
21
  :to => to,
22
22
  :from => from,
23
23
  :headers => headers
@@ -313,7 +313,7 @@ module Adhearsion
313
313
  end
314
314
 
315
315
  context "where the name is :item_not_found" do
316
- let(:response) { new_exception.new :item_not_found }
316
+ let(:response) { new_exception.new.setup :item_not_found }
317
317
 
318
318
  it "should raise a Hangup exception" do
319
319
  flexmock(Events).should_receive(:trigger).never
@@ -463,13 +463,13 @@ module Adhearsion
463
463
  let(:target) { flexmock Call.new, :id => call_id }
464
464
 
465
465
  it "should send a join command joining to the provided call ID" do
466
- expect_join_with_options :other_call_id => call_id
466
+ expect_join_with_options :call_id => call_id
467
467
  subject.join target
468
468
  end
469
469
 
470
470
  context "and direction/media options" do
471
471
  it "should send a join command with the correct options" do
472
- expect_join_with_options :other_call_id => call_id, :media => :bridge, :direction => :recv
472
+ expect_join_with_options :call_id => call_id, :media => :bridge, :direction => :recv
473
473
  subject.join target, :media => :bridge, :direction => :recv
474
474
  end
475
475
  end
@@ -479,13 +479,13 @@ module Adhearsion
479
479
  let(:target) { rand.to_s }
480
480
 
481
481
  it "should send a join command joining to the provided call ID" do
482
- expect_join_with_options :other_call_id => target
482
+ expect_join_with_options :call_id => target
483
483
  subject.join target
484
484
  end
485
485
 
486
486
  context "and direction/media options" do
487
487
  it "should send a join command with the correct options" do
488
- expect_join_with_options :other_call_id => target, :media => :bridge, :direction => :recv
488
+ expect_join_with_options :call_id => target, :media => :bridge, :direction => :recv
489
489
  subject.join target, :media => :bridge, :direction => :recv
490
490
  end
491
491
  end
@@ -496,13 +496,13 @@ module Adhearsion
496
496
  let(:target) { { :call_id => call_id } }
497
497
 
498
498
  it "should send a join command joining to the provided call ID" do
499
- expect_join_with_options :other_call_id => call_id
499
+ expect_join_with_options :call_id => call_id
500
500
  subject.join target
501
501
  end
502
502
 
503
503
  context "and direction/media options" do
504
504
  it "should send a join command with the correct options" do
505
- expect_join_with_options :other_call_id => call_id, :media => :bridge, :direction => :recv
505
+ expect_join_with_options :call_id => call_id, :media => :bridge, :direction => :recv
506
506
  subject.join target.merge({:media => :bridge, :direction => :recv})
507
507
  end
508
508
  end
@@ -548,7 +548,7 @@ module Adhearsion
548
548
  let(:target) { flexmock Call.new, :id => call_id }
549
549
 
550
550
  it "should send an unjoin command unjoining from the provided call ID" do
551
- expect_unjoin_with_options :other_call_id => call_id
551
+ expect_unjoin_with_options :call_id => call_id
552
552
  subject.unjoin target
553
553
  end
554
554
  end
@@ -557,7 +557,7 @@ module Adhearsion
557
557
  let(:target) { rand.to_s }
558
558
 
559
559
  it "should send an unjoin command unjoining from the provided call ID" do
560
- expect_unjoin_with_options :other_call_id => target
560
+ expect_unjoin_with_options :call_id => target
561
561
  subject.unjoin target
562
562
  end
563
563
  end
@@ -567,7 +567,7 @@ module Adhearsion
567
567
  let(:target) { { :call_id => call_id } }
568
568
 
569
569
  it "should send an unjoin command unjoining from the provided call ID" do
570
- expect_unjoin_with_options :other_call_id => call_id
570
+ expect_unjoin_with_options :call_id => call_id
571
571
  subject.unjoin target
572
572
  end
573
573
  end
@@ -617,20 +617,13 @@ module Adhearsion
617
617
 
618
618
  it "should call #execute on the controller instance" do
619
619
  flexmock(CallController).should_receive(:exec).once.with mock_controller
620
- subject.execute_controller mock_controller, latch
621
- latch.wait(3).should be_true
622
- end
623
-
624
- it "should hangup the call after all controllers have executed" do
625
- flexmock(CallController).should_receive(:exec).once.with mock_controller
626
- subject.should_receive(:hangup).once
627
- subject.execute_controller mock_controller, latch
620
+ subject.execute_controller mock_controller, lambda { |call| latch.countdown! }
628
621
  latch.wait(3).should be_true
629
622
  end
630
623
 
631
624
  it "should add the controller thread to the important threads" do
632
625
  flexmock(CallController).should_receive(:exec)
633
- controller_thread = subject.execute_controller mock_controller, latch
626
+ controller_thread = subject.execute_controller mock_controller, lambda { |call| latch.countdown! }
634
627
  Adhearsion::Process.important_threads.should include controller_thread
635
628
  end
636
629
 
@@ -641,10 +634,18 @@ module Adhearsion
641
634
  l.should be subject.logger
642
635
  latch.countdown!
643
636
  end
644
- subject.execute_controller BrokenController.new(subject), latch
637
+ subject.execute_controller BrokenController.new(subject), lambda { |call| latch.countdown! }
645
638
  latch.wait(3).should be true
646
639
  Adhearsion::Events.clear_handlers :exception
647
640
  end
641
+
642
+ it "should execute a callback after the controller executes" do
643
+ flexmock(CallController).should_receive(:exec)
644
+ foo = nil
645
+ subject.execute_controller mock_controller, lambda { |call| foo = call; latch.countdown! }
646
+ latch.wait(3).should be_true
647
+ foo.should be subject
648
+ end
648
649
  end
649
650
 
650
651
  describe "#register_controller" do
@@ -12,7 +12,7 @@ module Adhearsion
12
12
  end
13
13
 
14
14
  def new_offer(call_id = nil, headers = {})
15
- Punchblock::Event::Offer.new :call_id => call_id || random_call_id, :headers => headers
15
+ Punchblock::Event::Offer.new :target_call_id => call_id || random_call_id, :headers => headers
16
16
  end
17
17
 
18
18
  it 'can create a call and add it to the collection' do
@@ -60,7 +60,7 @@ module Adhearsion
60
60
  describe "#dial" do
61
61
  def expect_message_waiting_for_response(message)
62
62
  flexmock(subject.wrapped_object).should_receive(:write_and_await_response).once.with(message, 60).and_return do
63
- message.call_id = call_id
63
+ message.target_call_id = call_id
64
64
  message
65
65
  end
66
66
  end
@@ -52,7 +52,7 @@ module Adhearsion
52
52
  end
53
53
 
54
54
  let(:call_id) { rand }
55
- let(:offer) { ::Punchblock::Event::Offer.new.tap { |o| o.call_id = call_id } }
55
+ let(:offer) { ::Punchblock::Event::Offer.new.tap { |o| o.target_call_id = call_id } }
56
56
  let(:mock_call) { flexmock('Call', :id => call_id).tap { |call| call.should_ignore_missing } }
57
57
 
58
58
  describe "starts the client with the default values" do
@@ -245,7 +245,7 @@ module Adhearsion
245
245
 
246
246
  describe "dispatching a component event" do
247
247
  let(:component) { flexmock 'ComponentNode' }
248
- let(:mock_event) { flexmock 'Event', :call_id => call_id, :source => component }
248
+ let(:mock_event) { flexmock 'Event', :target_call_id => call_id, :source => component }
249
249
 
250
250
  before do
251
251
  initialize_punchblock
@@ -258,7 +258,7 @@ module Adhearsion
258
258
  end
259
259
 
260
260
  describe "dispatching a call event" do
261
- let(:mock_event) { flexmock 'Event', :call_id => call_id }
261
+ let(:mock_event) { flexmock 'Event', :target_call_id => call_id }
262
262
 
263
263
  describe "with an active call" do
264
264
  before do
@@ -273,7 +273,7 @@ module Adhearsion
273
273
  end
274
274
 
275
275
  describe "with an inactive call" do
276
- let(:mock_event) { flexmock 'Event', :call_id => call_id }
276
+ let(:mock_event) { flexmock 'Event', :target_call_id => call_id }
277
277
 
278
278
  it "should log an error" do
279
279
  flexmock(Adhearsion::Logging.get_logger(Initializer)).should_receive(:error).once.with("Event received for inactive call #{call_id}: #{mock_event.inspect}")
@@ -102,14 +102,33 @@ module Adhearsion
102
102
  describe "dispatching a call" do
103
103
  let(:call) { Call.new }
104
104
 
105
+ let(:latch) { CountDownLatch.new 1 }
106
+
105
107
  context "via a call controller" do
106
108
  let(:controller) { CallController }
107
109
  let(:route) { Route.new 'foobar', controller }
108
110
 
109
111
  it "should instruct the call to use an instance of the controller" do
110
- flexmock(call).should_receive(:execute_controller).once.with controller
112
+ flexmock(call).should_receive(:execute_controller).once.with controller, Proc
111
113
  route.dispatcher.call call
112
114
  end
115
+
116
+ it "should hangup the call after all controllers have executed" do
117
+ flexmock(call).should_receive(:hangup).once
118
+ route.dispatcher.call call, lambda { latch.countdown! }
119
+ latch.wait(2).should be true
120
+ end
121
+
122
+ context "if hangup raises a Call::Hangup" do
123
+ before { flexmock(call).should_receive(:hangup).once.and_raise Call::Hangup }
124
+
125
+ it "should not raise an exception" do
126
+ lambda do
127
+ route.dispatcher.call call, lambda { latch.countdown! }
128
+ latch.wait(2).should be true
129
+ end.should_not raise_error
130
+ end
131
+ end
113
132
  end
114
133
 
115
134
  context "via a block" do
@@ -120,7 +139,7 @@ module Adhearsion
120
139
  end
121
140
 
122
141
  it "should instruct the call to use a CallController with the correct block" do
123
- flexmock(call).should_receive(:execute_controller).once.with(CallController).and_return do |controller|
142
+ flexmock(call).should_receive(:execute_controller).once.with(CallController, Proc).and_return do |controller|
124
143
  controller.block.call.should be == :foobar
125
144
  end
126
145
  route.dispatcher.call call
@@ -28,6 +28,8 @@ end
28
28
 
29
29
  Thread.abort_on_exception = true
30
30
 
31
+ UUID.state_file = false
32
+
31
33
  Bundler.require(:default, :test) if defined?(Bundler)
32
34
 
33
35
  Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each { |f| require f }
@@ -28,6 +28,11 @@ module CallControllerTestHelpers
28
28
  message.request!
29
29
  end
30
30
 
31
+ def expect_message_of_type_waiting_for_response(message)
32
+ subject.should_receive(:write_and_await_response).once.with(message.class).and_return message
33
+ message.request!
34
+ end
35
+
31
36
  def expect_component_execution(component)
32
37
  subject.should_receive(:execute_component_and_await_completion).once.with(component).and_return(component)
33
38
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: adhearsion
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.rc3
4
+ version: 2.0.0.rc4
5
5
  prerelease: 6
6
6
  platform: ruby
7
7
  authors:
@@ -12,11 +12,11 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2012-03-23 00:00:00.000000000 Z
15
+ date: 2012-03-30 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: bundler
19
- requirement: &2156158800 !ruby/object:Gem::Requirement
19
+ requirement: &2156866840 !ruby/object:Gem::Requirement
20
20
  none: false
21
21
  requirements:
22
22
  - - ! '>='
@@ -24,21 +24,21 @@ dependencies:
24
24
  version: 1.0.10
25
25
  type: :runtime
26
26
  prerelease: false
27
- version_requirements: *2156158800
27
+ version_requirements: *2156866840
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: punchblock
30
- requirement: &2156157380 !ruby/object:Gem::Requirement
30
+ requirement: &2156865600 !ruby/object:Gem::Requirement
31
31
  none: false
32
32
  requirements:
33
33
  - - ! '>='
34
34
  - !ruby/object:Gem::Version
35
- version: 0.10.0
35
+ version: 0.12.0
36
36
  type: :runtime
37
37
  prerelease: false
38
- version_requirements: *2156157380
38
+ version_requirements: *2156865600
39
39
  - !ruby/object:Gem::Dependency
40
40
  name: logging
41
- requirement: &2156151240 !ruby/object:Gem::Requirement
41
+ requirement: &2156864400 !ruby/object:Gem::Requirement
42
42
  none: false
43
43
  requirements:
44
44
  - - ! '>='
@@ -46,10 +46,10 @@ dependencies:
46
46
  version: 1.6.1
47
47
  type: :runtime
48
48
  prerelease: false
49
- version_requirements: *2156151240
49
+ version_requirements: *2156864400
50
50
  - !ruby/object:Gem::Dependency
51
51
  name: adhearsion-loquacious
52
- requirement: &2156150320 !ruby/object:Gem::Requirement
52
+ requirement: &2156863220 !ruby/object:Gem::Requirement
53
53
  none: false
54
54
  requirements:
55
55
  - - ! '>='
@@ -57,10 +57,10 @@ dependencies:
57
57
  version: 1.9.0
58
58
  type: :runtime
59
59
  prerelease: false
60
- version_requirements: *2156150320
60
+ version_requirements: *2156863220
61
61
  - !ruby/object:Gem::Dependency
62
62
  name: activesupport
63
- requirement: &2156145860 !ruby/object:Gem::Requirement
63
+ requirement: &2156862080 !ruby/object:Gem::Requirement
64
64
  none: false
65
65
  requirements:
66
66
  - - ! '>='
@@ -68,10 +68,10 @@ dependencies:
68
68
  version: 3.0.10
69
69
  type: :runtime
70
70
  prerelease: false
71
- version_requirements: *2156145860
71
+ version_requirements: *2156862080
72
72
  - !ruby/object:Gem::Dependency
73
73
  name: i18n
74
- requirement: &2156145040 !ruby/object:Gem::Requirement
74
+ requirement: &2156861160 !ruby/object:Gem::Requirement
75
75
  none: false
76
76
  requirements:
77
77
  - - ! '>='
@@ -79,10 +79,10 @@ dependencies:
79
79
  version: 0.5.0
80
80
  type: :runtime
81
81
  prerelease: false
82
- version_requirements: *2156145040
82
+ version_requirements: *2156861160
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: json
85
- requirement: &2156144460 !ruby/object:Gem::Requirement
85
+ requirement: &2156860540 !ruby/object:Gem::Requirement
86
86
  none: false
87
87
  requirements:
88
88
  - - ! '>='
@@ -90,10 +90,10 @@ dependencies:
90
90
  version: '0'
91
91
  type: :runtime
92
92
  prerelease: false
93
- version_requirements: *2156144460
93
+ version_requirements: *2156860540
94
94
  - !ruby/object:Gem::Dependency
95
95
  name: thor
96
- requirement: &2156143460 !ruby/object:Gem::Requirement
96
+ requirement: &2156859720 !ruby/object:Gem::Requirement
97
97
  none: false
98
98
  requirements:
99
99
  - - ! '>='
@@ -101,10 +101,10 @@ dependencies:
101
101
  version: '0'
102
102
  type: :runtime
103
103
  prerelease: false
104
- version_requirements: *2156143460
104
+ version_requirements: *2156859720
105
105
  - !ruby/object:Gem::Dependency
106
106
  name: rake
107
- requirement: &2156142480 !ruby/object:Gem::Requirement
107
+ requirement: &2156858580 !ruby/object:Gem::Requirement
108
108
  none: false
109
109
  requirements:
110
110
  - - ! '>='
@@ -112,10 +112,10 @@ dependencies:
112
112
  version: '0'
113
113
  type: :runtime
114
114
  prerelease: false
115
- version_requirements: *2156142480
115
+ version_requirements: *2156858580
116
116
  - !ruby/object:Gem::Dependency
117
117
  name: pry
118
- requirement: &2156141680 !ruby/object:Gem::Requirement
118
+ requirement: &2156857240 !ruby/object:Gem::Requirement
119
119
  none: false
120
120
  requirements:
121
121
  - - ! '>='
@@ -123,10 +123,10 @@ dependencies:
123
123
  version: '0'
124
124
  type: :runtime
125
125
  prerelease: false
126
- version_requirements: *2156141680
126
+ version_requirements: *2156857240
127
127
  - !ruby/object:Gem::Dependency
128
128
  name: uuid
129
- requirement: &2156140700 !ruby/object:Gem::Requirement
129
+ requirement: &2156855960 !ruby/object:Gem::Requirement
130
130
  none: false
131
131
  requirements:
132
132
  - - ! '>='
@@ -134,10 +134,10 @@ dependencies:
134
134
  version: '0'
135
135
  type: :runtime
136
136
  prerelease: false
137
- version_requirements: *2156140700
137
+ version_requirements: *2156855960
138
138
  - !ruby/object:Gem::Dependency
139
139
  name: future-resource
140
- requirement: &2156139480 !ruby/object:Gem::Requirement
140
+ requirement: &2156854240 !ruby/object:Gem::Requirement
141
141
  none: false
142
142
  requirements:
143
143
  - - ! '>='
@@ -145,10 +145,10 @@ dependencies:
145
145
  version: 0.0.2
146
146
  type: :runtime
147
147
  prerelease: false
148
- version_requirements: *2156139480
148
+ version_requirements: *2156854240
149
149
  - !ruby/object:Gem::Dependency
150
150
  name: ruby_speech
151
- requirement: &2156127780 !ruby/object:Gem::Requirement
151
+ requirement: &2156852180 !ruby/object:Gem::Requirement
152
152
  none: false
153
153
  requirements:
154
154
  - - ! '>='
@@ -156,10 +156,10 @@ dependencies:
156
156
  version: 0.4.0
157
157
  type: :runtime
158
158
  prerelease: false
159
- version_requirements: *2156127780
159
+ version_requirements: *2156852180
160
160
  - !ruby/object:Gem::Dependency
161
161
  name: countdownlatch
162
- requirement: &2156126940 !ruby/object:Gem::Requirement
162
+ requirement: &2156851480 !ruby/object:Gem::Requirement
163
163
  none: false
164
164
  requirements:
165
165
  - - ! '>='
@@ -167,10 +167,10 @@ dependencies:
167
167
  version: '0'
168
168
  type: :runtime
169
169
  prerelease: false
170
- version_requirements: *2156126940
170
+ version_requirements: *2156851480
171
171
  - !ruby/object:Gem::Dependency
172
172
  name: has-guarded-handlers
173
- requirement: &2156123960 !ruby/object:Gem::Requirement
173
+ requirement: &2156850640 !ruby/object:Gem::Requirement
174
174
  none: false
175
175
  requirements:
176
176
  - - ! '>='
@@ -178,10 +178,10 @@ dependencies:
178
178
  version: 1.1.0
179
179
  type: :runtime
180
180
  prerelease: false
181
- version_requirements: *2156123960
181
+ version_requirements: *2156850640
182
182
  - !ruby/object:Gem::Dependency
183
183
  name: girl_friday
184
- requirement: &2156121080 !ruby/object:Gem::Requirement
184
+ requirement: &2156849760 !ruby/object:Gem::Requirement
185
185
  none: false
186
186
  requirements:
187
187
  - - ! '>='
@@ -189,10 +189,10 @@ dependencies:
189
189
  version: '0'
190
190
  type: :runtime
191
191
  prerelease: false
192
- version_requirements: *2156121080
192
+ version_requirements: *2156849760
193
193
  - !ruby/object:Gem::Dependency
194
194
  name: ffi
195
- requirement: &2156120300 !ruby/object:Gem::Requirement
195
+ requirement: &2156848240 !ruby/object:Gem::Requirement
196
196
  none: false
197
197
  requirements:
198
198
  - - ! '>='
@@ -200,10 +200,10 @@ dependencies:
200
200
  version: 1.0.11
201
201
  type: :runtime
202
202
  prerelease: false
203
- version_requirements: *2156120300
203
+ version_requirements: *2156848240
204
204
  - !ruby/object:Gem::Dependency
205
205
  name: celluloid
206
- requirement: &2156119260 !ruby/object:Gem::Requirement
206
+ requirement: &2156847120 !ruby/object:Gem::Requirement
207
207
  none: false
208
208
  requirements:
209
209
  - - ! '>='
@@ -211,10 +211,10 @@ dependencies:
211
211
  version: 0.9.0
212
212
  type: :runtime
213
213
  prerelease: false
214
- version_requirements: *2156119260
214
+ version_requirements: *2156847120
215
215
  - !ruby/object:Gem::Dependency
216
216
  name: deep_merge
217
- requirement: &2156118360 !ruby/object:Gem::Requirement
217
+ requirement: &2156846580 !ruby/object:Gem::Requirement
218
218
  none: false
219
219
  requirements:
220
220
  - - ! '>='
@@ -222,10 +222,10 @@ dependencies:
222
222
  version: '0'
223
223
  type: :runtime
224
224
  prerelease: false
225
- version_requirements: *2156118360
225
+ version_requirements: *2156846580
226
226
  - !ruby/object:Gem::Dependency
227
227
  name: rspec
228
- requirement: &2156117620 !ruby/object:Gem::Requirement
228
+ requirement: &2156844180 !ruby/object:Gem::Requirement
229
229
  none: false
230
230
  requirements:
231
231
  - - ~>
@@ -233,10 +233,10 @@ dependencies:
233
233
  version: 2.7.0
234
234
  type: :development
235
235
  prerelease: false
236
- version_requirements: *2156117620
236
+ version_requirements: *2156844180
237
237
  - !ruby/object:Gem::Dependency
238
238
  name: flexmock
239
- requirement: &2156116220 !ruby/object:Gem::Requirement
239
+ requirement: &2156843420 !ruby/object:Gem::Requirement
240
240
  none: false
241
241
  requirements:
242
242
  - - ! '>='
@@ -244,10 +244,10 @@ dependencies:
244
244
  version: '0'
245
245
  type: :development
246
246
  prerelease: false
247
- version_requirements: *2156116220
247
+ version_requirements: *2156843420
248
248
  - !ruby/object:Gem::Dependency
249
249
  name: activerecord
250
- requirement: &2156115240 !ruby/object:Gem::Requirement
250
+ requirement: &2156842020 !ruby/object:Gem::Requirement
251
251
  none: false
252
252
  requirements:
253
253
  - - ! '>='
@@ -255,10 +255,10 @@ dependencies:
255
255
  version: 3.0.10
256
256
  type: :development
257
257
  prerelease: false
258
- version_requirements: *2156115240
258
+ version_requirements: *2156842020
259
259
  - !ruby/object:Gem::Dependency
260
260
  name: simplecov
261
- requirement: &2156114600 !ruby/object:Gem::Requirement
261
+ requirement: &2156841380 !ruby/object:Gem::Requirement
262
262
  none: false
263
263
  requirements:
264
264
  - - ! '>='
@@ -266,10 +266,10 @@ dependencies:
266
266
  version: '0'
267
267
  type: :development
268
268
  prerelease: false
269
- version_requirements: *2156114600
269
+ version_requirements: *2156841380
270
270
  - !ruby/object:Gem::Dependency
271
271
  name: simplecov-rcov
272
- requirement: &2156113920 !ruby/object:Gem::Requirement
272
+ requirement: &2156840600 !ruby/object:Gem::Requirement
273
273
  none: false
274
274
  requirements:
275
275
  - - ! '>='
@@ -277,10 +277,10 @@ dependencies:
277
277
  version: '0'
278
278
  type: :development
279
279
  prerelease: false
280
- version_requirements: *2156113920
280
+ version_requirements: *2156840600
281
281
  - !ruby/object:Gem::Dependency
282
282
  name: ci_reporter
283
- requirement: &2156113000 !ruby/object:Gem::Requirement
283
+ requirement: &2156839920 !ruby/object:Gem::Requirement
284
284
  none: false
285
285
  requirements:
286
286
  - - ! '>='
@@ -288,10 +288,10 @@ dependencies:
288
288
  version: '0'
289
289
  type: :development
290
290
  prerelease: false
291
- version_requirements: *2156113000
291
+ version_requirements: *2156839920
292
292
  - !ruby/object:Gem::Dependency
293
293
  name: yard
294
- requirement: &2156111640 !ruby/object:Gem::Requirement
294
+ requirement: &2164576620 !ruby/object:Gem::Requirement
295
295
  none: false
296
296
  requirements:
297
297
  - - ! '>='
@@ -299,10 +299,10 @@ dependencies:
299
299
  version: '0'
300
300
  type: :development
301
301
  prerelease: false
302
- version_requirements: *2156111640
302
+ version_requirements: *2164576620
303
303
  - !ruby/object:Gem::Dependency
304
304
  name: guard-rspec
305
- requirement: &2152231160 !ruby/object:Gem::Requirement
305
+ requirement: &2168963940 !ruby/object:Gem::Requirement
306
306
  none: false
307
307
  requirements:
308
308
  - - ! '>='
@@ -310,10 +310,10 @@ dependencies:
310
310
  version: '0'
311
311
  type: :development
312
312
  prerelease: false
313
- version_requirements: *2152231160
313
+ version_requirements: *2168963940
314
314
  - !ruby/object:Gem::Dependency
315
315
  name: guard-cucumber
316
- requirement: &2152229220 !ruby/object:Gem::Requirement
316
+ requirement: &2157043100 !ruby/object:Gem::Requirement
317
317
  none: false
318
318
  requirements:
319
319
  - - ! '>='
@@ -321,10 +321,10 @@ dependencies:
321
321
  version: '0'
322
322
  type: :development
323
323
  prerelease: false
324
- version_requirements: *2152229220
324
+ version_requirements: *2157043100
325
325
  - !ruby/object:Gem::Dependency
326
326
  name: ruby_gntp
327
- requirement: &2152227900 !ruby/object:Gem::Requirement
327
+ requirement: &2156949860 !ruby/object:Gem::Requirement
328
328
  none: false
329
329
  requirements:
330
330
  - - ! '>='
@@ -332,10 +332,10 @@ dependencies:
332
332
  version: '0'
333
333
  type: :development
334
334
  prerelease: false
335
- version_requirements: *2152227900
335
+ version_requirements: *2156949860
336
336
  - !ruby/object:Gem::Dependency
337
337
  name: cucumber
338
- requirement: &2152226420 !ruby/object:Gem::Requirement
338
+ requirement: &2156953860 !ruby/object:Gem::Requirement
339
339
  none: false
340
340
  requirements:
341
341
  - - ! '>='
@@ -343,10 +343,10 @@ dependencies:
343
343
  version: '0'
344
344
  type: :development
345
345
  prerelease: false
346
- version_requirements: *2152226420
346
+ version_requirements: *2156953860
347
347
  - !ruby/object:Gem::Dependency
348
348
  name: aruba
349
- requirement: &2168873960 !ruby/object:Gem::Requirement
349
+ requirement: &2156944220 !ruby/object:Gem::Requirement
350
350
  none: false
351
351
  requirements:
352
352
  - - ! '>='
@@ -354,7 +354,7 @@ dependencies:
354
354
  version: '0'
355
355
  type: :development
356
356
  prerelease: false
357
- version_requirements: *2168873960
357
+ version_requirements: *2156944220
358
358
  description: Adhearsion is an open-source telephony development framework
359
359
  email: dev&Adhearsion.com
360
360
  executables:
@@ -420,7 +420,9 @@ files:
420
420
  - lib/adhearsion/generators/app/templates/config/environment.rb
421
421
  - lib/adhearsion/generators/app/templates/gitignore
422
422
  - lib/adhearsion/generators/app/templates/lib/simon_game.rb
423
+ - lib/adhearsion/generators/app/templates/rspec
423
424
  - lib/adhearsion/generators/app/templates/script/ahn
425
+ - lib/adhearsion/generators/app/templates/spec/spec_helper.rb
424
426
  - lib/adhearsion/generators/controller/controller_generator.rb
425
427
  - lib/adhearsion/generators/controller/templates/lib/controller.rb
426
428
  - lib/adhearsion/generators/controller/templates/spec/controller_spec.rb
@@ -458,6 +460,7 @@ files:
458
460
  - lib/adhearsion/punchblock_plugin/initializer.rb
459
461
  - lib/adhearsion/router.rb
460
462
  - lib/adhearsion/router/route.rb
463
+ - lib/adhearsion/rspec.rb
461
464
  - lib/adhearsion/script_ahn_loader.rb
462
465
  - lib/adhearsion/tasks.rb
463
466
  - lib/adhearsion/tasks/configuration.rb
@@ -517,7 +520,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
517
520
  version: '0'
518
521
  segments:
519
522
  - 0
520
- hash: 4509344095409013612
523
+ hash: 1219852997240048480
521
524
  required_rubygems_version: !ruby/object:Gem::Requirement
522
525
  none: false
523
526
  requirements: