queri 0.0.2
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 +7 -0
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +96 -0
- data/Rakefile +7 -0
- data/lib/queri/realtime/agents.rb +80 -0
- data/lib/queri/realtime/queues.rb +64 -0
- data/lib/queri/realtime.rb +14 -0
- data/lib/queri/stats/agents_and_sessions/agent_availability.rb +76 -0
- data/lib/queri/stats/agents_and_sessions.rb +11 -0
- data/lib/queri/stats/answered_calls/agents_on_queue.rb +73 -0
- data/lib/queri/stats/answered_calls/all_calls.rb +81 -0
- data/lib/queri/stats/answered_calls.rb +11 -0
- data/lib/queri/stats/unanswered_calls/all_calls.rb +80 -0
- data/lib/queri/stats/unanswered_calls.rb +11 -0
- data/lib/queri/stats.rb +9 -0
- data/lib/queri/version.rb +3 -0
- data/lib/queri.rb +113 -0
- data/queri.gemspec +25 -0
- data/spec/queri_spec.rb +268 -0
- data/spec/realtime/agents_spec.rb +18 -0
- data/spec/realtime/queues_spec.rb +18 -0
- data/spec/realtime/realtime_spec.rb +10 -0
- data/spec/spec_helper.rb +11 -0
- data/spec/stats/agents_and_sessions/agent_availability_spec.rb +18 -0
- data/spec/stats/agents_and_sessions/agents_and_sessions_spec.rb +7 -0
- data/spec/stats/answered_calls/agents_on_queue_spec.rb +18 -0
- data/spec/stats/answered_calls/all_calls_spec.rb +18 -0
- data/spec/stats/answered_calls/answered_calls_spec.rb +7 -0
- data/spec/stats/stats_spec.rb +7 -0
- data/spec/stats/unanswered_calls/all_calls_spec.rb +18 -0
- data/spec/stats/unanswered_calls/unanswered_calls_spec.rb +7 -0
- data/spec/support/constantize.rb +27 -0
- data/spec/support/shared/shared_examples_for_agent_level_report_instance.rb +37 -0
- data/spec/support/shared/shared_examples_for_aggregate_report_instance.rb +37 -0
- data/spec/support/shared/shared_examples_for_private_constant.rb +9 -0
- data/spec/support/shared/shared_examples_for_queuemetrics_report.rb +25 -0
- data/spec/support/shared/shared_examples_for_realtime_report.rb +32 -0
- data/spec/support/shared/shared_examples_for_realtime_report_instance.rb +26 -0
- data/spec/support/shared/shared_examples_for_report_class.rb +13 -0
- data/spec/support/shared/shared_examples_for_report_method.rb +13 -0
- data/spec/support/shared/shared_examples_for_stats_report.rb +44 -0
- data/spec/support/time_helper.rb +17 -0
- metadata +154 -0
data/lib/queri.rb
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
require "queri/version"
|
2
|
+
require "yaml"
|
3
|
+
require "xmlrpc/client"
|
4
|
+
|
5
|
+
Dir[ File.join( File.dirname(__FILE__), "**", "*.rb" ) ].each {|f| require f}
|
6
|
+
|
7
|
+
module Queri
|
8
|
+
LOGFILE = ""
|
9
|
+
PERIOD = ""
|
10
|
+
AGENT_FILTER = ""
|
11
|
+
|
12
|
+
@config = {
|
13
|
+
:host => "127.0.0.1",
|
14
|
+
:path => "/path/to/queuemetrics.do",
|
15
|
+
:port => "8080",
|
16
|
+
:username => "username",
|
17
|
+
:password => "some_secret"
|
18
|
+
}
|
19
|
+
|
20
|
+
@valid_config_keys = @config.keys
|
21
|
+
|
22
|
+
@@server = nil
|
23
|
+
|
24
|
+
private_constant :LOGFILE, :PERIOD, :AGENT_FILTER
|
25
|
+
|
26
|
+
def self.config
|
27
|
+
@config
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.configure opts={}
|
31
|
+
raise ArgumentError, "expected hash, got something else" if opts.class != Hash
|
32
|
+
unless opts.empty?
|
33
|
+
if (@valid_config_keys - opts.keys).any?
|
34
|
+
puts "WARNING: erroneous keys given to ::config. Acceptible keys include #{@valid_config_keys}"
|
35
|
+
end
|
36
|
+
if (opts.keys & @valid_config_keys).empty?
|
37
|
+
raise ArgumentError, "erroneous keys given to ::config. Acceptible keys include #{@valid_config_keys}"
|
38
|
+
else
|
39
|
+
opts.each {|k,v| @config[k.to_sym] = v if @valid_config_keys.include?(k.to_sym)}
|
40
|
+
@@server = XMLRPC::Client.new(host = @config[:host], path = @config[:path], port = @config[:port])
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.configure_with path_to_yaml_file
|
46
|
+
raise ArgumentError, "expected path to yaml file as string, got something else" if path_to_yaml_file.class != String
|
47
|
+
begin
|
48
|
+
config = YAML.load(IO.read(path_to_yaml_file))
|
49
|
+
rescue Errno::ENOENT
|
50
|
+
raise LoadError, "the specified configuration file could not be found"
|
51
|
+
rescue Psych::SyntaxError
|
52
|
+
raise LoadError, "the specified configuration file contains invalid syntax"
|
53
|
+
end
|
54
|
+
configure(config)
|
55
|
+
@@server = XMLRPC::Client.new(host = @config[:host], path = @config[:path], port = @config[:port])
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.send_request *args
|
59
|
+
raise LoadError, "client configs not set. Assign by passing a hash to Queri.configure or a yaml file path to Queri.configure_with" if (@config.nil? || @config.empty?)
|
60
|
+
request = Request.new(*args)
|
61
|
+
response = @@server.call(*request.parameters)
|
62
|
+
return response[request.report.class.xml_code]
|
63
|
+
end
|
64
|
+
|
65
|
+
class Request
|
66
|
+
attr_reader :report
|
67
|
+
|
68
|
+
def initialize *args
|
69
|
+
raise ArgumentError, "expected arguments: queues(Array), report(Stats or Realtime obj), period_start(Time or Nil), period_end(Time or Nil)" unless valid_args?(args)
|
70
|
+
@queues, @report, @period_start, @period_end = validate_args(args)
|
71
|
+
end
|
72
|
+
|
73
|
+
def parameters
|
74
|
+
if @period_start.nil? && @period_end.nil?
|
75
|
+
[@report.class.query_method, @queues.join("|"), Queri.config[:username], Queri.config[:password], LOGFILE, AGENT_FILTER, [@report.class.xml_code]]
|
76
|
+
else
|
77
|
+
[@report.class.query_method, @queues.join("|"), Queri.config[:username], Queri.config[:password], LOGFILE, PERIOD, @period_start, @period_end, AGENT_FILTER, [@report.class.xml_code]]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
def valid_args? args
|
84
|
+
valid = true
|
85
|
+
valid = false if args[0].class != Array
|
86
|
+
valid = false if args[1].class == NilClass
|
87
|
+
valid = false if (args[2].class != NilClass && args[2].class != Time)
|
88
|
+
valid = false if (args[3].class != NilClass && args[3].class != Time)
|
89
|
+
return valid
|
90
|
+
end
|
91
|
+
|
92
|
+
def validate_args args
|
93
|
+
raise ArgumentError, "queues array cannot be empty" if args[0].empty?
|
94
|
+
if args[1].class.name.include?("Queri::Stats::")
|
95
|
+
if (args[2].nil? || args[3].nil?)
|
96
|
+
raise ArgumentError, "Queri::Stats reports require non-nil period start and end times"
|
97
|
+
end
|
98
|
+
elsif args[1].class.name.include?("Queri::Realtime::")
|
99
|
+
unless (args[2].nil? && args[3].nil?)
|
100
|
+
raise ArgumentError, "Queri::Realtime reports require nil period start and end times"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
args[2] = format_time(args[2])
|
104
|
+
args[3] = format_time(args[3])
|
105
|
+
return args
|
106
|
+
end
|
107
|
+
|
108
|
+
def format_time time
|
109
|
+
return time unless time.respond_to?(:strftime)
|
110
|
+
time.strftime("%Y-%m-%d.%H:%M:%S")
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
data/queri.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'queri/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "queri"
|
8
|
+
spec.version = Queri::VERSION
|
9
|
+
spec.authors = ["Brad Rice"]
|
10
|
+
spec.email = ["bradley_rice@mac.com"]
|
11
|
+
spec.description = %q{Queuemetrics Reporting Interface}
|
12
|
+
spec.summary = %q{Send requests to QM's XMLRPC client and receive human-readable responses}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.files -= ["spec/config.yml"]
|
18
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
19
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
23
|
+
spec.add_development_dependency "rake"
|
24
|
+
spec.add_development_dependency "rspec", "~> 2.14.1"
|
25
|
+
end
|
data/spec/queri_spec.rb
ADDED
@@ -0,0 +1,268 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Queri do
|
4
|
+
let(:queues) { ["10000"] }
|
5
|
+
let(:report) { double(Queri::Realtime::Queues) }
|
6
|
+
|
7
|
+
describe "constants" do
|
8
|
+
describe "for log file" do
|
9
|
+
let(:const_symbol) { :LOGFILE }
|
10
|
+
let(:constant) { Queri::LOGFILE }
|
11
|
+
|
12
|
+
it_behaves_like "a private constant"
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "for period" do
|
16
|
+
let(:const_symbol) { :PERIOD }
|
17
|
+
let(:constant) { Queri::PERIOD }
|
18
|
+
|
19
|
+
it_behaves_like "a private constant"
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "for agent filter" do
|
23
|
+
let(:const_symbol) { :AGENT_FILTER }
|
24
|
+
let(:constant) { Queri::AGENT_FILTER }
|
25
|
+
|
26
|
+
it_behaves_like "a private constant"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "::config" do
|
31
|
+
subject { Queri.config }
|
32
|
+
|
33
|
+
it "should respond" do
|
34
|
+
expect{ subject }.to_not raise_error
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should return a Hash" do
|
38
|
+
subject.should be_a Hash
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "::configure" do
|
43
|
+
let(:configs) { Hash[:password, "new_secret"] }
|
44
|
+
|
45
|
+
before do
|
46
|
+
@saved_configs = Queri.config.dup
|
47
|
+
end
|
48
|
+
|
49
|
+
subject { Queri.configure(configs) }
|
50
|
+
|
51
|
+
after do
|
52
|
+
Queri.configure(@saved_configs)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should respond" do
|
56
|
+
expect{ subject }.to_not raise_error
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should require a Hash" do
|
60
|
+
expect{ Queri.configure(configs.to_a) }.to raise_error(ArgumentError)
|
61
|
+
expect{ Queri.configure(configs) }.to_not raise_error
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should default to accept a Hash" do
|
65
|
+
expect{ Queri.configure }.to_not raise_error
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should update project configurations" do
|
69
|
+
old_configs = Queri.config.dup
|
70
|
+
subject
|
71
|
+
Queri.config.should_not eq old_configs
|
72
|
+
end
|
73
|
+
|
74
|
+
context "given some erroneous keys" do
|
75
|
+
let(:configs) { Hash[:password, "new_secret", :foo, "bar"] }
|
76
|
+
|
77
|
+
it "should warn the user against bad data" do
|
78
|
+
Queri.should_receive(:puts).with("WARNING: erroneous keys given to ::config. Acceptible keys include #{Queri.instance_variable_get(:@valid_config_keys)}")
|
79
|
+
subject
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should update project configurations" do
|
83
|
+
old_configs = Queri.config.dup
|
84
|
+
subject
|
85
|
+
Queri.config.should_not eq old_configs
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context "given all erroneous keys" do
|
90
|
+
let(:configs) { Hash[:foo, "bar"] }
|
91
|
+
|
92
|
+
it "should raise ArgumentError" do
|
93
|
+
expect{ subject }.to raise_error(ArgumentError)
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should not update project configurations" do
|
97
|
+
old_configs = Queri.config
|
98
|
+
begin
|
99
|
+
subject
|
100
|
+
rescue ArgumentError
|
101
|
+
end
|
102
|
+
Queri.config.should eq old_configs
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe "::configure_with" do
|
108
|
+
let(:test_config_file) { File.join(File.dirname(__FILE__), 'test_config.yml') }
|
109
|
+
|
110
|
+
before do
|
111
|
+
@saved_configs = Queri.config.dup
|
112
|
+
File.open(test_config_file, 'w') do |f|
|
113
|
+
f << "---\n"
|
114
|
+
f << " :password: \"new_secret\""
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
subject { Queri.configure_with(test_config_file) }
|
119
|
+
|
120
|
+
after do
|
121
|
+
FileUtils.rm(test_config_file)
|
122
|
+
Queri.configure(@saved_configs)
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should respond" do
|
126
|
+
expect{ subject }.to_not raise_error
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should require a String" do
|
130
|
+
expect{ Queri.configure_with(Array.new) }.to raise_error(ArgumentError)
|
131
|
+
expect{ Queri.configure_with(test_config_file) }.to_not raise_error
|
132
|
+
end
|
133
|
+
|
134
|
+
it "should update project configurations" do
|
135
|
+
old_configs = Queri.config.dup
|
136
|
+
subject
|
137
|
+
Queri.config.should_not eq old_configs
|
138
|
+
end
|
139
|
+
|
140
|
+
context "given a bad file path" do
|
141
|
+
let(:bad_config_file) { File.join(File.dirname(__FILE__), 'nonexistant_config.yml') }
|
142
|
+
|
143
|
+
subject { Queri.configure_with(bad_config_file) }
|
144
|
+
|
145
|
+
it "should raise LoadError" do
|
146
|
+
expect{ subject }.to raise_error(LoadError)
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should not update project configurations" do
|
150
|
+
old_configs = Queri.config.dup
|
151
|
+
begin
|
152
|
+
subject
|
153
|
+
rescue LoadError
|
154
|
+
end
|
155
|
+
Queri.config.should eq old_configs
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
context "given file with syntax error" do
|
160
|
+
before do
|
161
|
+
File.open(test_config_file, 'w') do |f|
|
162
|
+
f << "---"
|
163
|
+
f << "\t:password: bad_syntax"
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
it "should raise LoadError" do
|
168
|
+
expect{ subject }.to raise_error(LoadError)
|
169
|
+
end
|
170
|
+
|
171
|
+
it "should not update project configurations" do
|
172
|
+
old_configs = Queri.config.dup
|
173
|
+
begin
|
174
|
+
subject
|
175
|
+
rescue LoadError
|
176
|
+
end
|
177
|
+
Queri.config.should eq old_configs
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
describe "::send_request" do
|
183
|
+
before do
|
184
|
+
@client = double(XMLRPC::Client)
|
185
|
+
@client.stub(:call).and_return( {"xml_code" => [:keys, :for, :report]} )
|
186
|
+
end
|
187
|
+
|
188
|
+
subject { Queri.send_request(queues, report) }
|
189
|
+
|
190
|
+
context "without configurations" do
|
191
|
+
before do
|
192
|
+
@saved_configs = Queri.config.dup
|
193
|
+
Queri.instance_variable_set(:@config, {})
|
194
|
+
end
|
195
|
+
|
196
|
+
after do
|
197
|
+
Queri.configure(@saved_configs)
|
198
|
+
end
|
199
|
+
|
200
|
+
it "should raise LoadError" do
|
201
|
+
expect{ subject }.to raise_error(LoadError)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
context "with configurations" do
|
206
|
+
|
207
|
+
before do
|
208
|
+
Queri.configure_with(File.join(File.dirname(__FILE__), 'config.yml'))
|
209
|
+
report.stub(:class).and_return( Queri::Realtime::Queues )
|
210
|
+
end
|
211
|
+
|
212
|
+
it "should respond" do
|
213
|
+
expect{ subject }.to_not raise_error
|
214
|
+
end
|
215
|
+
|
216
|
+
it "should call the XMLRPC client" do
|
217
|
+
xml_client = Queri.class_variable_get(:@@server)
|
218
|
+
Queri.class_variable_set(:@@server, @client)
|
219
|
+
subject
|
220
|
+
@client.should have_received(:call)
|
221
|
+
Queri.class_variable_set(:@@server, xml_client)
|
222
|
+
end
|
223
|
+
|
224
|
+
context "given no arguments" do
|
225
|
+
subject { Queri.send_request }
|
226
|
+
|
227
|
+
it "should raise ArgumentError" do
|
228
|
+
expect{ subject }.to raise_error(ArgumentError)
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
context "given an empty queues array" do
|
233
|
+
subject { Queri.send_request([], report) }
|
234
|
+
|
235
|
+
it "should raise ArgumentError" do
|
236
|
+
expect{ subject }.to raise_error(ArgumentError)
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
context "given a Stats report object" do
|
241
|
+
context "and period_start or period_end are nil" do
|
242
|
+
let(:report) { double(Queri::Stats::AnsweredCalls::AllCalls) }
|
243
|
+
let(:period_start) { Time.now - 10 }
|
244
|
+
let(:period_end) { nil }
|
245
|
+
|
246
|
+
subject { Queri.send_request(queues, report, period_start, period_end) }
|
247
|
+
|
248
|
+
it "should raise ArgumentError" do
|
249
|
+
expect{ subject }.to raise_error(ArgumentError)
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
context "given a Realtime report object" do
|
255
|
+
context "and period_start or period_end are not nil" do
|
256
|
+
let(:period_start) { Time.now - 10 }
|
257
|
+
let(:period_end) { nil }
|
258
|
+
|
259
|
+
subject { Queri.send_request(queues, report, period_start, period_end) }
|
260
|
+
|
261
|
+
it "should raise ArgumentError" do
|
262
|
+
expect{ subject }.to raise_error(ArgumentError)
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require File.join( File.dirname(__FILE__), '..', 'spec_helper' )
|
2
|
+
|
3
|
+
describe Queri::Realtime::Agents do
|
4
|
+
let(:report_class) { Queri::Realtime::Agents }
|
5
|
+
let(:xml_code) { report_class.xml_code }
|
6
|
+
|
7
|
+
it_behaves_like "a report class"
|
8
|
+
|
9
|
+
it_behaves_like "a report method"
|
10
|
+
|
11
|
+
it_behaves_like "a queuemetrics report"
|
12
|
+
|
13
|
+
it_behaves_like "a realtime report"
|
14
|
+
|
15
|
+
describe "An instance of", Queri::Realtime::Agents do
|
16
|
+
it_behaves_like "a realtime report instance"
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require File.join( File.dirname(__FILE__), '..', 'spec_helper' )
|
2
|
+
|
3
|
+
describe Queri::Realtime::Queues do
|
4
|
+
let(:report_class) { Queri::Realtime::Queues }
|
5
|
+
let(:xml_code) { report_class.xml_code }
|
6
|
+
|
7
|
+
it_behaves_like "a report class"
|
8
|
+
|
9
|
+
it_behaves_like "a report method"
|
10
|
+
|
11
|
+
it_behaves_like "a queuemetrics report"
|
12
|
+
|
13
|
+
it_behaves_like "a realtime report"
|
14
|
+
|
15
|
+
describe "An instance of", Queri::Realtime::Queues do
|
16
|
+
it_behaves_like "a realtime report instance"
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require File.join( File.dirname(__FILE__), '..', 'spec_helper' )
|
2
|
+
|
3
|
+
describe Queri::Realtime do
|
4
|
+
let(:report_method) { Queri::Realtime }
|
5
|
+
let(:report_class) { Queri::Realtime }
|
6
|
+
|
7
|
+
it_behaves_like "a report method"
|
8
|
+
|
9
|
+
it_behaves_like "a report class"
|
10
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
require 'queri'
|
4
|
+
Dir[File.join( File.dirname(__FILE__), 'support', '**', '*.rb' )].each {|f| require f}
|
5
|
+
#require File.join(File.dirname(__FILE__), '..', 'lib', 'queuemetrics.rb')
|
6
|
+
|
7
|
+
RSpec.configure do |config|
|
8
|
+
include TimeHelper
|
9
|
+
include Constantize
|
10
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
11
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require File.join( File.dirname(__FILE__), '..', '..', 'spec_helper' )
|
2
|
+
|
3
|
+
describe Queri::Stats::AgentsAndSessions::AgentAvailability do
|
4
|
+
let(:report_class) { Queri::Stats::AgentsAndSessions::AgentAvailability }
|
5
|
+
let(:xml_code) { report_class.xml_code }
|
6
|
+
|
7
|
+
it_behaves_like "a report class"
|
8
|
+
|
9
|
+
it_behaves_like "a report method"
|
10
|
+
|
11
|
+
it_behaves_like "a queuemetrics report"
|
12
|
+
|
13
|
+
it_behaves_like "a stats report"
|
14
|
+
|
15
|
+
describe "An instance of", Queri::Stats::AgentsAndSessions::AgentAvailability do
|
16
|
+
it_behaves_like "an agent-level report instance"
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require File.join( File.dirname(__FILE__), '..', '..', 'spec_helper' )
|
2
|
+
|
3
|
+
describe Queri::Stats::AnsweredCalls::AgentsOnQueue do
|
4
|
+
let(:report_class) { Queri::Stats::AnsweredCalls::AgentsOnQueue }
|
5
|
+
let(:xml_code) { report_class.xml_code }
|
6
|
+
|
7
|
+
it_behaves_like "a report class"
|
8
|
+
|
9
|
+
it_behaves_like "a report method"
|
10
|
+
|
11
|
+
it_behaves_like "a queuemetrics report"
|
12
|
+
|
13
|
+
it_behaves_like "a stats report"
|
14
|
+
|
15
|
+
describe "An instance of", Queri::Stats::AnsweredCalls::AgentsOnQueue do
|
16
|
+
it_behaves_like "an agent-level report instance"
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require File.join( File.dirname(__FILE__), '..', '..', 'spec_helper' )
|
2
|
+
|
3
|
+
describe Queri::Stats::AnsweredCalls::AllCalls do
|
4
|
+
let(:report_class) { Queri::Stats::AnsweredCalls::AllCalls }
|
5
|
+
let(:xml_code) { report_class.xml_code }
|
6
|
+
|
7
|
+
it_behaves_like "a report class"
|
8
|
+
|
9
|
+
it_behaves_like "a report method"
|
10
|
+
|
11
|
+
it_behaves_like "a queuemetrics report"
|
12
|
+
|
13
|
+
it_behaves_like "a stats report"
|
14
|
+
|
15
|
+
describe "An instance of", Queri::Stats::AnsweredCalls::AllCalls do
|
16
|
+
it_behaves_like "an aggregate report instance"
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require File.join( File.dirname(__FILE__), '..', '..', 'spec_helper' )
|
2
|
+
|
3
|
+
describe Queri::Stats::UnansweredCalls::AllCalls do
|
4
|
+
let(:report_class) { Queri::Stats::UnansweredCalls::AllCalls }
|
5
|
+
let(:xml_code) { report_class.xml_code }
|
6
|
+
|
7
|
+
it_behaves_like "a report class"
|
8
|
+
|
9
|
+
it_behaves_like "a report method"
|
10
|
+
|
11
|
+
it_behaves_like "a queuemetrics report"
|
12
|
+
|
13
|
+
it_behaves_like "a stats report"
|
14
|
+
|
15
|
+
describe "An instance of", Queri::Stats::UnansweredCalls::AllCalls do
|
16
|
+
it_behaves_like "an aggregate report instance"
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Constantize
|
2
|
+
def constantize(camel_cased_word)
|
3
|
+
names = camel_cased_word.split('::')
|
4
|
+
names.shift if names.empty? || names.first.empty?
|
5
|
+
|
6
|
+
names.inject(Object) do |constant, name|
|
7
|
+
if constant == Object
|
8
|
+
constant.const_get(name)
|
9
|
+
else
|
10
|
+
candidate = constant.const_get(name)
|
11
|
+
next candidate if constant.const_defined?(name, false)
|
12
|
+
next candidate unless Object.const_defined?(name)
|
13
|
+
|
14
|
+
# Go down the ancestors to check it it's owned
|
15
|
+
# directly before we reach Object or the end of ancestors.
|
16
|
+
constant = constant.ancestors.inject do |const, ancestor|
|
17
|
+
break const if ancestor == Object
|
18
|
+
break ancestor if ancestor.const_defined?(name, false)
|
19
|
+
const
|
20
|
+
end
|
21
|
+
|
22
|
+
# owner is in Object, so raise
|
23
|
+
constant.const_get(name, false)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
shared_examples "an agent-level report instance" do
|
2
|
+
let(:queues) { ["10000"] }
|
3
|
+
let(:period_start) { Time.now - 7200 }
|
4
|
+
let(:period_end) { Time.now - 3600 }
|
5
|
+
|
6
|
+
before do
|
7
|
+
@client = double(XMLRPC::Client)
|
8
|
+
@client.stub(:call).and_return( {xml_code => [report_class.keys]} )
|
9
|
+
end
|
10
|
+
|
11
|
+
subject { report_class.new(queues, period_start, period_end) }
|
12
|
+
|
13
|
+
it { should_not respond_to :response= }
|
14
|
+
|
15
|
+
describe "#response" do
|
16
|
+
subject { report_class.new(queues, period_start, period_end).response }
|
17
|
+
|
18
|
+
it "should respond" do
|
19
|
+
XMLRPC::Client.stub(:new).and_return(@client)
|
20
|
+
expect{ subject }.to_not raise_error
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should be an Array" do
|
24
|
+
XMLRPC::Client.stub(:new).and_return(@client)
|
25
|
+
subject.should be_a Array
|
26
|
+
end
|
27
|
+
|
28
|
+
context "for a period during which records are saved" do
|
29
|
+
let(:period_start) { most_recent_11_am_hour }
|
30
|
+
let(:period_end) { most_recent_12_pm_hour }
|
31
|
+
|
32
|
+
it "should contain Hashes" do
|
33
|
+
subject.each {|obj| obj.should be_a Hash}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
shared_examples "an aggregate report instance" do
|
2
|
+
let(:queues) { ["10000"] }
|
3
|
+
let(:period_start) { Time.now - 7200 }
|
4
|
+
let(:period_end) { Time.now - 3600 }
|
5
|
+
|
6
|
+
before do
|
7
|
+
@client = double(XMLRPC::Client)
|
8
|
+
@client.stub(:call).and_return( {xml_code => []} )
|
9
|
+
end
|
10
|
+
|
11
|
+
subject { report_class.new(queues, period_start, period_end) }
|
12
|
+
|
13
|
+
it { should_not respond_to :response= }
|
14
|
+
|
15
|
+
describe "#response" do
|
16
|
+
subject { report_class.new(queues, period_start, period_end).response }
|
17
|
+
|
18
|
+
it "should respond" do
|
19
|
+
XMLRPC::Client.stub(:new).and_return(@client)
|
20
|
+
expect{ subject }.to_not raise_error
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should be a Hash" do
|
24
|
+
XMLRPC::Client.stub(:new).and_return(@client)
|
25
|
+
subject.should be_a Hash
|
26
|
+
end
|
27
|
+
|
28
|
+
context "for a period during which records are saved" do
|
29
|
+
let(:period_start) { most_recent_11_am_hour }
|
30
|
+
let(:period_end) { most_recent_12_pm_hour }
|
31
|
+
|
32
|
+
it "should not be an empty Hash" do
|
33
|
+
subject.should_not be_empty
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|