1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2026-05-22 10:15:16 +02:00
Files
pgbackrest/test/lib/pgBackRestTest/Common/RunTest.pm
T

568 lines
19 KiB
Perl
Raw Normal View History

2016-12-23 08:22:59 -05:00
####################################################################################################################################
# RunTest.pm - All tests are inherited from this object
####################################################################################################################################
package pgBackRestTest::Common::RunTest;
####################################################################################################################################
# Perl includes
####################################################################################################################################
use strict;
use warnings FATAL => qw(all);
use Carp qw(confess);
use English '-no_match_vars';
use Exporter qw(import);
our @EXPORT = qw();
use File::Basename qw(dirname);
2016-12-23 08:22:59 -05:00
use pgBackRest::Common::Exception;
2016-12-23 08:22:59 -05:00
use pgBackRest::Common::Log;
2017-04-10 13:53:19 -04:00
use pgBackRest::Common::String;
2017-01-27 09:42:30 -05:00
use pgBackRest::Common::Wait;
2019-06-26 08:24:58 -04:00
use pgBackRest::Storage::Base;
use pgBackRest::Storage::Storage;
use pgBackRest::Version;
2016-12-23 08:22:59 -05:00
2019-06-26 08:24:58 -04:00
use pgBackRestTest::Common::BuildTest;
2016-12-23 08:22:59 -05:00
use pgBackRestTest::Common::DefineTest;
2017-01-27 09:42:30 -05:00
use pgBackRestTest::Common::ExecuteTest;
use pgBackRestTest::Common::LogTest;
use pgBackRestTest::Common::VmTest;
2016-12-23 08:22:59 -05:00
####################################################################################################################################
# Constant to use when bogus data is required
####################################################################################################################################
use constant BOGUS => 'bogus';
push @EXPORT, qw(BOGUS);
####################################################################################################################################
2019-08-26 12:05:36 -04:00
# The current test run that is executing. Only a single run should ever occur in a process to prevent various cleanup issues from
2016-12-23 08:22:59 -05:00
# affecting the next run. Of course multiple subtests can be executed in a single run.
####################################################################################################################################
my $oTestRun;
2017-06-09 17:51:41 -04:00
my $oStorage;
2016-12-23 08:22:59 -05:00
####################################################################################################################################
# new
####################################################################################################################################
sub new
{
my $class = shift; # Class name
# Create the class hash
my $self = {};
bless $self, $class;
# Assign function parameters, defaults, and log debug info
my ($strOperation) = logDebugParam(__PACKAGE__ . '->new');
# Initialize run counter
$self->{iRun} = 0;
# Return from function and log return values if any
return logDebugReturn
(
$strOperation,
{name => 'self', value => $self, trace => true}
);
}
####################################################################################################################################
2017-01-27 09:42:30 -05:00
# initModule
#
2019-08-26 12:05:36 -04:00
# Empty init sub in case the ancestor class does not declare one.
2017-01-27 09:42:30 -05:00
####################################################################################################################################
sub initModule {}
####################################################################################################################################
# initTest
2016-12-23 08:22:59 -05:00
#
2019-08-26 12:05:36 -04:00
# Empty init sub in case the ancestor class does not declare one.
2016-12-23 08:22:59 -05:00
####################################################################################################################################
2017-01-27 09:42:30 -05:00
sub initTest {}
2016-12-23 08:22:59 -05:00
####################################################################################################################################
2017-01-27 09:42:30 -05:00
# cleanTest
#
# Delete all files in test directory.
####################################################################################################################################
sub cleanTest
{
my $self = shift;
2019-10-12 09:45:18 -04:00
executeTest('rm -rf ' . $self->testPath() . '/*');
2017-01-27 09:42:30 -05:00
}
####################################################################################################################################
# cleanModule
2016-12-23 08:22:59 -05:00
#
2019-08-26 12:05:36 -04:00
# Empty final sub in case the ancestor class does not declare one.
2016-12-23 08:22:59 -05:00
####################################################################################################################################
2017-01-27 09:42:30 -05:00
sub cleanModule {}
2016-12-23 08:22:59 -05:00
####################################################################################################################################
# process
####################################################################################################################################
sub process
{
my $self = shift;
# Assign function parameters, defaults, and log debug info
(
my $strOperation,
$self->{strVm},
$self->{iVmId},
$self->{strBasePath},
$self->{strTestPath},
$self->{strBackRestExeC},
$self->{strBackRestExeHelper},
2016-12-23 08:22:59 -05:00
$self->{strPgBinPath},
$self->{strPgVersion},
$self->{strModule},
$self->{strModuleTest},
$self->{iyModuleTestRun},
2016-12-23 08:22:59 -05:00
$self->{bOutput},
$self->{bDryRun},
$self->{bCleanup},
$self->{bLogForce},
$self->{strLogLevelTestFile},
2016-12-23 08:22:59 -05:00
$self->{strPgUser},
$self->{strGroup},
) =
logDebugParam
(
__PACKAGE__ . '->process', \@_,
{name => 'strVm'},
{name => 'iVmId'},
{name => 'strBasePath'},
{name => 'strTestPath'},
{name => 'strBackRestExeC'},
{name => 'strBackRestExeHelper'},
2016-12-23 08:22:59 -05:00
{name => 'strPgBinPath', required => false},
{name => 'strPgVersion', required => false},
{name => 'strModule'},
{name => 'strModuleTest'},
{name => 'iModuleTestRun', required => false},
{name => 'bOutput'},
{name => 'bDryRun'},
{name => 'bCleanup'},
{name => 'bLogForce'},
{name => 'strLogLevelTestFile'},
2016-12-23 08:22:59 -05:00
{name => 'strPgUser'},
{name => 'strGroup'},
);
2017-01-27 09:42:30 -05:00
# Init will only be run on first test, clean/init on subsequent tests
$self->{bFirstTest} = true;
2017-06-09 17:51:41 -04:00
# Initialize test storage
2019-06-26 08:24:58 -04:00
$oStorage = new pgBackRest::Storage::Storage(STORAGE_LOCAL, {strPath => $self->testPath()});
2017-06-09 17:51:41 -04:00
2018-02-05 12:32:30 -05:00
# Generate backrest exe
2019-07-05 16:55:17 -04:00
$self->{strBackRestExe} = defined($self->{strBackRestExeC}) ? $self->{strBackRestExeC} : $self->{strBackRestExeHelper};
2018-02-05 12:32:30 -05:00
projectBinSet($self->{strBackRestExe});
2018-02-05 12:32:30 -05:00
2016-12-23 08:22:59 -05:00
# Init, run, and end the test(s)
2017-01-27 09:42:30 -05:00
$self->initModule();
2016-12-23 08:22:59 -05:00
$self->run();
$self->end();
2017-01-27 09:42:30 -05:00
$self->cleanModule();
2016-12-23 08:22:59 -05:00
# Make sure the correct number of tests ran
my $hModuleTest = testDefModuleTest($self->{strModule}, $self->{strModuleTest});
2016-12-23 08:22:59 -05:00
if ($hModuleTest->{&TESTDEF_TOTAL} != $self->runCurrent())
2016-12-23 08:22:59 -05:00
{
confess &log(ASSERT, "expected $hModuleTest->{&TESTDEF_TOTAL} tests to run but $self->{iRun} ran");
2016-12-23 08:22:59 -05:00
}
# Return from function and log return values if any
return logDebugReturn
(
$strOperation,
{name => 'self', value => $self, trace => true}
);
}
####################################################################################################################################
# begin
####################################################################################################################################
sub begin
{
my $self = shift;
# Assign function parameters, defaults, and log debug info
my
(
$strOperation,
$strDescription,
$bExpect,
) =
logDebugParam
(
__PACKAGE__ . '->begin', \@_,
{name => 'strDescription'},
{name => 'bExpect', required => false},
);
# Save the previous expect log
$self->end();
# If bExpect is defined then it is an override of the default
2017-11-14 17:16:39 -05:00
$self->{bExpect} = false;
if ($self->vm() eq VM_EXPECT)
2016-12-23 08:22:59 -05:00
{
2017-11-14 17:16:39 -05:00
if (defined($bExpect))
{
$self->{bExpect} = $bExpect;
}
# Else get the default expect setting
else
{
$self->{bExpect} = (testDefModuleTest($self->{strModule}, $self->{strModuleTest}))->{&TESTDEF_EXPECT};
}
2016-12-23 08:22:59 -05:00
}
# Increment the run counter;
$self->{iRun}++;
# Return if this test should not be run
if (@{$self->{iyModuleTestRun}} != 0 && !grep(/^$self->{iRun}$/i, @{$self->{iyModuleTestRun}}))
2016-12-23 08:22:59 -05:00
{
return false;
}
# Output information about test to run
&log(INFO, 'run ' . sprintf('%03d', $self->runCurrent()) . ' - ' . $strDescription);
if ($self->isDryRun())
{
return false;
}
2017-11-14 17:16:39 -05:00
# Create an ExpectTest object
if ($self->doExpect())
2016-12-23 08:22:59 -05:00
{
$self->{oExpect} = new pgBackRestTest::Common::LogTest(
$self->module(), $self->moduleTest(), $self->runCurrent(), $self->doLogForce(), $strDescription,
$self->{strBackRestExe}, $self->pgBinPath(), $self->testPath());
2016-12-23 08:22:59 -05:00
&log(INFO, ' expect log: ' . $self->{oExpect}->{strFileName});
}
2017-01-27 09:42:30 -05:00
if (!$self->{bFirstTest})
{
$self->cleanTest();
}
$self->initTest();
$self->{bFirstTest} = false;
2016-12-23 08:22:59 -05:00
return true;
}
####################################################################################################################################
# end
####################################################################################################################################
sub end
{
my $self = shift;
# Save the previous test log
if (defined($self->expect()))
{
$self->expect()->logWrite($self->basePath(), $self->testPath());
delete($self->{oExpect});
}
}
####################################################################################################################################
# testResult
####################################################################################################################################
sub testResult
{
my $self = shift;
2017-01-27 09:42:30 -05:00
# Assign function parameters, defaults, and log debug info
my
(
$strOperation,
$fnSub,
$strExpected,
$strDescription,
$iWaitSeconds,
2017-04-10 13:53:19 -04:00
$strLogExpect,
$strLogLevel,
) =
logDebugParam
(
__PACKAGE__ . '::testResult', \@_,
{name => 'fnSub', trace => true},
{name => 'strExpected', required => false, trace => true},
{name => 'strDescription', trace => true},
{name => 'iWaitSeconds', optional => true, default => 0, trace => true},
2017-04-10 13:53:19 -04:00
{name => 'strLogExpect', optional => true, trace => true},
{name => 'strLogLevel', optional => true, default => WARN, trace => true},
);
&log(INFO, ' ' . $strDescription);
2017-01-27 09:42:30 -05:00
my $strActual;
2017-04-10 13:53:19 -04:00
my $bWarnValid = true;
my $oWait = waitInit($iWaitSeconds);
2017-01-27 09:42:30 -05:00
my $bDone = false;
# Save the current log levels and set the file level to strLogLevel, console to off, and timestamp false
2017-04-10 13:53:19 -04:00
my ($strLogLevelFile, $strLogLevelConsole, $strLogLevelStdErr, $bLogTimestamp) = logLevel();
logLevelSet($strLogLevel, OFF, undef, false);
2017-04-10 13:53:19 -04:00
# Clear the cache for this test
logFileCacheClear();
2017-06-09 17:51:41 -04:00
my @stryResult;
2017-01-27 09:42:30 -05:00
do
{
2017-01-27 09:42:30 -05:00
eval
{
2017-06-09 17:51:41 -04:00
@stryResult = ref($fnSub) eq 'CODE' ? $fnSub->() : $fnSub;
2017-01-27 09:42:30 -05:00
if (@stryResult <= 1)
{
$strActual = ${logDebugBuild($stryResult[0])};
}
else
{
$strActual = ${logDebugBuild(\@stryResult)};
}
2017-04-10 13:53:19 -04:00
# Restore the log level
logLevelSet($strLogLevelFile, $strLogLevelConsole, $strLogLevelStdErr, $bLogTimestamp);
2017-01-27 09:42:30 -05:00
return true;
}
or do
{
2017-04-10 13:53:19 -04:00
# Restore the log level
logLevelSet($strLogLevelFile, $strLogLevelConsole, $strLogLevelStdErr, $bLogTimestamp);
2017-01-27 09:42:30 -05:00
if (!isException(\$EVAL_ERROR))
2017-01-27 09:42:30 -05:00
{
confess "unexpected standard Perl exception" . (defined($EVAL_ERROR) ? ": ${EVAL_ERROR}" : '');
}
confess &logException($EVAL_ERROR);
};
if ($strActual ne (defined($strExpected) ? $strExpected : "[undef]"))
{
if (!waitMore($oWait))
{
confess
2017-02-21 11:47:45 -05:00
"expected:\n" . (defined($strExpected) ? "\"${strExpected}\"" : '[undef]') .
"\nbut actual was:\n" . (defined($strActual) ? "\"${strActual}\"" : '[undef]');
2017-01-27 09:42:30 -05:00
}
}
else
{
$bDone = true;
}
} while (!$bDone);
2017-04-10 13:53:19 -04:00
# If we get here then test any warning message
if (defined($strLogExpect))
{
my $strLogMessage = trim(logFileCache());
# Strip leading Process marker and whitespace from each line
$strLogMessage =~ s/^(P[0-9]{2})*\s+//mg;
# If the expected message does not exactly match the logged message or is not at least contained in it, then error
if (!($strLogMessage eq $strLogExpect || $strLogMessage =~ $strLogExpect))
{
confess &log(ERROR,
"the log message:\n$strLogMessage\ndoes not match or does not contain the expected message:\n" .
$strLogExpect);
}
}
# Return from function and log return values if any
2017-06-09 17:51:41 -04:00
return logDebugReturn
(
$strOperation,
{name => 'result', value => \@stryResult, trace => true}
);
}
####################################################################################################################################
# testException
####################################################################################################################################
sub testException
{
my $self = shift;
my $fnSub = shift;
my $iCodeExpected = shift;
my $strMessageExpected = shift;
2017-01-27 09:42:30 -05:00
# Output first line of the error message
2017-06-09 17:51:41 -04:00
&log(INFO,
" [${iCodeExpected}] " . (defined($strMessageExpected) ? (split('\n', $strMessageExpected))[0] : 'undef error message'));
2017-01-27 09:42:30 -05:00
my $bError = false;
2017-06-09 17:51:41 -04:00
my $strError =
"exception ${iCodeExpected}, " . (defined($strMessageExpected) ? "'${strMessageExpected}'" : '[UNDEF]') . " was expected";
eval
{
2017-01-27 09:42:30 -05:00
logDisable();
$fnSub->();
2017-01-27 09:42:30 -05:00
logEnable();
return true;
}
or do
{
2017-01-27 09:42:30 -05:00
logEnable();
if (!isException(\$EVAL_ERROR))
{
2017-01-27 09:42:30 -05:00
confess "${strError} but actual was standard Perl exception" . (defined($EVAL_ERROR) ? ": ${EVAL_ERROR}" : '');
}
2017-01-27 09:42:30 -05:00
if (!($EVAL_ERROR->code() == $iCodeExpected &&
2017-06-09 17:51:41 -04:00
(!defined($strMessageExpected) && !defined($EVAL_ERROR->message()) ||
(defined($strMessageExpected) && defined($EVAL_ERROR->message()) &&
($EVAL_ERROR->message() eq $strMessageExpected || $EVAL_ERROR->message() =~ "^${strMessageExpected}" ||
$EVAL_ERROR->message() =~ "^${strMessageExpected} at ")))))
{
2017-06-09 17:51:41 -04:00
confess
"${strError} but actual was " . $EVAL_ERROR->code() . ', ' .
(defined($EVAL_ERROR->message()) ? qw{'} . $EVAL_ERROR->message() . qw{'} : '[UNDEF]');
}
$bError = true;
};
if (!$bError)
{
confess "${strError} but no exception was thrown";
}
}
2016-12-23 08:22:59 -05:00
####################################################################################################################################
# testRunName
#
# Create module/test names by upper-casing the first letter and then inserting capitals after each -.
####################################################################################################################################
sub testRunName
{
my $strName = shift;
2017-10-12 12:55:48 -04:00
my $bInitCapFirst = shift;
$bInitCapFirst = defined($bInitCapFirst) ? $bInitCapFirst : true;
my $bFirst = true;
2016-12-23 08:22:59 -05:00
my @stryName = split('\-', $strName);
$strName = undef;
foreach my $strPart (@stryName)
{
2017-10-12 12:55:48 -04:00
$strName .= ($bFirst && $bInitCapFirst) || !$bFirst ? ucfirst($strPart) : $strPart;
$bFirst = false;
2016-12-23 08:22:59 -05:00
}
return $strName;
}
2017-10-12 12:55:48 -04:00
push @EXPORT, qw(testRunName);
2016-12-23 08:22:59 -05:00
####################################################################################################################################
# testRun
####################################################################################################################################
sub testRun
{
# Assign function parameters, defaults, and log debug info
my
(
$strOperation,
$strModule,
$strModuleTest,
) =
logDebugParam
(
__PACKAGE__ . '::testRun', \@_,
{name => 'strModule', trace => true},
{name => 'strModuleTest', trace => true},
);
# Error if the test run is already defined - only one run per process is allowed
if (defined($oTestRun))
{
confess &log(ASSERT, 'a test run has already been created in this process');
}
my $strModuleName =
'pgBackRestTest::Module::' . testRunName($strModule) . '::' . testRunName($strModule) . testRunName($strModuleTest) .
'Test';
2016-12-23 08:22:59 -05:00
2019-07-05 16:55:17 -04:00
$oTestRun = eval("require ${strModuleName}; ${strModuleName}->import(); return new ${strModuleName}();")
2016-12-23 08:22:59 -05:00
or do {confess $EVAL_ERROR};
# Return from function and log return values if any
return logDebugReturn
(
$strOperation,
{name => 'oRun', value => $oTestRun, trace => true}
);
}
push @EXPORT, qw(testRun);
####################################################################################################################################
# testRunGet
####################################################################################################################################
sub testRunGet
{
return $oTestRun;
}
push @EXPORT, qw(testRunGet);
####################################################################################################################################
2017-06-09 17:51:41 -04:00
# storageTest - get the storage for the current test
####################################################################################################################################
sub storageTest
{
return $oStorage;
}
push(@EXPORT, qw(storageTest));
2016-12-23 08:22:59 -05:00
####################################################################################################################################
# Getters
####################################################################################################################################
sub archBits {return vmArchBits(shift->{strVm})}
2016-12-23 08:22:59 -05:00
sub backrestExe {return shift->{strBackRestExe}}
sub basePath {return shift->{strBasePath}}
sub dataPath {return shift->basePath() . '/test/data'}
sub doCleanup {return shift->{bCleanup}}
sub doExpect {return shift->{bExpect}}
sub doLogForce {return shift->{bLogForce}}
sub logLevelTestFile {return shift->{strLogLevelTestFile}}
2016-12-23 08:22:59 -05:00
sub group {return shift->{strGroup}}
sub isDryRun {return shift->{bDryRun}}
sub expect {return shift->{oExpect}}
sub module {return shift->{strModule}}
sub moduleTest {return shift->{strModuleTest}}
sub pgBinPath {return shift->{strPgBinPath}}
sub pgUser {return shift->{strPgUser}}
sub pgVersion {return shift->{strPgVersion}}
sub runCurrent {return shift->{iRun}}
sub stanza {return 'db'}
sub testPath {return shift->{strTestPath}}
sub vm {return shift->{strVm}}
sub vmId {return shift->{iVmId}}
1;