Revision control

Copy as Markdown

#!/usr/bin/env perl
use 5.010;
use strict;
use warnings;
=head1 NAME
23-testrunner-crashreporter.t - test testrunner's crashreporter plugin
=head1 SYNOPSIS
perl ./23-testrunner-crashreporter.t
This test will run the testrunner.pl script with some crashing processes
and do a basic verification that the CrashReporter crash logs are
correctly printed.
=cut
use Capture::Tiny qw( capture );
use English qw( -no_match_vars );
use FindBin;
use File::Basename;
use File::Slurp qw( read_file );
use File::Temp qw( tempdir );
use File::Spec::Functions;
use FindBin;
use Readonly;
use Test::More;
use lib "$FindBin::Bin/../../lib/perl5";
use QtQA::Test::More qw( is_or_like );
Readonly my $HELPER_DIR => catfile( $FindBin::Bin, 'helpers' );
# regex snippet when process exits due to segfault
Readonly my $PROCESS_EXITED_DUE_TO_SIGNAL => qr{
\QQtQA::App::TestRunner: Process exited due to signal 11\E
(?:\Q; dumped core\E)? # we don't care if it dumped core
\n
}xms;
# Matches text expected when a segfault occurs
Readonly my $SIGSEGV_CRASHLOG => qr{
\A
$PROCESS_EXITED_DUE_TO_SIGNAL
\QQtQA::App::TestRunner: ============================= crash report follows: ============================\E\n
# We are doing a basic check that some crash log appears to have been printed.
# The actual content is only verified very loosely.
.*
\QQtQA::App::TestRunner: OS Version: Mac OS X \E
.*
\QQtQA::App::TestRunner: Exception Type: EXC_BAD_ACCESS (SIGSEGV)\E\n
.*
\QQtQA::App::TestRunner: ================================================================================\E\n
\z
}xms;
sub test_run
{
my ($params_ref) = @_;
my @args = @{$params_ref->{ args }};
my $expected_stdout = $params_ref->{ expected_stdout };
my $expected_stderr = $params_ref->{ expected_stderr };
my $expected_success = $params_ref->{ expected_success };
my $expected_logfile = $params_ref->{ expected_logfile };
my $expected_logtext = $params_ref->{ expected_logtext } // "";
my $testname = $params_ref->{ testname } // q{};
my $status;
my ($output, $error) = capture {
$status = system( 'perl', "$FindBin::Bin/../testrunner.pl", @args );
};
if ($expected_success) {
is ( $status, 0, "$testname exits zero" );
}
else {
isnt( $status, 0, "$testname exits non-zero" );
}
is_or_like( $output, $expected_stdout, "$testname output looks correct" );
is_or_like( $error, $expected_stderr, "$testname error looks correct" );
# The rest of the verification steps are only applicable if a log file is expected and created
return if (!$expected_logfile);
return if (!ok( -e $expected_logfile, "$testname created $expected_logfile" ));
my $logtext = read_file( $expected_logfile ); # dies on error
is_or_like( $logtext, $expected_logtext, "$testname logtext is as expected" );
return;
}
sub test_testrunner
{
# control; check that `--plugin crashreporter' can load OK
test_run({
testname => 'plugin loads OK 0 exitcode',
args => [ '--plugin', 'crashreporter', '--', 'true' ],
expected_success => 1,
expected_stdout => q{},
expected_stderr => q{},
});
# another control; check that it doesn't break non-zero exit code
test_run({
testname => 'plugin loads OK !0 exitcode',
args => [ '--plugin', 'crashreporter', '--', 'false' ],
expected_success => 0,
expected_stdout => q{},
expected_stderr => q{},
});
my @crash_command = ( 'perl', catfile( $HELPER_DIR, 'dereference_bad_pointer.pl' ) );
# check that a crash log is captured if process crashes
test_run({
testname => 'simple backtrace',
args => [ '--plugin', 'crashreporter', '--', @crash_command ],
expected_success => 0,
expected_stdout => q{},
expected_stderr => $SIGSEGV_CRASHLOG,
});
# check that the crashlog is captured via --capture-logs OK
my $tempdir = tempdir( basename($0).'.XXXXXX', TMPDIR => 1, CLEANUP => 1 );
test_run({
testname => 'crash to log [capture]',
args => [
'--capture-logs',
$tempdir,
'--plugin',
'crashreporter',
'--sync-output',
'--',
@crash_command,
],
expected_success => 0,
expected_stdout => q{},
expected_stderr => q{},
expected_logfile => "$tempdir/perl-00.txt",
expected_logtext => $SIGSEGV_CRASHLOG,
});
# And again, with --tee
test_run({
testname => 'crash to log [tee]',
args => [
'--tee-logs',
$tempdir,
'--plugin',
'crashreporter',
'--',
@crash_command,
],
expected_success => 0,
expected_stdout => q{},
expected_stderr => $SIGSEGV_CRASHLOG,
expected_logfile => "$tempdir/perl-01.txt",
expected_logtext => $SIGSEGV_CRASHLOG,
});
# check what happens if a crash log can't be found
{
local $ENV{ QTQA_CRASHREPORTER_DIR } = '/bogus/crashreport/dir';
test_run({
testname => 'no crash report',
args => [ '--plugin', 'crashreporter', '--', @crash_command ],
expected_success => 0,
expected_stdout => q{},
expected_stderr => qr{
\A
$PROCESS_EXITED_DUE_TO_SIGNAL
\QQtQA::App::TestRunner: Sorry, a crash report could not be found in /bogus/crashreport/dir.\E\n
\z
}xms
});
}
return;
}
sub run
{
if ($OSNAME !~ m{darwin}i) {
plan 'skip_all', "test is not relevant on $OSNAME";
}
TODO: {
local $TODO = 'QTQAINFRA-488, mac crash report collection is unstable';
test_testrunner;
}
done_testing;
return;
}
run if (!caller);
1;