adhearsion 2.0.0.rc3 → 2.0.0.rc4

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