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