adhearsion 2.1.3 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/CHANGELOG.md +87 -0
  2. data/Guardfile +1 -1
  3. data/Rakefile +1 -2
  4. data/adhearsion.gemspec +1 -1
  5. data/features/cli_create.feature +1 -0
  6. data/features/step_definitions/cli_steps.rb +0 -10
  7. data/lib/adhearsion.rb +11 -0
  8. data/lib/adhearsion/call.rb +27 -12
  9. data/lib/adhearsion/call_controller.rb +1 -1
  10. data/lib/adhearsion/call_controller/dial.rb +3 -1
  11. data/lib/adhearsion/call_controller/input.rb +4 -4
  12. data/lib/adhearsion/call_controller/menu_dsl.rb +1 -0
  13. data/lib/adhearsion/call_controller/menu_dsl/array_match_calculator.rb +26 -0
  14. data/lib/adhearsion/call_controller/menu_dsl/fixnum_match_calculator.rb +2 -14
  15. data/lib/adhearsion/call_controller/menu_dsl/string_match_calculator.rb +6 -6
  16. data/lib/adhearsion/call_controller/output.rb +20 -14
  17. data/lib/adhearsion/call_controller/output/abstract_player.rb +5 -5
  18. data/lib/adhearsion/call_controller/output/formatter.rb +68 -68
  19. data/lib/adhearsion/call_controller/record.rb +91 -28
  20. data/lib/adhearsion/call_controller/utility.rb +12 -5
  21. data/lib/adhearsion/calls.rb +1 -1
  22. data/lib/adhearsion/configuration.rb +4 -0
  23. data/lib/adhearsion/events.rb +2 -1
  24. data/lib/adhearsion/generators/app/app_generator.rb +2 -2
  25. data/lib/adhearsion/generators/app/templates/Gemfile.erb +4 -0
  26. data/lib/adhearsion/generators/app/templates/Rakefile +5 -0
  27. data/lib/adhearsion/generators/app/templates/lib/simon_game.rb +3 -0
  28. data/lib/adhearsion/generators/app/templates/rspec +2 -0
  29. data/lib/adhearsion/generators/app/templates/spec/call_controllers/simon_game_spec.rb +142 -0
  30. data/lib/adhearsion/generators/controller/templates/lib/controller.rb +1 -1
  31. data/lib/adhearsion/generators/controller/templates/spec/controller_spec.rb +2 -0
  32. data/lib/adhearsion/initializer.rb +3 -2
  33. data/lib/adhearsion/outbound_call.rb +5 -2
  34. data/lib/adhearsion/router/route.rb +13 -2
  35. data/lib/adhearsion/rspec.rb +1 -1
  36. data/lib/adhearsion/statistics.rb +138 -0
  37. data/lib/adhearsion/tasks/environment.rb +1 -1
  38. data/lib/adhearsion/version.rb +1 -1
  39. data/spec/adhearsion/call_controller/dial_spec.rb +26 -0
  40. data/spec/adhearsion/call_controller/input_spec.rb +13 -1
  41. data/spec/adhearsion/call_controller/menu_dsl/array_match_calculator_spec.rb +76 -0
  42. data/spec/adhearsion/call_controller/menu_dsl/fixnum_match_calculator_spec.rb +8 -6
  43. data/spec/adhearsion/call_controller/menu_dsl/range_match_calculator_spec.rb +4 -4
  44. data/spec/adhearsion/call_controller/menu_dsl/string_match_calculator_spec.rb +6 -6
  45. data/spec/adhearsion/call_controller/output/formatter_spec.rb +3 -5
  46. data/spec/adhearsion/call_controller/output_spec.rb +59 -25
  47. data/spec/adhearsion/call_controller/record_spec.rb +123 -2
  48. data/spec/adhearsion/call_controller/utility_spec.rb +31 -11
  49. data/spec/adhearsion/call_spec.rb +77 -36
  50. data/spec/adhearsion/calls_spec.rb +13 -0
  51. data/spec/adhearsion/initializer_spec.rb +7 -0
  52. data/spec/adhearsion/outbound_call_spec.rb +14 -0
  53. data/spec/adhearsion/punchblock_plugin_spec.rb +5 -2
  54. data/spec/adhearsion/router/openended_route_spec.rb +2 -1
  55. data/spec/adhearsion/router/route_spec.rb +9 -1
  56. data/spec/adhearsion/router/unaccepting_route_spec.rb +2 -1
  57. data/spec/adhearsion/statistics/dump_spec.rb +38 -0
  58. data/spec/adhearsion/statistics_spec.rb +61 -0
  59. data/spec/adhearsion_spec.rb +21 -1
  60. data/spec/spec_helper.rb +2 -0
  61. metadata +16 -7
@@ -10,15 +10,15 @@ module Adhearsion
10
10
  it "matching with a Range should handle the case of two potential matches in the range" do
11
11
  digits_that_begin_with_eleven = [110..119, 1100..1111].map { |x| Array(x) }.flatten
12
12
  calculator = RangeMatchCalculator.new 11..1111, :match_payload_doesnt_matter
13
- match = calculator.match 11
14
- match.exact_matches.should be == [11]
13
+ match = calculator.match '11'
14
+ match.exact_matches.should be == ['11']
15
15
  match.potential_matches.should be == digits_that_begin_with_eleven
16
16
  end
17
17
 
18
18
  it "return values of #match should be an instance of CalculatedMatch" do
19
19
  calculator = RangeMatchCalculator.new 1..9, :match_payload_doesnt_matter
20
- calculator.match(0).should be_an_instance_of CalculatedMatch
21
- calculator.match(1000).should be_an_instance_of CalculatedMatch
20
+ calculator.match('0').should be_an_instance_of CalculatedMatch
21
+ calculator.match('1000').should be_an_instance_of CalculatedMatch
22
22
  end
23
23
 
24
24
  it "returns a failed match if the query is not numeric or coercible to numeric" do
@@ -14,13 +14,13 @@ module Adhearsion
14
14
  calculator = StringMatchCalculator.new str, match_payload
15
15
 
16
16
  match_case = calculator.match str[0,2]
17
- match_case.exact_match?.should_not be true
18
- match_case.potential_match?.should be true
17
+ match_case.should_not be_exact_match
18
+ match_case.should be_potential_match
19
19
  match_case.potential_matches.should be == [str]
20
20
 
21
21
  match_case = calculator.match str
22
- match_case.exact_match?.should be true
23
- match_case.potential_match?.should_not be true
22
+ match_case.should be_exact_match
23
+ match_case.should_not be_potential_match
24
24
  match_case.exact_matches.should be == [str]
25
25
  end
26
26
  end
@@ -29,9 +29,9 @@ module Adhearsion
29
29
  %w[* #].each do |special_digit|
30
30
  calculator = StringMatchCalculator.new(special_digit, match_payload)
31
31
  match_case = calculator.match special_digit
32
- match_case.potential_match?.should_not be true
33
- match_case.exact_match?.should be true
34
32
  match_case.exact_matches.first.should be == special_digit
33
+ match_case.should be_exact_match
34
+ match_case.should_not be_potential_match
35
35
  end
36
36
  end
37
37
  end
@@ -6,9 +6,7 @@ module Adhearsion
6
6
  class CallController
7
7
  module Output
8
8
  describe Formatter do
9
- subject { Formatter }
10
-
11
- describe ".ssml_for" do
9
+ describe "#ssml_for" do
12
10
  let(:prompt) { "Please stand by" }
13
11
 
14
12
  let(:ssml) do
@@ -24,7 +22,7 @@ module Adhearsion
24
22
  end
25
23
  end
26
24
 
27
- describe ".ssml_for_collection" do
25
+ describe "#ssml_for_collection" do
28
26
  let(:collection) { ["/foo/bar.wav", 1, Time.now] }
29
27
  let :ssml do
30
28
  file = collection[0]
@@ -42,7 +40,7 @@ module Adhearsion
42
40
  end
43
41
  end
44
42
 
45
- describe ".detect_type" do
43
+ describe "#detect_type" do
46
44
  it "detects an HTTP path" do
47
45
  http_path = "http://adhearsion.com/sounds/hello.mp3"
48
46
  subject.detect_type(http_path).should be :audio
@@ -7,12 +7,12 @@ module Adhearsion
7
7
  describe Output do
8
8
  include CallControllerTestHelpers
9
9
 
10
- def expect_ssml_output(ssml)
11
- expect_component_execution Punchblock::Component::Output.new(:ssml => ssml)
10
+ def expect_ssml_output(ssml, options = {})
11
+ expect_component_execution Punchblock::Component::Output.new(options.merge(:ssml => ssml))
12
12
  end
13
13
 
14
- def expect_async_ssml_output(ssml)
15
- expect_message_waiting_for_response Punchblock::Component::Output.new(:ssml => ssml)
14
+ def expect_async_ssml_output(ssml, options = {})
15
+ expect_message_waiting_for_response Punchblock::Component::Output.new(options.merge(:ssml => ssml))
16
16
  end
17
17
 
18
18
  describe "#player" do
@@ -350,6 +350,25 @@ module Adhearsion
350
350
  end
351
351
  end
352
352
 
353
+ describe "with a collection of arguments" do
354
+ let(:args) { ["/foo/bar.wav", 1, Time.now] }
355
+ let :ssml do
356
+ file = args[0]
357
+ n = args[1].to_s
358
+ t = args[2].to_s
359
+ RubySpeech::SSML.draw do
360
+ audio :src => file
361
+ say_as(:interpret_as => 'cardinal') { n }
362
+ say_as(:interpret_as => 'time') { t }
363
+ end
364
+ end
365
+
366
+ it 'plays all arguments in one document' do
367
+ expect_ssml_output ssml
368
+ subject.play(args).should be true
369
+ end
370
+ end
371
+
353
372
  describe "with a number" do
354
373
  let(:argument) { 123 }
355
374
 
@@ -413,7 +432,7 @@ module Adhearsion
413
432
  end
414
433
  end
415
434
 
416
- describe "with an array containing a Date/DateTime/Time object and a hash" do
435
+ describe "with an hash containing a Date/DateTime/Time object and format options" do
417
436
  let(:date) { Date.parse '2011-01-23' }
418
437
  let(:format) { "d-m-y" }
419
438
  let(:strftime) { "%d-%m%Y" }
@@ -619,42 +638,31 @@ module Adhearsion
619
638
  :grammar => { :value => grammar.to_s }
620
639
  }
621
640
 
641
+ def expect_component_complete_event
642
+ complete_event = Punchblock::Event::Complete.new
643
+ flexmock(complete_event).should_receive(:reason => flexmock(:utterance => 'dtmf-5'))
644
+ flexmock(Punchblock::Component::Input).new_instances do |input|
645
+ input.should_receive(:complete?).and_return(false)
646
+ input.should_receive(:complete_event).and_return(complete_event)
647
+ end
648
+ end
649
+
622
650
  #test does pass and method works, but not sure if the empty method is a good idea
623
651
  it "plays the correct output" do
624
652
  def controller.write_and_await_response(input_component)
625
653
  # it is actually a no-op here
626
654
  end
627
655
 
628
- def expect_component_complete_event
629
- complete_event = Punchblock::Event::Complete.new
630
- flexmock(complete_event).should_receive(:reason => flexmock(:interpretation => 'dtmf-5', :name => :input))
631
- flexmock(Punchblock::Component::Input).new_instances do |input|
632
- input.should_receive(:complete?).and_return(false)
633
- input.should_receive(:complete_event).and_return(complete_event)
634
- end
635
- end
636
-
637
656
  expect_component_complete_event
638
657
  expect_component_execution Punchblock::Component::Output.new(:ssml => ssml.to_s)
639
658
  subject.stream_file prompt, allowed_digits
640
659
  end
641
660
 
642
661
  it "returns a single digit amongst the allowed when pressed" do
643
- flexmock(Punchblock::Event::Complete).new_instances.should_receive(:reason => flexmock(:interpretation => 'dtmf-5', :name => :input))
644
-
645
662
  def controller.write_and_await_response(input_component)
646
663
  input_component.trigger_event_handler Punchblock::Event::Complete.new
647
664
  end
648
665
 
649
- def expect_component_complete_event
650
- complete_event = Punchblock::Event::Complete.new
651
- flexmock(complete_event).should_receive(:reason => flexmock(:interpretation => 'dtmf-5', :name => :input))
652
- flexmock(Punchblock::Component::Input).new_instances do |input|
653
- input.should_receive(:complete?).and_return(false)
654
- input.should_receive(:complete_event).and_return(complete_event)
655
- end
656
- end
657
-
658
666
  expect_component_complete_event
659
667
  flexmock(Punchblock::Component::Output).new_instances.should_receive(:stop!)
660
668
  expect_component_execution output_component
@@ -680,6 +688,19 @@ module Adhearsion
680
688
  end
681
689
  end
682
690
 
691
+ describe "with a default voice set" do
692
+ before { Adhearsion.config.punchblock.default_voice = 'foo' }
693
+
694
+ it 'sets the voice on the output component' do
695
+ str = "Hello world"
696
+ ssml = RubySpeech::SSML.draw { string str }
697
+ expect_ssml_output ssml, voice: 'foo'
698
+ subject.say(str)
699
+ end
700
+
701
+ after { Adhearsion.config.punchblock.default_voice = nil }
702
+ end
703
+
683
704
  describe "converts the argument to a string" do
684
705
  it 'calls output with a string' do
685
706
  argument = 123
@@ -714,6 +735,19 @@ module Adhearsion
714
735
  end
715
736
  end
716
737
 
738
+ describe "with a default voice set" do
739
+ before { Adhearsion.config.punchblock.default_voice = 'foo' }
740
+
741
+ it 'sets the voice on the output component' do
742
+ str = "Hello world"
743
+ ssml = RubySpeech::SSML.draw { string str }
744
+ expect_async_ssml_output ssml, voice: 'foo'
745
+ subject.say!(str)
746
+ end
747
+
748
+ after { Adhearsion.config.punchblock.default_voice = nil }
749
+ end
750
+
717
751
  describe "converts the argument to a string" do
718
752
  it 'calls output with a string' do
719
753
  argument = 123
@@ -7,8 +7,129 @@ module Adhearsion
7
7
  describe Record do
8
8
  include CallControllerTestHelpers
9
9
 
10
+ describe Recorder do
11
+ let(:interruptible) { false }
12
+ let(:async) { false }
13
+ let(:component_options) { { :start_beep => true } }
14
+ let :options do
15
+ component_options.merge :interruptible => interruptible,
16
+ :async => async
17
+ end
18
+
19
+ let(:component) { Punchblock::Component::Record.new component_options }
20
+ let :stopper_grammar do
21
+ RubySpeech::GRXML.draw :mode => 'dtmf', :root => 'inputdigits' do
22
+ rule id: 'inputdigits', scope: 'public' do
23
+ one_of do
24
+ item { '0' }
25
+ item { '1' }
26
+ item { '2' }
27
+ item { '3' }
28
+ item { '4' }
29
+ item { '5' }
30
+ item { '6' }
31
+ item { '7' }
32
+ item { '8' }
33
+ item { '9' }
34
+ item { '#' }
35
+ item { '*' }
36
+ end
37
+ end
38
+ end
39
+ end
40
+ let(:input_component) { Punchblock::Component::Input.new mode: :dtmf, grammar: { :value => stopper_grammar } }
41
+
42
+ subject { Recorder.new controller, options }
43
+
44
+ its(:record_component) { should == component }
45
+
46
+ context "when passing time related options" do
47
+ let :component_options do
48
+ { :max_duration => 5.5, :initial_timeout => 6.5, :final_timeout => 3.2 }
49
+ end
50
+
51
+ let :component do
52
+ Punchblock::Component::Record.new :max_duration => 5500,
53
+ :initial_timeout => 6500,
54
+ :final_timeout => 3200
55
+ end
56
+
57
+ it "takes seconds but sets milliseconds on the command" do
58
+ subject.record_component.should == component
59
+ end
60
+ end
61
+
62
+ describe "#run" do
63
+ context "with :async => false" do
64
+ it "executes the component synchronously" do
65
+ expect_component_execution subject.record_component
66
+ subject.run
67
+ end
68
+ end
69
+
70
+ context "with :async => true" do
71
+ let(:async) { true }
72
+
73
+ it "executes the component asynchronously" do
74
+ expect_message_waiting_for_response subject.record_component
75
+ subject.run
76
+ end
77
+ end
78
+
79
+ context "with :interruptible => false" do
80
+ its(:stopper_component) { should be_nil }
81
+
82
+ it "does not use an Input component" do
83
+ controller.should_receive(:execute_component_and_await_completion).once.with(component)
84
+ controller.should_receive(:write_and_await_response).never.with(input_component)
85
+ subject.run
86
+ end
87
+ end
88
+
89
+ context "with :interruptible => true" do
90
+ let(:interruptible) { true }
91
+
92
+ its(:stopper_component) { should == input_component }
93
+
94
+ describe "when the input component completes" do
95
+ let(:complete_event) { Punchblock::Event::Complete.new }
96
+
97
+ before do
98
+ subject.stopper_component.request!
99
+ subject.stopper_component.execute!
100
+ end
101
+
102
+ it "stops the recording" do
103
+ flexmock(subject.record_component).should_receive(:stop!).once
104
+ subject.stopper_component.trigger_event_handler complete_event
105
+ end
106
+ end
107
+
108
+ describe "when the recording completes" do
109
+ it "stops the input component" do
110
+ controller.should_receive(:execute_component_and_await_completion).once.with(component)
111
+ controller.should_receive(:write_and_await_response).once.with(input_component)
112
+ flexmock(subject.stopper_component).should_receive(:stop!).once
113
+ subject.run
114
+ end
115
+ end
116
+ end
117
+ end
118
+
119
+ describe "setting completion handlers" do
120
+ let(:complete_event) { Punchblock::Event::Complete.new }
121
+
122
+ it "should execute those handlers when recording completes" do
123
+ foo = flexmock 'foo'
124
+ foo.should_receive(:call).once.with Punchblock::Event::Complete
125
+ subject.handle_record_completion { |e| foo.call e }
126
+ subject.record_component.trigger_event_handler complete_event
127
+ end
128
+ end
129
+ end
130
+
10
131
  describe "#record" do
11
- let(:max_duration) { 5 }
132
+ let(:max_duration) { 5.5 }
12
133
  let(:options) do
13
134
  {
14
135
  :start_beep => true,
@@ -104,7 +225,7 @@ module Adhearsion
104
225
  complete_event = Punchblock::Event::Complete.new
105
226
  flexmock(complete_event).should_receive(:reason => flexmock(:name => :input))
106
227
  flexmock(Punchblock::Component::Input).new_instances do |input|
107
- input.should_receive(:complete?).and_return(false)
228
+ input.should_receive(:complete?).and_return(true)
108
229
  input.should_receive(:complete_event).and_return(complete_event)
109
230
  end
110
231
  flexmock(Punchblock::Component::Record).new_instances.should_receive(:stop!)
@@ -47,21 +47,41 @@ module Adhearsion
47
47
  end
48
48
  end # grammar_accept
49
49
 
50
- describe "#parse_single_dtmf" do
51
- it "correctly returns the parsed input" do
52
- subject.parse_single_dtmf("dtmf-3").should be == '3'
53
- end
50
+ describe "#parse_dtmf" do
51
+ context "with a single digit" do
52
+ it "correctly returns the parsed input" do
53
+ subject.parse_dtmf("dtmf-3").should be == '3'
54
+ end
54
55
 
55
- it "correctly returns star as *" do
56
- subject.parse_single_dtmf("dtmf-star").should be == '*'
57
- end
56
+ it "correctly returns star as *" do
57
+ subject.parse_dtmf("dtmf-star").should be == '*'
58
+ end
59
+
60
+ it "correctly returns * as *" do
61
+ subject.parse_dtmf("*").should be == '*'
62
+ end
63
+
64
+ it "correctly returns pound as #" do
65
+ subject.parse_dtmf("dtmf-pound").should be == '#'
66
+ end
67
+
68
+ it "correctly returns # as #" do
69
+ subject.parse_dtmf("#").should be == '#'
70
+ end
58
71
 
59
- it "correctly returns pound as #" do
60
- subject.parse_single_dtmf("dtmf-pound").should be == '#'
72
+ it "correctly parses digits without the dtmf- prefix" do
73
+ subject.parse_dtmf('1').should be == '1'
74
+ end
75
+
76
+ it "correctly returns nil when input is nil" do
77
+ subject.parse_dtmf(nil).should be == nil
78
+ end
61
79
  end
62
80
 
63
- it "correctly returns nil when input is nil" do
64
- subject.parse_single_dtmf(nil).should be == nil
81
+ context "with multiple digits separated by spaces" do
82
+ it "returns the digits without space separation" do
83
+ subject.parse_dtmf('1 dtmf-5 dtmf-star # 2').should be == '15*#2'
84
+ end
65
85
  end
66
86
  end # describe #grammar_accept
67
87
  end
@@ -43,47 +43,45 @@ module Adhearsion
43
43
  its(:id) { should be == call_id }
44
44
  its(:to) { should be == to }
45
45
  its(:from) { should be == from }
46
- its(:offer) { should be offer }
47
- its(:client) { should be mock_client }
48
-
49
- its(:after_end_hold_time) { should be == 30 }
50
46
 
51
47
  describe "its variables" do
52
- context "with an offer with headers" do
53
- let(:headers) { {:x_foo => 'bar'} }
54
- its(:variables) { should be == headers }
48
+ context "with an offer" do
49
+ context "with headers" do
50
+ let(:headers) { {:x_foo => 'bar'} }
51
+ its(:variables) { should be == headers }
55
52
 
56
- it "should be made available via []" do
57
- subject[:x_foo].should be == 'bar'
58
- end
53
+ it "should be made available via []" do
54
+ subject[:x_foo].should be == 'bar'
55
+ end
59
56
 
60
- it "should be alterable using []=" do
61
- subject[:x_foo] = 'baz'
62
- subject[:x_foo].should be == 'baz'
63
- end
57
+ it "should be alterable using []=" do
58
+ subject[:x_foo] = 'baz'
59
+ subject[:x_foo].should be == 'baz'
60
+ end
64
61
 
65
- context "when receiving an event with headers" do
66
- let(:event) { Punchblock::Event::End.new :headers => {:x_bar => 'foo'} }
62
+ context "when receiving an event with headers" do
63
+ let(:event) { Punchblock::Event::End.new :headers => {:x_bar => 'foo'} }
67
64
 
68
- it "should merge later headers" do
69
- subject << event
70
- subject.variables.should be == {:x_foo => 'bar', :x_bar => 'foo'}
65
+ it "should merge later headers" do
66
+ subject << event
67
+ subject.variables.should be == {:x_foo => 'bar', :x_bar => 'foo'}
68
+ end
71
69
  end
72
- end
73
70
 
74
- context "when sending a command with headers" do
75
- let(:command) { Punchblock::Command::Accept.new :headers => {:x_bar => 'foo'} }
71
+ context "when sending a command with headers" do
72
+ let(:command) { Punchblock::Command::Accept.new :headers => {:x_bar => 'foo'} }
76
73
 
77
- it "should merge later headers" do
78
- subject.write_command command
79
- subject.variables.should be == {:x_foo => 'bar', :x_bar => 'foo'}
74
+ it "should merge later headers" do
75
+ subject.write_command command
76
+ subject.variables.should be == {:x_foo => 'bar', :x_bar => 'foo'}
77
+ end
80
78
  end
81
79
  end
82
- end
83
80
 
84
- context "with an offer without headers" do
85
- let(:headers) { nil }
86
- its(:variables) { should be == {} }
81
+ context "without headers" do
82
+ let(:headers) { nil }
83
+ its(:variables) { should be == {} }
84
+ end
87
85
  end
88
86
 
89
87
  context "without an offer" do
@@ -273,6 +271,49 @@ module Adhearsion
273
271
  end
274
272
  end
275
273
 
274
+ context "peer registry" do
275
+ let(:other_call_id) { 'foobar' }
276
+ let(:other_call) { flexmock Call.new, :id => other_call_id }
277
+
278
+ let :joined_event do
279
+ Punchblock::Event::Joined.new :call_id => other_call_id
280
+ end
281
+
282
+ let :unjoined_event do
283
+ Punchblock::Event::Unjoined.new :call_id => other_call_id
284
+ end
285
+
286
+ context "when we know about the joined call" do
287
+ before { Adhearsion.active_calls << other_call }
288
+
289
+ it "should add the peer to its registry" do
290
+ subject << joined_event
291
+ subject.peers.should == {'foobar' => other_call}
292
+ end
293
+ end
294
+
295
+ context "when we don't know about the joined call" do
296
+ it "should add a nil entry to its registry" do
297
+ subject << joined_event
298
+ subject.peers.should == {'foobar' => nil}
299
+ end
300
+ end
301
+
302
+ it "should not return the same registry every call" do
303
+ subject.peers.should_not be subject.peers
304
+ end
305
+
306
+ context "when being unjoined from a previously joined call" do
307
+ before { subject << joined_event }
308
+
309
+ it "should remove the peer from its registry" do
310
+ subject.peers.should_not eql({})
311
+ subject << unjoined_event
312
+ subject.peers.should eql({})
313
+ end
314
+ end
315
+ end
316
+
276
317
  describe "#<<" do
277
318
  describe "with a Punchblock End" do
278
319
  let :end_event do
@@ -307,7 +348,7 @@ module Adhearsion
307
348
  end
308
349
 
309
350
  it "shuts down the actor" do
310
- flexmock subject.wrapped_object, :after_end_hold_time => 2
351
+ Adhearsion.config.platform.after_hangup_lifetime = 2
311
352
  subject << end_event
312
353
  sleep 2.1
313
354
  subject.should_not be_alive
@@ -539,6 +580,12 @@ module Adhearsion
539
580
  subject.reject nil, headers
540
581
  end
541
582
  end
583
+
584
+ it "should immediately fire the :call_rejected event giving the call and the reason" do
585
+ expect_message_waiting_for_response Punchblock::Command::Reject
586
+ flexmock(Adhearsion::Events).should_receive(:trigger_immediately).once.with(:call_rejected, :call => subject, :reason => :decline)
587
+ subject.reject :decline
588
+ end
542
589
  end
543
590
 
544
591
  describe "#hangup" do
@@ -760,12 +807,6 @@ module Adhearsion
760
807
  lambda { subject.execute_controller(mock_controller) { foo } }.should raise_error(ArgumentError)
761
808
  end
762
809
 
763
- it "should add the controller thread to the important threads" do
764
- flexmock(CallController).should_receive(:exec)
765
- controller_thread = subject.execute_controller mock_controller, lambda { |call| latch.countdown! }
766
- Adhearsion::Process.important_threads.should include controller_thread
767
- end
768
-
769
810
  it "should pass the exception to the events system" do
770
811
  latch = CountDownLatch.new 1
771
812
  Adhearsion::Events.exception do |e, l|