package tests::functional::LrCronTest; use strict; use base qw/Lire::Test::FunctionalTestCase tests::functional::TestSchemaFixture tests::ChartTypesFixture tests::OutputFormatsFixture /; use Lire::Config; use Lire::DlfStore; use Lire::Utils qw/create_file/; use File::Copy qw/copy/; use POSIX qw/strftime/; use File::Basename qw/basename/; { # See LrMailTest.pm for rationale use utf8; use MIME::Parser; } use Time::Local; #our @TESTS = qw//; sub new { my $self = shift->SUPER::new(@_); $self->tests::functional::TestSchemaFixture::init(@_); $self->{'log_file'} = $self->tests_datadir() . "/test.dlf"; return $self; } sub set_up { my $self = $_[0]; $self->SUPER::set_up(); $self->set_up_test_schemas(); $self->set_up_test_specs(); $self->set_up_TestDlfConverter(); $self->set_up_test_analysers(); $self->set_up_test_another_analyser(); Lire::Config->init(); $self->{'store_path'} = $self->homedir() . "/store"; return; } sub tear_down { my $self = $_[0]; $self->SUPER::tear_down(); $self->tests::functional::TestSchemaFixture::tear_down(); return; } sub test_usage_period { my $self = $_[0]; my $result = $self->lire_run( "lr_cron" ); $self->annotate( $result->stderr() ); $self->assert_not_equals( 0, $result->status() ); $self->assert( !$result->stdout(), "stdout should be empty" ); $self->assert_str_equals( "Missing 'period' argument.\nUsage: lr_cron \n", $result->stderr() ); } sub test_usage_store { my $self = $_[0]; my $result = $self->lire_run( "lr_cron daily" ); $self->annotate( $result->stderr() ); $self->assert_not_equals( 0, $result->status() ); $self->assert( !$result->stdout(), "stdout should be empty" ); $self->assert_str_equals( "Missing 'store' argument.\nUsage: lr_cron \n", $result->stderr() ); } sub test_usage_bad_period { my $self = $_[0]; my $result = $self->lire_run( "lr_cron bad" ); $self->annotate( $result->stderr() ); $self->assert_not_equals( 0, $result->status() ); $self->assert( !$result->stdout(), "stdout should be empty" ); $self->assert_str_equals( "Invalid period 'bad'. Should be one of hourly, daily, weekly, monthly or yearly.\nUsage: lr_cron \n", $result->stderr() ); } sub set_up_import_jobs { my $self = $_[0]; my $store = Lire::DlfStore->open( $self->{'store_path'}, 1 ); my $cfg = $store->config(); my $jobs = $cfg->get( 'import_jobs' ); my $hourly_job = $jobs->spec()->get( 'import_job' )->instance(); $hourly_job->get( 'name' )->set( 'hourly' ); $hourly_job->get( 'period' )->set( 'hourly' ); $hourly_job->get( 'service' )->set_plugin( 'test_newapi' ); $hourly_job->get( 'log_file' )->set( $self->{'log_file'} ); $hourly_job->get( 'log_encoding' )->set( '' ); $hourly_job->get( 'filter' )->set( '' ); my $daily_job = $jobs->spec()->get( 'import_job' )->instance(); $daily_job->get( 'name' )->set( 'daily' ); $daily_job->get( 'period' )->set( 'daily' ); $daily_job->get( 'service' )->set_plugin( 'test_newapi' ); $daily_job->get( 'log_file' )->set( $self->{'log_file'} ); $daily_job->get( 'log_encoding' )->set( '' ); $daily_job->get( 'filter' )->set( 'grep " flacoste "' ); $jobs->append( $hourly_job ); $jobs->append( $daily_job ); $store->get_stream_config( 'test-derived' )->get( 'test-extended' )->set_plugin( 'none' ); $store->close(); } sub test_import_daily_job { my $self = $_[0]; $self->set_up_import_jobs(); my $jan26_2003 = timelocal( 0, 0, 1, 26, 0, 2003 ); my $result = $self->lire_run( "lr_cron daily $self->{'store_path'} $jan26_2003" ); $self->annotate( $result->stderr() ); $self->assert_num_equals( 0, $result->status() ); $self->assert( !$result->stdout(), "stdout should be empty" ); $self->assert( !$result->stderr(), "stderr should be empty" ); my $store = Lire::DlfStore->open( $self->{'store_path'} ); my $stream = $store->open_dlf_stream( 'lire_import_stats', 'r' ); my $stats = $stream->read_dlf(); $self->assert_str_equals( 'daily', $stats->{'job_name'} ); $self->assert_num_equals( 0, $stats->{'line_count'} ); $self->assert_num_equals( 2, $stats->{'dlf_count'} ); $self->assert_num_equals( 0, $stats->{'ignored_count'} ); $self->assert_num_equals( 0, $stats->{'saved_count'} ); $self->assert_num_equals( 0, $stats->{'error_count'} ); $stats = $stream->read_dlf(); $self->assert_str_equals( 'derived', $stats->{'job_name'} ); $self->assert_num_equals( 2, $stats->{'dlf_count'} ); $self->assert_num_equals( 0, $stats->{'error_count'} ); $stats = $stream->read_dlf(); $self->assert_str_equals( 'extended', $stats->{'job_name'} ); $self->assert_num_equals( 2, $stats->{'dlf_count'} ); $self->assert_num_equals( 0, $stats->{'error_count'} ); $self->assert_null( $stream->read_dlf() ); $stream->close(); $stream = $store->open_dlf_stream( 'test', 'r' ); $self->assert_num_equals( 2, $stream->nrecords() ); $self->assert_num_equals( 1043514300, $stream->start_time() ); $self->assert_num_equals( 1043515075, $stream->end_time() ); $stream->close(); $stream = $store->open_dlf_stream( 'test-extended', 'r' ); $self->assert_num_equals( 2, $stream->nrecords() ); $stream->close(); $stream = $store->open_dlf_stream( 'test-derived', 'r' ); $self->assert_num_equals( 2, $stream->nrecords() ); $stream->close(); $store->close(); } sub set_up_store_config { my $self = $_[0]; my $cfg_file = $self->create_test_cfg_file( 'lr_week_numbering' ); $cfg_file->get( 'lr_week_numbering' )->set( 'ISO' ); $cfg_file->save(); my $store = Lire::DlfStore->open( $self->rundir() . "/store", 1 ); $self->{'store_path'} = $store->path(); $store->close(); copy( $self->tests_datadir() . "/jobs-config.xml", "$self->{'store_path'}/config.xml" ); } # We will run a daily job from 21 to 27 # that is the jobs for the week Jan 20th to 26th 2003 # # The configuration should be identifcal to the one # tested in Lire::Test::test_configure_jobs(). These # two tests making a central Lire use-case sub test_lr_cron_one_week { my $self = $_[0]; $self->set_up_chart_types(); $self->set_up_output_formats(); my $jan21_2003 = timelocal( 0, 0, 1, 21, 0, 2003 ); $self->set_up_store_config(); for ( my $i=0; $i < 7; $i++ ) { my $time = $jan21_2003 + $i*86400; if ( $i == 5 ) { # 25th copy( $self->tests_datadir() . "/test.dlf", $self->rundir() . "/test.dlf" ); } else { create_file( $self->rundir() . "/test.dlf", '' ); } $self->annotate( strftime( "==> lr_cron daily %Y-%m-%d %H:%M\n\n", localtime $time ) ); my $result = $self->lire_run( "lr_cron daily $self->{'store_path'} $time" ); $self->annotate( $result->stderr() ); $self->assert_num_equals( 0, $result->status() ); $self->assert( ! $result->stdout(), "stdout should be empty" ); $self->assert_does_not_match( qr/ (crit|err|warning) /, $result->stderr(), "There were warnings or error messages." ); if ( $i == 5 ) { # 25th we have DLF data $self->check_daily_report( $time, $result->sent_mail() ); } else { $self->check_nodata_report( $time, $result->sent_mail() ); } } my $time = $jan21_2003 + 6 * 86400; $self->annotate( strftime( "==> lr_cron weekly %Y-%m-%d %H:%M\n\n", localtime( $time ) ) ); my $result = $self->lire_run( "lr_cron weekly $self->{'store_path'} $time" ); $self->annotate( $result->stderr() ); $self->assert_num_equals( 0, $result->status() ); $self->assert( ! $result->stdout(), "stdout should be empty" ); $self->assert_does_not_match( qr/ (crit|err|warning) /, $result->stderr(), "There were warnings or error messages." ); $self->check_weekly_report( $time, $result->sent_mail() ); # We run lr_cron daily another time to check for streams cleaning # since on the 2003/01/27 01:00 - 1d (cron offset) - 1d (keep_days) = # delete records < 2003/01/25 01:00 $time = $jan21_2003 + 7 * 86400; $self->annotate( strftime( "==> lr_cron daily %Y-%m-%d %H:%M\n\n", localtime( $time ) ) ); $result = $self->lire_run( "lr_cron daily $self->{'store_path'} $time" ); $self->annotate( $result->stderr() ); $self->assert_num_equals( 0, $result->status() ); $self->assert( ! $result->stdout(), "stdout should be empty" ); $self->assert_does_not_match( qr/ (crit|err|warning) /, $result->stderr(), "There were warnings or error messages." ); $self->check_streams_cleaning(); } sub check_streams_cleaning { my $self = $_[0]; my $store = Lire::DlfStore->open( $self->{'store_path'} ); foreach my $name ( qw/ test test-derived test-extended / ) { my $stream = $store->open_dlf_stream( $name, 'r' ); $self->assert_num_equals( 0, $stream->nrecords(), "$name wasn't cleaned" ); $stream->close(); } $store->close(); } sub check_nodata_report { my ( $self, $time, $mails ) = @_; # Since reports are generated for the previous period my $day = (localtime( $time ))[3] - 1; my $xml_report = "$self->{'store_path'}/daily_reports/Test_Report/200301/$day.xml"; $self->assert( ! -s $xml_report, "File '$xml_report' exists" ); $self->assert_num_equals( 0, scalar @$mails ); } sub check_daily_report { my ( $self, $time, $mails ) = @_; # Since reports are generated for the previous period my $day = (localtime( $time ))[3] - 1; my $xml_report = "$self->{'store_path'}/daily_reports/Test_Report/200301/$day.xml"; $self->assert( -s $xml_report, "File '$xml_report' is missing" ); $self->check_xml_report( $self->tests_datadir() . "/TestReport_daily_jan25_2003.xml", $xml_report ); $self->assert_num_equals( 1, scalar @$mails ); $self->assert_deep_equals( [ 'flacoste@logreport.org' ], $mails->[0]{'recipients'} ); my $parser = new MIME::Parser(); $parser->output_under( $self->rundir() ); my $msg = $parser->parse_data( $mails->[0]{'message'} ); $self->assert_str_equals( "PDF Report\n", $msg->head()->get( 'Subject' ) ); $self->assert_str_equals( 'application/pdf', $msg->mime_type() ); $self->assert( length( $msg->bodyhandle()->as_string() ) > 0, "PDF report is empty" ); return; } sub check_weekly_report { my ( $self, $time, $mails ) = @_; my $xml_report = "$self->{'store_path'}/weekly_reports/Test_Report/2003/04.xml"; $self->assert( -s $xml_report, "File '$xml_report' is missing" ); $self->check_xml_report( $self->tests_datadir() . "/TestReport_weekly_w04_2003.xml", $xml_report ); $self->assert( -d $self->rundir() . "/report 2003-W04", "HTML report 'report 2003-W04' is missing" ); $self->assert( -s $self->rundir() . "/report 2003-W04/index.html", "File 'report 2003-W04/index.html' is missing" ); $self->assert_num_equals( 1, scalar @$mails ); $self->assert_deep_equals( [ 'wolfgang@logreport.org' ], $mails->[0]{'recipients'} ); my $parser = new MIME::Parser(); $parser->output_under( $self->rundir() ); my $msg = $parser->parse_data( $mails->[0]{'message'} ); $self->assert_str_equals( "Text Report\n", $msg->head()->get( 'Subject' )); $self->assert_str_equals( 'text/plain', $msg->mime_type() ); $self->assert_matches( qr/movies\/001145\.mpg/, $msg->bodyhandle()->as_string() ); } 1;