adhearsion-asterisk 0.1.0
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.
- data/.gitignore +10 -0
- data/.rspec +3 -0
- data/CHANGELOG.md +14 -0
- data/Gemfile +6 -0
- data/Guardfile +5 -0
- data/LICENSE.txt +22 -0
- data/README.md +143 -0
- data/Rakefile +23 -0
- data/adhearsion-asterisk.gemspec +35 -0
- data/lib/adhearsion-asterisk.rb +1 -0
- data/lib/adhearsion/asterisk.rb +12 -0
- data/lib/adhearsion/asterisk/config_generator.rb +103 -0
- data/lib/adhearsion/asterisk/config_generator/agents.rb +138 -0
- data/lib/adhearsion/asterisk/config_generator/queues.rb +247 -0
- data/lib/adhearsion/asterisk/config_generator/voicemail.rb +238 -0
- data/lib/adhearsion/asterisk/config_manager.rb +60 -0
- data/lib/adhearsion/asterisk/plugin.rb +464 -0
- data/lib/adhearsion/asterisk/queue_proxy.rb +177 -0
- data/lib/adhearsion/asterisk/queue_proxy/agent_proxy.rb +81 -0
- data/lib/adhearsion/asterisk/queue_proxy/queue_agents_list_proxy.rb +132 -0
- data/lib/adhearsion/asterisk/version.rb +5 -0
- data/spec/adhearsion/asterisk/config_generators/agents_spec.rb +258 -0
- data/spec/adhearsion/asterisk/config_generators/queues_spec.rb +322 -0
- data/spec/adhearsion/asterisk/config_generators/voicemail_spec.rb +306 -0
- data/spec/adhearsion/asterisk/config_manager_spec.rb +125 -0
- data/spec/adhearsion/asterisk/plugin_spec.rb +618 -0
- data/spec/adhearsion/asterisk/queue_proxy/agent_proxy_spec.rb +90 -0
- data/spec/adhearsion/asterisk/queue_proxy/queue_agents_list_proxy_spec.rb +145 -0
- data/spec/adhearsion/asterisk/queue_proxy_spec.rb +156 -0
- data/spec/adhearsion/asterisk_spec.rb +9 -0
- data/spec/spec_helper.rb +23 -0
- data/spec/support/the_following_code.rb +3 -0
- metadata +229 -0
@@ -0,0 +1,177 @@
|
|
1
|
+
module Adhearsion
|
2
|
+
module Asterisk
|
3
|
+
class QueueProxy
|
4
|
+
|
5
|
+
extend ActiveSupport::Autoload
|
6
|
+
|
7
|
+
autoload :AgentProxy
|
8
|
+
autoload :QueueAgentsListProxy
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def format_join_hash_key_arguments(options)
|
12
|
+
bad_argument = lambda do |(key, value)|
|
13
|
+
raise ArgumentError, "Unrecognize value for #{key.inspect} -- #{value.inspect}"
|
14
|
+
end
|
15
|
+
|
16
|
+
# Direct Queue() arguments:
|
17
|
+
timeout = options.delete :timeout
|
18
|
+
announcement = options.delete :announce
|
19
|
+
|
20
|
+
# Terse single-character options
|
21
|
+
ring_style = options.delete :play
|
22
|
+
allow_hangup = options.delete :allow_hangup
|
23
|
+
allow_transfer = options.delete :allow_transfer
|
24
|
+
agi = options.delete :agi
|
25
|
+
|
26
|
+
raise ArgumentError, "Unrecognized args to join!: #{options.inspect}" if options.any?
|
27
|
+
|
28
|
+
ring_style = case ring_style
|
29
|
+
when :ringing then 'r'
|
30
|
+
when :music then ''
|
31
|
+
when nil
|
32
|
+
else bad_argument[:play => ring_style]
|
33
|
+
end.to_s
|
34
|
+
|
35
|
+
allow_hangup = case allow_hangup
|
36
|
+
when :caller then 'H'
|
37
|
+
when :agent then 'h'
|
38
|
+
when :everyone then 'Hh'
|
39
|
+
when nil
|
40
|
+
else bad_argument[:allow_hangup => allow_hangup]
|
41
|
+
end.to_s
|
42
|
+
|
43
|
+
allow_transfer = case allow_transfer
|
44
|
+
when :caller then 'T'
|
45
|
+
when :agent then 't'
|
46
|
+
when :everyone then 'Tt'
|
47
|
+
when nil
|
48
|
+
else bad_argument[:allow_transfer => allow_transfer]
|
49
|
+
end.to_s
|
50
|
+
|
51
|
+
terse_character_options = ring_style + allow_transfer + allow_hangup
|
52
|
+
|
53
|
+
[terse_character_options, '', announcement, timeout, agi].map(&:to_s)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
attr_reader :name, :environment
|
58
|
+
|
59
|
+
def initialize(name, environment)
|
60
|
+
@name, @environment = name, environment
|
61
|
+
end
|
62
|
+
|
63
|
+
# Makes the current channel join the queue.
|
64
|
+
#
|
65
|
+
# @param [Hash] options
|
66
|
+
#
|
67
|
+
# :timeout - The number of seconds to wait for an agent to answer
|
68
|
+
# :play - Can be :ringing or :music.
|
69
|
+
# :announce - A sound file to play instead of the normal queue announcement.
|
70
|
+
# :allow_transfer - Can be :caller, :agent, or :everyone. Allow someone to transfer the call.
|
71
|
+
# :allow_hangup - Can be :caller, :agent, or :everyone. Allow someone to hangup with the * key.
|
72
|
+
# :agi - An AGI script to be called on the calling parties channel just before being connected.
|
73
|
+
#
|
74
|
+
# @example
|
75
|
+
# queue('sales').join!
|
76
|
+
# @example
|
77
|
+
# queue('sales').join! :timeout => 1.minute
|
78
|
+
# @example
|
79
|
+
# queue('sales').join! :play => :music
|
80
|
+
# @example
|
81
|
+
# queue('sales').join! :play => :ringing
|
82
|
+
# @example
|
83
|
+
# queue('sales').join! :announce => "custom/special-queue-announcement"
|
84
|
+
# @example
|
85
|
+
# queue('sales').join! :allow_transfer => :caller
|
86
|
+
# @example
|
87
|
+
# queue('sales').join! :allow_transfer => :agent
|
88
|
+
# @example
|
89
|
+
# queue('sales').join! :allow_hangup => :caller
|
90
|
+
# @example
|
91
|
+
# queue('sales').join! :allow_hangup => :agent
|
92
|
+
# @example
|
93
|
+
# queue('sales').join! :allow_hangup => :everyone
|
94
|
+
# @example
|
95
|
+
# queue('sales').join! :agi => 'agi://localhost/sales_queue_callback'
|
96
|
+
# @example
|
97
|
+
# queue('sales').join! :allow_transfer => :agent, :timeout => 30.seconds,
|
98
|
+
def join!(options = {})
|
99
|
+
environment.execute("queue", name, *self.class.format_join_hash_key_arguments(options))
|
100
|
+
normalize_queue_status_variable environment.get_variable("QUEUESTATUS")
|
101
|
+
end
|
102
|
+
|
103
|
+
# Get the agents associated with a queue
|
104
|
+
#
|
105
|
+
# @param [Hash] options
|
106
|
+
# @return [QueueAgentsListProxy]
|
107
|
+
def agents(options = {})
|
108
|
+
cached = options.has_key?(:cache) ? options.delete(:cache) : true
|
109
|
+
raise ArgumentError, "Unrecognized arguments to #agents: #{options.inspect}" if options.keys.any?
|
110
|
+
if cached
|
111
|
+
@cached_proxy ||= QueueAgentsListProxy.new(self, true)
|
112
|
+
else
|
113
|
+
@uncached_proxy ||= QueueAgentsListProxy.new(self, false)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# Check how many channels are waiting in the queue
|
118
|
+
# @return [Integer]
|
119
|
+
# @raise QueueDoesNotExistError
|
120
|
+
def waiting_count
|
121
|
+
raise QueueDoesNotExistError.new(name) unless exists?
|
122
|
+
environment.get_variable("QUEUE_WAITING_COUNT(#{name})").to_i
|
123
|
+
end
|
124
|
+
|
125
|
+
# Check whether the waiting count is zero
|
126
|
+
# @return [Boolean]
|
127
|
+
def empty?
|
128
|
+
waiting_count == 0
|
129
|
+
end
|
130
|
+
|
131
|
+
# Check whether any calls are waiting in the queue
|
132
|
+
# @return [Boolean]
|
133
|
+
def any?
|
134
|
+
waiting_count > 0
|
135
|
+
end
|
136
|
+
|
137
|
+
# Check whether a queue exists/is defined in Asterisk
|
138
|
+
# @return [Boolean]
|
139
|
+
def exists?
|
140
|
+
environment.execute('RemoveQueueMember', name, 'SIP/AdhearsionQueueExistenceCheck')
|
141
|
+
environment.get_variable("RQMSTATUS") != 'NOSUCHQUEUE'
|
142
|
+
end
|
143
|
+
|
144
|
+
private
|
145
|
+
|
146
|
+
# Ensure the queue exists by interpreting the QUEUESTATUS variable
|
147
|
+
#
|
148
|
+
# According to http://www.voip-info.org/wiki/view/Asterisk+cmd+Queue
|
149
|
+
# possible values are:
|
150
|
+
#
|
151
|
+
# TIMEOUT => :timeout
|
152
|
+
# FULL => :full
|
153
|
+
# JOINEMPTY => :joinempty
|
154
|
+
# LEAVEEMPTY => :leaveempty
|
155
|
+
# JOINUNAVAIL => :joinunavail
|
156
|
+
# LEAVEUNAVAIL => :leaveunavail
|
157
|
+
# CONTINUE => :continue
|
158
|
+
#
|
159
|
+
# If the QUEUESTATUS variable is not set the call was successfully connected,
|
160
|
+
# and Adhearsion will return :completed.
|
161
|
+
#
|
162
|
+
# @param [String] QUEUESTATUS variable from Asterisk
|
163
|
+
# @return [Symbol] Symbolized version of QUEUESTATUS
|
164
|
+
# @raise QueueDoesNotExistError
|
165
|
+
def normalize_queue_status_variable(variable)
|
166
|
+
variable = "COMPLETED" if variable.nil?
|
167
|
+
variable.downcase.to_sym
|
168
|
+
end
|
169
|
+
|
170
|
+
class QueueDoesNotExistError < StandardError
|
171
|
+
def initialize(queue_name)
|
172
|
+
super "Queue #{queue_name} does not exist!"
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module Adhearsion
|
2
|
+
module Asterisk
|
3
|
+
class QueueProxy
|
4
|
+
class AgentProxy
|
5
|
+
|
6
|
+
SUPPORTED_METADATA_NAMES = %w[status password name mohclass exten channel] unless defined? SUPPORTED_METADATA_NAMES
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def id_from_agent_channel(id)
|
10
|
+
id = id.to_s
|
11
|
+
id.starts_with?('Agent/') ? id[%r[^Agent/(.+)$],1] : id
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :interface, :proxy, :queue_name, :id
|
16
|
+
def initialize(interface, proxy)
|
17
|
+
@interface, @proxy = interface, proxy
|
18
|
+
@id = self.class.id_from_agent_channel interface
|
19
|
+
@queue_name = proxy.name
|
20
|
+
end
|
21
|
+
|
22
|
+
def remove!
|
23
|
+
proxy.environment.execute 'RemoveQueueMember', queue_name, interface
|
24
|
+
case proxy.environment.get_variable("RQMSTATUS")
|
25
|
+
when "REMOVED" then true
|
26
|
+
when "NOTINQUEUE" then false
|
27
|
+
when "NOSUCHQUEUE"
|
28
|
+
raise QueueDoesNotExistError.new(queue_name)
|
29
|
+
else
|
30
|
+
raise "Unrecognized RQMSTATUS variable!"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Pauses the given agent for this queue only. If you wish to pause this agent
|
35
|
+
# for all queues, pass in :everywhere => true. Returns true if the agent was
|
36
|
+
# successfully paused and false if the agent was not found.
|
37
|
+
def pause!(options = {})
|
38
|
+
args = [(options.delete(:everywhere) ? nil : queue_name), interface]
|
39
|
+
proxy.environment.execute 'PauseQueueMember', *args
|
40
|
+
case proxy.environment.get_variable("PQMSTATUS")
|
41
|
+
when "PAUSED" then true
|
42
|
+
when "NOTFOUND" then false
|
43
|
+
else
|
44
|
+
raise "Unrecognized PQMSTATUS value!"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Pauses the given agent for this queue only. If you wish to pause this agent
|
49
|
+
# for all queues, pass in :everywhere => true. Returns true if the agent was
|
50
|
+
# successfully paused and false if the agent was not found.
|
51
|
+
def unpause!(options = {})
|
52
|
+
args = [(options.delete(:everywhere) ? nil : queue_name), interface]
|
53
|
+
proxy.environment.execute 'UnpauseQueueMember', *args
|
54
|
+
case proxy.environment.get_variable("UPQMSTATUS")
|
55
|
+
when "UNPAUSED" then true
|
56
|
+
when "NOTFOUND" then false
|
57
|
+
else
|
58
|
+
raise "Unrecognized UPQMSTATUS value!"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Returns true/false depending on whether this agent is logged in.
|
63
|
+
def logged_in?
|
64
|
+
status == 'LOGGEDIN'
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def status
|
70
|
+
agent_metadata 'status'
|
71
|
+
end
|
72
|
+
|
73
|
+
def agent_metadata(data_name)
|
74
|
+
data_name = data_name.to_s.downcase
|
75
|
+
raise ArgumentError, "unrecognized agent metadata name #{data_name}" unless SUPPORTED_METADATA_NAMES.include? data_name
|
76
|
+
proxy.environment.variable "AGENT(#{id}:#{data_name})"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
module Adhearsion
|
2
|
+
module Asterisk
|
3
|
+
class QueueProxy
|
4
|
+
class QueueAgentsListProxy
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
attr_reader :proxy, :agents
|
8
|
+
|
9
|
+
def initialize(proxy, cached = false)
|
10
|
+
@proxy = proxy
|
11
|
+
@cached = cached
|
12
|
+
end
|
13
|
+
|
14
|
+
def count
|
15
|
+
if cached? && @cached_count
|
16
|
+
@cached_count
|
17
|
+
else
|
18
|
+
@cached_count = proxy.environment.get_variable("QUEUE_MEMBER_COUNT(#{proxy.name})").to_i
|
19
|
+
end
|
20
|
+
end
|
21
|
+
alias size count
|
22
|
+
alias length count
|
23
|
+
|
24
|
+
# @param [Hash] args
|
25
|
+
# :name value will be viewable in the queue_log
|
26
|
+
# :penalty is the penalty assigned to this agent for answering calls on this queue
|
27
|
+
def new(*args)
|
28
|
+
options = args.last.kind_of?(Hash) ? args.pop : {}
|
29
|
+
interface = args.shift
|
30
|
+
|
31
|
+
raise ArgumentError, "You must specify an interface to add." if interface.nil?
|
32
|
+
raise ArgumentError, "You may only supply an interface and a Hash argument!" if args.any?
|
33
|
+
|
34
|
+
penalty = options.delete(:penalty) || ''
|
35
|
+
name = options.delete(:name) || ''
|
36
|
+
state_interface = options.delete(:state_interface) || ''
|
37
|
+
|
38
|
+
raise ArgumentError, "Unrecognized argument(s): #{options.inspect}" if options.any?
|
39
|
+
|
40
|
+
proxy.environment.execute "AddQueueMember", proxy.name, interface, penalty, '', name, state_interface
|
41
|
+
|
42
|
+
added = case proxy.environment.get_variable("AQMSTATUS")
|
43
|
+
when "ADDED" then true
|
44
|
+
when "MEMBERALREADY" then false
|
45
|
+
when "NOSUCHQUEUE" then raise QueueDoesNotExistError.new(proxy.name)
|
46
|
+
else
|
47
|
+
raise "UNRECOGNIZED AQMSTATUS VALUE!"
|
48
|
+
end
|
49
|
+
|
50
|
+
if added
|
51
|
+
check_agent_cache!
|
52
|
+
AgentProxy.new(interface, proxy).tap do |agent_proxy|
|
53
|
+
@agents << agent_proxy
|
54
|
+
end
|
55
|
+
else
|
56
|
+
false
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Logs a pre-defined agent into this queue and waits for calls. Pass in :silent => true to stop
|
61
|
+
# the message which says "Agent logged in".
|
62
|
+
def login!(*args)
|
63
|
+
options = args.last.kind_of?(Hash) ? args.pop : {}
|
64
|
+
|
65
|
+
silent = options.delete(:silent).equal?(false) ? '' : 's'
|
66
|
+
id = args.shift
|
67
|
+
id &&= AgentProxy.id_from_agent_channel(id)
|
68
|
+
raise ArgumentError, "Unrecognized Hash options to #login: #{options.inspect}" if options.any?
|
69
|
+
raise ArgumentError, "Unrecognized argument to #login: #{args.inspect}" if args.any?
|
70
|
+
|
71
|
+
proxy.environment.execute 'AgentLogin', id, silent
|
72
|
+
end
|
73
|
+
|
74
|
+
# Removes the current channel from this queue
|
75
|
+
def logout!
|
76
|
+
# TODO: DRY this up. Repeated in the AgentProxy...
|
77
|
+
proxy.environment.execute 'RemoveQueueMember', proxy.name
|
78
|
+
case proxy.environment.get_variable("RQMSTATUS")
|
79
|
+
when "REMOVED" then true
|
80
|
+
when "NOTINQUEUE" then false
|
81
|
+
when "NOSUCHQUEUE"
|
82
|
+
raise QueueDoesNotExistError.new(proxy.name)
|
83
|
+
else
|
84
|
+
raise "Unrecognized RQMSTATUS variable!"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def each(&block)
|
89
|
+
check_agent_cache!
|
90
|
+
agents.each &block
|
91
|
+
end
|
92
|
+
|
93
|
+
def first
|
94
|
+
check_agent_cache!
|
95
|
+
agents.first
|
96
|
+
end
|
97
|
+
|
98
|
+
def last
|
99
|
+
check_agent_cache!
|
100
|
+
agents.last
|
101
|
+
end
|
102
|
+
|
103
|
+
def cached?
|
104
|
+
@cached
|
105
|
+
end
|
106
|
+
|
107
|
+
def to_a
|
108
|
+
check_agent_cache!
|
109
|
+
@agents
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def check_agent_cache!
|
115
|
+
if cached?
|
116
|
+
load_agents! unless agents
|
117
|
+
else
|
118
|
+
load_agents!
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def load_agents!
|
123
|
+
raw_data = proxy.environment.get_variable "QUEUE_MEMBER_LIST(#{proxy.name})"
|
124
|
+
@agents = raw_data.split(',').map(&:strip).reject(&:empty?).map do |agent|
|
125
|
+
AgentProxy.new agent, proxy
|
126
|
+
end
|
127
|
+
@cached_count = @agents.size
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,258 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'adhearsion/asterisk/config_generator/agents'
|
3
|
+
|
4
|
+
module AgentsConfigGeneratorTestHelper
|
5
|
+
|
6
|
+
def reset_agents!
|
7
|
+
@agents = Adhearsion::Asterisk::ConfigGenerator::Agents.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def generated_config_has_pair(pair)
|
11
|
+
agents.conf.split("\n").grep(/=[^>]/).each do |line|
|
12
|
+
key, value = line.strip.split('=')
|
13
|
+
return true if pair == {key.to_sym => value}
|
14
|
+
end
|
15
|
+
false
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "The agents.conf config file agents" do
|
21
|
+
|
22
|
+
include AgentsConfigGeneratorTestHelper
|
23
|
+
|
24
|
+
attr_reader :agents
|
25
|
+
before(:each) do
|
26
|
+
reset_agents!
|
27
|
+
end
|
28
|
+
it "The agent() method should enqueue a Hash into Agents#agent_definitions" do
|
29
|
+
agents.agent 1337, :password => 9876, :name => "Jay Phillips"
|
30
|
+
agents.agent_definitions.size.should be 1
|
31
|
+
agents.agent_definitions.first.should == {:id => 1337, :password => 9876, :name => "Jay Phillips"}
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should add the warning message to the to_s output' do
|
35
|
+
agents.conf.should =~ /^\s*;.{10}/
|
36
|
+
end
|
37
|
+
|
38
|
+
it "The conf() method should always create a general section" do
|
39
|
+
agents.conf.should =~ /^\[general\]/
|
40
|
+
end
|
41
|
+
|
42
|
+
it "The agent() method should generate a proper String" do
|
43
|
+
agents.agent 123, :name => "Otto Normalverbraucher", :password => "007"
|
44
|
+
agents.agent 889, :name => "John Doe", :password => "998"
|
45
|
+
|
46
|
+
agents.conf.split("\n").grep(/^agent =>/).map(&:strip).should == [
|
47
|
+
"agent => 123,007,Otto Normalverbraucher",
|
48
|
+
"agent => 889,998,John Doe"
|
49
|
+
]
|
50
|
+
end
|
51
|
+
|
52
|
+
it "The persistent_agents() method should generate a persistentagents yes/no pair" do
|
53
|
+
agents.persistent_agents true
|
54
|
+
generated_config_has_pair(:persistentagents => "yes").should be true
|
55
|
+
|
56
|
+
reset_agents!
|
57
|
+
|
58
|
+
agents.persistent_agents false
|
59
|
+
generated_config_has_pair(:persistentagents => "no").should be true
|
60
|
+
end
|
61
|
+
|
62
|
+
it "The persistent_agents() method should be in the [general] section" do
|
63
|
+
agents.persistent_agents true
|
64
|
+
agents.general_section.should == {:persistentagents => "yes"}
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
it "max_login_tries() should generate a 'maxlogintries' numerical pair" do
|
69
|
+
agents.max_login_tries 50
|
70
|
+
generated_config_has_pair(:maxlogintries => "50").should be true
|
71
|
+
end
|
72
|
+
|
73
|
+
it "max_login_tries() should be in the agents section" do
|
74
|
+
agents.max_login_tries 0
|
75
|
+
agents.agent_section.should == {:maxlogintries => 0}
|
76
|
+
end
|
77
|
+
|
78
|
+
it "log_off_after_duration should generate autologoff" do
|
79
|
+
agents.log_off_after_duration 15.seconds
|
80
|
+
generated_config_has_pair(:autologoff => "15").should be true
|
81
|
+
end
|
82
|
+
|
83
|
+
it "log_off_if_unavailable should add autologoffunavail to the agents section" do
|
84
|
+
agents.log_off_if_unavailable false
|
85
|
+
agents.agent_section.should == {:autologoffunavail => "no"}
|
86
|
+
end
|
87
|
+
|
88
|
+
it "require_hash_to_acknowledge() should generate a 'ackcall' yes/no pair" do
|
89
|
+
agents.require_hash_to_acknowledge false
|
90
|
+
agents.agent_section.should == {:ackcall => "no"}
|
91
|
+
end
|
92
|
+
|
93
|
+
it "allow_star_to_hangup should generate a 'endcall' yes/no pair" do
|
94
|
+
agents.allow_star_to_hangup false
|
95
|
+
agents.agent_section.should == {:endcall => "no"}
|
96
|
+
end
|
97
|
+
|
98
|
+
it "time_between_calls should convert its argument to milliseconds" do
|
99
|
+
agents.time_between_calls 1.hour
|
100
|
+
agents.agent_section.should == {:wrapuptime => 1.hour * 1_000}
|
101
|
+
end
|
102
|
+
|
103
|
+
it "hold_music_class should convert its argument to a String" do
|
104
|
+
agents.hold_music_class :podcast
|
105
|
+
agents.agent_section_special.should == {:musiconhold => "podcast"}
|
106
|
+
end
|
107
|
+
|
108
|
+
it "play_on_agent_goodbye should generate 'agentgoodbye'" do
|
109
|
+
agents.play_on_agent_goodbye "tt-monkeys"
|
110
|
+
agents.agent_section_special.should == {:agentgoodbye => "tt-monkeys"}
|
111
|
+
end
|
112
|
+
|
113
|
+
it "change_cdr_source should generate updatecdr" do
|
114
|
+
agents.change_cdr_source false
|
115
|
+
agents.agent_section.should == {:updatecdr => "no"}
|
116
|
+
end
|
117
|
+
|
118
|
+
it "play_for_waiting_keep_alive" do
|
119
|
+
agents.play_for_waiting_keep_alive "tt-weasels"
|
120
|
+
agents.agent_section.should == {:custom_beep => "tt-weasels"}
|
121
|
+
end
|
122
|
+
|
123
|
+
it "save_recordings_in should generate 'savecallsin'" do
|
124
|
+
agents.save_recordings_in "/second/star/on/the/right"
|
125
|
+
agents.agent_section.should == {:savecallsin => "/second/star/on/the/right"}
|
126
|
+
end
|
127
|
+
|
128
|
+
it "recording_prefix should generate 'urlprefix'" do
|
129
|
+
agents.recording_prefix "ohai"
|
130
|
+
agents.agent_section.should == {:urlprefix => "ohai"}
|
131
|
+
end
|
132
|
+
|
133
|
+
it "recording_format should only allow a few symbols as an argument" do
|
134
|
+
the_following_code {
|
135
|
+
agents.recording_format :wav
|
136
|
+
agents.agent_section.should == {:recordformat => :wav}
|
137
|
+
}.should_not raise_error
|
138
|
+
|
139
|
+
reset_agents!
|
140
|
+
|
141
|
+
the_following_code {
|
142
|
+
agents.recording_format :wav49
|
143
|
+
agents.agent_section.should == {:recordformat => :wav49}
|
144
|
+
}.should_not raise_error
|
145
|
+
|
146
|
+
reset_agents!
|
147
|
+
|
148
|
+
the_following_code {
|
149
|
+
agents.recording_format :gsm
|
150
|
+
agents.agent_section.should == {:recordformat => :gsm}
|
151
|
+
}.should_not raise_error
|
152
|
+
|
153
|
+
reset_agents!
|
154
|
+
|
155
|
+
the_following_code {
|
156
|
+
agents.recording_format :mp3
|
157
|
+
agents.agent_section.should == {:recordformat => :mp3}
|
158
|
+
}.should raise_error ArgumentError
|
159
|
+
|
160
|
+
end
|
161
|
+
|
162
|
+
it "record_agent_calls should generate a 'recordagentcalls' yes/no pair" do
|
163
|
+
agents.record_agent_calls false
|
164
|
+
agents.agent_section.should == {:recordagentcalls => 'no'}
|
165
|
+
end
|
166
|
+
|
167
|
+
it "allow_multiple_logins_per_extension should generate 'multiplelogin' in [general]" do
|
168
|
+
agents.allow_multiple_logins_per_extension true
|
169
|
+
agents.general_section.should == {:multiplelogin => 'yes'}
|
170
|
+
end
|
171
|
+
|
172
|
+
end
|
173
|
+
|
174
|
+
describe "The default agents.conf config file converted to this syntax" do
|
175
|
+
|
176
|
+
include AgentsConfigGeneratorTestHelper
|
177
|
+
|
178
|
+
attr_reader :default_config, :agents
|
179
|
+
before(:each) do
|
180
|
+
reset_agents!
|
181
|
+
@default_config = <<-CONFIG
|
182
|
+
[general]
|
183
|
+
persistentagents=yes
|
184
|
+
|
185
|
+
[agents]
|
186
|
+
maxlogintries=5
|
187
|
+
autologoff=15
|
188
|
+
ackcall=no
|
189
|
+
endcall=yes
|
190
|
+
wrapuptime=5000
|
191
|
+
musiconhold => default
|
192
|
+
agentgoodbye => goodbye_file
|
193
|
+
updatecdr=no
|
194
|
+
group=1,2
|
195
|
+
recordagentcalls=yes
|
196
|
+
recordformat=gsm
|
197
|
+
urlprefix=http://localhost/calls/
|
198
|
+
savecallsin=/var/calls
|
199
|
+
custom_beep=beep
|
200
|
+
|
201
|
+
agent => 1001,4321,Mark Spencer
|
202
|
+
agent => 1002,4321,Will Meadows
|
203
|
+
CONFIG
|
204
|
+
end
|
205
|
+
|
206
|
+
it "they're basically the same" do
|
207
|
+
agents.persistent_agents true
|
208
|
+
agents.max_login_tries 5
|
209
|
+
agents.log_off_after_duration 15
|
210
|
+
agents.require_hash_to_acknowledge false
|
211
|
+
agents.allow_star_to_hangup true
|
212
|
+
agents.time_between_calls 5
|
213
|
+
agents.hold_music_class :default
|
214
|
+
agents.play_on_agent_goodbye "goodbye_file"
|
215
|
+
agents.change_cdr_source false
|
216
|
+
agents.groups 1,2
|
217
|
+
agents.record_agent_calls true
|
218
|
+
agents.recording_format :gsm
|
219
|
+
agents.recording_prefix "http://localhost/calls/"
|
220
|
+
agents.save_recordings_in "/var/calls"
|
221
|
+
agents.play_for_waiting_keep_alive "beep"
|
222
|
+
|
223
|
+
agents.agent 1001, :password => 4321, :name => "Mark Spencer"
|
224
|
+
agents.agent 1002, :password => 4321, :name => "Will Meadows"
|
225
|
+
|
226
|
+
cleaned_up_default_config =
|
227
|
+
Adhearsion::Asterisk::ConfigGenerator.create_sanitary_hash_from(default_config)
|
228
|
+
|
229
|
+
cleaned_up_generated_config = agents.to_sanitary_hash
|
230
|
+
|
231
|
+
cleaned_up_generated_config.should == cleaned_up_default_config
|
232
|
+
end
|
233
|
+
|
234
|
+
end
|
235
|
+
|
236
|
+
|
237
|
+
describe "AgentsConfigGeneratorTestHelper" do
|
238
|
+
|
239
|
+
include AgentsConfigGeneratorTestHelper
|
240
|
+
|
241
|
+
attr_reader :agents
|
242
|
+
before(:each) do
|
243
|
+
reset_agents!
|
244
|
+
end
|
245
|
+
|
246
|
+
it "generated_config_has_pair() works properly with one pair" do
|
247
|
+
@agents = mock "A fake agents with just one pair", :conf => "foo=bar"
|
248
|
+
generated_config_has_pair(:foo => "bar").should be true
|
249
|
+
end
|
250
|
+
|
251
|
+
it "generated_config_has_pair() works properly with two pairs" do
|
252
|
+
@agents = mock "A fake agents with just one pair"
|
253
|
+
@agents.expects(:conf).twice.returns("[general]\n\nqaz=qwerty\nagent => 1,2,3")
|
254
|
+
|
255
|
+
generated_config_has_pair(:qaz => "qwerty").should be true
|
256
|
+
generated_config_has_pair(:foo => "bar").should be false
|
257
|
+
end
|
258
|
+
end
|