package tests::TimegroupTest; use strict; use base qw/Lire::Test::TestCase tests::TestStoreFixture/; use Lire::Timegroup; use Lire::ReportSpec; use Lire::Param; use Lire::Report::Group; use Lire::Report::TableInfo; use Lire::DlfQuery; use Lire::Test::Mock; use Time::Local; #our @TESTS = qw/ /; sub new { my $self = shift()->SUPER::new( @_ ); $self->init(); return $self; } sub set_up { my $self = $_[0]; $self->SUPER::set_up(); $self->set_up_test_schema(); $self->set_up_tz( 'UTC' ); $self->{'spec'} = new Lire::ReportSpec(); $self->{'spec'}->superservice( 'test' ); $self->{'spec'}->id( 'timegroup-test' ); foreach my $p ( qw/4h 1d 1w 3M 1y/ ) { $self->{ $p . '_timegroup'} = new Lire::Timegroup( 'report_spec' => $self->{'spec'}, 'period' => $p, 'label' => 'Period', ); } return; } sub tear_down { my $self = $_[0]; $self->SUPER::tear_down(); return; } sub test_name { my $self = $_[0]; $self->assert_equals( 'timegroup:time_start', $self->{'1d_timegroup'}->name() ); } sub test_create_categorical_info { my $self = $_[0]; my $info = new Lire::Report::TableInfo(); $self->{'1d_timegroup'}->create_categorical_info( $info ); my @cols = $info->children(); $self->assert_equals( 1, scalar @cols ); my $col = $cols[0]; $self->assert_equals( 'categorical', $col->class() ); $self->assert_equals( 'timegroup:time_start', $col->name() ); $self->assert_equals( 'timestamp', $col->type() ); $self->assert_equals( 'Period', $col->label() ); } sub test_period { my $self = $_[0]; $self->{'spec'}->param( 'dur', new Lire::Param( 'name' => 'dur', 'type' => 'duration', 'default' => '1d' ) ); $self->{'spec'}->param( 'int', new Lire::Param( 'name' => 'int', 'type' => 'int', 'default' => '100' ) ); my $timegroup = $self->{'1d_timegroup'}; $self->assert_equals( '1d', $timegroup->period() ); $self->assert_died( sub { $timegroup->period( undef ) }, qr/missing 'period' parameter/ ); $self->assert_died( sub { $timegroup->period( 'wawa' ) }, qr/'period' parameter isn't a valid duration: 'wawa'/); $self->assert_died( sub { $timegroup->period( '$wawa' ) }, qr/parameter 'wawa' isn't defined/ ); $self->assert_died( sub { $timegroup->period( '2d' ) }, qr/can't use multiple with period of type 'd'/ ); $self->assert_died( sub { $timegroup->period( '$int' ) }, qr/parameter 'int' isn't a 'duration' parameter: 'int'/ ); $timegroup->period( '$dur' ); $self->assert_equals( '$dur', $timegroup->{'period'} ); $timegroup->period( '2h' ); $self->assert_equals( '2h', $timegroup->{'period'} ); } sub test_build_query { my $self = $_[0]; foreach my $t ( [ '4h', 'lr_timegroup_sec("time-start",14400)' ], [ '1d', 'lr_timegroup_day("time-start")' ], [ '1w', 'lr_timegroup_week("time-start",1)' ], [ '3M', 'lr_timegroup_month("time-start",3)' ], [ '1y', 'lr_timegroup_year("time-start",1)' ] ) { my $timegroup = $self->{ $t->[0] . '_timegroup' }; $timegroup->{'field'} = 'time-start'; my $e_query = new Lire::DlfQuery( 'test' ); $e_query->add_aggr_field( '_lr_nrecords', 'count(*)' ); $e_query->add_group_field( "timegroup:time-start", $t->[1] ); $e_query->set_sort_spec( "timegroup:time-start" ); my $query = new Lire::DlfQuery( 'test' ); $timegroup->build_query( $query ); $self->assert_deep_equals( $e_query, $query ); } } sub test_create_entry { my $self = $_[0]; $self->{'cfg'}{'lr_week_numbering'} = 'ISO'; my $info = new Lire::Report::TableInfo(); $self->{'1d_timegroup'}->create_categorical_info( $info ); foreach my $t ( [ '4h', '2003-10-14 20:00', 1066161600, 4*3600 ], [ '1d', '2003-10-14', 1066089600, 24*3600 ], [ '1w', '2003-W42', 1064966400, 7*24*3600 ], [ '3M', 'April 2003', 1049155200, 30*24*3600*3 ], [ '1y', '2003', 1041379200, 365*24*3600 ], ) { my ( $period, $fmt_value, $value, $period_sec ) = @$t; my $timegroup = $self->{$period . '_timegroup'}; my $group = new Lire::Report::Group( bless( {}, 'Lire::Report::Entry'), $info ); my $dlf = { 'timegroup:time_start' => $value }; my $entry = $timegroup->create_entry( $group, $dlf ); $self->assert_not_null( $entry, "create_entry() returned undef" ); my @data = $entry->data(); $self->assert_equals( 1, scalar @data ); $self->assert_equals( $fmt_value, $data[0]->{'content'} ); $self->assert_equals( $value, $data[0]->{'value'} ); $self->assert_equals( $period_sec, $data[0]->{'range'} ); } } sub test_create_entry_mc { my $self = $_[0]; my $timegroup = $self->{'1d_timegroup'}; my $info = new Lire::Report::TableInfo(); $self->{'1d_timegroup'}->create_categorical_info( $info ); my $group = new Lire::Report::Group( bless( {}, 'Lire::Report::Entry'), $info ); my $entry = $timegroup->create_entry( $group, { 'timegroup:time_start' => undef, '_lr_nrecords' => 24 } ); $self->assert_null( $entry, "create_entry() should have returned undef" ); $self->assert_equals( 24, $group->missing_cases() ); } sub test_create_entry_day_change { my $self = $_[0]; my $info = new Lire::Report::TableInfo(); $self->{'1d_timegroup'}->create_categorical_info( $info ); my $group = new Lire::Report::Group( bless( {}, 'Lire::Report::Entry'), $info ); foreach my $t ( [ '2003-10-14 16:00', 1066147200 ], [ ' 20:00', 1066161600 ], [ '2003-10-15 00:00', 1066176000 ], ) { my $timegroup = $self->{'4h_timegroup'}; my $dlf = { 'timegroup:time_start' => $t->[1] }; my $entry = $timegroup->create_entry( $group, $dlf ); $self->assert_not_null( $entry, "create_entry() returned undef" ); $self->assert_str_equals( $t->[0], ($entry->data())[0]->{'content'} ); } } sub set_up_merge_fixture { my $self = $_[0]; my $spec = new Lire::ReportSpec(); $spec->superservice( 'test' ); $spec->param( 'period', new Lire::Param( 'name' => 'period', 'type' => 'duration', 'value' => '1d' ) ); $self->{'timegroup'} = new Lire::Timegroup( 'report_spec' => $spec, 'period' => '$period' ); $self->{'aggregate'} = new Lire::Test::Mock( 'Lire::Aggregate', 'name' => 'aggr' ); $self->{'timegroup'}->ops( [ $self->{'aggregate'} ] ); return; } sub test_init_merge { my $self = $_[0]; $self->set_up_merge_fixture(); $self->{'timegroup'}->init_merge(); $self->assert_num_equals( 86400, $self->{'timegroup'}{'period_sec'} ); $self->assert_isa( 'Lire::Timegroup::SecHelper', $self->{'timegroup'}{'helper'} ); $self->assert_num_equals( 86400, $self->{'timegroup'}{'helper'}{'period'}); $self->assert_num_equals( 1, $self->{'timegroup'}{'helper'}{'multiple'} ); $self->assert_num_equals( 1, $self->{'aggregate'}->invocation_count( 'init_merge' ) ); $self->assert_num_equals( 0, $self->{'timegroup'}{'_merge_started'} ); $self->{'timegroup'}{'period'} = '4w'; $self->{'timegroup'}->init_merge(); $self->assert_isa( 'Lire::Timegroup::WeekHelper', $self->{'timegroup'}{'helper'} ); $self->assert_num_equals( 4, $self->{'timegroup'}{'helper'}{'multiple'} ); $self->{'timegroup'}{'period'} = '1M'; $self->{'timegroup'}->init_merge(); $self->assert_isa( 'Lire::Timegroup::MonthHelper', $self->{'timegroup'}{'helper'} ); $self->{'timegroup'}{'period'} = '4y'; $self->{'timegroup'}->init_merge(); $self->assert_isa( 'Lire::Timegroup::YearHelper', $self->{'timegroup'}{'helper'} ); } sub test_merge_aggregator_data { my $self = $_[0]; $self->set_up_merge_fixture(); my $entry = new Lire::Test::Mock( 'Lire::Report::Entry' ); my $group = new Lire::Test::Mock( 'Lire::Report::Group', 'entries' => sub { return ( $entry ) } ); $self->{'timegroup'}->init_merge(); $self->_test_merge_aggregator_data_errors( $group, $entry ); my $timeslices = []; $self->{'aggregate'}->set_result( 'init_group_data' => [] ); my $data = { 'aggr' => {} }; $entry->set_result( 'names' => { 'range' => 3600, 'value' => timelocal( 0, 0, 11, 1, 0, 2004 ) }, 'data_by_name' => sub { $data->{$_[1]} } ); $self->{'timegroup'}->merge_aggregator_data( $group, $timeslices ); $self->assert_num_equals( 1, $self->{'timegroup'}{'_merge_started'} ); $self->assert_deep_equals( [ $self->{'aggregate'}, {}, [] ], $self->{'aggregate'}->get_invocation( 'merge_group_data' ) ); $self->assert_deep_equals( [ [ timelocal( 0, 0, 0, 1, 0, 2004 ), [] ] ], $timeslices ); $entry->set_result( 'names' => { 'range' => 3600, 'value' => timelocal( 0, 0, 11, 3, 0, 2004 ) } ); $self->{'timegroup'}->merge_aggregator_data( $group, $timeslices ); $self->assert_deep_equals( [ [ timelocal( 0, 0, 0, 1, 0, 2004 ), [] ], undef, [ timelocal( 0, 0, 0, 3, 0, 2004 ), [] ] ], $timeslices ); $self->assert_num_equals( 2, $self->{'aggregate'}->invocation_count( 'merge_group_data' ) ); $entry->set_result( 'names' => { 'range' => 3600, 'value' => timelocal( 0, 0, 11, 30, 11, 2003 ) } ); $self->{'timegroup'}->merge_aggregator_data( $group, $timeslices ); $self->assert_deep_equals( [ [ timelocal( 0, 0, 0, 30, 11, 2003 ), [] ], undef, [ timelocal( 0, 0, 0, 1, 0, 2004 ), [] ], undef, [ timelocal( 0, 0, 0, 3, 0, 2004 ), [] ] ], $timeslices ); $entry->set_result( 'names' => { 'range' => 3600, 'value' => timelocal( 0, 0, 11, 31, 11, 2003 ) } ); $self->{'timegroup'}->merge_aggregator_data( $group, $timeslices ); $self->assert_deep_equals( [ [ timelocal( 0, 0, 0, 30, 11, 2003 ), [] ], [ timelocal( 0, 0, 0, 31, 11, 2003 ), [] ], [ timelocal( 0, 0, 0, 1, 0, 2004 ), [] ], undef, [ timelocal( 0, 0, 0, 3, 0, 2004 ), [] ] ], $timeslices ); } sub _test_merge_aggregator_data_errors { my ( $self, $group, $entry ) = @_; $entry->set_result( 'names' => { 'range' => 86400 * 2, 'value' => 0 } ); $self->assert_dies( qr/incompatible merge:/, sub { $self->{'timegroup'}->merge_aggregator_data( $group, [] ) } ); $entry->set_result( 'names' => { 'range' => 3601, 'value' => 0 } ); $self->assert_dies( qr/incompatible merge:/, sub { $self->{'timegroup'}->merge_aggregator_data( $group, [] ) } ); } sub test_WeekHelper_init { my $self = $_[0]; $self->{'cfg'}{'lr_week_numbering'} = 'ISO'; my $helper = new Lire::Timegroup::WeekHelper( 7*86400, 1 ); $helper->init( timelocal( 0, 0, 0, 1, 0, 2004 ) ); $self->assert_num_equals( 0, $helper->{'week_start'} ); $self->assert_num_equals( 2004, $helper->{'year_start'} ); $helper->init( timelocal( 0, 0, 0, 31, 11, 2003 ) ); $self->assert_num_equals( 0, $helper->{'week_start'} ); $self->assert_num_equals( 2004, $helper->{'year_start'} ); $helper->init( timelocal( 0, 0, 0, 1, 1, 2004 ) ); $self->assert_num_equals( 4, $helper->{'week_start'} ); $self->assert_num_equals( 2004, $helper->{'year_start'} ); $helper->init( timelocal( 0, 0, 0, 1, 0, 2005 ) ); $self->assert_num_equals( 52, $helper->{'week_start'} ); $self->assert_num_equals( 2004, $helper->{'year_start'} ); $self->{'cfg'}{'lr_week_numbering'} = 'U'; $helper->init( timelocal( 0, 0, 0, 1, 0, 2004 ) ); $self->assert_num_equals( 51, $helper->{'week_start'} ); $self->assert_num_equals( 2003, $helper->{'year_start'} ); $helper->init( timelocal( 0, 0, 0, 1, 1, 2004 ) ); $self->assert_num_equals( 4, $helper->{'week_start'} ); $self->assert_num_equals( 2004, $helper->{'year_start'} ); } sub test_WeekHelper_find_idx { my $self = $_[0]; $self->{'cfg'}{'lr_week_numbering'} = 'ISO'; my $helper = new Lire::Timegroup::WeekHelper( 7*86400, 1 ); $helper->init( timelocal( 0, 0, 0, 1, 0, 2004 ) ); $self->assert_num_equals( 0, $helper->find_idx( timelocal(0,0,0,1,0,2004))); $self->assert_num_equals( 0, $helper->find_idx( timelocal(0,0,0,31,11,2003))); $self->assert_num_equals( 4, $helper->find_idx( timelocal(0,0,0,1,1,2004))); $self->assert_num_equals( 52, $helper->find_idx( timelocal(0,0,0,1,0,2005))); $self->assert_num_equals( -1, $helper->find_idx( timelocal(0,0,0,25,11,2003))); $self->assert_num_equals( -52, $helper->find_idx( timelocal(0,0,0,1,0,2003))); $self->assert_num_equals( -53, $helper->find_idx( timelocal(0,0,0,25,11,2002))); $helper->{'week_start'} = 4; $self->assert_num_equals( 0, $helper->find_idx( timelocal(0,0,0,1,1,2004))); $self->assert_num_equals( 0, $helper->find_idx( timelocal(0,0,0,31,0,2004))); $self->assert_num_equals( 1, $helper->find_idx( timelocal(0,0,0,2,1,2004))); $self->assert_num_equals( 48, $helper->find_idx( timelocal(0,0,0,1,0,2005))); $self->assert_num_equals( -4, $helper->find_idx( timelocal(0,0,0,1,0,2004))); $self->assert_num_equals( -5, $helper->find_idx( timelocal(0,0,0,25,11,2003))); $helper->{'multiple'} = 4; $self->assert_num_equals( 0, $helper->find_idx( timelocal(0,0,0,1,1,2004))); $self->assert_num_equals( 0, $helper->find_idx( timelocal(0,0,0,2,1,2004))); $self->assert_num_equals( 12, $helper->find_idx( timelocal(0,0,0,1,0,2005))); $self->assert_num_equals( -2, $helper->find_idx( timelocal(0,0,0,25,11,2003))); $self->assert_num_equals( -13, $helper->find_idx( timelocal(0,0,0,1,1,2003))); $self->assert_num_equals( -14, $helper->find_idx( timelocal(0,0,0,1,0,2003))); } sub test_WeekHelper_slice_start { my $self = $_[0]; $self->{'cfg'}{'lr_week_numbering'} = 'ISO'; my $helper = new Lire::Timegroup::WeekHelper( 7*86400, 1 ); $helper->init( timelocal( 0, 0, 0, 1, 0, 2004 ) ); $self->assert_num_equals( timelocal( 0, 0, 0, 29, 11, 2003 ), $helper->slice_start( 0 ) ); $self->assert_num_equals( timelocal( 0, 0, 0, 26, 0, 2004 ), $helper->slice_start( 4 ) ); $self->assert_num_equals( timelocal( 0, 0, 0, 27, 11, 2004 ), $helper->slice_start( 52 ) ); $self->assert_num_equals( timelocal( 0, 0, 0, 3, 0, 2005 ), $helper->slice_start( 53 ) ); $self->assert_num_equals( timelocal( 0, 0, 0, 31, 0, 2005 ), $helper->slice_start( 57 ) ); $helper->{'week_start'} = 4; $self->assert_num_equals( timelocal( 0, 0, 0, 26, 0, 2004 ), $helper->slice_start( 0 ) ); $self->assert_num_equals( timelocal( 0, 0, 0, 20, 11, 2004 ), $helper->slice_start( 47 ) ); $self->assert_num_equals( timelocal( 0, 0, 0, 27, 11, 2004 ), $helper->slice_start( 48 ) ); $self->assert_num_equals( timelocal( 0, 0, 0, 24, 0, 2005 ), $helper->slice_start( 52 ) ); $self->assert_num_equals( timelocal( 0, 0, 0, 26, 11, 2005 ), $helper->slice_start( 100 ) ); $self->assert_num_equals( timelocal( 0, 0, 0, 23, 0, 2006 ), $helper->slice_start( 104 ) ); $helper->{'multiple'} = 4; $self->assert_num_equals( timelocal( 0, 0, 0, 26, 0, 2004 ), $helper->slice_start( 0 ) ); $self->assert_num_equals( timelocal( 0, 0, 0, 23, 1, 2004 ), $helper->slice_start( 1 ) ); $self->assert_num_equals( timelocal( 0, 0, 0, 27, 11, 2004 ), $helper->slice_start( 12 ) ); } sub test_MonthHelper_find_idx { my $self = $_[0]; my $helper = new Lire::Timegroup::MonthHelper( 7*86400, 1 ); $helper->init( timelocal( 0, 0, 0, 1, 0, 2004 ) ); $self->assert_num_equals( 104, $helper->{'year_start'} ); $self->assert_num_equals( 0, $helper->{'month_start'} ); $self->assert_num_equals( 0, $helper->find_idx( timelocal( 0, 0, 0, 15, 0, 2004 ) ) ); $self->assert_num_equals( 11, $helper->find_idx( timelocal( 0, 0, 0, 15, 11, 2004 ) ) ); $self->assert_num_equals( 12, $helper->find_idx( timelocal( 0, 0, 0, 15, 0, 2005 ) ) ); $self->assert_num_equals( -1, $helper->find_idx( timelocal( 0, 0, 0, 31, 11, 2003 ) ) ); $self->assert_num_equals( -13, $helper->find_idx( timelocal( 0, 0, 0, 31, 11, 2002 ) ) ); $helper->{'month_start'} = 2; $self->assert_num_equals( 9, $helper->find_idx( timelocal( 0, 0, 0, 15, 11, 2004 ) ) ); $self->assert_num_equals( -2, $helper->find_idx( timelocal( 0, 0, 0, 15, 0, 2004 ) ) ); $helper->{'multiple'} = 3; $self->assert_num_equals( -1, $helper->find_idx( timelocal( 0, 0, 0, 15, 0, 2004 ) ) ); $self->assert_num_equals( 0, $helper->find_idx( timelocal( 0, 0, 0, 15, 2, 2004 ) ) ); $self->assert_num_equals( 3, $helper->find_idx( timelocal( 0, 0, 0, 15, 0, 2005 ) ) ); $self->assert_num_equals( -1, $helper->find_idx( timelocal( 0, 0, 0, 31, 11, 2003 ) ) ); $self->assert_num_equals( -5, $helper->find_idx( timelocal( 0, 0, 0, 31, 11, 2002 ) ) ); } sub test_MonthHelper_slice_start { my $self = $_[0]; my $helper = new Lire::Timegroup::MonthHelper( 7*86400, 1 ); $helper->{'year_start'} = 104; $helper->{'month_start'} = 2; $self->assert_num_equals( timelocal( 0, 0, 0, 1, 2, 2004 ), $helper->slice_start( 0 ) ); $self->assert_num_equals( timelocal( 0, 0, 0, 1, 11, 2004 ), $helper->slice_start( 9 ) ); $self->assert_num_equals( timelocal( 0, 0, 0, 1, 2, 2005 ), $helper->slice_start( 12 ) ); $helper->{'multiple'} = 3 ; $self->assert_num_equals( timelocal( 0, 0, 0, 1, 2, 2004 ), $helper->slice_start( 0 ) ); $self->assert_num_equals( timelocal( 0, 0, 0, 1, 11, 2004 ), $helper->slice_start( 3 ) ); $self->assert_num_equals( timelocal( 0, 0, 0, 1, 2, 2005 ), $helper->slice_start( 4 ) ); } 1;