1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2025-11-06 08:49:29 +02:00

v0.50: restore and much more

* Added restore functionality.

* All options can now be set on the command-line making pg_backrest.conf optional.

* De/compression is now performed without threads and checksum/size is calculated in stream.  That means file checksums are no longer optional.

* Added option `--no-start-stop` to allow backups when Postgres is shut down.  If `postmaster.pid` is present then `--force` is required to make the backup run (though if Postgres is running an inconsistent backup will likely be created).  This option was added primarily for the purpose of unit testing, but there may be applications in the real world as well.

* Fixed broken checksums and now they work with normal and resumed backups.  Finally realized that checksums and checksum deltas should be functionally separated and this simplied a number of things.  Issue #28 has been created for checksum deltas.

* Fixed an issue where a backup could be resumed from an aborted backup that didn't have the same type and prior backup.

* Removed dependency on Moose.  It wasn't being used extensively and makes for longer startup times.

* Checksum for backup.manifest to detect corrupted/modified manifest.

* Link `latest` always points to the last backup.  This has been added for convenience and to make restores simpler.

* More comprehensive unit tests in all areas.
This commit is contained in:
David Steele
2015-03-25 15:15:55 -04:00
parent 4bc4d97f2b
commit b37d59832f
29 changed files with 11752 additions and 2353 deletions

BIN
test/data/test.archive1.bin Normal file

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -8,28 +8,36 @@ package BackRestTest::CommonTest;
# Perl includes
####################################################################################################################################
use strict;
use warnings;
use Carp;
use warnings FATAL => qw(all);
use Carp qw(confess);
use File::Basename;
use File::Path qw(remove_tree);
use Cwd 'abs_path';
use IPC::Open3;
use POSIX ':sys_wait_h';
use IO::Select;
use File::Copy qw(move);
use lib dirname($0) . '/../lib';
use BackRest::Utility;
use BackRest::Remote;
use BackRest::File;
use BackRest::Manifest;
use Exporter qw(import);
our @EXPORT = qw(BackRestTestCommon_Setup BackRestTestCommon_ExecuteBegin BackRestTestCommon_ExecuteEnd
BackRestTestCommon_Execute BackRestTestCommon_ExecuteBackRest
BackRestTestCommon_ConfigCreate BackRestTestCommon_Run BackRestTestCommon_Cleanup
BackRestTestCommon_PgSqlBinPathGet BackRestTestCommon_StanzaGet BackRestTestCommon_CommandMainGet
BackRestTestCommon_CommandRemoteGet BackRestTestCommon_HostGet BackRestTestCommon_UserGet
BackRestTestCommon_GroupGet BackRestTestCommon_UserBackRestGet BackRestTestCommon_TestPathGet
BackRestTestCommon_DataPathGet BackRestTestCommon_BackupPathGet BackRestTestCommon_ArchivePathGet
BackRestTestCommon_DbPathGet BackRestTestCommon_DbCommonPathGet BackRestTestCommon_DbPortGet);
our @EXPORT = qw(BackRestTestCommon_Create BackRestTestCommon_Drop BackRestTestCommon_Setup BackRestTestCommon_ExecuteBegin
BackRestTestCommon_ExecuteEnd BackRestTestCommon_Execute BackRestTestCommon_ExecuteBackRest
BackRestTestCommon_PathCreate BackRestTestCommon_PathMode BackRestTestCommon_PathRemove
BackRestTestCommon_FileCreate BackRestTestCommon_FileRemove BackRestTestCommon_PathCopy BackRestTestCommon_PathMove
BackRestTestCommon_ConfigCreate BackRestTestCommon_ConfigRemap BackRestTestCommon_ConfigRecovery
BackRestTestCommon_Run BackRestTestCommon_Cleanup BackRestTestCommon_PgSqlBinPathGet
BackRestTestCommon_StanzaGet BackRestTestCommon_CommandMainGet BackRestTestCommon_CommandRemoteGet
BackRestTestCommon_HostGet BackRestTestCommon_UserGet BackRestTestCommon_GroupGet
BackRestTestCommon_UserBackRestGet BackRestTestCommon_TestPathGet BackRestTestCommon_DataPathGet
BackRestTestCommon_RepoPathGet BackRestTestCommon_LocalPathGet BackRestTestCommon_DbPathGet
BackRestTestCommon_DbCommonPathGet BackRestTestCommon_ClusterStop BackRestTestCommon_DbTablespacePathGet
BackRestTestCommon_DbPortGet);
my $strPgSqlBin;
my $strCommonStanza;
@@ -42,10 +50,11 @@ my $strCommonGroup;
my $strCommonUserBackRest;
my $strCommonTestPath;
my $strCommonDataPath;
my $strCommonBackupPath;
my $strCommonArchivePath;
my $strCommonRepoPath;
my $strCommonLocalPath;
my $strCommonDbPath;
my $strCommonDbCommonPath;
my $strCommonDbTablespacePath;
my $iCommonDbPort;
my $iModuleTestRun;
my $bDryRun;
@@ -59,8 +68,58 @@ my $hOut;
my $pId;
my $strCommand;
####################################################################################################################################
# BackRestTestBackup_Run
# BackRestTestCommon_ClusterStop
####################################################################################################################################
sub BackRestTestCommon_ClusterStop
{
my $strPath = shift;
my $bImmediate = shift;
# Set default
$strPath = defined($strPath) ? $strPath : BackRestTestCommon_DbCommonPathGet();
$bImmediate = defined($bImmediate) ? $bImmediate : false;
# If postmaster process is running then stop the cluster
if (-e $strPath . '/postmaster.pid')
{
BackRestTestCommon_Execute(BackRestTestCommon_PgSqlBinPathGet() . "/pg_ctl stop -D ${strPath} -w -s -m " .
($bImmediate ? 'immediate' : 'fast'));
}
}
####################################################################################################################################
# BackRestTestCommon_Drop
####################################################################################################################################
sub BackRestTestCommon_Drop
{
# Drop the cluster if it exists
BackRestTestCommon_ClusterStop(BackRestTestCommon_DbCommonPathGet(), true);
# Remove the backrest private directory
while (-e BackRestTestCommon_RepoPathGet())
{
BackRestTestCommon_PathRemove(BackRestTestCommon_RepoPathGet(), true, true);
BackRestTestCommon_PathRemove(BackRestTestCommon_RepoPathGet(), false, true);
hsleep(.1);
}
# Remove the test directory
BackRestTestCommon_PathRemove(BackRestTestCommon_TestPathGet());
}
####################################################################################################################################
# BackRestTestCommon_Create
####################################################################################################################################
sub BackRestTestCommon_Create
{
# Create the test directory
BackRestTestCommon_PathCreate(BackRestTestCommon_TestPathGet(), '0770');
}
####################################################################################################################################
# BackRestTestCommon_Run
####################################################################################################################################
sub BackRestTestCommon_Run
{
@@ -83,7 +142,7 @@ sub BackRestTestCommon_Run
}
####################################################################################################################################
# BackRestTestBackup_Cleanup
# BackRestTestCommon_Cleanup
####################################################################################################################################
sub BackRestTestCommon_Cleanup
{
@@ -91,7 +150,7 @@ sub BackRestTestCommon_Cleanup
}
####################################################################################################################################
# BackRestTestBackup_ExecuteBegin
# BackRestTestCommon_ExecuteBegin
####################################################################################################################################
sub BackRestTestCommon_ExecuteBegin
{
@@ -122,15 +181,18 @@ sub BackRestTestCommon_ExecuteBegin
}
####################################################################################################################################
# BackRestTestBackup_ExecuteEnd
# BackRestTestCommon_ExecuteEnd
####################################################################################################################################
sub BackRestTestCommon_ExecuteEnd
{
my $strTest = shift;
my $bSuppressError = shift;
my $bShowOutput = shift;
my $iExpectedExitStatus = shift;
# Set defaults
$bSuppressError = defined($bSuppressError) ? $bSuppressError : false;
$bShowOutput = defined($bShowOutput) ? $bShowOutput : false;
# Create select objects
my $oErrorSelect = IO::Select->new();
@@ -169,15 +231,34 @@ sub BackRestTestCommon_ExecuteEnd
# Check the exit status and output an error if needed
my $iExitStatus = ${^CHILD_ERROR_NATIVE} >> 8;
if ($iExitStatus != 0 && !$bSuppressError)
if (defined($iExpectedExitStatus) && $iExitStatus == $iExpectedExitStatus)
{
confess &log(ERROR, "command '${strCommand}' returned " . $iExitStatus . "\n" .
($strOutLog ne '' ? "STDOUT:\n${strOutLog}" : '') .
($strErrorLog ne '' ? "STDERR:\n${strErrorLog}" : ''));
return $iExitStatus;
}
else
if ($iExitStatus != 0 || (defined($iExpectedExitStatus) && $iExitStatus != $iExpectedExitStatus))
{
&log(DEBUG, "suppressed error was ${iExitStatus}");
if ($bSuppressError)
{
&log(DEBUG, "suppressed error was ${iExitStatus}");
}
else
{
confess &log(ERROR, "command '${strCommand}' returned " . $iExitStatus .
(defined($iExpectedExitStatus) ? ", but ${iExpectedExitStatus} was expected" : '') . "\n" .
($strOutLog ne '' ? "STDOUT:\n${strOutLog}" : '') .
($strErrorLog ne '' ? "STDERR:\n${strErrorLog}" : ''));
}
}
if ($bShowOutput)
{
print "output:\n${strOutLog}\n";
}
if (defined($strTest))
{
confess &log(ASSERT, "test point ${strTest} was not found");
}
$hError = undef;
@@ -187,16 +268,159 @@ sub BackRestTestCommon_ExecuteEnd
}
####################################################################################################################################
# BackRestTestBackup_Execute
# BackRestTestCommon_Execute
####################################################################################################################################
sub BackRestTestCommon_Execute
{
my $strCommand = shift;
my $bRemote = shift;
my $bSuppressError = shift;
my $bShowOutput = shift;
my $iExpectedExitStatus = shift;
BackRestTestCommon_ExecuteBegin($strCommand, $bRemote);
return BackRestTestCommon_ExecuteEnd(undef, $bSuppressError);
return BackRestTestCommon_ExecuteEnd(undef, $bSuppressError, $bShowOutput, $iExpectedExitStatus);
}
####################################################################################################################################
# BackRestTestCommon_PathCreate
#
# Create a path and set mode.
####################################################################################################################################
sub BackRestTestCommon_PathCreate
{
my $strPath = shift;
my $strMode = shift;
# Create the path
mkdir($strPath)
or confess "unable to create ${strPath} path";
# Set the mode
chmod(oct(defined($strMode) ? $strMode : '0700'), $strPath)
or confess 'unable to set mode ${strMode} for ${strPath}';
}
####################################################################################################################################
# BackRestTestCommon_PathMode
#
# Set mode of an existing path.
####################################################################################################################################
sub BackRestTestCommon_PathMode
{
my $strPath = shift;
my $strMode = shift;
# Set the mode
chmod(oct($strMode), $strPath)
or confess 'unable to set mode ${strMode} for ${strPath}';
}
####################################################################################################################################
# BackRestTestCommon_PathRemove
#
# Remove a path and all subpaths.
####################################################################################################################################
sub BackRestTestCommon_PathRemove
{
my $strPath = shift;
my $bRemote = shift;
my $bSuppressError = shift;
BackRestTestCommon_Execute('rm -rf ' . $strPath, $bRemote, $bSuppressError);
# remove_tree($strPath, {result => \my $oError});
#
# if (@$oError)
# {
# my $strMessage = "error(s) occurred while removing ${strPath}:";
#
# for my $strFile (@$oError)
# {
# $strMessage .= "\nunable to remove: " . $strFile;
# }
#
# confess $strMessage;
# }
}
####################################################################################################################################
# BackRestTestCommon_PathCopy
#
# Copy a path.
####################################################################################################################################
sub BackRestTestCommon_PathCopy
{
my $strSourcePath = shift;
my $strDestinationPath = shift;
my $bRemote = shift;
my $bSuppressError = shift;
BackRestTestCommon_Execute("cp -rp ${strSourcePath} ${strDestinationPath}", $bRemote, $bSuppressError);
}
####################################################################################################################################
# BackRestTestCommon_PathMove
#
# Copy a path.
####################################################################################################################################
sub BackRestTestCommon_PathMove
{
my $strSourcePath = shift;
my $strDestinationPath = shift;
my $bRemote = shift;
my $bSuppressError = shift;
BackRestTestCommon_PathCopy($strSourcePath, $strDestinationPath, $bRemote, $bSuppressError);
BackRestTestCommon_PathRemove($strSourcePath, $bRemote, $bSuppressError);
}
####################################################################################################################################
# BackRestTestCommon_FileCreate
#
# Create a file specifying content, mode, and time.
####################################################################################################################################
sub BackRestTestCommon_FileCreate
{
my $strFile = shift;
my $strContent = shift;
my $lTime = shift;
my $strMode = shift;
# Open the file and save strContent to it
my $hFile = shift;
open($hFile, '>', $strFile)
or confess "unable to open ${strFile} for writing";
syswrite($hFile, $strContent)
or confess "unable to write to ${strFile}: $!";
close($hFile);
# Set the time
if (defined($lTime))
{
utime($lTime, $lTime, $strFile)
or confess 'unable to set time ${lTime} for ${strPath}';
}
# Set the mode
chmod(oct(defined($strMode) ? $strMode : '0600'), $strFile)
or confess 'unable to set mode ${strMode} for ${strFile}';
}
####################################################################################################################################
# BackRestTestCommon_FileRemove
#
# Remove a file.
####################################################################################################################################
sub BackRestTestCommon_FileRemove
{
my $strFile = shift;
unlink($strFile)
or confess "unable to remove ${strFile}: $!";
}
####################################################################################################################################
@@ -230,10 +454,11 @@ sub BackRestTestCommon_Setup
}
$strCommonDataPath = "${strBasePath}/test/data";
$strCommonBackupPath = "${strCommonTestPath}/backrest";
$strCommonArchivePath = "${strCommonTestPath}/archive";
$strCommonRepoPath = "${strCommonTestPath}/backrest";
$strCommonLocalPath = "${strCommonTestPath}/local";
$strCommonDbPath = "${strCommonTestPath}/db";
$strCommonDbCommonPath = "${strCommonTestPath}/db/common";
$strCommonDbTablespacePath = "${strCommonTestPath}/db/tablespace";
$strCommonCommandMain = "${strBasePath}/bin/pg_backrest.pl";
$strCommonCommandRemote = "${strBasePath}/bin/pg_backrest_remote.pl";
@@ -245,6 +470,116 @@ sub BackRestTestCommon_Setup
$bNoCleanup = $bNoCleanupParam;
}
####################################################################################################################################
# BackRestTestCommon_ConfigRemap
####################################################################################################################################
sub BackRestTestCommon_ConfigRemap
{
my $oRemapHashRef = shift;
my $oManifestRef = shift;
my $bRemote = shift;
# Create config filename
my $strConfigFile = BackRestTestCommon_DbPathGet() . '/pg_backrest.conf';
my $strStanza = BackRestTestCommon_StanzaGet();
# Load Config file
my %oConfig;
ini_load($strConfigFile, \%oConfig);
# Load remote config file
my %oRemoteConfig;
my $strRemoteConfigFile = BackRestTestCommon_TestPathGet() . '/pg_backrest.conf.remote';
if ($bRemote)
{
BackRestTestCommon_Execute("mv " . BackRestTestCommon_RepoPathGet() . "/pg_backrest.conf ${strRemoteConfigFile}", true);
ini_load($strRemoteConfigFile, \%oRemoteConfig);
}
# Rewrite remap section
delete($oConfig{"${strStanza}:restore:tablespace-map"});
foreach my $strRemap (sort(keys $oRemapHashRef))
{
my $strRemapPath = ${$oRemapHashRef}{$strRemap};
if ($strRemap eq 'base')
{
$oConfig{$strStanza}{'db-path'} = $strRemapPath;
${$oManifestRef}{'backup:path'}{base} = $strRemapPath;
if ($bRemote)
{
$oRemoteConfig{$strStanza}{'db-path'} = $strRemapPath;
}
}
else
{
$oConfig{"${strStanza}:restore:tablespace-map"}{$strRemap} = $strRemapPath;
${$oManifestRef}{'backup:path'}{"tablespace:${strRemap}"} = $strRemapPath;
${$oManifestRef}{'backup:tablespace'}{$strRemap}{'path'} = $strRemapPath;
${$oManifestRef}{'base:link'}{"pg_tblspc/${strRemap}"}{'link_destination'} = $strRemapPath;
}
}
# Resave the config file
ini_save($strConfigFile, \%oConfig);
# Load remote config file
if ($bRemote)
{
ini_save($strRemoteConfigFile, \%oRemoteConfig);
BackRestTestCommon_Execute("mv ${strRemoteConfigFile} " . BackRestTestCommon_RepoPathGet() . '/pg_backrest.conf', true);
}
}
####################################################################################################################################
# BackRestTestCommon_ConfigRecovery
####################################################################################################################################
sub BackRestTestCommon_ConfigRecovery
{
my $oRecoveryHashRef = shift;
my $bRemote = shift;
# Create config filename
my $strConfigFile = BackRestTestCommon_DbPathGet() . '/pg_backrest.conf';
my $strStanza = BackRestTestCommon_StanzaGet();
# Load Config file
my %oConfig;
ini_load($strConfigFile, \%oConfig);
# Load remote config file
my %oRemoteConfig;
my $strRemoteConfigFile = BackRestTestCommon_TestPathGet() . '/pg_backrest.conf.remote';
if ($bRemote)
{
BackRestTestCommon_Execute("mv " . BackRestTestCommon_RepoPathGet() . "/pg_backrest.conf ${strRemoteConfigFile}", true);
ini_load($strRemoteConfigFile, \%oRemoteConfig);
}
# Rewrite remap section
delete($oConfig{"${strStanza}:recovery:option"});
foreach my $strOption (sort(keys $oRecoveryHashRef))
{
$oConfig{"${strStanza}:recovery:option"}{$strOption} = ${$oRecoveryHashRef}{$strOption};
}
# Resave the config file
ini_save($strConfigFile, \%oConfig);
# Load remote config file
if ($bRemote)
{
ini_save($strRemoteConfigFile, \%oRemoteConfig);
BackRestTestCommon_Execute("mv ${strRemoteConfigFile} " . BackRestTestCommon_RepoPathGet() . '/pg_backrest.conf', true);
}
}
####################################################################################################################################
# BackRestTestCommon_ConfigCreate
####################################################################################################################################
@@ -256,54 +591,64 @@ sub BackRestTestCommon_ConfigCreate
my $bChecksum = shift;
my $bHardlink = shift;
my $iThreadMax = shift;
my $bArchiveLocal = shift;
my $bArchiveAsync = shift;
my $bCompressAsync = shift;
my %oParamHash;
if (defined($strRemote))
{
$oParamHash{'global:command'}{'remote'} = $strCommonCommandRemote;
$oParamHash{'global:command'}{'cmd-remote'} = $strCommonCommandRemote;
}
$oParamHash{'global:command'}{'psql'} = $strCommonCommandPsql;
$oParamHash{'global:command'}{'cmd-psql'} = $strCommonCommandPsql;
if (defined($strRemote) && $strRemote eq REMOTE_BACKUP)
if (defined($strRemote) && $strRemote eq BACKUP)
{
$oParamHash{'global:backup'}{'host'} = $strCommonHost;
$oParamHash{'global:backup'}{'user'} = $strCommonUserBackRest;
$oParamHash{'global:backup'}{'backup-host'} = $strCommonHost;
$oParamHash{'global:backup'}{'backup-user'} = $strCommonUserBackRest;
}
elsif (defined($strRemote) && $strRemote eq REMOTE_DB)
elsif (defined($strRemote) && $strRemote eq DB)
{
$oParamHash{$strCommonStanza}{'host'} = $strCommonHost;
$oParamHash{$strCommonStanza}{'user'} = $strCommonUser;
$oParamHash{$strCommonStanza}{'db-host'} = $strCommonHost;
$oParamHash{$strCommonStanza}{'db-user'} = $strCommonUser;
}
$oParamHash{'global:log'}{'level-console'} = 'error';
$oParamHash{'global:log'}{'level-file'} = 'trace';
$oParamHash{'global:log'}{'log-level-console'} = 'error';
$oParamHash{'global:log'}{'log-level-file'} = 'trace';
if ($strLocal eq REMOTE_BACKUP)
if ($strLocal eq BACKUP)
{
if (defined($bHardlink) && $bHardlink)
{
$oParamHash{'global:backup'}{'hardlink'} = 'y';
}
$oParamHash{'global:general'}{'repo-path'} = $strCommonRepoPath;
}
elsif ($strLocal eq REMOTE_DB)
elsif ($strLocal eq DB)
{
$oParamHash{'global:general'}{'repo-path'} = $strCommonLocalPath;
if (defined($strRemote))
{
$oParamHash{'global:log'}{'level-console'} = 'trace';
$oParamHash{'global:log'}{'log-level-console'} = 'trace';
# if ($bArchiveAsync)
# {
# $oParamHash{'global:archive'}{path} = BackRestTestCommon_LocalPathGet();
# }
$oParamHash{'global:general'}{'repo-remote-path'} = $strCommonRepoPath;
}
else
{
$oParamHash{'global:general'}{'repo-path'} = $strCommonRepoPath;
}
if ($bArchiveLocal)
if ($bArchiveAsync)
{
$oParamHash{'global:archive'}{path} = BackRestTestCommon_ArchivePathGet();
if (!$bCompressAsync)
{
$oParamHash{'global:archive'}{'compress_async'} = 'n';
}
$oParamHash{'global:archive'}{'archive-async'} = 'y';
#
# if (!$bCompressAsync)
# {
# $oParamHash{'global:archive'}{'compress_async'} = 'n';
# }
}
}
else
@@ -311,32 +656,37 @@ sub BackRestTestCommon_ConfigCreate
confess "invalid local type ${strLocal}";
}
if (($strLocal eq REMOTE_BACKUP) || ($strLocal eq REMOTE_DB && !defined($strRemote)))
if (defined($iThreadMax) && $iThreadMax > 1)
{
$oParamHash{'db:command:option'}{'psql'} = "--port=${iCommonDbPort}";
$oParamHash{'global:general'}{'thread-max'} = $iThreadMax;
}
if (($strLocal eq BACKUP) || ($strLocal eq DB && !defined($strRemote)))
{
$oParamHash{'db:command'}{'cmd-psql-option'} = "--port=${iCommonDbPort}";
$oParamHash{'global:backup'}{'thread-max'} = $iThreadMax;
if (defined($bHardlink) && $bHardlink)
{
$oParamHash{'global:backup'}{'hardlink'} = 'y';
}
}
if (defined($bCompress) && !$bCompress)
{
$oParamHash{'global:backup'}{'compress'} = 'n';
$oParamHash{'global:general'}{'compress'} = 'n';
}
if (defined($bChecksum) && !$bChecksum)
{
$oParamHash{'global:backup'}{'checksum'} = 'n';
}
# if (defined($bChecksum) && $bChecksum)
# {
# $oParamHash{'global:backup'}{'checksum'} = 'y';
# }
$oParamHash{$strCommonStanza}{'path'} = $strCommonDbCommonPath;
$oParamHash{'global:backup'}{'path'} = $strCommonBackupPath;
if (defined($iThreadMax))
{
$oParamHash{'global:backup'}{'thread-max'} = $iThreadMax;
}
$oParamHash{$strCommonStanza}{'db-path'} = $strCommonDbCommonPath;
# Write out the configuration file
my $strFile = BackRestTestCommon_TestPathGet() . '/pg_backrest.conf';
config_save($strFile, \%oParamHash);
ini_save($strFile, \%oParamHash);
# Move the configuration file based on local
if ($strLocal eq 'db')
@@ -346,12 +696,12 @@ sub BackRestTestCommon_ConfigCreate
}
elsif ($strLocal eq 'backup' && !defined($strRemote))
{
rename($strFile, BackRestTestCommon_BackupPathGet() . '/pg_backrest.conf')
or die "unable to move ${strFile} to " . BackRestTestCommon_BackupPathGet() . '/pg_backrest.conf path';
rename($strFile, BackRestTestCommon_RepoPathGet() . '/pg_backrest.conf')
or die "unable to move ${strFile} to " . BackRestTestCommon_RepoPathGet() . '/pg_backrest.conf path';
}
else
{
BackRestTestCommon_Execute("mv ${strFile} " . BackRestTestCommon_BackupPathGet() . '/pg_backrest.conf', true);
BackRestTestCommon_Execute("mv ${strFile} " . BackRestTestCommon_RepoPathGet() . '/pg_backrest.conf', true);
}
}
@@ -408,14 +758,14 @@ sub BackRestTestCommon_DataPathGet
return $strCommonDataPath;
}
sub BackRestTestCommon_BackupPathGet
sub BackRestTestCommon_RepoPathGet
{
return $strCommonBackupPath;
return $strCommonRepoPath;
}
sub BackRestTestCommon_ArchivePathGet
sub BackRestTestCommon_LocalPathGet
{
return $strCommonArchivePath;
return $strCommonLocalPath;
}
sub BackRestTestCommon_DbPathGet
@@ -425,7 +775,17 @@ sub BackRestTestCommon_DbPathGet
sub BackRestTestCommon_DbCommonPathGet
{
return $strCommonDbCommonPath;
my $iIndex = shift;
return $strCommonDbCommonPath . (defined($iIndex) ? "-${iIndex}" : '');
}
sub BackRestTestCommon_DbTablespacePathGet
{
my $iTablespace = shift;
my $iIndex = shift;
return $strCommonDbTablespacePath . (defined($iTablespace) ? "/ts${iTablespace}" . (defined($iIndex) ? "-${iIndex}" : '') : '');
}
sub BackRestTestCommon_DbPortGet

View File

@@ -0,0 +1,816 @@
#!/usr/bin/perl
####################################################################################################################################
# ConfigTest.pl - Unit Tests for BackRest::Param and BackRest::Config
####################################################################################################################################
package BackRestTest::ConfigTest;
####################################################################################################################################
# Perl includes
####################################################################################################################################
use strict;
use warnings FATAL => qw(all);
use Carp qw(confess);
use File::Basename qw(dirname);
use Cwd qw(abs_path);
use Scalar::Util 'blessed';
#use Data::Dumper qw(Dumper);
#use Scalar::Util qw(blessed);
# use Test::More qw(no_plan);
# use Test::Deep;
use lib dirname($0) . '/../lib';
use BackRest::Exception;
use BackRest::Utility;
use BackRest::Config;
use BackRestTest::CommonTest;
use Exporter qw(import);
our @EXPORT = qw(BackRestTestConfig_Test);
sub optionSetTest
{
my $oOption = shift;
my $strKey = shift;
my $strValue = shift;
$$oOption{option}{$strKey} = $strValue;
}
sub optionSetBoolTest
{
my $oOption = shift;
my $strKey = shift;
my $bValue = shift;
$$oOption{boolean}{$strKey} = defined($bValue) ? $bValue : true;
}
sub operationSetTest
{
my $oOption = shift;
my $strOperation = shift;
$$oOption{operation} = $strOperation;
}
sub optionRemoveTest
{
my $oOption = shift;
my $strKey = shift;
delete($$oOption{option}{$strKey});
delete($$oOption{boolean}{$strKey});
}
sub argvWriteTest
{
my $oOption = shift;
@ARGV = ();
if (defined($$oOption{boolean}))
{
foreach my $strKey (keys $$oOption{boolean})
{
if ($$oOption{boolean}{$strKey})
{
$ARGV[@ARGV] = "--${strKey}";
}
else
{
$ARGV[@ARGV] = "--no-${strKey}";
}
}
}
if (defined($$oOption{option}))
{
foreach my $strKey (keys $$oOption{option})
{
$ARGV[@ARGV] = "--${strKey}=$$oOption{option}{$strKey}";
}
}
$ARGV[@ARGV] = $$oOption{operation};
&log(INFO, " command line: " . join(" ", @ARGV));
%$oOption = ();
}
sub configLoadExpect
{
my $oOption = shift;
my $strOperation = shift;
my $iExpectedError = shift;
my $strErrorParam1 = shift;
my $strErrorParam2 = shift;
my $strErrorParam3 = shift;
my $oOptionRuleExpected = optionRuleGet();
operationSetTest($oOption, $strOperation);
argvWriteTest($oOption);
eval
{
configLoad();
};
if ($@)
{
if (!defined($iExpectedError))
{
confess $@;
}
my $oMessage = $@;
if (blessed($oMessage) && $oMessage->isa('BackRest::Exception'))
{
if ($oMessage->code() != $iExpectedError)
{
confess "expected error ${iExpectedError} from configLoad but got " . $oMessage->code() .
" '" . $oMessage->message() . "'";
}
my $strError;
if ($iExpectedError == ERROR_OPTION_REQUIRED)
{
$strError = "backup operation requires option: ${strErrorParam1}";
}
elsif ($iExpectedError == ERROR_OPERATION_REQUIRED)
{
$strError = "operation must be specified";
}
elsif ($iExpectedError == ERROR_OPTION_INVALID)
{
$strError = "option '${strErrorParam1}' not valid without option '${strErrorParam2}'";
if (defined($strErrorParam3))
{
$strError .= @{$strErrorParam3} == 1 ? " = '$$strErrorParam3[0]'" :
" in ('" . join("', '",@{ $strErrorParam3}) . "')";
}
}
elsif ($iExpectedError == ERROR_OPTION_INVALID_VALUE)
{
$strError = "'${strErrorParam1}' is not valid for '${strErrorParam2}' option";
}
elsif ($iExpectedError == ERROR_OPTION_INVALID_RANGE)
{
$strError = "'${strErrorParam1}' is not valid for '${strErrorParam2}' option";
}
elsif ($iExpectedError == ERROR_OPTION_INVALID_PAIR)
{
$strError = "'${strErrorParam1}' not valid key/value for '${strErrorParam2}' option";
}
elsif ($iExpectedError == ERROR_OPTION_NEGATE)
{
$strError = "option '${strErrorParam1}' cannot be both set and negated";
}
elsif ($iExpectedError == ERROR_FILE_INVALID)
{
$strError = "'${strErrorParam1}' is not a file";
}
else
{
confess "must construct message for error ${iExpectedError}, use this as an example: '" . $oMessage->message() . "'";
}
if ($oMessage->message() ne $strError)
{
confess "expected error message \"${strError}\" from configLoad but got \"" . $oMessage->message() . "\"";
}
}
else
{
confess "configLoad should throw BackRest::Exception:\n$oMessage";
}
}
else
{
if (defined($iExpectedError))
{
confess "expected error ${iExpectedError} from configLoad but got success";
}
}
# cmp_deeply(OPTION_rule_get(), $oOptionRuleExpected, 'compare original and new rule hashes')
# or die 'comparison failed';
}
sub optionTestExpect
{
my $strOption = shift;
my $strExpectedValue = shift;
my $strExpectedKey = shift;
if (defined($strExpectedValue))
{
my $strActualValue = optionGet($strOption);
if (defined($strExpectedKey))
{
# use Data::Dumper;
# &log(INFO, Dumper($strActualValue));
# exit 0;
$strActualValue = $$strActualValue{$strExpectedKey};
}
if (!defined($strActualValue))
{
confess "expected option ${strOption} to have value ${strExpectedValue} but [undef] found instead";
}
$strActualValue eq $strExpectedValue
or confess "expected option ${strOption} to have value ${strExpectedValue} but ${strActualValue} found instead";
}
elsif (optionTest($strOption))
{
confess "expected option ${strOption} to be [undef], but " . optionGet($strOption) . ' found instead';
}
}
####################################################################################################################################
# BackRestTestConfig_Test
####################################################################################################################################
sub BackRestTestConfig_Test
{
my $strTest = shift;
# Setup test variables
my $iRun;
my $bCreate;
my $strStanza = 'main';
my $oOption = {};
my $oConfig = {};
my @oyArray;
my $strConfigFile = BackRestTestCommon_TestPathGet() . '/pg_backrest.conf';
use constant BOGUS => 'bogus';
# Print test banner
&log(INFO, 'CONFIG MODULE ******************************************************************');
BackRestTestCommon_Drop();
#-------------------------------------------------------------------------------------------------------------------------------
# Test command-line options
#-------------------------------------------------------------------------------------------------------------------------------
if ($strTest eq 'all' || $strTest eq 'option')
{
$iRun = 0;
&log(INFO, "Option module\n");
if (BackRestTestCommon_Run(++$iRun, 'backup with no stanza'))
{
optionSetTest($oOption, OPTION_DB_PATH, '/db');
configLoadExpect($oOption, OP_BACKUP, ERROR_OPTION_REQUIRED, OPTION_STANZA);
}
if (BackRestTestCommon_Run(++$iRun, 'backup with boolean stanza'))
{
optionSetBoolTest($oOption, OPTION_STANZA);
configLoadExpect($oOption, OP_BACKUP, ERROR_OPERATION_REQUIRED);
}
if (BackRestTestCommon_Run(++$iRun, 'backup type defaults to ' . BACKUP_TYPE_INCR))
{
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_DB_PATH, '/db');
configLoadExpect($oOption, OP_BACKUP);
optionTestExpect(OPTION_TYPE, BACKUP_TYPE_INCR);
}
if (BackRestTestCommon_Run(++$iRun, 'backup type set to ' . BACKUP_TYPE_FULL))
{
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_DB_PATH, '/db');
optionSetTest($oOption, OPTION_TYPE, BACKUP_TYPE_FULL);
configLoadExpect($oOption, OP_BACKUP);
optionTestExpect(OPTION_TYPE, BACKUP_TYPE_FULL);
}
if (BackRestTestCommon_Run(++$iRun, 'backup type invalid'))
{
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_DB_PATH, '/db');
optionSetTest($oOption, OPTION_TYPE, BOGUS);
configLoadExpect($oOption, OP_BACKUP, ERROR_OPTION_INVALID_VALUE, BOGUS, OPTION_TYPE);
}
if (BackRestTestCommon_Run(++$iRun, 'backup invalid force'))
{
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_DB_PATH, '/db');
optionSetBoolTest($oOption, OPTION_FORCE);
configLoadExpect($oOption, OP_BACKUP, ERROR_OPTION_INVALID, OPTION_FORCE, OPTION_NO_START_STOP);
}
if (BackRestTestCommon_Run(++$iRun, 'backup valid force'))
{
# $oOption = {};
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_DB_PATH, '/db');
optionSetBoolTest($oOption, OPTION_NO_START_STOP);
optionSetBoolTest($oOption, OPTION_FORCE);
configLoadExpect($oOption, OP_BACKUP);
optionTestExpect(OPTION_NO_START_STOP, true);
optionTestExpect(OPTION_FORCE, true);
}
if (BackRestTestCommon_Run(++$iRun, 'backup invalid value for ' . OPTION_TEST_DELAY))
{
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_DB_PATH, '/db');
optionSetBoolTest($oOption, OPTION_TEST);
optionSetTest($oOption, OPTION_TEST_DELAY, BOGUS);
configLoadExpect($oOption, OP_BACKUP, ERROR_OPTION_INVALID_VALUE, BOGUS, OPTION_TEST_DELAY);
}
if (BackRestTestCommon_Run(++$iRun, 'backup invalid ' . OPTION_TEST_DELAY))
{
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_DB_PATH, '/db');
optionSetTest($oOption, OPTION_TEST_DELAY, 5);
configLoadExpect($oOption, OP_BACKUP, ERROR_OPTION_INVALID, OPTION_TEST_DELAY, OPTION_TEST);
}
if (BackRestTestCommon_Run(++$iRun, 'backup check ' . OPTION_TEST_DELAY . ' undef'))
{
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_DB_PATH, '/db');
configLoadExpect($oOption, OP_BACKUP);
optionTestExpect(OPTION_TEST_DELAY);
}
if (BackRestTestCommon_Run(++$iRun, 'restore invalid ' . OPTION_TARGET))
{
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_TYPE, RECOVERY_TYPE_DEFAULT);
optionSetTest($oOption, OPTION_TARGET, BOGUS);
@oyArray = (RECOVERY_TYPE_NAME, RECOVERY_TYPE_TIME, RECOVERY_TYPE_XID);
configLoadExpect($oOption, OP_RESTORE, ERROR_OPTION_INVALID, OPTION_TARGET, OPTION_TYPE, \@oyArray);
}
if (BackRestTestCommon_Run(++$iRun, 'restore ' . OPTION_TARGET))
{
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_TYPE, RECOVERY_TYPE_NAME);
optionSetTest($oOption, OPTION_TARGET, BOGUS);
configLoadExpect($oOption, OP_RESTORE);
optionTestExpect(OPTION_TYPE, RECOVERY_TYPE_NAME);
optionTestExpect(OPTION_TARGET, BOGUS);
optionTestExpect(OPTION_TARGET_TIMELINE);
}
if (BackRestTestCommon_Run(++$iRun, 'invalid string ' . OPTION_THREAD_MAX))
{
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_DB_PATH, '/db');
optionSetTest($oOption, OPTION_THREAD_MAX, BOGUS);
configLoadExpect($oOption, OP_BACKUP, ERROR_OPTION_INVALID_VALUE, BOGUS, OPTION_THREAD_MAX);
}
if (BackRestTestCommon_Run(++$iRun, 'invalid float ' . OPTION_THREAD_MAX))
{
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_DB_PATH, '/db');
optionSetTest($oOption, OPTION_THREAD_MAX, '0.0');
configLoadExpect($oOption, OP_BACKUP, ERROR_OPTION_INVALID_VALUE, '0.0', OPTION_THREAD_MAX);
}
if (BackRestTestCommon_Run(++$iRun, 'valid ' . OPTION_THREAD_MAX))
{
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_DB_PATH, '/db');
optionSetTest($oOption, OPTION_THREAD_MAX, '2');
configLoadExpect($oOption, OP_BACKUP);
}
if (BackRestTestCommon_Run(++$iRun, 'valid float ' . OPTION_TEST_DELAY))
{
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_DB_PATH, '/db');
optionSetBoolTest($oOption, OPTION_TEST);
optionSetTest($oOption, OPTION_TEST_DELAY, '0.25');
configLoadExpect($oOption, OP_BACKUP);
}
if (BackRestTestCommon_Run(++$iRun, 'valid int ' . OPTION_TEST_DELAY))
{
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_DB_PATH, '/db');
optionSetBoolTest($oOption, OPTION_TEST);
optionSetTest($oOption, OPTION_TEST_DELAY, 3);
configLoadExpect($oOption, OP_BACKUP);
}
if (BackRestTestCommon_Run(++$iRun, 'restore valid ' . OPTION_TARGET_TIMELINE))
{
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_TARGET_TIMELINE, 2);
configLoadExpect($oOption, OP_RESTORE);
}
if (BackRestTestCommon_Run(++$iRun, 'invalid ' . OPTION_BUFFER_SIZE))
{
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_BUFFER_SIZE, '512');
configLoadExpect($oOption, OP_RESTORE, ERROR_OPTION_INVALID_RANGE, '512', OPTION_BUFFER_SIZE);
}
if (BackRestTestCommon_Run(++$iRun, OP_BACKUP . ' invalid option' . OPTION_RETENTION_ARCHIVE_TYPE))
{
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_DB_PATH, '/db');
optionSetTest($oOption, OPTION_RETENTION_ARCHIVE_TYPE, BOGUS);
configLoadExpect($oOption, OP_BACKUP, ERROR_OPTION_INVALID, OPTION_RETENTION_ARCHIVE_TYPE, OPTION_RETENTION_ARCHIVE);
}
if (BackRestTestCommon_Run(++$iRun, OP_BACKUP . ' invalid value ' . OPTION_RETENTION_ARCHIVE_TYPE))
{
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_DB_PATH, '/db');
optionSetTest($oOption, OPTION_RETENTION_ARCHIVE, 3);
optionSetTest($oOption, OPTION_RETENTION_ARCHIVE_TYPE, BOGUS);
configLoadExpect($oOption, OP_BACKUP, ERROR_OPTION_INVALID_VALUE, BOGUS, OPTION_RETENTION_ARCHIVE_TYPE);
}
if (BackRestTestCommon_Run(++$iRun, OP_BACKUP . ' valid value ' . OPTION_RETENTION_ARCHIVE_TYPE))
{
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_DB_PATH, '/db');
optionSetTest($oOption, OPTION_RETENTION_ARCHIVE, 1);
optionSetTest($oOption, OPTION_RETENTION_ARCHIVE_TYPE, BACKUP_TYPE_FULL);
configLoadExpect($oOption, OP_BACKUP);
optionTestExpect(OPTION_RETENTION_ARCHIVE, 1);
optionTestExpect(OPTION_RETENTION_ARCHIVE_TYPE, BACKUP_TYPE_FULL);
}
if (BackRestTestCommon_Run(++$iRun, OP_RESTORE . ' invalid value ' . OPTION_RESTORE_RECOVERY_SETTING))
{
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_RESTORE_RECOVERY_SETTING, '=');
configLoadExpect($oOption, OP_RESTORE, ERROR_OPTION_INVALID_PAIR, '=', OPTION_RESTORE_RECOVERY_SETTING);
}
if (BackRestTestCommon_Run(++$iRun, OP_RESTORE . ' invalid value ' . OPTION_RESTORE_RECOVERY_SETTING))
{
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_RESTORE_RECOVERY_SETTING, '=' . BOGUS);
configLoadExpect($oOption, OP_RESTORE, ERROR_OPTION_INVALID_PAIR, '=' . BOGUS, OPTION_RESTORE_RECOVERY_SETTING);
}
if (BackRestTestCommon_Run(++$iRun, OP_RESTORE . ' invalid value ' . OPTION_RESTORE_RECOVERY_SETTING))
{
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_RESTORE_RECOVERY_SETTING, BOGUS . '=');
configLoadExpect($oOption, OP_RESTORE, ERROR_OPTION_INVALID_PAIR, BOGUS . '=', OPTION_RESTORE_RECOVERY_SETTING);
}
if (BackRestTestCommon_Run(++$iRun, OP_RESTORE . ' valid value ' . OPTION_RESTORE_RECOVERY_SETTING))
{
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_RESTORE_RECOVERY_SETTING, 'primary-conn-info=db.domain.net');
configLoadExpect($oOption, OP_RESTORE);
optionTestExpect(OPTION_RESTORE_RECOVERY_SETTING, 'db.domain.net', 'primary-conn-info');
}
if (BackRestTestCommon_Run(++$iRun, OP_BACKUP . ' valid value ' . OPTION_COMMAND_PSQL))
{
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_DB_PATH, '/db');
optionSetTest($oOption, OPTION_COMMAND_PSQL, '/psql -X %option%');
optionSetTest($oOption, OPTION_COMMAND_PSQL_OPTION, '--port 5432');
configLoadExpect($oOption, OP_BACKUP);
optionTestExpect(OPTION_COMMAND_PSQL, '/psql -X --port 5432');
}
if (BackRestTestCommon_Run(++$iRun, OP_BACKUP . ' default value ' . OPTION_COMMAND_REMOTE))
{
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_DB_PATH, '/db');
optionSetTest($oOption, OPTION_COMMAND_PSQL, '/psql -X %option%');
optionSetTest($oOption, OPTION_COMMAND_PSQL_OPTION, '--port 5432');
configLoadExpect($oOption, OP_BACKUP);
optionTestExpect(OPTION_COMMAND_REMOTE, dirname(abs_path($0)) . '/pg_backrest_remote.pl');
}
}
#-------------------------------------------------------------------------------------------------------------------------------
# Test mixed command-line/config
#-------------------------------------------------------------------------------------------------------------------------------
if ($strTest eq 'all' || $strTest eq 'config')
{
$iRun = 0;
&log(INFO, "Config module\n");
BackRestTestCommon_Create();
if (BackRestTestCommon_Run(++$iRun, 'set and negate option ' . OPTION_CONFIG))
{
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_DB_PATH, '/db');
optionSetTest($oOption, OPTION_CONFIG, '/dude/dude.conf');
optionSetBoolTest($oOption, OPTION_CONFIG, false);
configLoadExpect($oOption, OP_BACKUP, ERROR_OPTION_NEGATE, OPTION_CONFIG);
}
if (BackRestTestCommon_Run(++$iRun, 'option ' . OPTION_CONFIG))
{
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_DB_PATH, '/db');
optionSetBoolTest($oOption, OPTION_CONFIG, false);
configLoadExpect($oOption, OP_BACKUP);
optionTestExpect(OPTION_CONFIG);
}
if (BackRestTestCommon_Run(++$iRun, 'default option ' . OPTION_CONFIG))
{
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_DB_PATH, '/db');
configLoadExpect($oOption, OP_BACKUP);
optionTestExpect(OPTION_CONFIG, OPTION_DEFAULT_CONFIG);
}
if (BackRestTestCommon_Run(++$iRun, 'config file is a path'))
{
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_DB_PATH, '/db');
optionSetTest($oOption, OPTION_CONFIG, BackRestTestCommon_TestPathGet());
configLoadExpect($oOption, OP_BACKUP, ERROR_FILE_INVALID, BackRestTestCommon_TestPathGet());
}
if (BackRestTestCommon_Run(++$iRun, 'load from config stanza section - option ' . OPTION_THREAD_MAX))
{
$oConfig = {};
$$oConfig{"$strStanza:" . &OP_BACKUP}{&OPTION_THREAD_MAX} = 2;
ini_save($strConfigFile, $oConfig);
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_DB_PATH, '/db');
optionSetTest($oOption, OPTION_CONFIG, $strConfigFile);
configLoadExpect($oOption, OP_BACKUP);
optionTestExpect(OPTION_THREAD_MAX, 2);
}
if (BackRestTestCommon_Run(++$iRun, 'load from config stanza inherited section - option ' . OPTION_THREAD_MAX))
{
$oConfig = {};
$$oConfig{"$strStanza:" . &CONFIG_SECTION_GENERAL}{&OPTION_THREAD_MAX} = 3;
ini_save($strConfigFile, $oConfig);
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_DB_PATH, '/db');
optionSetTest($oOption, OPTION_CONFIG, $strConfigFile);
configLoadExpect($oOption, OP_BACKUP);
optionTestExpect(OPTION_THREAD_MAX, 3);
}
if (BackRestTestCommon_Run(++$iRun, 'load from config global section - option ' . OPTION_THREAD_MAX))
{
$oConfig = {};
$$oConfig{&CONFIG_GLOBAL . ':' . &OP_BACKUP}{&OPTION_THREAD_MAX} = 2;
ini_save($strConfigFile, $oConfig);
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_DB_PATH, '/db');
optionSetTest($oOption, OPTION_CONFIG, $strConfigFile);
configLoadExpect($oOption, OP_BACKUP);
optionTestExpect(OPTION_THREAD_MAX, 2);
}
if (BackRestTestCommon_Run(++$iRun, 'load from config global inherited section - option ' . OPTION_THREAD_MAX))
{
$oConfig = {};
$$oConfig{&CONFIG_GLOBAL . ':' . &CONFIG_SECTION_GENERAL}{&OPTION_THREAD_MAX} = 5;
ini_save($strConfigFile, $oConfig);
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_DB_PATH, '/db');
optionSetTest($oOption, OPTION_CONFIG, $strConfigFile);
configLoadExpect($oOption, OP_BACKUP);
optionTestExpect(OPTION_THREAD_MAX, 5);
}
if (BackRestTestCommon_Run(++$iRun, 'default - option ' . OPTION_THREAD_MAX))
{
$oConfig = {};
ini_save($strConfigFile, $oConfig);
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_DB_PATH, '/db');
optionSetTest($oOption, OPTION_CONFIG, $strConfigFile);
configLoadExpect($oOption, OP_BACKUP);
optionTestExpect(OPTION_THREAD_MAX, 1);
}
if (BackRestTestCommon_Run(++$iRun, 'command-line override - option ' . OPTION_THREAD_MAX))
{
$oConfig = {};
$$oConfig{&CONFIG_GLOBAL . ':' . &CONFIG_SECTION_GENERAL}{&OPTION_THREAD_MAX} = 9;
ini_save($strConfigFile, $oConfig);
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_DB_PATH, '/db');
optionSetTest($oOption, OPTION_THREAD_MAX, 7);
optionSetTest($oOption, OPTION_CONFIG, $strConfigFile);
configLoadExpect($oOption, OP_BACKUP);
optionTestExpect(OPTION_THREAD_MAX, 7);
}
if (BackRestTestCommon_Run(++$iRun, 'invalid boolean - option ' . OPTION_HARDLINK))
{
$oConfig = {};
$$oConfig{&CONFIG_GLOBAL . ':' . &OP_BACKUP}{&OPTION_HARDLINK} = 'Y';
ini_save($strConfigFile, $oConfig);
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_DB_PATH, '/db');
optionSetTest($oOption, OPTION_CONFIG, $strConfigFile);
configLoadExpect($oOption, OP_BACKUP, ERROR_OPTION_INVALID_VALUE, 'Y', OPTION_HARDLINK);
}
if (BackRestTestCommon_Run(++$iRun, 'invalid value - option ' . OPTION_LOG_LEVEL_CONSOLE))
{
$oConfig = {};
$$oConfig{&CONFIG_GLOBAL . ':' . &CONFIG_SECTION_LOG}{&OPTION_LOG_LEVEL_CONSOLE} = BOGUS;
ini_save($strConfigFile, $oConfig);
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_DB_PATH, '/db');
optionSetTest($oOption, OPTION_CONFIG, $strConfigFile);
configLoadExpect($oOption, OP_BACKUP, ERROR_OPTION_INVALID_VALUE, BOGUS, OPTION_LOG_LEVEL_CONSOLE);
}
if (BackRestTestCommon_Run(++$iRun, 'valid value - option ' . OPTION_LOG_LEVEL_CONSOLE))
{
$oConfig = {};
$$oConfig{&CONFIG_GLOBAL . ':' . &CONFIG_SECTION_LOG}{&OPTION_LOG_LEVEL_CONSOLE} = lc(INFO);
ini_save($strConfigFile, $oConfig);
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_CONFIG, $strConfigFile);
configLoadExpect($oOption, OP_RESTORE);
}
if (BackRestTestCommon_Run(++$iRun, 'archive-push - option ' . OPTION_LOG_LEVEL_CONSOLE))
{
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_CONFIG, $strConfigFile);
configLoadExpect($oOption, OP_ARCHIVE_PUSH);
}
if (BackRestTestCommon_Run(++$iRun, OP_EXPIRE . ' ' . OPTION_RETENTION_FULL))
{
$oConfig = {};
$$oConfig{&CONFIG_GLOBAL . ':' . &CONFIG_SECTION_EXPIRE}{&OPTION_RETENTION_FULL} = 2;
ini_save($strConfigFile, $oConfig);
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_CONFIG, $strConfigFile);
configLoadExpect($oOption, OP_EXPIRE);
optionTestExpect(OPTION_RETENTION_FULL, 2);
}
if (BackRestTestCommon_Run(++$iRun, OP_BACKUP . ' option ' . OPTION_COMPRESS))
{
$oConfig = {};
$$oConfig{&CONFIG_GLOBAL . ':' . &CONFIG_SECTION_BACKUP}{&OPTION_COMPRESS} = 'n';
ini_save($strConfigFile, $oConfig);
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_DB_PATH, '/db');
optionSetTest($oOption, OPTION_CONFIG, $strConfigFile);
configLoadExpect($oOption, OP_BACKUP);
optionTestExpect(OPTION_COMPRESS, false);
}
if (BackRestTestCommon_Run(++$iRun, OP_RESTORE . ' option ' . OPTION_RESTORE_RECOVERY_SETTING))
{
$oConfig = {};
$$oConfig{&CONFIG_GLOBAL . ':' . &CONFIG_SECTION_RESTORE_RECOVERY_SETTING}{'archive-command'} = '/path/to/pg_backrest.pl';
ini_save($strConfigFile, $oConfig);
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_CONFIG, $strConfigFile);
configLoadExpect($oOption, OP_RESTORE);
optionTestExpect(OPTION_RESTORE_RECOVERY_SETTING, '/path/to/pg_backrest.pl', 'archive-command');
}
if (BackRestTestCommon_Run(++$iRun, OP_BACKUP . ' option ' . OPTION_DB_PATH))
{
$oConfig = {};
$$oConfig{$strStanza}{&OPTION_DB_PATH} = '/path/to/db';
ini_save($strConfigFile, $oConfig);
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_CONFIG, $strConfigFile);
configLoadExpect($oOption, OP_BACKUP);
optionTestExpect(OPTION_DB_PATH, '/path/to/db');
}
if (BackRestTestCommon_Run(++$iRun, OP_ARCHIVE_PUSH . ' option ' . OPTION_DB_PATH))
{
$oConfig = {};
$$oConfig{$strStanza}{&OPTION_DB_PATH} = '/path/to/db';
ini_save($strConfigFile, $oConfig);
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_CONFIG, $strConfigFile);
configLoadExpect($oOption, OP_ARCHIVE_PUSH);
optionTestExpect(OPTION_DB_PATH, '/path/to/db');
}
if (BackRestTestCommon_Run(++$iRun, OP_BACKUP . ' option ' . OPTION_REPO_PATH))
{
$oConfig = {};
$$oConfig{&CONFIG_GLOBAL . ':' . &CONFIG_SECTION_GENERAL}{&OPTION_REPO_PATH} = '/repo';
ini_save($strConfigFile, $oConfig);
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_DB_PATH, '/db');
optionSetTest($oOption, OPTION_CONFIG, $strConfigFile);
configLoadExpect($oOption, OP_BACKUP);
optionTestExpect(OPTION_REPO_PATH, '/repo');
}
if (BackRestTestCommon_Run(++$iRun, OP_BACKUP . ' valid value ' . OPTION_COMMAND_PSQL))
{
$oConfig = {};
$$oConfig{&CONFIG_GLOBAL . ':' . &CONFIG_SECTION_COMMAND}{&OPTION_COMMAND_PSQL} = '/psql -X %option%';
$$oConfig{&CONFIG_GLOBAL . ':' . &CONFIG_SECTION_COMMAND}{&OPTION_COMMAND_PSQL_OPTION} = '--port=5432';
ini_save($strConfigFile, $oConfig);
optionSetTest($oOption, OPTION_STANZA, $strStanza);
optionSetTest($oOption, OPTION_DB_PATH, '/db');
optionSetTest($oOption, OPTION_CONFIG, $strConfigFile);
configLoadExpect($oOption, OP_BACKUP);
optionTestExpect(OPTION_COMMAND_PSQL, '/psql -X --port=5432');
}
# Cleanup
if (BackRestTestCommon_Cleanup())
{
&log(INFO, 'cleanup');
BackRestTestCommon_Drop(true);
}
}
}
1;

View File

@@ -8,17 +8,20 @@ package BackRestTest::FileTest;
# Perl includes
####################################################################################################################################
use strict;
use warnings;
use Carp;
use warnings FATAL => qw(all);
use Carp qw(confess);
use File::Basename;
use Cwd 'abs_path';
use File::stat;
use Fcntl ':mode';
use Scalar::Util 'blessed';
use Time::HiRes qw(gettimeofday usleep);
use POSIX qw(ceil);
use lib dirname($0) . '/../lib';
use BackRest::Utility;
use BackRest::Config;
use BackRest::File;
use BackRest::Remote;
@@ -87,13 +90,26 @@ sub BackRestTestFile_Test
&log(INFO, 'FILE MODULE ********************************************************************');
#-------------------------------------------------------------------------------------------------------------------------------
# Create remote
# Create remotes
#-------------------------------------------------------------------------------------------------------------------------------
my $oRemote = BackRest::Remote->new
(
strHost => $strHost,
strUser => $strUser,
strCommand => BackRestTestCommon_CommandRemoteGet()
$strHost, # Host
$strUser, # User
BackRestTestCommon_CommandRemoteGet(), # Command
OPTION_DEFAULT_BUFFER_SIZE, # Buffer size
OPTION_DEFAULT_COMPRESS_LEVEL, # Compress level
OPTION_DEFAULT_COMPRESS_LEVEL_NETWORK, # Compress network level
);
my $oLocal = new BackRest::Remote
(
undef, # Host
undef, # User
undef, # Command
OPTION_DEFAULT_BUFFER_SIZE, # Buffer size
OPTION_DEFAULT_COMPRESS_LEVEL, # Compress level
OPTION_DEFAULT_COMPRESS_LEVEL_NETWORK, # Compress network level
);
#-------------------------------------------------------------------------------------------------------------------------------
@@ -109,25 +125,25 @@ sub BackRestTestFile_Test
for (my $bRemote = 0; $bRemote <= 1; $bRemote++)
{
# Create the file object
my $oFile = (BackRest::File->new
my $oFile = new BackRest::File
(
strStanza => $strStanza,
strBackupPath => $strTestPath,
strRemote => $bRemote ? 'backup' : undef,
oRemote => $bRemote ? $oRemote : undef
))->clone();
$strStanza,
$strTestPath,
$bRemote ? 'backup' : undef,
$bRemote ? $oRemote : $oLocal
);
# Loop through error
for (my $bError = 0; $bError <= 1; $bError++)
{
# Loop through permission (permission will be set on true)
for (my $bPermission = 0; $bPermission <= 1; $bPermission++)
# Loop through mode (mode will be set on true)
for (my $bMode = 0; $bMode <= 1; $bMode++)
{
my $strPathType = PATH_BACKUP_CLUSTER;
# Increment the run, log, and decide whether this unit test should be run
if (!BackRestTestCommon_Run(++$iRun,
"rmt ${bRemote}, err ${bError}, prm ${bPermission}")) {next}
"rmt ${bRemote}, err ${bError}, mode ${bMode}")) {next}
# Setup test directory
BackRestTestFile_Setup($bError);
@@ -136,12 +152,12 @@ sub BackRestTestFile_Test
mkdir("${strTestPath}/backup/db") or confess 'Unable to create test/backup/db directory';
my $strPath = 'path';
my $strPermission;
my $strMode;
# If permission then set one (other than the default)
if ($bPermission)
# If mode then set one (other than the default)
if ($bMode)
{
$strPermission = '0700';
$strMode = '0700';
}
# If not exists then set the path to something bogus
@@ -156,7 +172,7 @@ sub BackRestTestFile_Test
eval
{
$oFile->path_create($strPathType, $strPath, $strPermission);
$oFile->path_create($strPathType, $strPath, $strMode);
};
# Check for errors
@@ -184,7 +200,7 @@ sub BackRestTestFile_Test
confess 'path was not created';
}
# Check that the permissions were set correctly
# Check that the mode was set correctly
my $oStat = lstat($strPathCheck);
if (!defined($oStat))
@@ -192,11 +208,11 @@ sub BackRestTestFile_Test
confess "unable to stat ${strPathCheck}";
}
if ($bPermission)
if ($bMode)
{
if ($strPermission ne sprintf('%04o', S_IMODE($oStat->mode)))
if ($strMode ne sprintf('%04o', S_IMODE($oStat->mode)))
{
confess "permissions were not set to {$strPermission}";
confess "mode were not set to {$strMode}";
}
}
}
@@ -217,13 +233,13 @@ sub BackRestTestFile_Test
for (my $bRemote = 0; $bRemote <= 0; $bRemote++)
{
# Create the file object
my $oFile = BackRest::File->new
my $oFile = (new BackRest::File
(
strStanza => $strStanza,
strBackupPath => $strTestPath,
strRemote => $bRemote ? 'backup' : undef,
oRemote => $bRemote ? $oRemote : undef
);
$strStanza,
$strTestPath,
$bRemote ? 'backup' : undef,
$bRemote ? $oRemote : $oLocal
))->clone(1);
# Loop through source exists
for (my $bSourceExists = 0; $bSourceExists <= 1; $bSourceExists++)
@@ -316,12 +332,12 @@ sub BackRestTestFile_Test
for (my $bRemote = 0; $bRemote <= 0; $bRemote++)
{
# Create the file object
my $oFile = BackRest::File->new
my $oFile = new BackRest::File
(
strStanza => $strStanza,
strBackupPath => $strTestPath,
strRemote => $bRemote ? 'backup' : undef,
oRemote => $bRemote ? $oRemote : undef
$strStanza,
$strTestPath,
$bRemote ? 'backup' : undef,
$bRemote ? $oRemote : $oLocal
);
# Loop through exists
@@ -337,6 +353,7 @@ sub BackRestTestFile_Test
my $strFile = "${strTestPath}/test.txt";
my $strSourceHash;
my $iSourceSize;
if ($bError)
{
@@ -345,7 +362,7 @@ sub BackRestTestFile_Test
elsif ($bExists)
{
system("echo 'TESTDATA' > ${strFile}");
$strSourceHash = $oFile->hash(PATH_BACKUP_ABSOLUTE, $strFile);
($strSourceHash, $iSourceSize) = $oFile->hash_size(PATH_BACKUP_ABSOLUTE, $strFile);
}
# Execute in eval in case of error
@@ -383,7 +400,7 @@ sub BackRestTestFile_Test
system("gzip -d ${strDestinationFile}") == 0 or die "could not decompress ${strDestinationFile}";
my $strDestinationHash = $oFile->hash(PATH_BACKUP_ABSOLUTE, $strFile);
my ($strDestinationHash, $iDestinationSize) = $oFile->hash_size(PATH_BACKUP_ABSOLUTE, $strFile);
if ($strSourceHash ne $strDestinationHash)
{
@@ -394,6 +411,63 @@ sub BackRestTestFile_Test
}
}
#-------------------------------------------------------------------------------------------------------------------------------
# Test wait()
#-------------------------------------------------------------------------------------------------------------------------------
if ($strTest eq 'all' || $strTest eq 'wait')
{
$iRun = 0;
&log(INFO, '--------------------------------------------------------------------------------');
&log(INFO, "Test File->wait()\n");
for (my $bRemote = 0; $bRemote <= 1; $bRemote++)
{
# Create the file object
my $oFile = new BackRest::File
(
$strStanza,
$strTestPath,
$bRemote ? 'db' : undef,
$bRemote ? $oRemote : $oLocal
);
my $lTimeBegin = gettimeofday();
if (!BackRestTestCommon_Run(++$iRun,
"rmt ${bRemote}, begin ${lTimeBegin}")) {next}
# If there is not enough time to complete the test then sleep
if (ceil($lTimeBegin) - $lTimeBegin < .250)
{
my $lSleepMs = ceil(((int($lTimeBegin) + 1) - $lTimeBegin) * 1000);
usleep($lSleepMs * 1000);
&log(DEBUG, "slept ${lSleepMs}ms: begin ${lTimeBegin}, end " . gettimeofday());
$lTimeBegin = gettimeofday();
}
# Run the test
my $lTimeBeginCheck = $oFile->wait(PATH_DB_ABSOLUTE);
&log(DEBUG, "begin ${lTimeBegin}, check ${lTimeBeginCheck}, end " . time());
# Current time should have advanced by 1 second
if (time() == int($lTimeBegin))
{
confess "time was not advanced by 1 second";
}
# lTimeBegin and lTimeBeginCheck should be equal
if (int($lTimeBegin) != $lTimeBeginCheck)
{
confess 'time begin ' || int($lTimeBegin) || "and check ${lTimeBeginCheck} should be equal";
}
}
}
#-------------------------------------------------------------------------------------------------------------------------------
# Test manifest()
#-------------------------------------------------------------------------------------------------------------------------------
@@ -419,12 +493,12 @@ sub BackRestTestFile_Test
for (my $bRemote = 0; $bRemote <= 1; $bRemote++)
{
# Create the file object
my $oFile = BackRest::File->new
my $oFile = new BackRest::File
(
strStanza => $strStanza,
strBackupPath => $strTestPath,
strRemote => $bRemote ? 'backup' : undef,
oRemote => $bRemote ? $oRemote : undef
$strStanza,
$strTestPath,
$bRemote ? 'backup' : undef,
$bRemote ? $oRemote : $oLocal
);
for (my $bError = 0; $bError <= 1; $bError++)
@@ -527,8 +601,8 @@ sub BackRestTestFile_Test
$oManifestHash{name}{"${strName}"}{user} : '') . ',' .
(defined($oManifestHash{name}{"${strName}"}{group}) ?
$oManifestHash{name}{"${strName}"}{group} : '') . ',' .
(defined($oManifestHash{name}{"${strName}"}{permission}) ?
$oManifestHash{name}{"${strName}"}{permission} : '') . ',' .
(defined($oManifestHash{name}{"${strName}"}{mode}) ?
$oManifestHash{name}{"${strName}"}{mode} : '') . ',' .
(defined($oManifestHash{name}{"${strName}"}{modification_time}) ?
$oManifestHash{name}{"${strName}"}{modification_time} : '') . ',' .
(defined($oManifestHash{name}{"${strName}"}{inode}) ?
@@ -561,12 +635,12 @@ sub BackRestTestFile_Test
for (my $bRemote = false; $bRemote <= true; $bRemote++)
{
# Create the file object
my $oFile = BackRest::File->new
my $oFile = new BackRest::File
(
strStanza => $strStanza,
strBackupPath => $strTestPath,
strRemote => $bRemote ? 'backup' : undef,
oRemote => $bRemote ? $oRemote : undef
$strStanza,
$strTestPath,
$bRemote ? 'backup' : undef,
$bRemote ? $oRemote : $oLocal
);
for (my $bSort = false; $bSort <= true; $bSort++)
@@ -687,12 +761,12 @@ sub BackRestTestFile_Test
for (my $bRemote = 0; $bRemote <= 1; $bRemote++)
{
my $oFile = BackRest::File->new
my $oFile = new BackRest::File
(
strStanza => $strStanza,
strBackupPath => $strTestPath,
strRemote => $bRemote ? 'backup' : undef,
oRemote => $bRemote ? $oRemote : undef
$strStanza,
$strTestPath,
$bRemote ? 'backup' : undef,
$bRemote ? $oRemote : $oLocal
);
# Loop through exists
@@ -788,24 +862,27 @@ sub BackRestTestFile_Test
&log(INFO, '--------------------------------------------------------------------------------');
&log(INFO, "test File->hash()\n");
for (my $bRemote = 0; $bRemote <= 1; $bRemote++)
for (my $bRemote = false; $bRemote <= true; $bRemote++)
{
my $oFile = BackRest::File->new
my $oFile = new BackRest::File
(
strStanza => $strStanza,
strBackupPath => $strTestPath,
strRemote => $bRemote ? 'backup' : undef,
oRemote => $bRemote ? $oRemote : undef
$strStanza,
$strTestPath,
$bRemote ? 'backup' : undef,
$bRemote ? $oRemote : $oLocal
);
# Loop through error
for (my $bError = 0; $bError <= 1; $bError++)
for (my $bError = false; $bError <= true; $bError++)
{
# Loop through exists
for (my $bExists = 0; $bExists <= 1; $bExists++)
for (my $bExists = false; $bExists <= true; $bExists++)
{
# Loop through exists
for (my $bCompressed = false; $bCompressed <= true; $bCompressed++)
{
if (!BackRestTestCommon_Run(++$iRun,
"rmt ${bRemote}, err ${bError}, exists ${bExists}")) {next}
"rmt ${bRemote}, err ${bError}, exists ${bExists}, cmp ${bCompressed}")) {next}
# Setup test directory
BackRestTestFile_Setup($bError);
@@ -823,15 +900,22 @@ sub BackRestTestFile_Test
else
{
system("echo 'TESTDATA' > ${strFile}");
if ($bCompressed && !$bRemote)
{
$oFile->compress(PATH_BACKUP_ABSOLUTE, $strFile);
$strFile = $strFile . '.gz';
}
}
# Execute in eval in case of error
my $strHash;
my $iSize;
my $bErrorExpected = !$bExists || $bError || $bRemote;
eval
{
$strHash = $oFile->hash(PATH_BACKUP_ABSOLUTE, $strFile)
($strHash, $iSize) = $oFile->hash_size(PATH_BACKUP_ABSOLUTE, $strFile, $bCompressed)
};
if ($@)
@@ -855,6 +939,7 @@ sub BackRestTestFile_Test
}
}
}
}
}
}
@@ -870,12 +955,12 @@ sub BackRestTestFile_Test
for (my $bRemote = 0; $bRemote <= 1; $bRemote++)
{
my $oFile = BackRest::File->new
my $oFile = new BackRest::File
(
strStanza => $strStanza,
strBackupPath => $strTestPath,
strRemote => $bRemote ? 'backup' : undef,
oRemote => $bRemote ? $oRemote : undef
$strStanza,
$strTestPath,
$bRemote ? 'backup' : undef,
$bRemote ? $oRemote : $oLocal
);
# Loop through exists
@@ -952,6 +1037,9 @@ sub BackRestTestFile_Test
{
$iRun = 0;
# Loop through small/large
for (my $bLarge = false; $bLarge <= 2; $bLarge++)
{
# Loop through backup local vs remote
for (my $bBackupRemote = 0; $bBackupRemote <= 1; $bBackupRemote++)
{
@@ -968,34 +1056,34 @@ sub BackRestTestFile_Test
my $strRemote = $bBackupRemote ? 'backup' : $bDbRemote ? 'db' : undef;
# Create the file object
my $oFile = BackRest::File->new
my $oFile = new BackRest::File
(
strStanza => $strStanza,
strBackupPath => $strTestPath,
strRemote => $strRemote,
oRemote => defined($strRemote) ? $oRemote : undef
$strStanza,
$strTestPath,
$strRemote,
defined($strRemote) ? $oRemote : $oLocal
);
# Loop through source compression
for (my $bSourceCompressed = 0; $bSourceCompressed <= 1; $bSourceCompressed++)
{
# Loop through destination compression
for (my $bDestinationCompress = 0; $bDestinationCompress <= 1; $bDestinationCompress++)
{
# Loop through source path types
for (my $bSourcePathType = 0; $bSourcePathType <= 1; $bSourcePathType++)
{
# Loop through destination path types
for (my $bDestinationPathType = 0; $bDestinationPathType <= 1; $bDestinationPathType++)
{
# Loop through source ignore/require
for (my $bSourceIgnoreMissing = 0; $bSourceIgnoreMissing <= 1; $bSourceIgnoreMissing++)
{
# Loop through source missing/present
for (my $bSourceMissing = 0; $bSourceMissing <= 1; $bSourceMissing++)
for (my $bSourceMissing = 0; $bSourceMissing <= !$bLarge; $bSourceMissing++)
{
# Loop through small/large
for (my $bLarge = false; $bLarge <= defined($strRemote) && !$bSourceMissing; $bLarge++)
# Loop through source ignore/require
for (my $bSourceIgnoreMissing = 0; $bSourceIgnoreMissing <= !$bLarge; $bSourceIgnoreMissing++)
{
# Loop through checksum append
for (my $bChecksumAppend = 0; $bChecksumAppend <= !$bLarge; $bChecksumAppend++)
{
# Loop through source compression
for (my $bSourceCompressed = 0; $bSourceCompressed <= !$bSourceMissing; $bSourceCompressed++)
{
# Loop through destination compression
for (my $bDestinationCompress = 0; $bDestinationCompress <= !$bSourceMissing; $bDestinationCompress++)
{
my $strSourcePathType = $bSourcePathType ? PATH_DB_ABSOLUTE : PATH_BACKUP_ABSOLUTE;
my $strSourcePath = $bSourcePathType ? 'db' : 'backup';
@@ -1004,16 +1092,16 @@ sub BackRestTestFile_Test
my $strDestinationPath = $bDestinationPathType ? 'db' : 'backup';
if (!BackRestTestCommon_Run(++$iRun,
'rmt ' .
"lrg ${bLarge}, rmt " .
(defined($strRemote) && ($strRemote eq $strSourcePath ||
$strRemote eq $strDestinationPath) ? 1 : 0) .
", lrg ${bLarge}, " .
'srcpth ' . (defined($strRemote) && $strRemote eq $strSourcePath ? 'rmt' : 'lcl') .
":${strSourcePath}, srccmp $bSourceCompressed, srcmiss ${bSourceMissing}, " .
"srcignmiss ${bSourceIgnoreMissing}, " .
', srcpth ' . (defined($strRemote) && $strRemote eq $strSourcePath ? 'rmt' : 'lcl') .
":${strSourcePath}, srcmiss ${bSourceMissing}, " .
"srcignmiss ${bSourceIgnoreMissing}, srccmp $bSourceCompressed, " .
'dstpth ' .
(defined($strRemote) && $strRemote eq $strDestinationPath ? 'rmt' : 'lcl') .
":${strDestinationPath}, dstcmp $bDestinationCompress")) {next}
":${strDestinationPath}, chkapp ${bChecksumAppend}, " .
"dstcmp $bDestinationCompress")) {next}
# Setup test directory
BackRestTestFile_Setup(false);
@@ -1023,8 +1111,12 @@ sub BackRestTestFile_Test
my $strSourceFile = "${strTestPath}/${strSourcePath}/test-source";
my $strDestinationFile = "${strTestPath}/${strDestinationPath}/test-destination";
my $strCopyHash;
my $iCopySize;
# Create the compressed or uncompressed test file
my $strSourceHash;
my $iSourceSize;
if (!$bSourceMissing)
{
@@ -1033,7 +1125,7 @@ sub BackRestTestFile_Test
$strSourceFile .= '.bin';
$strDestinationFile .= '.bin';
BackRestTestCommon_Execute('cp ' . BackRestTestCommon_DataPathGet() . "/test.archive.bin ${strSourceFile}");
BackRestTestCommon_Execute('cp ' . BackRestTestCommon_DataPathGet() . "/test.archive${bLarge}.bin ${strSourceFile}");
}
else
{
@@ -1043,7 +1135,21 @@ sub BackRestTestFile_Test
system("echo 'TESTDATA' > ${strSourceFile}");
}
$strSourceHash = $oFile->hash(PATH_ABSOLUTE, $strSourceFile);
if ($bLarge == 1)
{
$strSourceHash = 'c2e63b6a49d53a53d6df1aa6b70c7c16747ca099';
$iSourceSize = 16777216;
}
elsif ($bLarge == 2)
{
$strSourceHash = '1c7e00fd09b9dd11fc2966590b3e3274645dd031';
$iSourceSize = 16777216;
}
else
{
$strSourceHash = '06364afe79d801433188262478a76d19777ef351';
$iSourceSize = 9;
}
if ($bSourceCompressed)
{
@@ -1062,11 +1168,12 @@ sub BackRestTestFile_Test
eval
{
$bReturn = $oFile->copy($strSourcePathType, $strSourceFile,
$strDestinationPathType, $strDestinationFile,
$bSourceCompressed, $bDestinationCompress,
$bSourceIgnoreMissing, undef,
'0700');
($bReturn, $strCopyHash, $iCopySize) =
$oFile->copy($strSourcePathType, $strSourceFile,
$strDestinationPathType, $strDestinationFile,
$bSourceCompressed, $bDestinationCompress,
$bSourceIgnoreMissing, undef, '0700', false, undef, undef,
$bChecksumAppend);
};
# Check for errors after copy
@@ -1109,6 +1216,24 @@ sub BackRestTestFile_Test
confess 'expected source file missing error';
}
if (!defined($strCopyHash))
{
confess 'copy hash must be defined';
}
if ($bChecksumAppend)
{
if ($bDestinationCompress)
{
$strDestinationFile =
substr($strDestinationFile, 0, length($strDestinationFile) -3) . "-${strSourceHash}.gz";
}
else
{
$strDestinationFile .= '-' . $strSourceHash;
}
}
unless (-e $strDestinationFile)
{
confess "could not find destination file ${strDestinationFile}";
@@ -1124,12 +1249,18 @@ sub BackRestTestFile_Test
or die "could not decompress ${strDestinationFile}";
}
my $strDestinationHash = $oFile->hash(PATH_ABSOLUTE, $strDestinationTest);
my ($strDestinationHash, $iDestinationSize) = $oFile->hash_size(PATH_ABSOLUTE, $strDestinationTest);
if ($strSourceHash ne $strDestinationHash)
if ($strSourceHash ne $strDestinationHash || $strSourceHash ne $strCopyHash)
{
confess "source ${strSourceHash} and destination ${strDestinationHash} file hashes do not match";
confess "source ${strSourceHash}, copy ${strCopyHash} and destination ${strDestinationHash} file hashes do not match";
}
if ($iSourceSize != $iDestinationSize || $iSourceSize != $iCopySize)
{
confess "source ${iSourceSize}, copy ${iCopySize} and destination ${iDestinationSize} sizes do not match";
}
}
}
}
}

View File

@@ -1,6 +1,6 @@
#!/usr/bin/perl
####################################################################################################################################
# BackupTest.pl - Unit Tests for BackRest::File
# UtilityTest.pl - Unit Tests for BackRest::Utility
####################################################################################################################################
package BackRestTest::UtilityTest;
@@ -8,13 +8,14 @@ package BackRestTest::UtilityTest;
# Perl includes
####################################################################################################################################
use strict;
use warnings;
use Carp;
use warnings FATAL => qw(all);
use Carp qw(confess);
use File::Basename;
use lib dirname($0) . '/../lib';
use BackRest::Utility;
use BackRest::Config;
use BackRest::File;
use BackRestTest::CommonTest;
@@ -22,29 +23,6 @@ use BackRestTest::CommonTest;
use Exporter qw(import);
our @EXPORT = qw(BackRestTestUtility_Test);
####################################################################################################################################
# BackRestTestUtility_Drop
####################################################################################################################################
sub BackRestTestUtility_Drop
{
# Remove the test directory
system('rm -rf ' . BackRestTestCommon_TestPathGet()) == 0
or die 'unable to remove ' . BackRestTestCommon_TestPathGet() . 'path';
}
####################################################################################################################################
# BackRestTestUtility_Create
####################################################################################################################################
sub BackRestTestUtility_Create
{
# Drop the old test directory
BackRestTestUtility_Drop();
# Create the test directory
mkdir(BackRestTestCommon_TestPathGet(), oct('0770'))
or confess 'Unable to create ' . BackRestTestCommon_TestPathGet() . ' path';
}
####################################################################################################################################
# BackRestTestUtility_Test
####################################################################################################################################
@@ -60,6 +38,19 @@ sub BackRestTestUtility_Test
# Print test banner
&log(INFO, 'UTILITY MODULE ******************************************************************');
#-------------------------------------------------------------------------------------------------------------------------------
# Create remote
#-------------------------------------------------------------------------------------------------------------------------------
my $oLocal = new BackRest::Remote
(
undef, # Host
undef, # User
undef, # Command
OPTION_DEFAULT_BUFFER_SIZE, # Buffer size
OPTION_DEFAULT_COMPRESS_LEVEL, # Compress level
OPTION_DEFAULT_COMPRESS_LEVEL_NETWORK, # Compress network level
);
#-------------------------------------------------------------------------------------------------------------------------------
# Test config
#-------------------------------------------------------------------------------------------------------------------------------
@@ -67,7 +58,14 @@ sub BackRestTestUtility_Test
{
$iRun = 0;
$bCreate = true;
my $oFile = BackRest::File->new();
my $oFile = new BackRest::File
(
undef,
undef,
undef,
$oLocal
);
&log(INFO, "Test config\n");
@@ -77,7 +75,8 @@ sub BackRestTestUtility_Test
# Create the test directory
if ($bCreate)
{
BackRestTestUtility_Create();
BackRestTestCommon_Drop();
BackRestTestCommon_Create();
$bCreate = false;
}
@@ -96,18 +95,18 @@ sub BackRestTestUtility_Test
# Save the test config
my $strFile = "${strTestPath}/config.cfg";
config_save($strFile, \%oConfig);
ini_save($strFile, \%oConfig);
my $strConfigHash = $oFile->hash(PATH_ABSOLUTE, $strFile);
# Reload the test config
my %oConfigTest;
config_load($strFile, \%oConfigTest);
ini_load($strFile, \%oConfigTest);
# Resave the test config and compare hashes
my $strFileTest = "${strTestPath}/config-test.cfg";
config_save($strFileTest, \%oConfigTest);
ini_save($strFileTest, \%oConfigTest);
my $strConfigTestHash = $oFile->hash(PATH_ABSOLUTE, $strFileTest);
@@ -119,7 +118,7 @@ sub BackRestTestUtility_Test
if (BackRestTestCommon_Cleanup())
{
&log(INFO, 'cleanup');
BackRestTestUtility_Drop();
BackRestTestCommon_Drop();
}
}
}

View File

@@ -13,7 +13,8 @@ use Carp;
use File::Basename;
use Getopt::Long;
use Cwd 'abs_path';
use Cwd;
use Pod::Usage;
#use Test::More;
use lib dirname($0) . '/../lib';
use BackRest::Utility;
@@ -21,30 +22,89 @@ use BackRest::Utility;
use lib dirname($0) . '/lib';
use BackRestTest::CommonTest;
use BackRestTest::UtilityTest;
use BackRestTest::ConfigTest;
use BackRestTest::FileTest;
use BackRestTest::BackupTest;
####################################################################################################################################
# Usage
####################################################################################################################################
=head1 NAME
test.pl - Simple Postgres Backup and Restore Unit Tests
=head1 SYNOPSIS
test.pl [options]
Test Options:
--module test module to execute:
--module-test execute the specified test in a module
--module-test-run execute only the specified test run
--thread-max max threads to run for backup/restore (default 4)
--dry-run show only the tests that would be executed but don't execute them
--no-cleanup don't cleaup after the last test is complete - useful for debugging
--infinite repeat selected tests forever
Configuration Options:
--psql-bin path to the psql executables (e.g. /usr/lib/postgresql/9.3/bin/)
--test-path path where tests are executed (defaults to ./test)
--log-level log level to use for tests (defaults to INFO)
--quiet, -q equivalent to --log-level=off
General Options:
--version display version and exit
--help display usage and exit
=cut
####################################################################################################################################
# Command line parameters
####################################################################################################################################
my $strLogLevel = 'off'; # Log level for tests
my $strLogLevel = 'info'; # Log level for tests
my $strModule = 'all';
my $strModuleTest = 'all';
my $iModuleTestRun = undef;
my $iThreadMax = 1;
my $bDryRun = false;
my $bNoCleanup = false;
my $strPgSqlBin;
my $strTestPath;
my $bVersion = false;
my $bHelp = false;
my $bQuiet = false;
my $bInfinite = false;
GetOptions ('pgsql-bin=s' => \$strPgSqlBin,
GetOptions ('q|quiet' => \$bQuiet,
'version' => \$bVersion,
'help' => \$bHelp,
'pgsql-bin=s' => \$strPgSqlBin,
'test-path=s' => \$strTestPath,
'log-level=s' => \$strLogLevel,
'module=s' => \$strModule,
'module-test=s' => \$strModuleTest,
'module-test-run=s' => \$iModuleTestRun,
'thread-max=s' => \$iThreadMax,
'dry-run' => \$bDryRun,
'no-cleanup' => \$bNoCleanup)
or die 'error in command line arguments';
'no-cleanup' => \$bNoCleanup,
'infinite' => \$bInfinite)
or pod2usage(2);
# Display version and exit if requested
if ($bVersion || $bHelp)
{
print 'pg_backrest ' . version_get() . " unit test\n";
if ($bHelp)
{
print "\n";
pod2usage();
}
exit 0;
}
# Test::More->builder->output('/dev/null');
####################################################################################################################################
# Setup
@@ -52,7 +112,12 @@ GetOptions ('pgsql-bin=s' => \$strPgSqlBin,
# Set a neutral umask so tests work as expected
umask(0);
# Set console log level to trace for testing
# Set console log level
if ($bQuiet)
{
$strLogLevel = 'off';
}
log_level_set(undef, uc($strLogLevel));
if ($strModuleTest ne 'all' && $strModule eq 'all')
@@ -65,10 +130,36 @@ if (defined($iModuleTestRun) && $strModuleTest eq 'all')
confess "--module-test must be provided for run \"${iModuleTestRun}\"";
}
# Make sure PG bin has been defined
# Search for psql bin
if (!defined($strPgSqlBin))
{
confess 'pgsql-bin was not defined';
my @strySearchPath = ('/usr/lib/postgresql/VERSION/bin', '/Library/PostgreSQL/VERSION/bin');
foreach my $strSearchPath (@strySearchPath)
{
for (my $fVersion = 9; $fVersion >= 0; $fVersion -= 1)
{
my $strVersionPath = $strSearchPath;
$strVersionPath =~ s/VERSION/9\.$fVersion/g;
if (-e "${strVersionPath}/initdb")
{
&log(INFO, "found pgsql-bin at ${strVersionPath}\n");
$strPgSqlBin = ${strVersionPath};
}
}
}
if (!defined($strPgSqlBin))
{
confess 'pgsql-bin was not defined and could not be located';
}
}
# Check thread total
if ($iThreadMax < 1 || $iThreadMax > 32)
{
confess 'thread-max must be between 1 and 32';
}
####################################################################################################################################
@@ -127,22 +218,39 @@ BackRestTestCommon_Setup($strTestPath, $strPgSqlBin, $iModuleTestRun, $bDryRun,
# &log(INFO, "Testing with test_path = " . BackRestTestCommon_TestPathGet() . ", host = {strHost}, user = {strUser}, " .
# "group = {strGroup}");
if ($strModule eq 'all' || $strModule eq 'utility')
{
BackRestTestUtility_Test($strModuleTest);
}
my $iRun = 0;
if ($strModule eq 'all' || $strModule eq 'file')
do
{
BackRestTestFile_Test($strModuleTest);
}
if ($bInfinite)
{
$iRun++;
&log(INFO, "INFINITE - RUN ${iRun}\n");
}
if ($strModule eq 'all' || $strModule eq 'backup')
{
BackRestTestBackup_Test($strModuleTest);
if ($strModule eq 'all' || $strModule eq 'utility')
{
BackRestTestUtility_Test($strModuleTest);
}
if ($strModule eq 'all' || $strModule eq 'config')
{
BackRestTestConfig_Test($strModuleTest);
}
if ($strModule eq 'all' || $strModule eq 'file')
{
BackRestTestFile_Test($strModuleTest);
}
if ($strModule eq 'all' || $strModule eq 'backup')
{
BackRestTestBackup_Test($strModuleTest, $iThreadMax);
}
}
while ($bInfinite);
if (!$bDryRun)
{
&log(ASSERT, 'TESTS COMPLETED SUCCESSFULLY (DESPITE ANY ERROR MESSAGES YOU SAW)');
&log(INFO, 'TESTS COMPLETED SUCCESSFULLY (DESPITE ANY ERROR MESSAGES YOU SAW)');
}