adhearsion 2.1.3 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +87 -0
- data/Guardfile +1 -1
- data/Rakefile +1 -2
- data/adhearsion.gemspec +1 -1
- data/features/cli_create.feature +1 -0
- data/features/step_definitions/cli_steps.rb +0 -10
- data/lib/adhearsion.rb +11 -0
- data/lib/adhearsion/call.rb +27 -12
- data/lib/adhearsion/call_controller.rb +1 -1
- data/lib/adhearsion/call_controller/dial.rb +3 -1
- data/lib/adhearsion/call_controller/input.rb +4 -4
- data/lib/adhearsion/call_controller/menu_dsl.rb +1 -0
- data/lib/adhearsion/call_controller/menu_dsl/array_match_calculator.rb +26 -0
- data/lib/adhearsion/call_controller/menu_dsl/fixnum_match_calculator.rb +2 -14
- data/lib/adhearsion/call_controller/menu_dsl/string_match_calculator.rb +6 -6
- data/lib/adhearsion/call_controller/output.rb +20 -14
- data/lib/adhearsion/call_controller/output/abstract_player.rb +5 -5
- data/lib/adhearsion/call_controller/output/formatter.rb +68 -68
- data/lib/adhearsion/call_controller/record.rb +91 -28
- data/lib/adhearsion/call_controller/utility.rb +12 -5
- data/lib/adhearsion/calls.rb +1 -1
- data/lib/adhearsion/configuration.rb +4 -0
- data/lib/adhearsion/events.rb +2 -1
- data/lib/adhearsion/generators/app/app_generator.rb +2 -2
- data/lib/adhearsion/generators/app/templates/Gemfile.erb +4 -0
- data/lib/adhearsion/generators/app/templates/Rakefile +5 -0
- data/lib/adhearsion/generators/app/templates/lib/simon_game.rb +3 -0
- data/lib/adhearsion/generators/app/templates/rspec +2 -0
- data/lib/adhearsion/generators/app/templates/spec/call_controllers/simon_game_spec.rb +142 -0
- data/lib/adhearsion/generators/controller/templates/lib/controller.rb +1 -1
- data/lib/adhearsion/generators/controller/templates/spec/controller_spec.rb +2 -0
- data/lib/adhearsion/initializer.rb +3 -2
- data/lib/adhearsion/outbound_call.rb +5 -2
- data/lib/adhearsion/router/route.rb +13 -2
- data/lib/adhearsion/rspec.rb +1 -1
- data/lib/adhearsion/statistics.rb +138 -0
- data/lib/adhearsion/tasks/environment.rb +1 -1
- data/lib/adhearsion/version.rb +1 -1
- data/spec/adhearsion/call_controller/dial_spec.rb +26 -0
- data/spec/adhearsion/call_controller/input_spec.rb +13 -1
- data/spec/adhearsion/call_controller/menu_dsl/array_match_calculator_spec.rb +76 -0
- data/spec/adhearsion/call_controller/menu_dsl/fixnum_match_calculator_spec.rb +8 -6
- data/spec/adhearsion/call_controller/menu_dsl/range_match_calculator_spec.rb +4 -4
- data/spec/adhearsion/call_controller/menu_dsl/string_match_calculator_spec.rb +6 -6
- data/spec/adhearsion/call_controller/output/formatter_spec.rb +3 -5
- data/spec/adhearsion/call_controller/output_spec.rb +59 -25
- data/spec/adhearsion/call_controller/record_spec.rb +123 -2
- data/spec/adhearsion/call_controller/utility_spec.rb +31 -11
- data/spec/adhearsion/call_spec.rb +77 -36
- data/spec/adhearsion/calls_spec.rb +13 -0
- data/spec/adhearsion/initializer_spec.rb +7 -0
- data/spec/adhearsion/outbound_call_spec.rb +14 -0
- data/spec/adhearsion/punchblock_plugin_spec.rb +5 -2
- data/spec/adhearsion/router/openended_route_spec.rb +2 -1
- data/spec/adhearsion/router/route_spec.rb +9 -1
- data/spec/adhearsion/router/unaccepting_route_spec.rb +2 -1
- data/spec/adhearsion/statistics/dump_spec.rb +38 -0
- data/spec/adhearsion/statistics_spec.rb +61 -0
- data/spec/adhearsion_spec.rb +21 -1
- data/spec/spec_helper.rb +2 -0
- 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.
|
18
|
-
match_case.
|
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.
|
23
|
-
match_case.
|
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
|
-
|
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 "
|
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 "
|
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
|
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(
|
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 "#
|
51
|
-
|
52
|
-
|
53
|
-
|
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
|
-
|
56
|
-
|
57
|
-
|
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
|
-
|
60
|
-
|
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
|
-
|
64
|
-
|
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
|
53
|
-
|
54
|
-
|
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
|
-
|
57
|
-
|
58
|
-
|
53
|
+
it "should be made available via []" do
|
54
|
+
subject[:x_foo].should be == 'bar'
|
55
|
+
end
|
59
56
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
57
|
+
it "should be alterable using []=" do
|
58
|
+
subject[:x_foo] = 'baz'
|
59
|
+
subject[:x_foo].should be == 'baz'
|
60
|
+
end
|
64
61
|
|
65
|
-
|
66
|
-
|
62
|
+
context "when receiving an event with headers" do
|
63
|
+
let(:event) { Punchblock::Event::End.new :headers => {:x_bar => 'foo'} }
|
67
64
|
|
68
|
-
|
69
|
-
|
70
|
-
|
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
|
-
|
75
|
-
|
71
|
+
context "when sending a command with headers" do
|
72
|
+
let(:command) { Punchblock::Command::Accept.new :headers => {:x_bar => 'foo'} }
|
76
73
|
|
77
|
-
|
78
|
-
|
79
|
-
|
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
|
-
|
85
|
-
|
86
|
-
|
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
|
-
|
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|
|