mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2026-06-20 01:17:49 +02:00
Refactor backupLabel() and add unit tests.
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/perl
|
||||
####################################################################################################################################
|
||||
# pgBackRest - Simple PostgreSQL Backup and Restore
|
||||
# pgBackRest - Reliable PostgreSQL Backup & Restore
|
||||
####################################################################################################################################
|
||||
|
||||
####################################################################################################################################
|
||||
|
||||
@@ -181,6 +181,10 @@
|
||||
<release-item>
|
||||
<p>Refactor <code>File->list()</code> and <code>fileList()</code> to accept optional parameters.</p>
|
||||
</release-item>
|
||||
|
||||
<release-item>
|
||||
<p>Refactor <code>backupLabel()</code> and add unit tests.</p>
|
||||
</release-item>
|
||||
</release-refactor-list>
|
||||
</release-core-list>
|
||||
|
||||
|
||||
@@ -941,27 +941,9 @@ sub process
|
||||
}
|
||||
}
|
||||
|
||||
# Create the path for the new backup
|
||||
# Create label for new backup
|
||||
my $lTimestampStop = time();
|
||||
my $strBackupLabel = backupLabelFormat($strType, $strBackupLastPath, $lTimestampStop);
|
||||
|
||||
# Make sure that the timestamp has not already been used by a prior backup. This is unlikely for online backups since there is
|
||||
# already a wait after the manifest is built but it's still possible if the remote and local systems don't have synchronized
|
||||
# clocks. In practice this is most useful for making offline testing faster since it allows the wait after manifest build to
|
||||
# be skipped by dealing with any backup label collisions here.
|
||||
if (fileList($oFileLocal->pathGet(PATH_BACKUP_CLUSTER),
|
||||
{strExpression =>
|
||||
($strType eq BACKUP_TYPE_FULL ? '^' : '_') . timestampFileFormat(undef, $lTimestampStop) .
|
||||
($strType eq BACKUP_TYPE_FULL ? 'F' : '(D|I)$')}) ||
|
||||
fileList($oFileLocal->pathGet(PATH_BACKUP_CLUSTER, PATH_BACKUP_HISTORY . '/' . timestampFormat('%4d', $lTimestampStop)),
|
||||
{strExpression =>
|
||||
($strType eq BACKUP_TYPE_FULL ? '^' : '_') . timestampFileFormat(undef, $lTimestampStop) .
|
||||
($strType eq BACKUP_TYPE_FULL ? 'F' : '(D|I)\.manifest\.' . $oFileLocal->{strCompressExtension}),
|
||||
bIgnoreMissing => true}))
|
||||
{
|
||||
waitRemainder();
|
||||
$strBackupLabel = backupLabelFormat($strType, $strBackupLastPath, time());
|
||||
}
|
||||
my $strBackupLabel = backupLabel($oFileLocal, $strType, $strBackupLastPath, $lTimestampStop);
|
||||
|
||||
# Record timestamp stop in the config
|
||||
$oBackupManifest->set(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_TIMESTAMP_STOP, undef, $lTimestampStop + 0);
|
||||
|
||||
@@ -13,7 +13,11 @@ use File::Basename;
|
||||
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::String;
|
||||
use pgBackRest::Common::Wait;
|
||||
use pgBackRest::Config::Config;
|
||||
use pgBackRest::File;
|
||||
use pgBackRest::FileCommon;
|
||||
use pgBackRest::Manifest;
|
||||
|
||||
####################################################################################################################################
|
||||
# Latest backup link constant
|
||||
@@ -184,4 +188,60 @@ sub backupLabelFormat
|
||||
|
||||
push @EXPORT, qw(backupLabelFormat);
|
||||
|
||||
####################################################################################################################################
|
||||
# backupLabel
|
||||
#
|
||||
# Get unique backup label.
|
||||
####################################################################################################################################
|
||||
sub backupLabel
|
||||
{
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$oFile,
|
||||
$strType,
|
||||
$strBackupLabelLast,
|
||||
$lTimestampStop
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '::backupLabelFormat', \@_,
|
||||
{name => 'oFile', trace => true},
|
||||
{name => 'strType', trace => true},
|
||||
{name => 'strBackupLabelLast', required => false, trace => true},
|
||||
{name => 'lTimestampStop', trace => true}
|
||||
);
|
||||
|
||||
# Create backup label
|
||||
my $strBackupLabel = backupLabelFormat($strType, $strBackupLabelLast, $lTimestampStop);
|
||||
|
||||
# Make sure that the timestamp has not already been used by a prior backup. This is unlikely for online backups since there is
|
||||
# already a wait after the manifest is built but it's still possible if the remote and local systems don't have synchronized
|
||||
# clocks. In practice this is most useful for making offline testing faster since it allows the wait after manifest build to
|
||||
# be skipped by dealing with any backup label collisions here.
|
||||
if (fileList($oFile->pathGet(PATH_BACKUP_CLUSTER),
|
||||
{strExpression =>
|
||||
($strType eq BACKUP_TYPE_FULL ? '^' : '_') . timestampFileFormat(undef, $lTimestampStop) .
|
||||
($strType eq BACKUP_TYPE_FULL ? 'F' : '(D|I)$')}) ||
|
||||
fileList($oFile->pathGet(PATH_BACKUP_CLUSTER, PATH_BACKUP_HISTORY . '/' . timestampFormat('%4d', $lTimestampStop)),
|
||||
{strExpression =>
|
||||
($strType eq BACKUP_TYPE_FULL ? '^' : '_') . timestampFileFormat(undef, $lTimestampStop) .
|
||||
($strType eq BACKUP_TYPE_FULL ? 'F' : '(D|I)\.manifest\.' . $oFile->{strCompressExtension}),
|
||||
bIgnoreMissing => true}))
|
||||
{
|
||||
waitRemainder();
|
||||
$strBackupLabel = backupLabelFormat($strType, $strBackupLabelLast, time());
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'strBackupLabel', value => $strBackupLabel, trace => true}
|
||||
);
|
||||
}
|
||||
|
||||
push @EXPORT, qw(backupLabel);
|
||||
|
||||
1;
|
||||
|
||||
@@ -17,7 +17,16 @@ use pgBackRest::BackupCommon;
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::String;
|
||||
use pgBackRest::Common::Wait;
|
||||
use pgBackRest::Config::Config;
|
||||
use pgBackRest::File;
|
||||
use pgBackRest::FileCommon;
|
||||
use pgBackRest::Protocol::Common;
|
||||
use pgBackRest::Protocol::Protocol;
|
||||
use pgBackRest::Manifest;
|
||||
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::Host::HostBackupTest;
|
||||
|
||||
####################################################################################################################################
|
||||
# run
|
||||
@@ -26,39 +35,8 @@ sub run
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Increment the run, log, and decide whether this unit test should be run
|
||||
if (!$self->begin('unit')) {return}
|
||||
|
||||
# Unit tests for backupLabelFormat()
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
{
|
||||
# Test full backup label
|
||||
my $strBackupLabelFull = timestampFileFormat(undef, 1482000000) . 'F';
|
||||
$self->testResult(sub {backupLabelFormat(BACKUP_TYPE_FULL, undef, 1482000000)}, $strBackupLabelFull);
|
||||
|
||||
# Make sure that an assertion is thrown if strBackupLabelLast is passed when formatting a full label
|
||||
$self->testException(
|
||||
sub {backupLabelFormat(BACKUP_TYPE_FULL, $strBackupLabelFull, 1482000000)},
|
||||
ERROR_ASSERT, "strBackupLabelLast must not be defined when strType = 'full'");
|
||||
|
||||
# Test diff backup label
|
||||
my $strBackupLabelDiff = "${strBackupLabelFull}_" . timestampFileFormat(undef, 1482000400) . 'D';
|
||||
$self->testResult(sub {backupLabelFormat(BACKUP_TYPE_DIFF, $strBackupLabelFull, 1482000400)}, $strBackupLabelDiff);
|
||||
|
||||
# Make sure that an assertion is thrown if strBackupLabelLast is not passed when formatting a diff label. The same
|
||||
# check is used from incr labels so no need for a separate test.
|
||||
$self->testException(
|
||||
sub {backupLabelFormat(BACKUP_TYPE_DIFF, undef, 1482000400)},
|
||||
ERROR_ASSERT, "strBackupLabelLast must be defined when strType = 'diff'");
|
||||
|
||||
# Test incr backup label
|
||||
$self->testResult(
|
||||
sub {backupLabelFormat(BACKUP_TYPE_INCR, $strBackupLabelDiff, 1482000800)},
|
||||
"${strBackupLabelFull}_" . timestampFileFormat(undef, 1482000800) . 'I');
|
||||
}
|
||||
|
||||
# Unit tests for backupRegExpGet()
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
################################################################################################################################
|
||||
if ($self->begin('backupRegExpGet()'))
|
||||
{
|
||||
# Expected results matrix
|
||||
my $hExpected = {};
|
||||
@@ -97,14 +75,129 @@ sub run
|
||||
else
|
||||
{
|
||||
$self->testResult(
|
||||
sub {backupRegExpGet($bFull, $bDiff, $bIncr, $bAnchor)},
|
||||
$hExpected->{$bFull}{$bDiff}{$bIncr}{$bAnchor});
|
||||
sub {backupRegExpGet($bFull, $bDiff, $bIncr, $bAnchor)}, $hExpected->{$bFull}{$bDiff}{$bIncr}{$bAnchor},
|
||||
"expression full $bFull, diff $bDiff, incr $bIncr, anchor $bAnchor = " .
|
||||
$hExpected->{$bFull}{$bDiff}{$bIncr}{$bAnchor});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('backupLabelFormat()'))
|
||||
{
|
||||
my $strBackupLabelFull = timestampFileFormat(undef, 1482000000) . 'F';
|
||||
$self->testResult(sub {backupLabelFormat(BACKUP_TYPE_FULL, undef, 1482000000)}, $strBackupLabelFull, 'full backup label');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testException(
|
||||
sub {backupLabelFormat(BACKUP_TYPE_FULL, $strBackupLabelFull, 1482000000)},
|
||||
ERROR_ASSERT, "strBackupLabelLast must not be defined when strType = 'full'");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $strBackupLabelDiff = "${strBackupLabelFull}_" . timestampFileFormat(undef, 1482000400) . 'D';
|
||||
$self->testResult(
|
||||
sub {backupLabelFormat(BACKUP_TYPE_DIFF, $strBackupLabelFull, 1482000400)}, $strBackupLabelDiff, 'diff backup label');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testException(
|
||||
sub {backupLabelFormat(BACKUP_TYPE_DIFF, undef, 1482000400)},
|
||||
ERROR_ASSERT, "strBackupLabelLast must be defined when strType = 'diff'");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {backupLabelFormat(BACKUP_TYPE_INCR, $strBackupLabelDiff, 1482000800)},
|
||||
"${strBackupLabelFull}_" . timestampFileFormat(undef, 1482000800) . 'I',
|
||||
'incremental backup label');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('backupLabel()'))
|
||||
{
|
||||
# Create the local file object
|
||||
my $strRepoPath = $self->testPath() . '/repo';
|
||||
|
||||
my $oFile =
|
||||
new pgBackRest::File
|
||||
(
|
||||
$self->stanza(),
|
||||
$strRepoPath,
|
||||
new pgBackRest::Protocol::Common
|
||||
(
|
||||
OPTION_DEFAULT_BUFFER_SIZE, # Buffer size
|
||||
OPTION_DEFAULT_COMPRESS_LEVEL, # Compress level
|
||||
OPTION_DEFAULT_COMPRESS_LEVEL_NETWORK, # Compress network level
|
||||
HOST_PROTOCOL_TIMEOUT # Protocol timeout
|
||||
)
|
||||
);
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $lTime = time();
|
||||
|
||||
my $strFullLabel = backupLabelFormat(BACKUP_TYPE_FULL, undef, $lTime);
|
||||
$oFile->pathCreate(PATH_BACKUP_CLUSTER, $strFullLabel, undef, undef, true);
|
||||
|
||||
my $strNewFullLabel = backupLabel($oFile, BACKUP_TYPE_FULL, undef, $lTime);
|
||||
|
||||
$self->testResult(sub {$strFullLabel ne $strNewFullLabel}, true, 'new full label <> existing full backup dir');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
executeTest('rmdir ' . $oFile->pathGet(PATH_BACKUP_CLUSTER, $strFullLabel));
|
||||
|
||||
$oFile->pathCreate(
|
||||
PATH_BACKUP_CLUSTER, PATH_BACKUP_HISTORY . '/' . timestampFormat('%4d', $lTime), undef, undef, true);
|
||||
fileStringWrite($oFile->pathGet(
|
||||
PATH_BACKUP_CLUSTER,
|
||||
PATH_BACKUP_HISTORY . '/' . timestampFormat('%4d', $lTime) .
|
||||
"/${strFullLabel}.manifest.$oFile->{strCompressExtension}"));
|
||||
|
||||
$strNewFullLabel = backupLabel($oFile, BACKUP_TYPE_FULL, undef, $lTime);
|
||||
|
||||
$self->testResult(sub {$strFullLabel ne $strNewFullLabel}, true, 'new full label <> existing full history file');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$lTime = time() + 1000;
|
||||
$strFullLabel = backupLabelFormat(BACKUP_TYPE_FULL, undef, $lTime);
|
||||
|
||||
$strNewFullLabel = backupLabel($oFile, BACKUP_TYPE_FULL, undef, $lTime);
|
||||
|
||||
$self->testResult(sub {$strFullLabel eq $strNewFullLabel}, true, 'new full label in future');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$lTime = time();
|
||||
|
||||
$strFullLabel = backupLabelFormat(BACKUP_TYPE_FULL, undef, $lTime);
|
||||
my $strDiffLabel = backupLabelFormat(BACKUP_TYPE_DIFF, $strFullLabel, $lTime);
|
||||
$oFile->pathCreate(PATH_BACKUP_CLUSTER, $strDiffLabel, undef, undef, true);
|
||||
|
||||
my $strNewDiffLabel = backupLabel($oFile, BACKUP_TYPE_DIFF, $strFullLabel, $lTime);
|
||||
|
||||
$self->testResult(sub {$strDiffLabel ne $strNewDiffLabel}, true, 'new diff label <> existing diff backup dir');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
executeTest('rmdir ' . $oFile->pathGet(PATH_BACKUP_CLUSTER, $strDiffLabel));
|
||||
|
||||
$oFile->pathCreate(
|
||||
PATH_BACKUP_CLUSTER, PATH_BACKUP_HISTORY . '/' . timestampFormat('%4d', $lTime), undef, true, true);
|
||||
fileStringWrite($oFile->pathGet(
|
||||
PATH_BACKUP_CLUSTER,
|
||||
PATH_BACKUP_HISTORY . '/' . timestampFormat('%4d', $lTime) .
|
||||
"/${strDiffLabel}.manifest.$oFile->{strCompressExtension}"));
|
||||
|
||||
$strNewDiffLabel = backupLabel($oFile, BACKUP_TYPE_DIFF, $strFullLabel, $lTime);
|
||||
|
||||
$self->testResult(sub {$strDiffLabel ne $strNewDiffLabel}, true, 'new full label <> existing diff history file');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$lTime = time() + 1000;
|
||||
$strDiffLabel = backupLabelFormat(BACKUP_TYPE_DIFF, $strFullLabel, $lTime);
|
||||
|
||||
$strNewDiffLabel = backupLabel($oFile, BACKUP_TYPE_DIFF, $strFullLabel, $lTime);
|
||||
|
||||
$self->testResult(sub {$strDiffLabel eq $strNewDiffLabel}, true, 'new diff label in future');
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
@@ -65,6 +65,9 @@ use constant TESTDEF_MODULE_ARCHIVE_PUSH_ASYNC => TESTDEF_M
|
||||
use constant TESTDEF_MODULE_ARCHIVE_PUSH_FILE => TESTDEF_MODULE_ARCHIVE_PUSH . 'File';
|
||||
push @EXPORT, qw(TESTDEF_MODULE_ARCHIVE_PUSH_FILE);
|
||||
|
||||
use constant TESTDEF_MODULE_BACKUP_COMMON => 'BackupCommon';
|
||||
push @EXPORT, qw(TESTDEF_MODULE_BACKUP_COMMON);
|
||||
|
||||
use constant TESTDEF_MODULE_INFO => 'Info';
|
||||
push @EXPORT, qw(TESTDEF_MODULE_INFO);
|
||||
|
||||
@@ -294,11 +297,16 @@ my $oTestDef =
|
||||
&TESTDEF_TEST_CONTAINER => false,
|
||||
&TESTDEF_EXPECT => false,
|
||||
|
||||
&TESTDEF_TEST_COVERAGE =>
|
||||
{
|
||||
&TESTDEF_MODULE_BACKUP_COMMON => TESTDEF_COVERAGE_FULL,
|
||||
},
|
||||
|
||||
&TESTDEF_TEST =>
|
||||
[
|
||||
{
|
||||
&TESTDEF_TEST_NAME => 'unit',
|
||||
&TESTDEF_TEST_TOTAL => 1,
|
||||
&TESTDEF_TEST_TOTAL => 3,
|
||||
&TESTDEF_TEST_INDIVIDUAL => false,
|
||||
},
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user