adhearsion 2.6.4 → 3.0.0.beta1
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.
- checksums.yaml +4 -4
- data/.travis.yml +6 -9
- data/CHANGELOG.md +22 -7
- data/Gemfile +2 -0
- data/README.markdown +4 -5
- data/Rakefile +1 -2
- data/adhearsion.gemspec +19 -8
- data/features/cli_create.feature +19 -3
- data/features/step_definitions/cli_steps.rb +0 -11
- data/features/support/env.rb +3 -4
- data/lib/adhearsion.rb +48 -27
- data/lib/adhearsion/call.rb +34 -50
- data/lib/adhearsion/call_controller.rb +6 -12
- data/lib/adhearsion/call_controller/dial.rb +15 -53
- data/lib/adhearsion/call_controller/input.rb +39 -162
- data/lib/adhearsion/call_controller/input/ask_grammar_builder.rb +44 -0
- data/lib/adhearsion/call_controller/input/menu_builder.rb +136 -0
- data/lib/adhearsion/call_controller/input/prompt_builder.rb +78 -0
- data/lib/adhearsion/call_controller/input/result.rb +46 -0
- data/lib/adhearsion/call_controller/output.rb +48 -67
- data/lib/adhearsion/call_controller/output/abstract_player.rb +3 -3
- data/lib/adhearsion/call_controller/output/async_player.rb +3 -3
- data/lib/adhearsion/call_controller/output/player.rb +1 -1
- data/lib/adhearsion/call_controller/record.rb +23 -8
- data/lib/adhearsion/calls.rb +1 -1
- data/lib/adhearsion/cli_commands/ahn_command.rb +2 -65
- data/lib/adhearsion/cli_commands/thor_errors.rb +0 -6
- data/lib/adhearsion/configuration.rb +91 -39
- data/lib/adhearsion/core_ext/blather/stanza.rb +41 -0
- data/lib/adhearsion/core_ext/blather/stanza/presence.rb +13 -0
- data/lib/adhearsion/error.rb +5 -0
- data/lib/adhearsion/event.rb +21 -0
- data/lib/adhearsion/event/active_speaker.rb +11 -0
- data/lib/adhearsion/event/answered.rb +11 -0
- data/lib/adhearsion/event/asterisk.rb +10 -0
- data/lib/adhearsion/event/asterisk/ami.rb +34 -0
- data/lib/adhearsion/event/complete.rb +75 -0
- data/lib/adhearsion/event/dtmf.rb +11 -0
- data/lib/adhearsion/event/end.rb +22 -0
- data/lib/adhearsion/event/input_timers_started.rb +9 -0
- data/lib/adhearsion/event/joined.rb +17 -0
- data/lib/adhearsion/event/offer.rb +14 -0
- data/lib/adhearsion/event/ringing.rb +11 -0
- data/lib/adhearsion/event/started_speaking.rb +13 -0
- data/lib/adhearsion/event/stopped_speaking.rb +13 -0
- data/lib/adhearsion/event/unjoined.rb +17 -0
- data/lib/adhearsion/events.rb +47 -66
- data/lib/adhearsion/foundation.rb +0 -1
- data/lib/adhearsion/foundation/object.rb +0 -5
- data/lib/adhearsion/generators/app/app_generator.rb +4 -1
- data/lib/adhearsion/generators/app/templates/Gemfile.erb +2 -10
- data/lib/adhearsion/generators/app/templates/adhearsion.erb +9 -9
- data/lib/adhearsion/generators/app/templates/config.ru +7 -0
- data/lib/adhearsion/generators/app/templates/en.yml +4 -0
- data/lib/adhearsion/generators/app/templates/events.erb +2 -2
- data/lib/adhearsion/generators/app/templates/hello_world.wav +0 -0
- data/lib/adhearsion/generators/app/templates/simon_game.rb +2 -1
- data/lib/adhearsion/generators/app/templates/simon_game_spec.rb +2 -2
- data/lib/adhearsion/has_headers.rb +34 -0
- data/lib/adhearsion/http_server.rb +37 -0
- data/lib/adhearsion/initializer.rb +19 -153
- data/lib/adhearsion/logging.rb +6 -25
- data/lib/adhearsion/outbound_call.rb +5 -5
- data/lib/adhearsion/plugin.rb +1 -0
- data/lib/adhearsion/protocol_error.rb +26 -0
- data/lib/adhearsion/rayo.rb +30 -0
- data/lib/adhearsion/rayo/client.rb +62 -0
- data/lib/adhearsion/rayo/client/component_registry.rb +33 -0
- data/lib/adhearsion/rayo/command.rb +21 -0
- data/lib/adhearsion/rayo/command/accept.rb +16 -0
- data/lib/adhearsion/rayo/command/answer.rb +16 -0
- data/lib/adhearsion/rayo/command/dial.rb +57 -0
- data/lib/adhearsion/rayo/command/hangup.rb +16 -0
- data/lib/adhearsion/rayo/command/join.rb +43 -0
- data/lib/adhearsion/rayo/command/mute.rb +13 -0
- data/lib/adhearsion/rayo/command/redirect.rb +23 -0
- data/lib/adhearsion/rayo/command/reject.rb +40 -0
- data/lib/adhearsion/rayo/command/unjoin.rb +24 -0
- data/lib/adhearsion/rayo/command/unmute.rb +13 -0
- data/lib/adhearsion/rayo/command_node.rb +47 -0
- data/lib/adhearsion/rayo/component.rb +21 -0
- data/lib/adhearsion/rayo/component/asterisk.rb +13 -0
- data/lib/adhearsion/rayo/component/asterisk/agi.rb +14 -0
- data/lib/adhearsion/rayo/component/asterisk/agi/command.rb +46 -0
- data/lib/adhearsion/rayo/component/asterisk/ami.rb +14 -0
- data/lib/adhearsion/rayo/component/asterisk/ami/action.rb +61 -0
- data/lib/adhearsion/rayo/component/component_node.rb +90 -0
- data/lib/adhearsion/rayo/component/input.rb +186 -0
- data/lib/adhearsion/rayo/component/output.rb +471 -0
- data/lib/adhearsion/rayo/component/prompt.rb +53 -0
- data/lib/adhearsion/rayo/component/receive_fax.rb +26 -0
- data/lib/adhearsion/rayo/component/record.rb +165 -0
- data/lib/adhearsion/rayo/component/send_fax.rb +64 -0
- data/lib/adhearsion/rayo/component/stop.rb +11 -0
- data/lib/adhearsion/rayo/connection.rb +12 -0
- data/lib/adhearsion/rayo/connection/asterisk.rb +74 -0
- data/lib/adhearsion/rayo/connection/connected.rb +22 -0
- data/lib/adhearsion/rayo/connection/generic_connection.rb +22 -0
- data/lib/adhearsion/rayo/connection/xmpp.rb +198 -0
- data/lib/adhearsion/rayo/disconnected_error.rb +22 -0
- data/lib/adhearsion/{punchblock_plugin → rayo}/initializer.rb +19 -19
- data/lib/adhearsion/rayo/rayo_node.rb +127 -0
- data/lib/adhearsion/rayo/ref.rb +57 -0
- data/lib/adhearsion/statistics.rb +1 -1
- data/lib/adhearsion/tasks.rb +1 -2
- data/lib/adhearsion/tasks/configuration.rb +1 -1
- data/lib/adhearsion/tasks/environment.rb +0 -2
- data/lib/adhearsion/tasks/i18n.rb +49 -0
- data/lib/adhearsion/translator.rb +11 -0
- data/lib/adhearsion/translator/asterisk.rb +234 -0
- data/lib/adhearsion/translator/asterisk/agi_app.rb +17 -0
- data/lib/adhearsion/translator/asterisk/agi_command.rb +45 -0
- data/lib/adhearsion/translator/asterisk/ami_error_converter.rb +20 -0
- data/lib/adhearsion/translator/asterisk/call.rb +416 -0
- data/lib/adhearsion/translator/asterisk/channel.rb +43 -0
- data/lib/adhearsion/translator/asterisk/component.rb +88 -0
- data/lib/adhearsion/translator/asterisk/component/asterisk.rb +15 -0
- data/lib/adhearsion/translator/asterisk/component/asterisk/agi_command.rb +42 -0
- data/lib/adhearsion/translator/asterisk/component/asterisk/ami_action.rb +68 -0
- data/lib/adhearsion/translator/asterisk/component/composed_prompt.rb +76 -0
- data/lib/adhearsion/translator/asterisk/component/dtmf_recognizer.rb +137 -0
- data/lib/adhearsion/translator/asterisk/component/input.rb +34 -0
- data/lib/adhearsion/translator/asterisk/component/input_component.rb +90 -0
- data/lib/adhearsion/translator/asterisk/component/mrcp_native_prompt.rb +71 -0
- data/lib/adhearsion/translator/asterisk/component/mrcp_prompt.rb +55 -0
- data/lib/adhearsion/translator/asterisk/component/mrcp_recog_prompt.rb +165 -0
- data/lib/adhearsion/translator/asterisk/component/output.rb +233 -0
- data/lib/adhearsion/translator/asterisk/component/record.rb +101 -0
- data/lib/adhearsion/translator/asterisk/component/stop_by_redirect.rb +30 -0
- data/lib/adhearsion/translator/asterisk/unimrcp_app.rb +28 -0
- data/lib/adhearsion/uri_list.rb +21 -0
- data/lib/adhearsion/version.rb +1 -1
- data/spec/adhearsion/call_controller/dial_spec.rb +79 -1420
- data/spec/adhearsion/call_controller/input_spec.rb +1141 -237
- data/spec/adhearsion/call_controller/output/async_player_spec.rb +10 -10
- data/spec/adhearsion/call_controller/output/player_spec.rb +8 -8
- data/spec/adhearsion/call_controller/output_spec.rb +162 -215
- data/spec/adhearsion/call_controller/record_spec.rb +15 -16
- data/spec/adhearsion/call_controller_spec.rb +23 -40
- data/spec/adhearsion/call_spec.rb +123 -129
- data/spec/adhearsion/calls_spec.rb +3 -3
- data/spec/adhearsion/configuration_spec.rb +94 -108
- data/spec/adhearsion/event/answered_spec.rb +50 -0
- data/spec/adhearsion/event/asterisk/Find Results +402 -0
- data/spec/adhearsion/event/asterisk/ami_spec.rb +81 -0
- data/spec/adhearsion/event/complete_spec.rb +176 -0
- data/spec/adhearsion/event/dtmf_spec.rb +35 -0
- data/spec/adhearsion/event/end_spec.rb +85 -0
- data/spec/adhearsion/event/input_timers_started_spec.rb +19 -0
- data/spec/adhearsion/event/joined_spec.rb +53 -0
- data/spec/adhearsion/event/offer_spec.rb +106 -0
- data/spec/adhearsion/event/ringing_spec.rb +50 -0
- data/spec/adhearsion/event/started_speaking_spec.rb +37 -0
- data/spec/adhearsion/event/stopped_speaking_spec.rb +37 -0
- data/spec/adhearsion/event/unjoined_spec.rb +48 -0
- data/spec/adhearsion/event/untitled +0 -0
- data/spec/adhearsion/events_spec.rb +19 -45
- data/spec/adhearsion/initializer_spec.rb +12 -184
- data/spec/adhearsion/logging_spec.rb +5 -20
- data/spec/adhearsion/outbound_call_spec.rb +13 -13
- data/spec/adhearsion/plugin_spec.rb +3 -4
- data/spec/adhearsion/protocol_error_spec.rb +91 -0
- data/spec/adhearsion/rayo/client/component_registry_spec.rb +26 -0
- data/spec/adhearsion/rayo/client_spec.rb +134 -0
- data/spec/adhearsion/rayo/command/accept_spec.rb +63 -0
- data/spec/adhearsion/rayo/command/answer_spec.rb +73 -0
- data/spec/adhearsion/rayo/command/dial_spec.rb +156 -0
- data/spec/adhearsion/rayo/command/hangup_spec.rb +63 -0
- data/spec/adhearsion/rayo/command/join_spec.rb +158 -0
- data/spec/adhearsion/rayo/command/mute_spec.rb +32 -0
- data/spec/adhearsion/rayo/command/redirect_spec.rb +89 -0
- data/spec/adhearsion/rayo/command/reject_spec.rb +117 -0
- data/spec/adhearsion/rayo/command/unjoin_spec.rb +82 -0
- data/spec/adhearsion/rayo/command/unmute_spec.rb +32 -0
- data/spec/adhearsion/rayo/command_node_spec.rb +101 -0
- data/spec/adhearsion/rayo/component/asterisk/agi/command_spec.rb +111 -0
- data/spec/adhearsion/rayo/component/asterisk/ami/action_spec.rb +173 -0
- data/spec/adhearsion/rayo/component/component_node_spec.rb +110 -0
- data/spec/adhearsion/rayo/component/input_spec.rb +715 -0
- data/spec/adhearsion/rayo/component/output_spec.rb +1030 -0
- data/spec/adhearsion/rayo/component/prompt_spec.rb +171 -0
- data/spec/adhearsion/rayo/component/receive_fax_spec.rb +136 -0
- data/spec/adhearsion/rayo/component/record_spec.rb +497 -0
- data/spec/adhearsion/rayo/component/send_fax_spec.rb +144 -0
- data/spec/adhearsion/rayo/connection/asterisk_spec.rb +118 -0
- data/spec/adhearsion/rayo/connection/xmpp_spec.rb +449 -0
- data/spec/adhearsion/rayo/initializer_spec.rb +353 -0
- data/spec/adhearsion/rayo/ref_spec.rb +168 -0
- data/spec/adhearsion/rayo_spec.rb +7 -0
- data/spec/adhearsion/router/route_spec.rb +1 -1
- data/spec/adhearsion/statistics_spec.rb +2 -5
- data/spec/adhearsion/translator/asterisk/call_spec.rb +2047 -0
- data/spec/adhearsion/translator/asterisk/component/asterisk/agi_command_spec.rb +256 -0
- data/spec/adhearsion/translator/asterisk/component/asterisk/ami_action_spec.rb +151 -0
- data/spec/adhearsion/translator/asterisk/component/composed_prompt_spec.rb +257 -0
- data/spec/adhearsion/translator/asterisk/component/input_spec.rb +571 -0
- data/spec/adhearsion/translator/asterisk/component/mrcp_native_prompt_spec.rb +774 -0
- data/spec/adhearsion/translator/asterisk/component/mrcp_prompt_spec.rb +1244 -0
- data/spec/adhearsion/translator/asterisk/component/output_spec.rb +1850 -0
- data/spec/adhearsion/translator/asterisk/component/record_spec.rb +426 -0
- data/spec/adhearsion/translator/asterisk/component/stop_by_redirect_spec.rb +62 -0
- data/spec/adhearsion/translator/asterisk/component_spec.rb +83 -0
- data/spec/adhearsion/translator/asterisk_spec.rb +685 -0
- data/spec/adhearsion/uri_list_spec.rb +88 -0
- data/spec/adhearsion_spec.rb +89 -14
- data/spec/fixtures/locale/en.yml +13 -0
- data/spec/fixtures/locale/it.yml +13 -0
- data/spec/spec_helper.rb +18 -5
- data/spec/support/call_controller_test_helpers.rb +3 -2
- data/spec/support/initializer_stubs.rb +3 -1
- data/spec/support/punchblock_examples.rb +65 -0
- data/spec/support/punchblock_mocks.rb +12 -0
- metadata +412 -70
- data/features/cli_daemon.feature +0 -20
- data/features/cli_restart.feature +0 -52
- data/features/cli_stop.feature +0 -50
- data/lib/adhearsion/call_controller/menu_dsl.rb +0 -21
- data/lib/adhearsion/call_controller/menu_dsl/array_match_calculator.rb +0 -26
- data/lib/adhearsion/call_controller/menu_dsl/calculated_match.rb +0 -43
- data/lib/adhearsion/call_controller/menu_dsl/calculated_match_collection.rb +0 -45
- data/lib/adhearsion/call_controller/menu_dsl/fixnum_match_calculator.rb +0 -11
- data/lib/adhearsion/call_controller/menu_dsl/match_calculator.rb +0 -40
- data/lib/adhearsion/call_controller/menu_dsl/menu.rb +0 -207
- data/lib/adhearsion/call_controller/menu_dsl/menu_builder.rb +0 -92
- data/lib/adhearsion/call_controller/menu_dsl/range_match_calculator.rb +0 -60
- data/lib/adhearsion/call_controller/menu_dsl/string_match_calculator.rb +0 -25
- data/lib/adhearsion/call_controller/utility.rb +0 -77
- data/lib/adhearsion/foundation/custom_daemonizer.rb +0 -52
- data/lib/adhearsion/punchblock_plugin.rb +0 -63
- data/scripts/cloc-1.64.pl +0 -10483
- data/spec/adhearsion/call_controller/menu_dsl/array_match_calculator_spec.rb +0 -76
- data/spec/adhearsion/call_controller/menu_dsl/calculated_match_collection_spec.rb +0 -60
- data/spec/adhearsion/call_controller/menu_dsl/calculated_match_spec.rb +0 -61
- data/spec/adhearsion/call_controller/menu_dsl/fixnum_match_calculator_spec.rb +0 -39
- data/spec/adhearsion/call_controller/menu_dsl/match_calculator_spec.rb +0 -17
- data/spec/adhearsion/call_controller/menu_dsl/menu_builder_spec.rb +0 -165
- data/spec/adhearsion/call_controller/menu_dsl/menu_spec.rb +0 -420
- data/spec/adhearsion/call_controller/menu_dsl/range_match_calculator_spec.rb +0 -32
- data/spec/adhearsion/call_controller/menu_dsl/string_match_calculator_spec.rb +0 -40
- data/spec/adhearsion/call_controller/utility_spec.rb +0 -90
- data/spec/adhearsion/punchblock_plugin/initializer_spec.rb +0 -356
- data/spec/adhearsion/punchblock_plugin_spec.rb +0 -59
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
module Adhearsion
|
|
6
|
+
module Translator
|
|
7
|
+
class Asterisk
|
|
8
|
+
describe Component do
|
|
9
|
+
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
module Component
|
|
13
|
+
describe Component do
|
|
14
|
+
let(:connection) { Adhearsion::Rayo::Connection::Asterisk.new }
|
|
15
|
+
let(:translator) { connection.translator }
|
|
16
|
+
let(:ami_client) { connection.ami_client }
|
|
17
|
+
let(:call) { Translator::Asterisk::Call.new 'foo', translator, ami_client, connection }
|
|
18
|
+
let(:command) { Adhearsion::Rayo::Component::Input.new }
|
|
19
|
+
|
|
20
|
+
subject { Component.new command, call }
|
|
21
|
+
|
|
22
|
+
before { command.request! }
|
|
23
|
+
|
|
24
|
+
describe "#send_event" do
|
|
25
|
+
before { command.execute! }
|
|
26
|
+
|
|
27
|
+
let :event do
|
|
28
|
+
Adhearsion::Event::Complete.new
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
let :expected_event do
|
|
32
|
+
Adhearsion::Event::Complete.new target_call_id: call.id,
|
|
33
|
+
component_id: subject.id, source_uri: subject.id
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "should send the event to the connection" do
|
|
37
|
+
expect(connection).to receive(:handle_event).once.with expected_event
|
|
38
|
+
subject.send_event event
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
describe "#send_complete_event" do
|
|
43
|
+
before { command.execute! }
|
|
44
|
+
|
|
45
|
+
let(:reason) { Adhearsion::Event::Complete::Stop.new }
|
|
46
|
+
let :expected_event do
|
|
47
|
+
Adhearsion::Event::Complete.new reason: reason
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "should send a complete event with the specified reason" do
|
|
51
|
+
expect(subject).to receive(:send_event).once.with expected_event
|
|
52
|
+
subject.send_complete_event reason
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
describe "#call_ended" do
|
|
57
|
+
it "should send a complete event with the call hangup reason" do
|
|
58
|
+
expect(subject).to receive(:send_complete_event).once.with Adhearsion::Event::Complete::Hangup.new
|
|
59
|
+
subject.call_ended
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
describe '#execute_command' do
|
|
64
|
+
before do
|
|
65
|
+
component_command.request!
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
context 'with a command we do not understand' do
|
|
69
|
+
let :component_command do
|
|
70
|
+
Adhearsion::Rayo::Component::Stop.new :component_id => subject.id
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
it 'sends an error in response to the command' do
|
|
74
|
+
subject.execute_command component_command
|
|
75
|
+
expect(component_command.response).to eq(Adhearsion::ProtocolError.new.setup('command-not-acceptable', "Did not understand command for component #{subject.id}", call.id, subject.id))
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -0,0 +1,685 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
require 'ostruct'
|
|
5
|
+
|
|
6
|
+
module Adhearsion
|
|
7
|
+
module Translator
|
|
8
|
+
describe Asterisk do
|
|
9
|
+
let(:ami_client) { double 'RubyAMI::Client' }
|
|
10
|
+
let(:connection) { Adhearsion::Rayo::Connection::Asterisk.new }
|
|
11
|
+
|
|
12
|
+
let(:translator) { Asterisk.new ami_client, connection }
|
|
13
|
+
|
|
14
|
+
subject { translator }
|
|
15
|
+
|
|
16
|
+
describe '#ami_client' do
|
|
17
|
+
subject { super().ami_client }
|
|
18
|
+
it { is_expected.to be ami_client }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
describe '#connection' do
|
|
22
|
+
subject { super().connection }
|
|
23
|
+
it { is_expected.to be connection }
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
before do
|
|
27
|
+
connection.event_handler = ->(*) {}
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
after { translator.terminate if translator.alive? }
|
|
31
|
+
|
|
32
|
+
describe '#execute_command' do
|
|
33
|
+
describe 'with a call command' do
|
|
34
|
+
let(:command) { Adhearsion::Rayo::Command::Answer.new }
|
|
35
|
+
let(:call_id) { 'abc123' }
|
|
36
|
+
|
|
37
|
+
it 'executes the call command' do
|
|
38
|
+
expect(subject.wrapped_object).to receive(:execute_call_command).with(satisfy { |c|
|
|
39
|
+
expect(c).to be command
|
|
40
|
+
expect(c.target_call_id).to eq(call_id)
|
|
41
|
+
})
|
|
42
|
+
subject.execute_command command, :call_id => call_id
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
describe 'with a global component command' do
|
|
47
|
+
let(:command) { Adhearsion::Rayo::Component::Stop.new }
|
|
48
|
+
let(:component_id) { '123abc' }
|
|
49
|
+
|
|
50
|
+
it 'executes the component command' do
|
|
51
|
+
expect(subject.wrapped_object).to receive(:execute_component_command).with(satisfy { |c|
|
|
52
|
+
expect(c).to be command
|
|
53
|
+
expect(c.component_id).to eq(component_id)
|
|
54
|
+
})
|
|
55
|
+
subject.execute_command command, :component_id => component_id
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
describe 'with a global command' do
|
|
60
|
+
let(:command) { Adhearsion::Rayo::Command::Dial.new }
|
|
61
|
+
|
|
62
|
+
it 'executes the command directly' do
|
|
63
|
+
expect(subject.wrapped_object).to receive(:execute_global_command).with command
|
|
64
|
+
subject.execute_command command
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
describe '#send_message' do
|
|
70
|
+
let(:call_id) { 'abc123' }
|
|
71
|
+
let(:body) { 'hello world' }
|
|
72
|
+
let(:call) { Translator::Asterisk::Call.new 'SIP/foo', subject, ami_client, connection }
|
|
73
|
+
|
|
74
|
+
before do
|
|
75
|
+
allow(call).to receive(:id).and_return call_id
|
|
76
|
+
subject.register_call call
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it 'sends the command to the call for execution' do
|
|
80
|
+
expect(call).to receive(:send_message).once.with body
|
|
81
|
+
subject.send_message call_id, 'example.com', body, subject: 'stuff'
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
context "when the call doesn't exist" do
|
|
85
|
+
it "should not crash the translator" do
|
|
86
|
+
subject.send_message 'oops', 'example.com', body, subject: 'stuff'
|
|
87
|
+
expect(subject).to be_alive
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
describe '#register_call' do
|
|
93
|
+
let(:call_id) { 'abc123' }
|
|
94
|
+
let(:channel) { 'SIP/foo' }
|
|
95
|
+
let(:call) { Translator::Asterisk::Call.new channel, subject, ami_client, connection }
|
|
96
|
+
|
|
97
|
+
before do
|
|
98
|
+
allow(call).to receive(:id).and_return call_id
|
|
99
|
+
subject.register_call call
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
it 'should make the call accessible by ID' do
|
|
103
|
+
expect(subject.call_with_id(call_id)).to be call
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
it 'should make the call accessible by channel' do
|
|
107
|
+
expect(subject.call_for_channel(channel)).to be call
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
describe '#deregister_call' do
|
|
112
|
+
let(:call_id) { 'abc123' }
|
|
113
|
+
let(:channel) { 'SIP/foo' }
|
|
114
|
+
let(:call) { Translator::Asterisk::Call.new channel, subject, ami_client, connection }
|
|
115
|
+
|
|
116
|
+
before do
|
|
117
|
+
allow(call).to receive(:id).and_return call_id
|
|
118
|
+
subject.register_call call
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it 'should make the call inaccessible by ID' do
|
|
122
|
+
expect(subject.call_with_id(call_id)).to be call
|
|
123
|
+
subject.deregister_call call_id, channel
|
|
124
|
+
expect(subject.call_with_id(call_id)).to be_nil
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
it 'should make the call inaccessible by channel' do
|
|
128
|
+
expect(subject.call_for_channel(channel)).to be call
|
|
129
|
+
subject.deregister_call call_id, channel
|
|
130
|
+
expect(subject.call_for_channel(channel)).to be_nil
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
describe '#register_component' do
|
|
135
|
+
let(:component_id) { 'abc123' }
|
|
136
|
+
let(:component) { double 'Asterisk::Component::Asterisk::AMIAction', :id => component_id }
|
|
137
|
+
|
|
138
|
+
it 'should make the component accessible by ID' do
|
|
139
|
+
subject.register_component component
|
|
140
|
+
expect(subject.component_with_id(component_id)).to be component
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
describe '#execute_call_command' do
|
|
145
|
+
let(:call_id) { 'abc123' }
|
|
146
|
+
let(:command) { Adhearsion::Rayo::Command::Answer.new target_call_id: call_id }
|
|
147
|
+
|
|
148
|
+
context "with a known call ID" do
|
|
149
|
+
let(:call) { Translator::Asterisk::Call.new 'SIP/foo', subject, ami_client, connection }
|
|
150
|
+
|
|
151
|
+
before do
|
|
152
|
+
command.request!
|
|
153
|
+
allow(call).to receive(:id).and_return call_id
|
|
154
|
+
subject.register_call call
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
it 'sends the command to the call for execution' do
|
|
158
|
+
expect(call).to receive(:execute_command).once.with command
|
|
159
|
+
subject.execute_call_command command
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
context 'when it raises' do
|
|
163
|
+
before do
|
|
164
|
+
expect(call).to receive(:execute_command).and_raise StandardError
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
let(:other_command) { Adhearsion::Rayo::Command::Answer.new target_call_id: call_id }
|
|
168
|
+
|
|
169
|
+
it 'sends an error in response to the command' do
|
|
170
|
+
subject.execute_call_command command
|
|
171
|
+
|
|
172
|
+
expect(subject.call_with_id(call_id)).to be_nil
|
|
173
|
+
|
|
174
|
+
other_command.request!
|
|
175
|
+
subject.execute_call_command other_command
|
|
176
|
+
expect(other_command.response).to eq(Adhearsion::ProtocolError.new.setup(:item_not_found, "Could not find a call with ID #{call_id}", call_id))
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
let :end_error_event do
|
|
182
|
+
Adhearsion::Event::End.new reason: :error, target_call_id: call_id
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
context "with an unknown call ID" do
|
|
186
|
+
it 'sends an error in response to the command' do
|
|
187
|
+
command.request!
|
|
188
|
+
subject.execute_call_command command
|
|
189
|
+
expect(command.response).to eq(Adhearsion::ProtocolError.new.setup(:item_not_found, "Could not find a call with ID #{call_id}", call_id, nil))
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
describe '#execute_component_command' do
|
|
195
|
+
let(:call) { Translator::Asterisk::Call.new 'SIP/foo', subject, ami_client, connection }
|
|
196
|
+
let(:component_node) { Adhearsion::Rayo::Component::Output.new }
|
|
197
|
+
let(:component) { Translator::Asterisk::Component::Output.new(component_node, call) }
|
|
198
|
+
|
|
199
|
+
let(:command) { Adhearsion::Rayo::Component::Stop.new component_id: component.id }
|
|
200
|
+
|
|
201
|
+
before do
|
|
202
|
+
command.request!
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
context 'with a known component ID' do
|
|
206
|
+
before do
|
|
207
|
+
subject.register_component component
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
it 'sends the command to the component for execution' do
|
|
211
|
+
expect(component).to receive(:execute_command).once.with command
|
|
212
|
+
subject.execute_component_command command
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
context "with an unknown component ID" do
|
|
217
|
+
it 'sends an error in response to the command' do
|
|
218
|
+
subject.execute_component_command command
|
|
219
|
+
expect(command.response).to eq(Adhearsion::ProtocolError.new.setup(:item_not_found, "Could not find a component with ID #{component.id}", nil, component.id))
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
describe '#execute_global_command' do
|
|
225
|
+
context 'with a Dial' do
|
|
226
|
+
let :command do
|
|
227
|
+
Adhearsion::Rayo::Command::Dial.new :to => 'SIP/1234', :from => 'abc123'
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
before do
|
|
231
|
+
command.request!
|
|
232
|
+
allow(ami_client).to receive(:send_action).and_return RubyAMI::Response.new
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
it 'should be able to look up the call by channel ID' do
|
|
236
|
+
subject.execute_global_command command
|
|
237
|
+
call = subject.call_for_channel('SIP/1234')
|
|
238
|
+
expect(call).to be_a Asterisk::Call
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
it 'should instruct the call to send a dial' do
|
|
242
|
+
mock_call = double('Asterisk::Call').as_null_object
|
|
243
|
+
expect(Asterisk::Call).to receive(:new).once.and_return mock_call
|
|
244
|
+
expect(mock_call).to receive(:dial).once.with command
|
|
245
|
+
subject.execute_global_command command
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
context 'when requesting a specific URI' do
|
|
249
|
+
let(:requested_uri) { connection.new_call_uri }
|
|
250
|
+
|
|
251
|
+
before do
|
|
252
|
+
command.uri = requested_uri
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
it "should assign the requested URI to the call" do
|
|
256
|
+
subject.execute_global_command command
|
|
257
|
+
expect(subject.call_with_id(requested_uri).id).to eq(requested_uri)
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
context 'and the requested URI already represents a known call' do
|
|
261
|
+
before do
|
|
262
|
+
earlier_command = Adhearsion::Rayo::Command::Dial.new to: 'SIP/1234', uri: requested_uri
|
|
263
|
+
earlier_command.request!
|
|
264
|
+
|
|
265
|
+
subject.execute_global_command earlier_command
|
|
266
|
+
|
|
267
|
+
@first_call = subject.call_with_id(requested_uri)
|
|
268
|
+
|
|
269
|
+
subject.execute_global_command command
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
it "should set the command response to a conflict error" do
|
|
273
|
+
expect(command.response(0.1)).to eq(Adhearsion::ProtocolError.new.setup(:conflict, 'Call ID already in use'))
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
it "should not replace the original call in the registry" do
|
|
277
|
+
expect(subject.call_with_id(requested_uri)).to be @first_call
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
context 'with an AMI action' do
|
|
284
|
+
let :command do
|
|
285
|
+
Adhearsion::Rayo::Component::Asterisk::AMI::Action.new :name => 'Status', :params => { :channel => 'foo' }
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
let(:mock_action) { double('Asterisk::Component::Asterisk::AMIAction').as_null_object }
|
|
289
|
+
|
|
290
|
+
it 'should create a component actor and execute it asynchronously' do
|
|
291
|
+
expect(Asterisk::Component::Asterisk::AMIAction).to receive(:new).once.with(command, subject, ami_client).and_return mock_action
|
|
292
|
+
expect(mock_action).to receive(:execute).once
|
|
293
|
+
subject.execute_global_command command
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
it 'registers the component' do
|
|
297
|
+
expect(Asterisk::Component::Asterisk::AMIAction).to receive(:new).once.with(command, subject, ami_client).and_return mock_action
|
|
298
|
+
expect(subject.wrapped_object).to receive(:register_component).with mock_action
|
|
299
|
+
subject.execute_global_command command
|
|
300
|
+
end
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
context "with a command we don't understand" do
|
|
304
|
+
let :command do
|
|
305
|
+
Adhearsion::Rayo::Command::Answer.new
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
it 'sends an error in response to the command' do
|
|
309
|
+
subject.execute_command command
|
|
310
|
+
expect(command.response).to eq(Adhearsion::ProtocolError.new.setup('command-not-acceptable', "Did not understand command"))
|
|
311
|
+
end
|
|
312
|
+
end
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
describe '#handle_pb_event' do
|
|
316
|
+
it 'should forward the event to the connection' do
|
|
317
|
+
event = double 'Adhearsion::Event'
|
|
318
|
+
expect(subject.connection).to receive(:handle_event).once.with event
|
|
319
|
+
subject.handle_pb_event event
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
describe '#handle_ami_event' do
|
|
324
|
+
let :ami_event do
|
|
325
|
+
RubyAMI::Event.new 'Newchannel',
|
|
326
|
+
'Channel' => "SIP/101-3f3f",
|
|
327
|
+
'State' => "Ring",
|
|
328
|
+
'Callerid' => "101",
|
|
329
|
+
'Uniqueid' => "1094154427.10"
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
let :expected_pb_event do
|
|
333
|
+
Adhearsion::Event::Asterisk::AMI.new name: 'Newchannel',
|
|
334
|
+
headers: { 'Channel' => "SIP/101-3f3f",
|
|
335
|
+
'State' => "Ring",
|
|
336
|
+
'Callerid' => "101",
|
|
337
|
+
'Uniqueid' => "1094154427.10"}
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
it 'should create a. AMI event object and pass it to the connection' do
|
|
341
|
+
expect(subject.connection).to receive(:handle_event).once.with expected_pb_event
|
|
342
|
+
subject.handle_ami_event ami_event
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
context "when the event doesn't pass the filter" do
|
|
346
|
+
before { described_class.event_filter = ->(event) { false } }
|
|
347
|
+
after { described_class.event_filter = nil }
|
|
348
|
+
|
|
349
|
+
it 'does not send the AMI event to the connection as a PB event' do
|
|
350
|
+
expect(subject.connection).to receive(:handle_event).never
|
|
351
|
+
subject.handle_ami_event ami_event
|
|
352
|
+
end
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
context 'with something that is not a RubyAMI::Event' do
|
|
356
|
+
it 'does not send anything to the connection' do
|
|
357
|
+
expect(subject.connection).to receive(:handle_event).never
|
|
358
|
+
subject.handle_ami_event :foo
|
|
359
|
+
end
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
describe 'with a FullyBooted event' do
|
|
363
|
+
let(:ami_event) { RubyAMI::Event.new 'FullyBooted' }
|
|
364
|
+
|
|
365
|
+
it 'sends a connected event to the event handler' do
|
|
366
|
+
expect(subject.connection).to receive(:handle_event).once.with Adhearsion::Rayo::Connection::Connected.new
|
|
367
|
+
expect(subject.wrapped_object).to receive(:run_at_fully_booted).once
|
|
368
|
+
subject.handle_ami_event ami_event
|
|
369
|
+
end
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
describe 'with an AsyncAGI Start event' do
|
|
373
|
+
let :ami_event do
|
|
374
|
+
RubyAMI::Event.new 'AsyncAGI',
|
|
375
|
+
'SubEvent' => "Start",
|
|
376
|
+
'Channel' => "SIP/1234-00000000",
|
|
377
|
+
'Env' => "agi_request%3A%20async%0Aagi_channel%3A%20SIP%2F1234-00000000%0Aagi_language%3A%20en%0Aagi_type%3A%20SIP%0Aagi_uniqueid%3A%201320835995.0%0Aagi_version%3A%201.8.4.1%0Aagi_callerid%3A%205678%0Aagi_calleridname%3A%20Jane%20Smith%0Aagi_callingpres%3A%200%0Aagi_callingani2%3A%200%0Aagi_callington%3A%200%0Aagi_callingtns%3A%200%0Aagi_dnid%3A%201000%0Aagi_rdnis%3A%20unknown%0Aagi_context%3A%20default%0Aagi_extension%3A%201000%0Aagi_priority%3A%201%0Aagi_enhanced%3A%200.0%0Aagi_accountcode%3A%20%0Aagi_threadid%3A%204366221312%0A%0A"
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
let :expected_agi_env do
|
|
381
|
+
{
|
|
382
|
+
:agi_request => 'async',
|
|
383
|
+
:agi_channel => 'SIP/1234-00000000',
|
|
384
|
+
:agi_language => 'en',
|
|
385
|
+
:agi_type => 'SIP',
|
|
386
|
+
:agi_uniqueid => '1320835995.0',
|
|
387
|
+
:agi_version => '1.8.4.1',
|
|
388
|
+
:agi_callerid => '5678',
|
|
389
|
+
:agi_calleridname => 'Jane Smith',
|
|
390
|
+
:agi_callingpres => '0',
|
|
391
|
+
:agi_callingani2 => '0',
|
|
392
|
+
:agi_callington => '0',
|
|
393
|
+
:agi_callingtns => '0',
|
|
394
|
+
:agi_dnid => '1000',
|
|
395
|
+
:agi_rdnis => 'unknown',
|
|
396
|
+
:agi_context => 'default',
|
|
397
|
+
:agi_extension => '1000',
|
|
398
|
+
:agi_priority => '1',
|
|
399
|
+
:agi_enhanced => '0.0',
|
|
400
|
+
:agi_accountcode => '',
|
|
401
|
+
:agi_threadid => '4366221312'
|
|
402
|
+
}
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
before { allow(subject.wrapped_object).to receive :handle_pb_event }
|
|
406
|
+
|
|
407
|
+
it 'should be able to look up the call by channel ID' do
|
|
408
|
+
subject.handle_ami_event ami_event
|
|
409
|
+
call = subject.call_for_channel('SIP/1234-00000000')
|
|
410
|
+
expect(call).to be_a Asterisk::Call
|
|
411
|
+
expect(call.agi_env).to be_a Hash
|
|
412
|
+
expect(call.agi_env).to eq(expected_agi_env)
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
it 'should instruct the call to send an offer' do
|
|
416
|
+
mock_call = double('Asterisk::Call').as_null_object
|
|
417
|
+
expect(Asterisk::Call).to receive(:new).once.and_return mock_call
|
|
418
|
+
expect(mock_call).to receive(:send_offer).once
|
|
419
|
+
subject.handle_ami_event ami_event
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
context 'with an Asterisk 13 AsyncAGIStart event' do
|
|
423
|
+
let :ami_event do
|
|
424
|
+
RubyAMI::Event.new 'AsyncAGIStart',
|
|
425
|
+
'Channel' => "SIP/1234-00000000",
|
|
426
|
+
'Env' => "agi_request%3A%20async%0Aagi_channel%3A%20SIP%2F1234-00000000%0Aagi_language%3A%20en%0Aagi_type%3A%20SIP%0Aagi_uniqueid%3A%201320835995.0%0Aagi_version%3A%201.8.4.1%0Aagi_callerid%3A%205678%0Aagi_calleridname%3A%20Jane%20Smith%0Aagi_callingpres%3A%200%0Aagi_callingani2%3A%200%0Aagi_callington%3A%200%0Aagi_callingtns%3A%200%0Aagi_dnid%3A%201000%0Aagi_rdnis%3A%20unknown%0Aagi_context%3A%20default%0Aagi_extension%3A%201000%0Aagi_priority%3A%201%0Aagi_enhanced%3A%200.0%0Aagi_accountcode%3A%20%0Aagi_threadid%3A%204366221312%0A%0A"
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
it 'should be able to look up the call by channel ID' do
|
|
430
|
+
subject.handle_ami_event ami_event
|
|
431
|
+
call = subject.call_for_channel('SIP/1234-00000000')
|
|
432
|
+
expect(call).to be_a Asterisk::Call
|
|
433
|
+
expect(call.agi_env).to be_a Hash
|
|
434
|
+
expect(call.agi_env).to eq(expected_agi_env)
|
|
435
|
+
end
|
|
436
|
+
|
|
437
|
+
it 'should instruct the call to send an offer' do
|
|
438
|
+
mock_call = double('Asterisk::Call').as_null_object
|
|
439
|
+
expect(Asterisk::Call).to receive(:new).once.and_return mock_call
|
|
440
|
+
expect(mock_call).to receive(:send_offer).once
|
|
441
|
+
subject.handle_ami_event ami_event
|
|
442
|
+
end
|
|
443
|
+
end
|
|
444
|
+
|
|
445
|
+
context 'if a call already exists for a matching channel' do
|
|
446
|
+
let(:call) { Asterisk::Call.new "SIP/1234-00000000", subject, ami_client, connection }
|
|
447
|
+
|
|
448
|
+
before do
|
|
449
|
+
subject.register_call call
|
|
450
|
+
end
|
|
451
|
+
|
|
452
|
+
it "should not create a new call" do
|
|
453
|
+
expect(Asterisk::Call).to receive(:new).never
|
|
454
|
+
subject.handle_ami_event ami_event
|
|
455
|
+
end
|
|
456
|
+
end
|
|
457
|
+
|
|
458
|
+
context "for a 'h' extension" do
|
|
459
|
+
let :ami_event do
|
|
460
|
+
RubyAMI::Event.new 'AsyncAGI',
|
|
461
|
+
'SubEvent' => "Start",
|
|
462
|
+
'Channel' => "SIP/1234-00000000",
|
|
463
|
+
'Env' => "agi_extension%3A%20h%0A%0A"
|
|
464
|
+
end
|
|
465
|
+
|
|
466
|
+
it "should not create a new call" do
|
|
467
|
+
expect(Asterisk::Call).to receive(:new).never
|
|
468
|
+
subject.handle_ami_event ami_event
|
|
469
|
+
end
|
|
470
|
+
|
|
471
|
+
it 'should not be able to look up the call by channel ID' do
|
|
472
|
+
subject.handle_ami_event ami_event
|
|
473
|
+
expect(subject.call_for_channel('SIP/1234-00000000')).to be nil
|
|
474
|
+
end
|
|
475
|
+
end
|
|
476
|
+
|
|
477
|
+
context "for a 'Kill' type" do
|
|
478
|
+
let :ami_event do
|
|
479
|
+
RubyAMI::Event.new 'AsyncAGI',
|
|
480
|
+
'SubEvent' => "Start",
|
|
481
|
+
'Channel' => "SIP/1234-00000000",
|
|
482
|
+
'Env' => "agi_type%3A%20Kill%0A%0A"
|
|
483
|
+
end
|
|
484
|
+
|
|
485
|
+
it "should not create a new call" do
|
|
486
|
+
expect(Asterisk::Call).to receive(:new).never
|
|
487
|
+
subject.handle_ami_event ami_event
|
|
488
|
+
end
|
|
489
|
+
|
|
490
|
+
it 'should not be able to look up the call by channel ID' do
|
|
491
|
+
subject.handle_ami_event ami_event
|
|
492
|
+
expect(subject.call_for_channel('SIP/1234-00000000')).to be nil
|
|
493
|
+
end
|
|
494
|
+
end
|
|
495
|
+
end
|
|
496
|
+
|
|
497
|
+
describe 'with a VarSet event including a adhearsion_call_id' do
|
|
498
|
+
let :ami_event do
|
|
499
|
+
RubyAMI::Event.new 'VarSet',
|
|
500
|
+
"Privilege" => "dialplan,all",
|
|
501
|
+
"Channel" => "SIP/1234-00000000",
|
|
502
|
+
"Variable" => "adhearsion_call_id",
|
|
503
|
+
"Value" => call_id,
|
|
504
|
+
"Uniqueid" => "1326210224.0"
|
|
505
|
+
end
|
|
506
|
+
|
|
507
|
+
before do
|
|
508
|
+
ami_client.as_null_object
|
|
509
|
+
allow(subject.wrapped_object).to receive :handle_pb_event
|
|
510
|
+
end
|
|
511
|
+
|
|
512
|
+
context "matching a call that was created by a Dial command" do
|
|
513
|
+
let(:dial_command) { Adhearsion::Rayo::Command::Dial.new :to => 'SIP/1234', :from => 'abc123' }
|
|
514
|
+
|
|
515
|
+
before do
|
|
516
|
+
dial_command.request!
|
|
517
|
+
subject.execute_global_command dial_command
|
|
518
|
+
call
|
|
519
|
+
end
|
|
520
|
+
|
|
521
|
+
let(:call) { subject.call_for_channel 'SIP/1234' }
|
|
522
|
+
let(:call_id) { call.id }
|
|
523
|
+
|
|
524
|
+
it "should set the correct channel on the call" do
|
|
525
|
+
subject.handle_ami_event ami_event
|
|
526
|
+
expect(call.channel).to eq('SIP/1234-00000000')
|
|
527
|
+
end
|
|
528
|
+
|
|
529
|
+
it "should make it possible to look up the call by the full channel name" do
|
|
530
|
+
subject.handle_ami_event ami_event
|
|
531
|
+
expect(subject.call_for_channel("SIP/1234-00000000")).to be call
|
|
532
|
+
end
|
|
533
|
+
|
|
534
|
+
it "should make looking up the channel by the requested channel name impossible" do
|
|
535
|
+
subject.handle_ami_event ami_event
|
|
536
|
+
expect(subject.call_for_channel('SIP/1234')).to be_nil
|
|
537
|
+
end
|
|
538
|
+
end
|
|
539
|
+
|
|
540
|
+
context "for a call that doesn't exist" do
|
|
541
|
+
let(:call_id) { 'foobarbaz' }
|
|
542
|
+
|
|
543
|
+
it "should not raise" do
|
|
544
|
+
expect { subject.handle_ami_event ami_event }.not_to raise_error
|
|
545
|
+
end
|
|
546
|
+
end
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
describe 'with an AMI event for a known channel' do
|
|
550
|
+
let :ami_event do
|
|
551
|
+
RubyAMI::Event.new 'Hangup',
|
|
552
|
+
'Uniqueid' => "1320842458.8",
|
|
553
|
+
'Calleridnum' => "5678",
|
|
554
|
+
'Calleridname' => "Jane Smith",
|
|
555
|
+
'Cause' => "0",
|
|
556
|
+
'Cause-txt' => "Unknown",
|
|
557
|
+
'Channel' => "SIP/1234-00000000"
|
|
558
|
+
end
|
|
559
|
+
|
|
560
|
+
let(:call) do
|
|
561
|
+
Asterisk::Call.new "SIP/1234-00000000", subject, ami_client, connection, "agi_request%3A%20async%0Aagi_channel%3A%20SIP%2F1234-00000000%0Aagi_language%3A%20en%0Aagi_type%3A%20SIP%0Aagi_uniqueid%3A%201320835995.0%0Aagi_version%3A%201.8.4.1%0Aagi_callerid%3A%205678%0Aagi_calleridname%3A%20Jane%20Smith%0Aagi_callingpres%3A%200%0Aagi_callingani2%3A%200%0Aagi_callington%3A%200%0Aagi_callingtns%3A%200%0Aagi_dnid%3A%201000%0Aagi_rdnis%3A%20unknown%0Aagi_context%3A%20default%0Aagi_extension%3A%201000%0Aagi_priority%3A%201%0Aagi_enhanced%3A%200.0%0Aagi_accountcode%3A%20%0Aagi_threadid%3A%204366221312%0A%0A"
|
|
562
|
+
end
|
|
563
|
+
|
|
564
|
+
before do
|
|
565
|
+
subject.register_call call
|
|
566
|
+
end
|
|
567
|
+
|
|
568
|
+
it 'sends the AMI event to the call and to the connection as a PB event' do
|
|
569
|
+
expect(call).to receive(:process_ami_event).once.with ami_event
|
|
570
|
+
subject.handle_ami_event ami_event
|
|
571
|
+
end
|
|
572
|
+
|
|
573
|
+
context 'with a Channel1 and Channel2 specified on the event' do
|
|
574
|
+
let :ami_event do
|
|
575
|
+
RubyAMI::Event.new 'BridgeAction',
|
|
576
|
+
'Privilege' => "call,all",
|
|
577
|
+
'Response' => "Success",
|
|
578
|
+
'Channel1' => "SIP/1234-00000000",
|
|
579
|
+
'Channel2' => "SIP/5678-00000000"
|
|
580
|
+
end
|
|
581
|
+
|
|
582
|
+
context 'with calls for those channels' do
|
|
583
|
+
let(:call2) do
|
|
584
|
+
Asterisk::Call.new "SIP/5678-00000000", subject, ami_client, connection, "agi_request%3A%20async%0Aagi_channel%3A%20SIP%2F1234-00000000%0Aagi_language%3A%20en%0Aagi_type%3A%20SIP%0Aagi_uniqueid%3A%201320835995.0%0Aagi_version%3A%201.8.4.1%0Aagi_callerid%3A%205678%0Aagi_calleridname%3A%20Jane%20Smith%0Aagi_callingpres%3A%200%0Aagi_callingani2%3A%200%0Aagi_callington%3A%200%0Aagi_callingtns%3A%200%0Aagi_dnid%3A%201000%0Aagi_rdnis%3A%20unknown%0Aagi_context%3A%20default%0Aagi_extension%3A%201000%0Aagi_priority%3A%201%0Aagi_enhanced%3A%200.0%0Aagi_accountcode%3A%20%0Aagi_threadid%3A%204366221312%0A%0A"
|
|
585
|
+
end
|
|
586
|
+
|
|
587
|
+
before { subject.register_call call2 }
|
|
588
|
+
|
|
589
|
+
it 'should send the event to both calls and to the connection once as a PB event' do
|
|
590
|
+
expect(call).to receive(:process_ami_event).once.with ami_event
|
|
591
|
+
expect(call2).to receive(:process_ami_event).once.with ami_event
|
|
592
|
+
subject.handle_ami_event ami_event
|
|
593
|
+
end
|
|
594
|
+
end
|
|
595
|
+
end
|
|
596
|
+
end
|
|
597
|
+
|
|
598
|
+
describe 'with an event for a channel with Bridge and special statuses appended' do
|
|
599
|
+
let :ami_event do
|
|
600
|
+
RubyAMI::Event.new 'AGIExec',
|
|
601
|
+
'SubEvent' => "End",
|
|
602
|
+
'Channel' => "Bridge/SIP/1234-00000000<ZOMBIE>"
|
|
603
|
+
end
|
|
604
|
+
|
|
605
|
+
let :ami_event2 do
|
|
606
|
+
RubyAMI::Event.new 'Hangup',
|
|
607
|
+
'Uniqueid' => "1320842458.8",
|
|
608
|
+
'Calleridnum' => "5678",
|
|
609
|
+
'Calleridname' => "Jane Smith",
|
|
610
|
+
'Cause' => "0",
|
|
611
|
+
'Cause-txt' => "Unknown",
|
|
612
|
+
'Channel' => "Bridge/SIP/1234-00000000<ZOMBIE>"
|
|
613
|
+
end
|
|
614
|
+
|
|
615
|
+
let(:call) do
|
|
616
|
+
Asterisk::Call.new "SIP/1234-00000000", subject, ami_client, connection, "agi_request%3A%20async%0Aagi_channel%3A%20SIP%2F1234-00000000%0Aagi_language%3A%20en%0Aagi_type%3A%20SIP%0Aagi_uniqueid%3A%201320835995.0%0Aagi_version%3A%201.8.4.1%0Aagi_callerid%3A%205678%0Aagi_calleridname%3A%20Jane%20Smith%0Aagi_callingpres%3A%200%0Aagi_callingani2%3A%200%0Aagi_callington%3A%200%0Aagi_callingtns%3A%200%0Aagi_dnid%3A%201000%0Aagi_rdnis%3A%20unknown%0Aagi_context%3A%20default%0Aagi_extension%3A%201000%0Aagi_priority%3A%201%0Aagi_enhanced%3A%200.0%0Aagi_accountcode%3A%20%0Aagi_threadid%3A%204366221312%0A%0A"
|
|
617
|
+
end
|
|
618
|
+
|
|
619
|
+
before do
|
|
620
|
+
subject.register_call call
|
|
621
|
+
end
|
|
622
|
+
|
|
623
|
+
it 'sends the AMI event to the call and to the connection as a PB event if it is an allowed event' do
|
|
624
|
+
expect(call).to receive(:process_ami_event).once.with ami_event
|
|
625
|
+
subject.handle_ami_event ami_event
|
|
626
|
+
end
|
|
627
|
+
|
|
628
|
+
it 'does not send the AMI event to a bridged channel if it is not allowed' do
|
|
629
|
+
expect(call).to receive(:process_ami_event).never.with ami_event2
|
|
630
|
+
subject.handle_ami_event ami_event2
|
|
631
|
+
end
|
|
632
|
+
|
|
633
|
+
end
|
|
634
|
+
end
|
|
635
|
+
|
|
636
|
+
describe '#run_at_fully_booted' do
|
|
637
|
+
let(:broken_path) { "/this/is/not/a/valid/path" }
|
|
638
|
+
|
|
639
|
+
let(:passed_show) do
|
|
640
|
+
OpenStruct.new text_body: "[ Context 'adhearsion-redirect' created by 'pbx_config' ]\n '1' => 1. AGI(agi:async)[pbx_config]\n\n-= 1 extension (1 priority) in 1 context. =-"
|
|
641
|
+
end
|
|
642
|
+
|
|
643
|
+
let(:failed_show) do
|
|
644
|
+
OpenStruct.new text_body: "There is no existence of 'adhearsion-redirect' context\nCommand 'dialplan show adhearsion-redirect' failed."
|
|
645
|
+
end
|
|
646
|
+
|
|
647
|
+
it 'should send the redirect extension Command to the AMI client' do
|
|
648
|
+
expect(ami_client).to receive(:send_action).once.with 'Command', 'Command' => "dialplan add extension #{Asterisk::REDIRECT_EXTENSION},#{Asterisk::REDIRECT_PRIORITY},AGI,agi:async into #{Asterisk::REDIRECT_CONTEXT}"
|
|
649
|
+
expect(ami_client).to receive(:send_action).once.with('Command', 'Command' => "dialplan show #{Asterisk::REDIRECT_CONTEXT}").and_return(passed_show)
|
|
650
|
+
subject.run_at_fully_booted
|
|
651
|
+
end
|
|
652
|
+
|
|
653
|
+
it 'should check the context for existence and do nothing if it is there' do
|
|
654
|
+
expect(ami_client).to receive(:send_action).once.with 'Command', 'Command' => "dialplan add extension #{Asterisk::REDIRECT_EXTENSION},#{Asterisk::REDIRECT_PRIORITY},AGI,agi:async into #{Asterisk::REDIRECT_CONTEXT}"
|
|
655
|
+
expect(ami_client).to receive(:send_action).once.with('Command', 'Command' => "dialplan show #{Asterisk::REDIRECT_CONTEXT}").and_return(passed_show)
|
|
656
|
+
subject.run_at_fully_booted
|
|
657
|
+
end
|
|
658
|
+
|
|
659
|
+
it 'should check the context for existence and log an error if it is not there' do
|
|
660
|
+
expect(ami_client).to receive(:send_action).once.with 'Command', 'Command' => "dialplan add extension #{Asterisk::REDIRECT_EXTENSION},#{Asterisk::REDIRECT_PRIORITY},AGI,agi:async into #{Asterisk::REDIRECT_CONTEXT}"
|
|
661
|
+
expect(ami_client).to receive(:send_action).once.with('Command', 'Command' => "dialplan show #{Asterisk::REDIRECT_CONTEXT}").and_return(failed_show)
|
|
662
|
+
expect(translator.logger).to receive(:error).once.with("Adhearsion failed to add the #{Asterisk::REDIRECT_EXTENSION} extension to the #{Asterisk::REDIRECT_CONTEXT} context. Please add a [#{Asterisk::REDIRECT_CONTEXT}] entry to your dialplan.")
|
|
663
|
+
subject.run_at_fully_booted
|
|
664
|
+
end
|
|
665
|
+
|
|
666
|
+
it 'should check the recording directory for existence' do
|
|
667
|
+
stub_const('Adhearsion::Translator::Asterisk::Component::Record::RECORDING_BASE_PATH', broken_path)
|
|
668
|
+
expect(ami_client).to receive(:send_action).once.with 'Command', 'Command' => "dialplan add extension #{Asterisk::REDIRECT_EXTENSION},#{Asterisk::REDIRECT_PRIORITY},AGI,agi:async into #{Asterisk::REDIRECT_CONTEXT}"
|
|
669
|
+
expect(ami_client).to receive(:send_action).once.with('Command', 'Command' => "dialplan show #{Asterisk::REDIRECT_CONTEXT}").and_return(passed_show)
|
|
670
|
+
expect(translator.logger).to receive(:warn).once.with("Recordings directory #{broken_path} does not exist. Recording might not work. This warning can be ignored if Adhearsion is running on a separate machine than Asterisk. See http://adhearsion.com/docs/call-controllers#recording")
|
|
671
|
+
subject.run_at_fully_booted
|
|
672
|
+
end
|
|
673
|
+
end
|
|
674
|
+
|
|
675
|
+
describe '#check_recording_directory' do
|
|
676
|
+
let(:broken_path) { "/this/is/not/a/valid/path" }
|
|
677
|
+
it 'logs a warning if the recording directory does not exist' do
|
|
678
|
+
stub_const('Adhearsion::Translator::Asterisk::Component::Record::RECORDING_BASE_PATH', broken_path)
|
|
679
|
+
expect(translator.logger).to receive(:warn).once.with("Recordings directory #{broken_path} does not exist. Recording might not work. This warning can be ignored if Adhearsion is running on a separate machine than Asterisk. See http://adhearsion.com/docs/call-controllers#recording")
|
|
680
|
+
subject.check_recording_directory
|
|
681
|
+
end
|
|
682
|
+
end
|
|
683
|
+
end
|
|
684
|
+
end
|
|
685
|
+
end
|