report_cache_spec.rb - reportable - Fork of reportable required by WarVox, from hdm/reportable.
(HTM) git clone git://jay.scot/reportable
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
---
report_cache_spec.rb (14393B)
---
1 require File.join(File.dirname(File.dirname(File.expand_path(__FILE__))),'spec_helper')
2
3 describe Saulabs::Reportable::ReportCache do
4
5 before do
6 @report = Saulabs::Reportable::Report.new(User, :registrations, :limit => 10)
7 end
8
9 describe 'validations' do
10
11 before do
12 @report_cache = Saulabs::Reportable::ReportCache.new(
13 :model_name => User.name,
14 :report_name => 'registrations',
15 :grouping => 'date',
16 :aggregation => 'count',
17 :value => 1.0,
18 :reporting_period => '2070/03/23'
19 )
20 end
21
22 it 'should succeed when all required attributes are set' do
23 @report_cache.should be_valid
24 end
25
26 it 'should not succeed when no model_name is set' do
27 @report_cache.model_name = nil
28
29 @report_cache.should_not be_valid
30 end
31
32 it 'should not succeed when a blank model_name is set' do
33 @report_cache.model_name = ''
34
35 @report_cache.should_not be_valid
36 end
37
38 it 'should not succeed when no report_name is set' do
39 @report_cache.report_name = nil
40
41 @report_cache.should_not be_valid
42 end
43
44 it 'should not succeed when a blank report_name is set' do
45 @report_cache.report_name = ''
46
47 @report_cache.should_not be_valid
48 end
49
50 it 'should not succeed when no grouping is set' do
51 @report_cache.grouping = nil
52
53 @report_cache.should_not be_valid
54 end
55
56 it 'should not succeed when a blank grouping is set' do
57 @report_cache.grouping = ''
58
59 @report_cache.should_not be_valid
60 end
61
62 it 'should not succeed when no aggregation is set' do
63 @report_cache.aggregation = nil
64
65 @report_cache.should_not be_valid
66 end
67
68 it 'should not succeed when a blank aggregation is set' do
69 @report_cache.aggregation = ''
70
71 @report_cache.should_not be_valid
72 end
73
74 it 'should not succeed when no value is set' do
75 @report_cache.value = nil
76
77 @report_cache.should_not be_valid
78 end
79
80 it 'should not succeed when no reporting_period is set' do
81 @report_cache.reporting_period = nil
82
83 @report_cache.should_not be_valid
84 end
85
86 it 'should not succeed when a blank reporting_period is set' do
87 @report_cache.reporting_period = ''
88
89 @report_cache.should_not be_valid
90 end
91
92 end
93
94 describe '.process' do
95
96 before do
97 Saulabs::Reportable::ReportCache.stub!(:find).and_return([])
98 Saulabs::Reportable::ReportCache.stub!(:prepare_result).and_return([])
99 end
100
101 it 'should raise an ArgumentError if no block is given' do
102 lambda do
103 Saulabs::Reportable::ReportCache.process(@report, @report.options)
104 end.should raise_error(ArgumentError)
105 end
106
107 it 'sould start a transaction' do
108 Saulabs::Reportable::ReportCache.should_receive(:transaction)
109
110 Saulabs::Reportable::ReportCache.process(@report, @report.options) {}
111 end
112
113 describe 'with :live_data = true' do
114
115 before do
116 @options = @report.options.merge(:live_data => true)
117 end
118
119 it 'should yield to the given block' do
120 lambda {
121 Saulabs::Reportable::ReportCache.process(@report, @options) { raise YieldMatchException.new }
122 }.should raise_error(YieldMatchException)
123 end
124
125 it 'should yield the first reporting period if not all required data could be retrieved from the cache' do
126 Saulabs::Reportable::ReportCache.stub!(:read_cached_data).and_return([Saulabs::Reportable::ReportCache.new])
127
128 Saulabs::Reportable::ReportCache.process(@report, @options) do |begin_at, end_at|
129 begin_at.should == Saulabs::Reportable::ReportingPeriod.first(@report.options[:grouping], @report.options[:limit]).date_time
130 end_at.should == nil
131 []
132 end
133 end
134
135 it 'should yield the reporting period after the last one in the cache if all required data could be retrieved from the cache' do
136 reporting_period = Saulabs::Reportable::ReportingPeriod.new(
137 @report.options[:grouping],
138 Time.now - @report.options[:limit].send(@report.options[:grouping].identifier)
139 )
140 cached = Saulabs::Reportable::ReportCache.new
141 cached.stub!(:reporting_period).and_return(reporting_period.date_time)
142 Saulabs::Reportable::ReportCache.stub!(:read_cached_data).and_return(Array.new(@report.options[:limit] - 1, Saulabs::Reportable::ReportCache.new), cached)
143
144 Saulabs::Reportable::ReportCache.process(@report, @options) do |begin_at, end_at|
145 begin_at.should == reporting_period.date_time
146 end_at.should == nil
147 []
148 end
149 end
150
151 end
152
153 describe 'with :live_data = false' do
154
155 it 'should not yield if all required data could be retrieved from the cache' do
156 Saulabs::Reportable::ReportCache.stub!(:read_cached_data).and_return(Array.new(@report.options[:limit], Saulabs::Reportable::ReportCache.new))
157
158 lambda {
159 Saulabs::Reportable::ReportCache.process(@report, @report.options) { raise YieldMatchException.new }
160 }.should_not raise_error(YieldMatchException)
161 end
162
163 it 'should yield to the block if no data could be retrieved from the cache' do
164 Saulabs::Reportable::ReportCache.stub!(:read_cached_data).and_return([])
165
166 lambda {
167 Saulabs::Reportable::ReportCache.process(@report, @report.options) { raise YieldMatchException.new }
168 }.should raise_error(YieldMatchException)
169 end
170
171 describe 'with :end_date = <some date>' do
172
173 before do
174 @options = @report.options.merge(:end_date => Time.now - 1.send(@report.options[:grouping].identifier))
175 end
176
177 it 'should yield the last date and time of the reporting period for the specified end date' do
178 reporting_period = Saulabs::Reportable::ReportingPeriod.new(@report.options[:grouping], @options[:end_date])
179
180 Saulabs::Reportable::ReportCache.process(@report, @options) do |begin_at, end_at|
181 end_at.should == reporting_period.last_date_time
182 []
183 end
184 end
185
186 end
187
188 end
189
190 xit 'should read existing data from the cache' do
191 Saulabs::Reportable::ReportCache.should_receive(:all).once.with(
192 :conditions => [
193 %w(model_name report_name grouping aggregation conditions).map do |column_name|
194 "#{Saulabs::Reportable::ReportCache.connection.quote_column_name(column_name)} = ?"
195 end.join(' AND ') + ' AND reporting_period >= ?',
196 @report.klass.to_s,
197 @report.name.to_s,
198 @report.options[:grouping].identifier.to_s,
199 @report.aggregation.to_s,
200 '',
201 Saulabs::Reportable::ReportingPeriod.first(@report.options[:grouping], 10).date_time
202 ],
203 :limit => 10,
204 :order => 'reporting_period ASC'
205 ).and_return([])
206
207 Saulabs::Reportable::ReportCache.process(@report, @report.options) { [] }
208 end
209
210 xit 'should utilize the end_date in the conditions' do
211 end_date = Time.now - 1.send(@report.options[:grouping].identifier)
212 Saulabs::Reportable::ReportCache.should_receive(:all).once.with(
213 :conditions => [
214 %w(model_name report_name grouping aggregation conditions).map do |column_name|
215 "#{Saulabs::Reportable::ReportCache.connection.quote_column_name(column_name)} = ?"
216 end.join(' AND ') + ' AND reporting_period BETWEEN ? AND ?',
217 @report.klass.to_s,
218 @report.name.to_s,
219 @report.options[:grouping].identifier.to_s,
220 @report.aggregation.to_s,
221 '',
222 Saulabs::Reportable::ReportingPeriod.first(@report.options[:grouping], 10).date_time,
223 Saulabs::Reportable::ReportingPeriod.new(@report.options[:grouping], end_date).date_time
224 ],
225 :limit => 10,
226 :order => 'reporting_period ASC'
227 ).and_return([])
228
229 Saulabs::Reportable::ReportCache.process(@report, @report.options.merge(:end_date => end_date)) { [] }
230 end
231
232 xit "should read existing data from the cache for the correct grouping if one other than the report's default grouping is specified" do
233 grouping = Saulabs::Reportable::Grouping.new(:month)
234 Saulabs::Reportable::ReportCache.should_receive(:all).once.with(
235 :conditions => [
236 %w(model_name report_name grouping aggregation conditions).map do |column_name|
237 "#{Saulabs::Reportable::ReportCache.connection.quote_column_name(column_name)} = ?"
238 end.join(' AND ') + ' AND reporting_period >= ?',
239 @report.klass.to_s,
240 @report.name.to_s,
241 grouping.identifier.to_s,
242 @report.aggregation.to_s,
243 '',
244 Saulabs::Reportable::ReportingPeriod.first(grouping, 10).date_time
245 ],
246 :limit => 10,
247 :order => 'reporting_period ASC'
248 ).and_return([])
249
250 Saulabs::Reportable::ReportCache.process(@report, { :limit => 10, :grouping => grouping }) { [] }
251 end
252
253 it 'should yield the first reporting period if the cache is empty' do
254 Saulabs::Reportable::ReportCache.process(@report, @report.options) do |begin_at, end_at|
255 begin_at.should == Saulabs::Reportable::ReportingPeriod.first(@report.options[:grouping], 10).date_time
256 end_at.should == nil
257 []
258 end
259 end
260 end
261
262 describe '.get_first_reporting_period_to_read' do
263 it 'returns first reporting period if no cached data' do
264 Saulabs::Reportable::ReportCache.should_receive(:get_first_reporting_period).once.and_return('first')
265 result = Saulabs::Reportable::ReportCache.send(:get_first_reporting_period_to_read, [], {})
266 result.should == 'first'
267 end
268 end
269
270 describe '.serialize_conditions' do
271
272 it 'should serialize empty conditions correctly' do
273 result = Saulabs::Reportable::ReportCache.send(:serialize_conditions, [])
274 result.should eql('')
275 end
276
277 it 'should serialize a conditions array correctly' do
278 result = Saulabs::Reportable::ReportCache.send(:serialize_conditions, ['active = ? AND gender = ?', true, 'male'])
279 result.should eql('active = ? AND gender = ?truemale')
280 end
281
282 it 'should serialize a conditions hash correctly' do
283 result = Saulabs::Reportable::ReportCache.send(:serialize_conditions, { :gender => 'male', :active => true })
284 result.should eql('activetruegendermale')
285 end
286
287 end
288
289 describe '.prepare_result' do
290
291 before do
292 @current_reporting_period = Saulabs::Reportable::ReportingPeriod.new(@report.options[:grouping])
293 @new_data = [[@current_reporting_period.previous.date_time, 1.0]]
294 Saulabs::Reportable::ReportingPeriod.stub!(:from_db_string).and_return(@current_reporting_period.previous)
295 @cached = Saulabs::Reportable::ReportCache.new
296 @cached.stub!(:save!)
297 Saulabs::Reportable::ReportCache.stub!(:build_cached_data).and_return(@cached)
298 end
299
300 it 'should create :limit instances of Saulabs::Reportable::ReportCache with value 0.0 if no new data has been read and nothing was cached' do
301 Saulabs::Reportable::ReportCache.should_receive(:build_cached_data).exactly(10).times.with(
302 @report,
303 @report.options[:grouping],
304 @report.options[:conditions],
305 anything(),
306 0.0
307 ).and_return(@cached)
308
309 Saulabs::Reportable::ReportCache.send(:prepare_result, [], [], @report, @report.options)
310 end
311
312 it 'should create a new Saulabs::Reportable::ReportCache with the correct value if new data has been read' do
313 Saulabs::Reportable::ReportCache.should_receive(:build_cached_data).exactly(9).times.with(
314 @report,
315 @report.options[:grouping],
316 @report.options[:conditions],
317 anything(),
318 0.0
319 ).and_return(@cached)
320 Saulabs::Reportable::ReportCache.should_receive(:build_cached_data).once.with(
321 @report,
322 @report.options[:grouping],
323 @report.options[:conditions],
324 @current_reporting_period.previous,
325 1.0
326 ).and_return(@cached)
327
328 Saulabs::Reportable::ReportCache.send(:prepare_result, @new_data, [], @report, @report.options)
329 end
330
331 it 'should save the created Saulabs::Reportable::ReportCache' do
332 @cached.should_receive(:save!)
333
334 Saulabs::Reportable::ReportCache.send(:prepare_result, @new_data, [], @report, @report.options)
335 end
336
337 it 'should return an array of arrays of Dates and Floats' do
338 result = Saulabs::Reportable::ReportCache.send(:prepare_result, @new_data, [], @report, @report.options)
339
340 result.should be_kind_of(Saulabs::Reportable::ResultSet)
341 result.to_a.should be_kind_of(Array)
342 result.to_a[0].should be_kind_of(Array)
343 result.to_a[0][0].should be_kind_of(Date)
344 result.to_a[0][1].should be_kind_of(Float)
345 end
346
347 describe 'with :live_data = false' do
348
349 before do
350 @result = Saulabs::Reportable::ReportCache.send(:prepare_result, @new_data, [], @report, @report.options).to_a
351 end
352
353 it 'should return an array of length :limit' do
354 @result.length.should == 10
355 end
356
357 it 'should not include an entry for the current reporting period' do
358 @result.find { |row| row[0] == @current_reporting_period.date_time }.should be_nil
359 end
360
361 end
362
363 describe 'with :live_data = true' do
364
365 before do
366 options = @report.options.merge(:live_data => true)
367 @result = Saulabs::Reportable::ReportCache.send(:prepare_result, @new_data, [], @report, options).to_a
368 end
369
370 it 'should return an array of length (:limit + 1)' do
371 @result.length.should == 11
372 end
373
374 it 'should include an entry for the current reporting period' do
375 @result.find { |row| row[0] == @current_reporting_period.date_time }.should_not be_nil
376 end
377
378 end
379 end
380
381 describe '.find_value' do
382
383 before do
384 @data = [[Saulabs::Reportable::ReportingPeriod.new(Saulabs::Reportable::Grouping.new(:day)), 3.0]]
385 end
386
387 it 'should return the correct value when new data has been read for the reporting period' do
388 Saulabs::Reportable::ReportCache.send(:find_value, @data, @data[0][0]).should == 3.0
389 end
390
391 it 'should return 0.0 when no data has been read for the reporting period' do
392 Saulabs::Reportable::ReportCache.send(:find_value, @data, @data[0][0].next).should == 0.0
393 end
394
395 end
396
397 end