You've already forked pgbackrest
mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2026-05-22 10:15:16 +02:00
Improvements to Ini.pm.
* Refactor Ini.pm to facilitate testing. * Complete statement/branch coverage for Ini.pm. * Improved functions used to test/munge manifest and info files.
This commit is contained in:
@@ -77,6 +77,11 @@ use constant TESTDEF_MODULE_ARCHIVE_PUSH_FILE => TESTDEF_M
|
||||
use constant TESTDEF_MODULE_BACKUP_COMMON => 'BackupCommon';
|
||||
push @EXPORT, qw(TESTDEF_MODULE_BACKUP_COMMON);
|
||||
|
||||
use constant TESTDEF_MODULE_COMMON => 'Common';
|
||||
push @EXPORT, qw(TESTDEF_MODULE_COMMON);
|
||||
use constant TESTDEF_MODULE_COMMON_INI => TESTDEF_MODULE_COMMON . '/Ini';
|
||||
push @EXPORT, qw(TESTDEF_MODULE_COMMON_INI);
|
||||
|
||||
use constant TESTDEF_MODULE_INFO => 'Info';
|
||||
push @EXPORT, qw(TESTDEF_MODULE_INFO);
|
||||
|
||||
@@ -206,6 +211,16 @@ my $oTestDef =
|
||||
|
||||
&TESTDEF_TEST =>
|
||||
[
|
||||
{
|
||||
&TESTDEF_NAME => 'ini-unit',
|
||||
&TESTDEF_CONTAINER => true,
|
||||
&TESTDEF_TOTAL => 10,
|
||||
|
||||
&TESTDEF_COVERAGE =>
|
||||
{
|
||||
&TESTDEF_MODULE_COMMON_INI => TESTDEF_COVERAGE_FULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
&TESTDEF_NAME => 'unit',
|
||||
&TESTDEF_TOTAL => 1,
|
||||
|
||||
@@ -13,6 +13,7 @@ use Carp qw(confess);
|
||||
|
||||
use Exporter qw(import);
|
||||
our @EXPORT = qw();
|
||||
use File::Basename qw(dirname);
|
||||
use Storable qw(dclone);
|
||||
|
||||
use pgBackRest::BackupCommon;
|
||||
@@ -240,8 +241,8 @@ sub backupEnd
|
||||
# because a running database is always in flux. Even so, it allows us test many things.
|
||||
if (!$self->synthetic())
|
||||
{
|
||||
$oExpectedManifest =
|
||||
iniLoad($self->repoPath() . '/backup/' . $self->stanza() . "/${strBackup}/" . FILE_MANIFEST, $oExpectedManifest);
|
||||
$oExpectedManifest = iniParse(
|
||||
fileStringRead($self->repoPath() . '/backup/' . $self->stanza() . "/${strBackup}/" . FILE_MANIFEST));
|
||||
}
|
||||
|
||||
# Make sure tablespace links are correct
|
||||
@@ -494,8 +495,8 @@ sub backupCompare
|
||||
|
||||
my $strTestPath = $self->testPath();
|
||||
|
||||
iniSave("${strTestPath}/actual.manifest", $oActualManifest->{oContent});
|
||||
iniSave("${strTestPath}/expected.manifest", $oExpectedManifest);
|
||||
fileStringWrite("${strTestPath}/actual.manifest", iniRender($oActualManifest->{oContent}));
|
||||
fileStringWrite("${strTestPath}/expected.manifest", iniRender($oExpectedManifest));
|
||||
|
||||
executeTest("diff ${strTestPath}/expected.manifest ${strTestPath}/actual.manifest");
|
||||
|
||||
@@ -1032,7 +1033,10 @@ sub configCreate
|
||||
}
|
||||
|
||||
# Write out the configuration file
|
||||
iniSave($self->backrestConfig(), \%oParamHash, true);
|
||||
fileStringWrite($self->backrestConfig(), iniRender(\%oParamHash, true));
|
||||
|
||||
# Modify the file permissions so it can be read/saved by all test users
|
||||
executeTest('sudo chmod 660 ' . $self->backrestConfig());
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
@@ -1050,59 +1054,48 @@ sub manifestMunge
|
||||
(
|
||||
$strOperation,
|
||||
$strBackup,
|
||||
$strSection,
|
||||
$strKey,
|
||||
$strSubKey,
|
||||
$strValue,
|
||||
$hParam,
|
||||
$bCache,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->manifestMunge', \@_,
|
||||
{name => '$strBackup'},
|
||||
{name => '$strSection'},
|
||||
{name => '$strKey'},
|
||||
{name => '$strSubKey', required => false},
|
||||
{name => '$strValue', required => false},
|
||||
{name => 'strBackup'},
|
||||
{name => '$hParam'},
|
||||
{name => 'bCache', default => true},
|
||||
);
|
||||
|
||||
my $strManifestFile = "${strBackup}/" . FILE_MANIFEST;
|
||||
$self->infoMunge($self->{oFile}->pathGet(PATH_BACKUP_CLUSTER, "${strBackup}/" . FILE_MANIFEST), $hParam, $bCache);
|
||||
|
||||
# Change mode on the backup path so it can be read/written
|
||||
if ($self->nameTest(HOST_BACKUP))
|
||||
{
|
||||
executeTest('sudo chmod g+w ' . $self->{oFile}->pathGet(PATH_BACKUP_CLUSTER, $strManifestFile));
|
||||
}
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn($strOperation);
|
||||
}
|
||||
|
||||
# Read the manifest
|
||||
my %oManifest;
|
||||
iniLoad($self->{oFile}->pathGet(PATH_BACKUP_CLUSTER, $strManifestFile), \%oManifest);
|
||||
####################################################################################################################################
|
||||
# manifestRestore
|
||||
####################################################################################################################################
|
||||
sub manifestRestore
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Write in the munged value
|
||||
if (defined($strSubKey))
|
||||
{
|
||||
if (defined($strValue))
|
||||
{
|
||||
$oManifest{$strSection}{$strKey}{$strSubKey} = $strValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete($oManifest{$strSection}{$strKey}{$strSubKey});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (defined($strValue))
|
||||
{
|
||||
$oManifest{$strSection}{$strKey} = $strValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete($oManifest{$strSection}{$strKey});
|
||||
}
|
||||
}
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strBackup,
|
||||
$bSave,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->manifestRestore', \@_,
|
||||
{name => 'strBackup'},
|
||||
{name => 'bSave', default => true},
|
||||
);
|
||||
|
||||
# Resave the manifest
|
||||
$self->iniSaveChecksum($self->{oFile}->pathGet(PATH_BACKUP_CLUSTER, $strManifestFile), \%oManifest, true);
|
||||
$self->infoRestore($self->{oFile}->pathGet(PATH_BACKUP_CLUSTER, "${strBackup}/" . FILE_MANIFEST), $bSave);
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn($strOperation);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
@@ -1121,38 +1114,64 @@ sub infoMunge
|
||||
(
|
||||
$strOperation,
|
||||
$strFileName,
|
||||
$hParam
|
||||
$hParam,
|
||||
$bCache,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->infoMunge', \@_,
|
||||
{name => 'strFileName'},
|
||||
{name => 'hParam'}
|
||||
{name => 'hParam'},
|
||||
{name => 'bCache', default => true},
|
||||
);
|
||||
|
||||
# If the original file content does not exist then load it
|
||||
if (!defined($self->{hInfoFile}{$strFileName}))
|
||||
{
|
||||
$self->{hInfoFile}{$strFileName} = iniLoad($strFileName);
|
||||
# Modify the file permissions so it can be saved
|
||||
executeTest("sudo chmod 660 ${strFileName}");
|
||||
$self->{hInfoFile}{$strFileName} = new pgBackRest::Common::Ini($strFileName);
|
||||
}
|
||||
|
||||
# Make a copy of the original file contents
|
||||
my $hContent = dclone($self->{hInfoFile}{$strFileName});
|
||||
my $oMungeIni = new pgBackRest::Common::Ini(
|
||||
$strFileName, {bLoad => false, strContent => iniRender($self->{hInfoFile}{$strFileName}->{oContent})});
|
||||
|
||||
# Load params
|
||||
foreach my $strSection (sort(keys(%{$hParam})))
|
||||
foreach my $strSection (keys(%{$hParam}))
|
||||
{
|
||||
foreach my $strKey (keys(%{$$hParam{$strSection}}))
|
||||
foreach my $strKey (keys(%{$hParam->{$strSection}}))
|
||||
{
|
||||
# Munge the copy with the new parameter values
|
||||
$$hContent{$strSection}{$strKey} = $$hParam{$strSection}{$strKey};
|
||||
if (ref($hParam->{$strSection}{$strKey}) eq 'HASH')
|
||||
{
|
||||
foreach my $strSubKey (keys(%{$hParam->{$strSection}{$strKey}}))
|
||||
{
|
||||
# Munge the copy with the new parameter values
|
||||
$oMungeIni->set($strSection, $strKey, $strSubKey, $hParam->{$strSection}{$strKey}{$strSubKey});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
# Munge the copy with the new parameter values
|
||||
$oMungeIni->set($strSection, $strKey, undef, $hParam->{$strSection}{$strKey});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Modify the file/directory permissions so it can be saved
|
||||
executeTest("sudo rm -f ${strFileName} && sudo chmod 770 " . dirname($strFileName));
|
||||
|
||||
# Save the munged data to the file
|
||||
$self->iniSaveChecksum($strFileName, \%{$hContent}, true);
|
||||
$oMungeIni->save();
|
||||
|
||||
# Fix permissions
|
||||
executeTest(
|
||||
"sudo chmod 640 ${strFileName} && sudo chmod 750 " . dirname($strFileName) .
|
||||
' && sudo chown ' . $self->userGet() . " ${strFileName}");
|
||||
|
||||
# Clear the cache is requested
|
||||
if (!$bCache)
|
||||
{
|
||||
delete($self->{hInfoFile}{$strFileName});
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn($strOperation);
|
||||
@@ -1179,7 +1198,7 @@ sub infoRestore
|
||||
(
|
||||
__PACKAGE__ . '->infoRestore', \@_,
|
||||
{name => 'strFileName'},
|
||||
{name => 'bSave', default => true, required => false},
|
||||
{name => 'bSave', default => true},
|
||||
);
|
||||
|
||||
# If the original file content exists in the global hash, then save it to the file
|
||||
@@ -1187,7 +1206,15 @@ sub infoRestore
|
||||
{
|
||||
if ($bSave)
|
||||
{
|
||||
iniSave($strFileName, $self->{hInfoFile}{$strFileName});
|
||||
# Modify the file/directory permissions so it can be saved
|
||||
executeTest("sudo rm -f ${strFileName} && sudo chmod 770 " . dirname($strFileName));
|
||||
|
||||
# Save the munged data to the file
|
||||
$self->{hInfoFile}{$strFileName}->{bModified} = true;
|
||||
$self->{hInfoFile}{$strFileName}->save();
|
||||
|
||||
# Fix permissions
|
||||
executeTest("sudo chmod 640 ${strFileName} && sudo chmod 750 " . dirname($strFileName));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1202,33 +1229,6 @@ sub infoRestore
|
||||
return logDebugReturn($strOperation);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# iniSaveChecksum
|
||||
#
|
||||
# Save an ini file an optionall recalculate the checksum so it's valid.
|
||||
####################################################################################################################################
|
||||
sub iniSaveChecksum
|
||||
{
|
||||
my $self = shift;
|
||||
my $strFileName = shift;
|
||||
my $oIniRef = shift;
|
||||
my $bChecksum = shift;
|
||||
|
||||
# Calculate a new checksum if requested
|
||||
if (defined($bChecksum) && $bChecksum)
|
||||
{
|
||||
delete($$oIniRef{&INI_SECTION_BACKREST}{&INI_KEY_CHECKSUM});
|
||||
|
||||
my $oSHA = Digest::SHA->new('sha1');
|
||||
my $oJSON = JSON::PP->new()->canonical()->allow_nonref();
|
||||
$oSHA->add($oJSON->encode($oIniRef));
|
||||
|
||||
$$oIniRef{&INI_SECTION_BACKREST}{&INI_KEY_CHECKSUM} = $oSHA->hexdigest();
|
||||
}
|
||||
|
||||
iniSave($strFileName, $oIniRef);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Getters
|
||||
####################################################################################################################################
|
||||
|
||||
@@ -15,6 +15,7 @@ use DBI;
|
||||
use Exporter qw(import);
|
||||
our @EXPORT = qw();
|
||||
use Fcntl ':mode';
|
||||
use File::Basename qw(dirname);
|
||||
use Storable qw(dclone);
|
||||
|
||||
use pgBackRest::Common::Exception;
|
||||
@@ -181,16 +182,7 @@ sub configRecovery
|
||||
my $strStanza = $self->stanza();
|
||||
|
||||
# Load db config file
|
||||
my %oConfig;
|
||||
iniLoad($self->backrestConfig(), \%oConfig, true);
|
||||
|
||||
# Load backup config file
|
||||
my %oRemoteConfig;
|
||||
|
||||
if ($oHostBackup->nameTest(HOST_BACKUP))
|
||||
{
|
||||
iniLoad($oHostBackup->backrestConfig(), \%oRemoteConfig, true);
|
||||
}
|
||||
my $oConfig = iniParse(fileStringRead($self->backrestConfig()), {bRelaxed => true});
|
||||
|
||||
# Rewrite recovery options
|
||||
my @stryRecoveryOption;
|
||||
@@ -202,17 +194,11 @@ sub configRecovery
|
||||
|
||||
if (@stryRecoveryOption)
|
||||
{
|
||||
$oConfig{$strStanza}{&OPTION_RESTORE_RECOVERY_OPTION} = \@stryRecoveryOption;
|
||||
$oConfig->{$strStanza}{&OPTION_RESTORE_RECOVERY_OPTION} = \@stryRecoveryOption;
|
||||
}
|
||||
|
||||
# Save db config file
|
||||
iniSave($self->backrestConfig(), \%oConfig, true);
|
||||
|
||||
# Save backup config file
|
||||
if ($oHostBackup->nameTest(HOST_BACKUP))
|
||||
{
|
||||
iniSave($oHostBackup->backrestConfig(), \%oRemoteConfig, true);
|
||||
}
|
||||
fileStringWrite($self->backrestConfig(), iniRender($oConfig, true));
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
@@ -228,22 +214,21 @@ sub configRemap
|
||||
my $strStanza = $self->stanza();
|
||||
|
||||
# Load db config file
|
||||
my %oConfig;
|
||||
iniLoad($self->backrestConfig(), \%oConfig, true);
|
||||
my $oConfig = iniParse(fileStringRead($self->backrestConfig()), {bRelaxed => true});
|
||||
|
||||
# Load backup config file
|
||||
my %oRemoteConfig;
|
||||
my $oRemoteConfig;
|
||||
my $oHostBackup =
|
||||
!$self->standby() && !$self->nameTest($self->backupDestination()) ?
|
||||
hostGroupGet()->hostGet($self->backupDestination()) : undef;
|
||||
|
||||
if (defined($oHostBackup))
|
||||
{
|
||||
iniLoad($oHostBackup->backrestConfig(), \%oRemoteConfig, true);
|
||||
$oRemoteConfig = iniParse(fileStringRead($oHostBackup->backrestConfig()), {bRelaxed => true});
|
||||
}
|
||||
|
||||
# Rewrite recovery section
|
||||
delete($oConfig{"${strStanza}:restore"}{&OPTION_TABLESPACE_MAP});
|
||||
delete($oConfig->{"${strStanza}:restore"}{&OPTION_TABLESPACE_MAP});
|
||||
my @stryTablespaceMap;
|
||||
|
||||
foreach my $strRemap (sort(keys(%$oRemapHashRef)))
|
||||
@@ -252,13 +237,13 @@ sub configRemap
|
||||
|
||||
if ($strRemap eq MANIFEST_TARGET_PGDATA)
|
||||
{
|
||||
$oConfig{$strStanza}{&OPTION_DB_PATH} = $strRemapPath;
|
||||
$oConfig->{$strStanza}{&OPTION_DB_PATH} = $strRemapPath;
|
||||
${$oManifestRef}{&MANIFEST_SECTION_BACKUP_TARGET}{&MANIFEST_TARGET_PGDATA}{&MANIFEST_SUBKEY_PATH} = $strRemapPath;
|
||||
|
||||
if (defined($oHostBackup))
|
||||
{
|
||||
my $bForce = $oHostBackup->nameTest(HOST_BACKUP) && defined(hostGroupGet()->hostGet(HOST_DB_STANDBY, true));
|
||||
$oRemoteConfig{$strStanza}{optionIndex(OPTION_DB_PATH, 1, $bForce)} = $strRemapPath;
|
||||
$oRemoteConfig->{$strStanza}{optionIndex(OPTION_DB_PATH, 1, $bForce)} = $strRemapPath;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -273,16 +258,25 @@ sub configRemap
|
||||
|
||||
if (@stryTablespaceMap)
|
||||
{
|
||||
$oConfig{"${strStanza}:restore"}{&OPTION_TABLESPACE_MAP} = \@stryTablespaceMap;
|
||||
$oConfig->{"${strStanza}:restore"}{&OPTION_TABLESPACE_MAP} = \@stryTablespaceMap;
|
||||
}
|
||||
|
||||
# Save db config file
|
||||
iniSave($self->backrestConfig(), \%oConfig, true);
|
||||
fileStringWrite($self->backrestConfig(), iniRender($oConfig, true));
|
||||
|
||||
# Save backup config file (but not is this is the standby which is not the source of backups)
|
||||
if (defined($oHostBackup))
|
||||
{
|
||||
iniSave($oHostBackup->backrestConfig(), \%oRemoteConfig, true);
|
||||
# Modify the file permissions so it can be read/saved by all test users
|
||||
executeTest(
|
||||
'sudo chmod 660 ' . $oHostBackup->backrestConfig() . ' && sudo chmod 770 ' . dirname($oHostBackup->backrestConfig()));
|
||||
|
||||
fileStringWrite($oHostBackup->backrestConfig(), iniRender($oRemoteConfig, true));
|
||||
|
||||
# Fix permissions
|
||||
executeTest(
|
||||
'sudo chmod 660 ' . $oHostBackup->backrestConfig() . ' && sudo chmod 770 ' . dirname($oHostBackup->backrestConfig()) .
|
||||
' && sudo chown ' . $oHostBackup->userGet() . ' ' . $oHostBackup->backrestConfig());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -676,9 +670,8 @@ sub restoreCompare
|
||||
|
||||
if ($self->synthetic())
|
||||
{
|
||||
$oActualManifest->remove(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_TIMESTAMP_COPY_START);
|
||||
$oActualManifest->remove(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_LABEL);
|
||||
$oActualManifest->remove(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_TYPE);
|
||||
$oActualManifest->remove(MANIFEST_SECTION_BACKUP);
|
||||
delete($oExpectedManifestRef->{&MANIFEST_SECTION_BACKUP});
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -730,8 +723,8 @@ sub restoreCompare
|
||||
|
||||
$self->manifestDefault($oExpectedManifestRef);
|
||||
|
||||
iniSave("${strTestPath}/actual.manifest", $oActualManifest->{oContent});
|
||||
iniSave("${strTestPath}/expected.manifest", $oExpectedManifestRef);
|
||||
fileStringWrite("${strTestPath}/actual.manifest", iniRender($oActualManifest->{oContent}));
|
||||
fileStringWrite("${strTestPath}/expected.manifest", iniRender($oExpectedManifestRef));
|
||||
|
||||
executeTest("diff ${strTestPath}/expected.manifest ${strTestPath}/actual.manifest");
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Ini;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Config::Config;
|
||||
use pgBackRest::FileCommon;
|
||||
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
|
||||
@@ -71,7 +72,7 @@ sub run
|
||||
{
|
||||
$oConfig = {};
|
||||
$$oConfig{$self->stanza() . ':' . &CMD_BACKUP}{&OPTION_PROCESS_MAX} = 2;
|
||||
iniSave($strConfigFile, $oConfig, true);
|
||||
fileStringWrite($strConfigFile, iniRender($oConfig, true));
|
||||
|
||||
$self->optionSetTest($oOption, OPTION_STANZA, $self->stanza());
|
||||
$self->optionSetTest($oOption, OPTION_DB_PATH, '/db');
|
||||
@@ -85,7 +86,7 @@ sub run
|
||||
{
|
||||
$oConfig = {};
|
||||
$$oConfig{$self->stanza()}{&OPTION_PROCESS_MAX} = 3;
|
||||
iniSave($strConfigFile, $oConfig, true);
|
||||
fileStringWrite($strConfigFile, iniRender($oConfig, true));
|
||||
|
||||
$self->optionSetTest($oOption, OPTION_STANZA, $self->stanza());
|
||||
$self->optionSetTest($oOption, OPTION_DB_PATH, '/db');
|
||||
@@ -99,7 +100,7 @@ sub run
|
||||
{
|
||||
$oConfig = {};
|
||||
$$oConfig{&CONFIG_SECTION_GLOBAL . ':' . &CMD_BACKUP}{'thread-max'} = 2;
|
||||
iniSave($strConfigFile, $oConfig, true);
|
||||
fileStringWrite($strConfigFile, iniRender($oConfig, true));
|
||||
|
||||
$self->optionSetTest($oOption, OPTION_STANZA, $self->stanza());
|
||||
$self->optionSetTest($oOption, OPTION_DB_PATH, '/db');
|
||||
@@ -113,7 +114,7 @@ sub run
|
||||
{
|
||||
$oConfig = {};
|
||||
$$oConfig{&CONFIG_SECTION_GLOBAL}{&OPTION_PROCESS_MAX} = 5;
|
||||
iniSave($strConfigFile, $oConfig, true);
|
||||
fileStringWrite($strConfigFile, iniRender($oConfig, true));
|
||||
|
||||
$self->optionSetTest($oOption, OPTION_STANZA, $self->stanza());
|
||||
$self->optionSetTest($oOption, OPTION_DB_PATH, '/db');
|
||||
@@ -126,7 +127,7 @@ sub run
|
||||
if ($self->begin('default - option ' . OPTION_PROCESS_MAX))
|
||||
{
|
||||
$oConfig = {};
|
||||
iniSave($strConfigFile, $oConfig, true);
|
||||
fileStringWrite($strConfigFile, iniRender($oConfig, true));
|
||||
|
||||
$self->optionSetTest($oOption, OPTION_STANZA, $self->stanza());
|
||||
$self->optionSetTest($oOption, OPTION_DB_PATH, '/db');
|
||||
@@ -140,7 +141,7 @@ sub run
|
||||
{
|
||||
$oConfig = {};
|
||||
$$oConfig{&CONFIG_SECTION_GLOBAL}{&OPTION_PROCESS_MAX} = 9;
|
||||
iniSave($strConfigFile, $oConfig, true);
|
||||
fileStringWrite($strConfigFile, iniRender($oConfig, true));
|
||||
|
||||
$self->optionSetTest($oOption, OPTION_STANZA, $self->stanza());
|
||||
$self->optionSetTest($oOption, OPTION_DB_PATH, '/db');
|
||||
@@ -155,7 +156,7 @@ sub run
|
||||
{
|
||||
$oConfig = {};
|
||||
$$oConfig{&CONFIG_SECTION_GLOBAL . ':' . &CMD_BACKUP}{&OPTION_HARDLINK} = 'Y';
|
||||
iniSave($strConfigFile, $oConfig, true);
|
||||
fileStringWrite($strConfigFile, iniRender($oConfig, true));
|
||||
|
||||
$self->optionSetTest($oOption, OPTION_STANZA, $self->stanza());
|
||||
$self->optionSetTest($oOption, OPTION_DB_PATH, '/db');
|
||||
@@ -168,7 +169,7 @@ sub run
|
||||
{
|
||||
$oConfig = {};
|
||||
$$oConfig{&CONFIG_SECTION_GLOBAL}{&OPTION_LOG_LEVEL_CONSOLE} = BOGUS;
|
||||
iniSave($strConfigFile, $oConfig, true);
|
||||
fileStringWrite($strConfigFile, iniRender($oConfig, true));
|
||||
|
||||
$self->optionSetTest($oOption, OPTION_STANZA, $self->stanza());
|
||||
$self->optionSetTest($oOption, OPTION_DB_PATH, '/db');
|
||||
@@ -181,7 +182,7 @@ sub run
|
||||
{
|
||||
$oConfig = {};
|
||||
$$oConfig{&CONFIG_SECTION_GLOBAL}{&OPTION_LOG_LEVEL_CONSOLE} = lc(INFO);
|
||||
iniSave($strConfigFile, $oConfig, true);
|
||||
fileStringWrite($strConfigFile, iniRender($oConfig, true));
|
||||
|
||||
$self->optionSetTest($oOption, OPTION_STANZA, $self->stanza());
|
||||
$self->optionSetTest($oOption, OPTION_DB_PATH, '/db');
|
||||
@@ -202,7 +203,7 @@ sub run
|
||||
{
|
||||
$oConfig = {};
|
||||
$$oConfig{$self->stanza() . ':' . &CMD_EXPIRE}{&OPTION_RETENTION_FULL} = 2;
|
||||
iniSave($strConfigFile, $oConfig, true);
|
||||
fileStringWrite($strConfigFile, iniRender($oConfig, true));
|
||||
|
||||
$self->optionSetTest($oOption, OPTION_STANZA, $self->stanza());
|
||||
$self->optionSetTest($oOption, OPTION_CONFIG, $strConfigFile);
|
||||
@@ -215,7 +216,7 @@ sub run
|
||||
{
|
||||
$oConfig = {};
|
||||
$$oConfig{&CONFIG_SECTION_GLOBAL . ':' . &CMD_BACKUP}{&OPTION_COMPRESS} = 'n';
|
||||
iniSave($strConfigFile, $oConfig, true);
|
||||
fileStringWrite($strConfigFile, iniRender($oConfig, true));
|
||||
|
||||
$self->optionSetTest($oOption, OPTION_STANZA, $self->stanza());
|
||||
$self->optionSetTest($oOption, OPTION_DB_PATH, '/db');
|
||||
@@ -229,7 +230,7 @@ sub run
|
||||
{
|
||||
$oConfig = {};
|
||||
$$oConfig{&CONFIG_SECTION_GLOBAL . ':' . &CMD_RESTORE}{&OPTION_RESTORE_RECOVERY_OPTION} = 'bogus=';
|
||||
iniSave($strConfigFile, $oConfig, true);
|
||||
fileStringWrite($strConfigFile, iniRender($oConfig, true));
|
||||
|
||||
$self->optionSetTest($oOption, OPTION_STANZA, $self->stanza());
|
||||
$self->optionSetTest($oOption, OPTION_DB_PATH, '/db');
|
||||
@@ -242,7 +243,7 @@ sub run
|
||||
{
|
||||
$oConfig = {};
|
||||
$$oConfig{&CONFIG_SECTION_GLOBAL . ':' . &CMD_RESTORE}{&OPTION_RESTORE_RECOVERY_OPTION} = '=bogus';
|
||||
iniSave($strConfigFile, $oConfig, true);
|
||||
fileStringWrite($strConfigFile, iniRender($oConfig, true));
|
||||
|
||||
$self->optionSetTest($oOption, OPTION_STANZA, $self->stanza());
|
||||
$self->optionSetTest($oOption, OPTION_DB_PATH, '/db');
|
||||
@@ -256,7 +257,7 @@ sub run
|
||||
$oConfig = {};
|
||||
$$oConfig{&CONFIG_SECTION_GLOBAL . ':' . &CMD_RESTORE}{&OPTION_RESTORE_RECOVERY_OPTION} =
|
||||
'archive-command=/path/to/pgbackrest';
|
||||
iniSave($strConfigFile, $oConfig, true);
|
||||
fileStringWrite($strConfigFile, iniRender($oConfig, true));
|
||||
|
||||
$self->optionSetTest($oOption, OPTION_STANZA, $self->stanza());
|
||||
$self->optionSetTest($oOption, OPTION_DB_PATH, '/db');
|
||||
@@ -270,7 +271,7 @@ sub run
|
||||
{
|
||||
$oConfig = {};
|
||||
$$oConfig{$self->stanza()}{&OPTION_RESTORE_RECOVERY_OPTION} = ['standby-mode=on', 'a=b'];
|
||||
iniSave($strConfigFile, $oConfig, true);
|
||||
fileStringWrite($strConfigFile, iniRender($oConfig, true));
|
||||
|
||||
$self->optionSetTest($oOption, OPTION_STANZA, $self->stanza());
|
||||
$self->optionSetTest($oOption, OPTION_DB_PATH, '/db');
|
||||
@@ -285,7 +286,7 @@ sub run
|
||||
{
|
||||
$oConfig = {};
|
||||
$$oConfig{$self->stanza()}{&OPTION_DB_PATH} = '/path/to/db';
|
||||
iniSave($strConfigFile, $oConfig, true);
|
||||
fileStringWrite($strConfigFile, iniRender($oConfig, true));
|
||||
|
||||
$self->optionSetTest($oOption, OPTION_STANZA, $self->stanza());
|
||||
$self->optionSetTest($oOption, OPTION_CONFIG, $strConfigFile);
|
||||
@@ -298,7 +299,7 @@ sub run
|
||||
{
|
||||
$oConfig = {};
|
||||
$$oConfig{$self->stanza()}{&OPTION_DB_PATH} = '/path/to/db';
|
||||
iniSave($strConfigFile, $oConfig, true);
|
||||
fileStringWrite($strConfigFile, iniRender($oConfig, true));
|
||||
|
||||
$self->optionSetTest($oOption, OPTION_STANZA, $self->stanza());
|
||||
$self->optionSetTest($oOption, OPTION_CONFIG, $strConfigFile);
|
||||
@@ -313,7 +314,7 @@ sub run
|
||||
{
|
||||
$oConfig = {};
|
||||
$$oConfig{$self->stanza()}{&OPTION_DB_PATH} = '/path/to/db';
|
||||
iniSave($strConfigFile, $oConfig, true);
|
||||
fileStringWrite($strConfigFile, iniRender($oConfig, true));
|
||||
|
||||
$self->optionSetTest($oOption, OPTION_STANZA, $self->stanza());
|
||||
$self->optionSetTest($oOption, OPTION_CONFIG, $strConfigFile);
|
||||
@@ -326,7 +327,7 @@ sub run
|
||||
{
|
||||
$oConfig = {};
|
||||
$$oConfig{&CONFIG_SECTION_GLOBAL}{&OPTION_REPO_PATH} = '/repo';
|
||||
iniSave($strConfigFile, $oConfig, true);
|
||||
fileStringWrite($strConfigFile, iniRender($oConfig, true));
|
||||
|
||||
$self->optionSetTest($oOption, OPTION_STANZA, $self->stanza());
|
||||
$self->optionSetTest($oOption, OPTION_DB_PATH, '/db');
|
||||
@@ -340,7 +341,7 @@ sub run
|
||||
{
|
||||
$oConfig = {};
|
||||
$$oConfig{&CONFIG_SECTION_GLOBAL}{&OPTION_REPO_PATH} = ['/repo', '/repo2'];
|
||||
iniSave($strConfigFile, $oConfig, true);
|
||||
fileStringWrite($strConfigFile, iniRender($oConfig, true));
|
||||
|
||||
$self->optionSetTest($oOption, OPTION_STANZA, $self->stanza());
|
||||
$self->optionSetTest($oOption, OPTION_DB_PATH, '/db');
|
||||
|
||||
@@ -11,9 +11,10 @@ use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
|
||||
use File::Basename qw(dirname);
|
||||
use File::Basename qw(basename dirname);
|
||||
|
||||
use pgBackRest::Archive::ArchiveInfo;
|
||||
use pgBackRest::BackupCommon;
|
||||
use pgBackRest::BackupInfo;
|
||||
use pgBackRest::DbVersion;
|
||||
use pgBackRest::Common::Exception;
|
||||
@@ -429,14 +430,16 @@ sub run
|
||||
|
||||
testPathMove($oHostBackup->repoPath() . '/backup/' . $self->stanza() . "/${strFullBackup}", $strTmpPath);
|
||||
|
||||
my $oMungeManifest = new pgBackRest::Manifest("$strTmpPath/backup.manifest");
|
||||
$oMungeManifest->remove(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . DB_FILE_PGVERSION, 'checksum');
|
||||
$oMungeManifest->save();
|
||||
$oHostBackup->infoMunge(
|
||||
"$strTmpPath/" . FILE_MANIFEST,
|
||||
{&MANIFEST_SECTION_TARGET_FILE =>
|
||||
{(&MANIFEST_TARGET_PGDATA . '/' . &DB_FILE_PGVERSION) => {&MANIFEST_SUBKEY_CHECKSUM => undef}}},
|
||||
false);
|
||||
|
||||
# Create a temp file in backup temp root to be sure it's deleted correctly
|
||||
executeTest("touch ${strTmpPath}/file.tmp" . ($bCompress ? '.gz' : ''),
|
||||
{bRemote => $bRemote});
|
||||
executeTest("sudo chmod -R g+w " . dirname($strTmpPath));
|
||||
executeTest("sudo chown -R " . $oHostBackup->userGet() . ' ' . dirname($strTmpPath));
|
||||
|
||||
$strFullBackup = $oHostBackup->backup(
|
||||
$strType, 'resume',
|
||||
@@ -567,9 +570,10 @@ sub run
|
||||
|
||||
# Munge the user to make sure it gets reset on the next run
|
||||
$oHostBackup->manifestMunge(
|
||||
$strFullBackup, MANIFEST_SECTION_TARGET_FILE, MANIFEST_FILE_PGCONTROL, MANIFEST_SUBKEY_USER, 'bogus');
|
||||
$oHostBackup->manifestMunge(
|
||||
$strFullBackup, MANIFEST_SECTION_TARGET_FILE, MANIFEST_FILE_PGCONTROL, MANIFEST_SUBKEY_GROUP, 'bogus');
|
||||
$strFullBackup,
|
||||
{&MANIFEST_SECTION_TARGET_FILE =>
|
||||
{&MANIFEST_FILE_PGCONTROL => {&MANIFEST_SUBKEY_USER => 'bogus', &MANIFEST_SUBKEY_GROUP => 'bogus'}}},
|
||||
false);
|
||||
|
||||
# Restore succeeds
|
||||
$oHostDbMaster->manifestLinkMap(\%oManifest, MANIFEST_TARGET_PGDATA . '/pg_stat');
|
||||
@@ -760,11 +764,13 @@ sub run
|
||||
$strTmpPath = $oHostBackup->repoPath() . '/temp/' .$self->stanza() . '.tmp';
|
||||
|
||||
testPathMove($oHostBackup->repoPath() . '/backup/' . $self->stanza() . "/${strBackup}", $strTmpPath);
|
||||
executeTest("sudo chmod -R g+w " . dirname($strTmpPath));
|
||||
executeTest("sudo chown -R " . $oHostBackup->userGet() . ' ' . dirname($strTmpPath));
|
||||
|
||||
$oMungeManifest = new pgBackRest::Manifest("$strTmpPath/" . FILE_MANIFEST);
|
||||
$oMungeManifest->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/badchecksum.txt', 'checksum', 'bogus');
|
||||
$oMungeManifest->save();
|
||||
$oHostBackup->infoMunge(
|
||||
"$strTmpPath/" . FILE_MANIFEST,
|
||||
{&MANIFEST_SECTION_TARGET_FILE =>
|
||||
{(&MANIFEST_TARGET_PGDATA . '/badchecksum.txt') => {&MANIFEST_SUBKEY_CHECKSUM => BOGUS}}},
|
||||
false);
|
||||
|
||||
# Add tablespace 2
|
||||
$oHostDbMaster->manifestTablespaceCreate(\%oManifest, 2);
|
||||
@@ -800,7 +806,7 @@ sub run
|
||||
$strTmpPath = $oHostBackup->repoPath() . '/temp/' . $self->stanza() . '.tmp';
|
||||
|
||||
testPathMove($oHostBackup->repoPath() . '/backup/' . $self->stanza() . "/${strBackup}", $strTmpPath);
|
||||
executeTest("sudo chmod -R g+w " . dirname($strTmpPath));
|
||||
executeTest("sudo chown -R " . $oHostBackup->userGet() . ' ' . dirname($strTmpPath));
|
||||
|
||||
$strBackup = $oHostBackup->backup(
|
||||
$strType, 'cannot resume - new diff',
|
||||
@@ -814,7 +820,7 @@ sub run
|
||||
$strTmpPath = $oHostBackup->repoPath() . '/temp/' . $self->stanza() . '.tmp';
|
||||
|
||||
testPathMove($oHostBackup->repoPath() . '/backup/' . $self->stanza() . "/${strBackup}", $strTmpPath);
|
||||
executeTest("sudo chmod -R g+w " . dirname($strTmpPath));
|
||||
executeTest("sudo chown -R " . $oHostBackup->userGet() . ' ' . dirname($strTmpPath));
|
||||
|
||||
$strBackup = $oHostBackup->backup(
|
||||
$strType, 'cannot resume - disabled / no repo link',
|
||||
@@ -831,22 +837,6 @@ sub run
|
||||
$strBackup, \%oManifest, undef, $bDelta, $bForce, undef, undef, undef, undef, undef, undef,
|
||||
'fail on used path', ERROR_PATH_NOT_EMPTY, '--log-level-console=detail');
|
||||
|
||||
# Fail on undef format
|
||||
$oHostBackup->manifestMunge($strBackup, INI_SECTION_BACKREST, INI_KEY_FORMAT);
|
||||
|
||||
$oHostDbMaster->restore(
|
||||
$strBackup, \%oManifest, undef, $bDelta, $bForce, undef, undef, undef, undef, undef, undef,
|
||||
'fail on undef format', ERROR_FORMAT, '--log-level-console=detail');
|
||||
|
||||
# Fail on mismatch format
|
||||
$oHostBackup->manifestMunge($strBackup, INI_SECTION_BACKREST, INI_KEY_FORMAT, undef, 0);
|
||||
|
||||
$oHostDbMaster->restore(
|
||||
$strBackup, \%oManifest, undef, $bDelta, $bForce, undef, undef, undef, undef, undef, undef,
|
||||
'fail on mismatch format', ERROR_FORMAT, '--log-level-console=detail');
|
||||
|
||||
$oHostBackup->manifestMunge($strBackup, INI_SECTION_BACKREST, INI_KEY_FORMAT, undef, BACKREST_FORMAT);
|
||||
|
||||
# Remap the base and tablespace paths
|
||||
my %oRemapHash;
|
||||
$oRemapHash{&MANIFEST_TARGET_PGDATA} = $oHostDbMaster->dbBasePath(2);
|
||||
@@ -887,7 +877,7 @@ sub run
|
||||
'e324463005236d83e6e54795dbddd20a74533bf3', $lTime, undef, undef, false);
|
||||
|
||||
# Munge the version to make sure it gets corrected on the next run
|
||||
$oHostBackup->manifestMunge($strBackup, INI_SECTION_BACKREST, INI_KEY_VERSION, undef, '0.00');
|
||||
$oHostBackup->manifestMunge($strBackup, {&INI_SECTION_BACKREST => {&INI_KEY_VERSION => '0.00'}}, false);
|
||||
|
||||
$strBackup = $oHostBackup->backup(
|
||||
$strType, 'add files and remove tablespace 2',
|
||||
@@ -1035,7 +1025,8 @@ sub run
|
||||
|
||||
# Munge the prior manifest so that option-checksum-page is missing to be sure the logic works for backups before page
|
||||
# checksums were introduced
|
||||
$oHostBackup->manifestMunge($strFullBackup, MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_CHECKSUM_PAGE, undef, undef);
|
||||
$oHostBackup->manifestMunge(
|
||||
$strFullBackup, {&MANIFEST_SECTION_BACKUP_OPTION => {&MANIFEST_KEY_CHECKSUM_PAGE => undef}}, false);
|
||||
|
||||
$strBackup = $oHostBackup->backup(
|
||||
$strType, 'add file', {oExpectedManifest => \%oManifest,
|
||||
|
||||
@@ -0,0 +1,471 @@
|
||||
####################################################################################################################################
|
||||
# InfoIniUnitTest.pm - Unit tests for Ini module
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Info::InfoIniUnitTest;
|
||||
use parent 'pgBackRestTest::Common::RunTest';
|
||||
|
||||
####################################################################################################################################
|
||||
# Perl includes
|
||||
####################################################################################################################################
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Ini;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::FileCommon;
|
||||
use pgBackRest::Version;
|
||||
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
|
||||
####################################################################################################################################
|
||||
# iniHeader
|
||||
####################################################################################################################################
|
||||
sub iniHeader
|
||||
{
|
||||
my $self = shift;
|
||||
my $oIni = shift;
|
||||
my $iFormat = shift;
|
||||
my $iVersion = shift;
|
||||
my $strChecksum = shift;
|
||||
|
||||
return
|
||||
"[backrest]" .
|
||||
"\nbackrest-checksum=\"" .
|
||||
(defined($strChecksum) ? $strChecksum : $oIni->get(INI_SECTION_BACKREST, INI_KEY_CHECKSUM)) . "\"" .
|
||||
"\nbackrest-format=" . (defined($iFormat) ? $iFormat : $oIni->get(INI_SECTION_BACKREST, INI_KEY_FORMAT)) .
|
||||
"\nbackrest-version=\"" . (defined($iVersion) ? $iVersion : $oIni->get(INI_SECTION_BACKREST, INI_KEY_VERSION)) . "\"" .
|
||||
"\n";
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# run
|
||||
####################################################################################################################################
|
||||
sub run
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Test ini file
|
||||
my $strTestFile = $self->testPath() . '/test.ini';
|
||||
my $strTestFileCopy = "${strTestFile}.copy";
|
||||
|
||||
# Test keys, values
|
||||
my $strSection = 'test-section';
|
||||
my $strKey = 'test-key';
|
||||
my $strSubKey = 'test-subkey';
|
||||
my $strValue = 'test-value';
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin("iniRender()"))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $oIni = {section1 => {key => 'value'}, section2 => {key => ['value1', 'value2']}};
|
||||
|
||||
$self->testResult(
|
||||
sub {iniRender($oIni, true)}, "[section1]\nkey=value\n\n[section2]\nkey=value1\nkey=value2\n",
|
||||
'relaxed formatting');
|
||||
$self->testResult(
|
||||
sub {iniRender($oIni, false)}, "[section1]\nkey=\"value\"\n\n[section2]\nkey=[\"value1\",\"value2\"]\n",
|
||||
'strict formatting');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin("iniParse()"))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $strIni = "[section]\nkey";
|
||||
|
||||
$self->testException(sub {iniParse($strIni)}, ERROR_CONFIG, "unable to find '=' in 'key'");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$strIni = "[section]\n# comment\n\nkey=\"value\"";
|
||||
|
||||
$self->testResult(sub {iniParse($strIni)}, '{section => {key => value}}', 'ignore blank lines and comments');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$strIni = "[section]\nkey=value";
|
||||
|
||||
$self->testResult(sub {iniParse($strIni, {bRelaxed => true})}, '{section => {key => value}}', 'relaxed value read');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$strIni = "[section]\nkey=value1\nkey=value2\nkey=value3";
|
||||
|
||||
$self->testResult(
|
||||
sub {iniParse($strIni, {bRelaxed => true})}, '{section => {key => (value1, value2, value3)}}', 'relaxed array read');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin("Ini->new()"))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $oIni = new pgBackRest::Common::Ini(
|
||||
$strTestFile, {bLoad => false, iInitFormat => 4, strInitVersion => '1.01'});
|
||||
|
||||
$self->testResult($oIni->exists(), false, 'file does not exist');
|
||||
|
||||
$oIni->save();
|
||||
|
||||
$self->testResult(
|
||||
sub {fileStringRead($strTestFile)},
|
||||
$self->iniHeader(undef, 4, '1.01', '488e5ca1a018cd7cd6d4e15150548f39f493dacd'),
|
||||
'empty with synthetic format and version');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
fileStringWrite($strTestFile);
|
||||
$self->testException(sub {new pgBackRest::Common::Ini($strTestFile)}, ERROR_CONFIG, 'no key/value pairs found');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oIni = new pgBackRest::Common::Ini($strTestFile, {bLoad => false});
|
||||
$oIni->save();
|
||||
|
||||
$self->testResult(
|
||||
sub {fileStringRead($strTestFile)},
|
||||
$self->iniHeader(undef, BACKREST_FORMAT, BACKREST_VERSION, $oIni->hash()),
|
||||
'empty with default format and version');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {new pgBackRest::Common::Ini($strTestFile)}, '[object]', 'normal load');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $hIni = iniParse(fileStringRead($strTestFile));
|
||||
$hIni->{&INI_SECTION_BACKREST}{&INI_KEY_CHECKSUM} = BOGUS;
|
||||
fileStringWrite($strTestFile, iniRender($hIni));
|
||||
fileStringWrite($strTestFileCopy, iniRender($hIni));
|
||||
|
||||
$self->testException(
|
||||
sub {new pgBackRest::Common::Ini($strTestFile)}, ERROR_CHECKSUM,
|
||||
"invalid checksum in '${strTestFile}', expected '" .
|
||||
$oIni->get(INI_SECTION_BACKREST, INI_KEY_CHECKSUM) . "' but found 'bogus'");
|
||||
|
||||
$hIni->{&INI_SECTION_BACKREST}{&INI_KEY_CHECKSUM} = $oIni->hash();
|
||||
fileStringWrite($strTestFile, iniRender($hIni));
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oIni->numericSet(INI_SECTION_BACKREST, INI_KEY_FORMAT, undef, BACKREST_FORMAT - 1);
|
||||
$oIni->save();
|
||||
|
||||
$self->testException(
|
||||
sub {new pgBackRest::Common::Ini($strTestFile)}, ERROR_FORMAT,
|
||||
"invalid format in '${strTestFile}', expected " . BACKREST_FORMAT . ' but found ' . (BACKREST_FORMAT - 1));
|
||||
|
||||
$oIni->numericSet(INI_SECTION_BACKREST, INI_KEY_FORMAT, undef, BACKREST_FORMAT);
|
||||
$oIni->save();
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oIni->set(INI_SECTION_BACKREST, INI_KEY_VERSION, undef, '1.01');
|
||||
$oIni->save();
|
||||
|
||||
$self->testResult(
|
||||
sub {fileStringRead($strTestFile)},
|
||||
$self->iniHeader($oIni, undef, '1.01'),
|
||||
'verify old version was written');
|
||||
|
||||
$oIni = new pgBackRest::Common::Ini($strTestFile);
|
||||
|
||||
$self->testResult(sub {$oIni->get(INI_SECTION_BACKREST, INI_KEY_VERSION)}, BACKREST_VERSION, 'version is updated on load');
|
||||
$self->testResult(sub {$oIni->save()}, true, 'save changes');
|
||||
|
||||
$self->testResult(
|
||||
sub {fileStringRead($strTestFile)},
|
||||
$self->iniHeader($oIni, undef, BACKREST_VERSION),
|
||||
'verify version is updated on load');
|
||||
|
||||
$self->testResult(sub {$oIni->save()}, false, 'save again with no changes');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {new pgBackRest::Common::Ini($strTestFile, {bLoad => false, strContent => fileStringRead($strTestFile)})},
|
||||
'[object]', 'new() passing content as a string');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
executeTest("rm -rf ${strTestFile}*");
|
||||
|
||||
$self->testException(
|
||||
sub {new pgBackRest::Common::Ini($strTestFile)}, ERROR_UNKNOWN,
|
||||
"unable to open ${strTestFile}");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
fileStringWrite($strTestFileCopy, BOGUS);
|
||||
|
||||
$self->testException(
|
||||
sub {new pgBackRest::Common::Ini($strTestFileCopy)}, ERROR_CONFIG,
|
||||
"key/value pair 'bogus' found outside of a section");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oIni = new pgBackRest::Common::Ini($strTestFile, {bLoad => false});
|
||||
|
||||
fileStringWrite($strTestFileCopy, iniRender($oIni->{oContent}));
|
||||
|
||||
$self->testException(
|
||||
sub {new pgBackRest::Common::Ini($strTestFileCopy)}, ERROR_CHECKSUM,
|
||||
"invalid checksum in '${strTestFileCopy}', expected '" .
|
||||
$oIni->hash() . "' but found [undef]");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oIni = new pgBackRest::Common::Ini($strTestFile, {bLoad => false});
|
||||
$oIni->{oContent}->{&INI_SECTION_BACKREST}{&INI_KEY_FORMAT} = 0;
|
||||
|
||||
$self->testResult(
|
||||
sub {$oIni->headerCheck({bIgnoreInvalid => true})}, false,
|
||||
'ignore invalid header');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
fileRemove($strTestFileCopy);
|
||||
|
||||
fileStringWrite($strTestFile, "[section]\n" . BOGUS);
|
||||
|
||||
$self->testException(sub {new pgBackRest::Common::Ini($strTestFile)}, ERROR_CONFIG, "unable to find '=' in 'bogus'");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {iniParse("[section]\n" . BOGUS, {bIgnoreInvalid => true})}, undef, 'ignore invalid content');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
fileStringWrite($strTestFile, BOGUS);
|
||||
|
||||
# main invalid, copy invalid
|
||||
$self->testException(
|
||||
sub {new pgBackRest::Common::Ini($strTestFile)}, ERROR_CONFIG, "key/value pair 'bogus' found outside of a section");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
fileStringWrite($strTestFile, iniRender($hIni));
|
||||
$hIni->{&INI_SECTION_BACKREST}{&INI_KEY_CHECKSUM} = BOGUS;
|
||||
fileStringWrite($strTestFileCopy, iniRender($hIni));
|
||||
|
||||
$self->testResult(sub {new pgBackRest::Common::Ini($strTestFile)}, '[object]', 'invalid header - load main');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin("Ini->set()"))
|
||||
{
|
||||
my $oIni = new pgBackRest::Common::Ini($strTestFile, {bLoad => false});
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testException(sub {$oIni->set()}, ERROR_ASSERT, 'strSection and strKey are required');
|
||||
$self->testException(sub {$oIni->set($strSection)}, ERROR_ASSERT, 'strSection and strKey are required');
|
||||
$self->testException(sub {$oIni->set(undef, $strKey)}, ERROR_ASSERT, 'strSection and strKey are required');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oIni->{bModified} = false;
|
||||
$self->testResult(sub {$oIni->set($strSection, $strKey, undef, $strValue)}, true, 'set key value');
|
||||
$self->testResult($oIni->modified(), true, ' check changed flag = true');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oIni->{bModified} = false;
|
||||
$self->testResult(sub {$oIni->set($strSection, $strKey, undef, $strValue)}, false, 'set same key value');
|
||||
$self->testResult($oIni->modified(), false, ' check changed flag remains false');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oIni->{bModified} = false;
|
||||
$self->testResult(sub {$oIni->set($strSection, $strKey, undef, "${strValue}2")}, true, 'set different key value');
|
||||
$self->testResult($oIni->modified(), true, ' check changed flag = true');
|
||||
|
||||
$self->testResult(sub {$oIni->get($strSection, $strKey)}, "${strValue}2", 'get last key value');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oIni->{bModified} = false;
|
||||
$self->testResult(sub {$oIni->set($strSection, $strKey, undef, undef)}, true, 'set undef key value');
|
||||
$self->testResult($oIni->modified(), true, ' check changed flag = true');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oIni->set($strSection, "${strKey}2", $strSubKey, $strValue)}, true, 'set subkey value');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin("Ini->get()"))
|
||||
{
|
||||
my $oIni = new pgBackRest::Common::Ini($strTestFile, {bLoad => false});
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testException(sub {$oIni->get()}, ERROR_ASSERT, 'strSection is required');
|
||||
|
||||
$self->testException(sub {$oIni->get($strSection)}, ERROR_ASSERT, "strSection '${strSection}' is required but not defined");
|
||||
|
||||
$self->testException(
|
||||
sub {$oIni->get($strSection, $strKey, undef)}, ERROR_ASSERT,
|
||||
"strSection '${strSection}', strKey '${strKey}' is required but not defined");
|
||||
|
||||
$self->testException(
|
||||
sub {$oIni->get($strSection, undef, $strSubKey)}, ERROR_ASSERT,
|
||||
"strKey is required when strSubKey '${strSubKey}' is requested");
|
||||
|
||||
$self->testException(
|
||||
sub {$oIni->get($strSection, $strKey, $strSubKey, true)}, ERROR_ASSERT,
|
||||
"strSection '${strSection}', strKey '${strKey}', strSubKey '${strSubKey}' is required but not defined");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oIni->get($strSection, undef, undef, false)}, '[undef]', 'section value is not required');
|
||||
|
||||
$self->testResult(sub {$oIni->get($strSection, undef, undef, false, $strValue)}, $strValue, 'section value is defaulted');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oIni->set($strSection, $strKey, $strSubKey, $strValue);
|
||||
|
||||
$self->testResult(sub {$oIni->get($strSection, "${strKey}2", "${strSubKey}2", false)}, undef, 'missing key value');
|
||||
|
||||
$self->testResult(sub {$oIni->get($strSection, $strKey, "${strSubKey}2", false)}, undef, 'missing subkey value');
|
||||
|
||||
$self->testResult(sub {$oIni->get($strSection, $strKey, $strSubKey)}, $strValue, 'get subkey value');
|
||||
|
||||
$self->testResult(sub {$oIni->get($strSection, $strKey)}, "{${strSubKey} => ${strValue}}", 'get key value');
|
||||
|
||||
$self->testResult(sub {$oIni->get($strSection)}, "{${strKey} => {${strSubKey} => ${strValue}}}", 'get section value');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin("Ini->remove()"))
|
||||
{
|
||||
my $oIni = new pgBackRest::Common::Ini($strTestFile, {bLoad => false});
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testException(sub {$oIni->remove()}, ERROR_ASSERT, 'strSection is required');
|
||||
|
||||
$self->testException(
|
||||
sub {$oIni->remove($strSection, undef, $strSubKey)}, ERROR_ASSERT,
|
||||
"strKey is required when strSubKey '${strSubKey}' is requested");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oIni->{bModified} = false;
|
||||
$self->testResult(sub {$oIni->remove($strSection)}, false, 'undefined section is not removed');
|
||||
$self->testResult($oIni->modified(), '0', ' check changed flag remains false');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oIni->set($strSection, $strKey, undef, $strValue)}, true, 'set key');
|
||||
|
||||
$oIni->{bModified} = false;
|
||||
$self->testResult(sub {$oIni->remove($strSection, $strKey)}, true, ' remove key');
|
||||
$self->testResult($oIni->modified(), '1', ' check changed flag = true');
|
||||
$self->testResult(sub {$oIni->test($strSection, $strKey)}, false, ' test key');
|
||||
$self->testResult(sub {$oIni->test($strSection)}, false, ' test section');
|
||||
|
||||
$self->testResult(sub {$oIni->set($strSection, $strKey, undef, $strValue)}, true, 'set key 1');
|
||||
$self->testResult(sub {$oIni->set($strSection, "${strKey}2", undef, $strValue)}, true, ' set key 2');
|
||||
$self->testResult(sub {$oIni->remove($strSection, $strKey)}, true, ' remove key 1');
|
||||
$self->testResult(sub {$oIni->test($strSection, $strKey)}, false, ' test key');
|
||||
$self->testResult(sub {$oIni->test($strSection)}, true, ' test section');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oIni->set($strSection, $strKey, undef, $strValue)}, true, 'set key');
|
||||
|
||||
$self->testResult(sub {$oIni->remove($strSection)}, true, ' remove section');
|
||||
$self->testResult(sub {$oIni->test($strSection)}, false, ' test section');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oIni->set($strSection, $strKey, $strSubKey, $strValue)}, true, 'set subkey');
|
||||
|
||||
$self->testResult(sub {$oIni->remove($strSection, $strKey, $strSubKey)}, true, ' remove subkey');
|
||||
$self->testResult(sub {$oIni->test($strSection, $strKey, $strSubKey)}, false, ' test subkey');
|
||||
$self->testResult(sub {$oIni->test($strSection, $strKey)}, true, ' test key');
|
||||
$self->testResult(sub {$oIni->test($strSection)}, true, ' test section');
|
||||
|
||||
$self->testResult(sub {$oIni->set($strSection, $strKey, $strSubKey, $strValue)}, true, 'set subkey 1');
|
||||
$self->testResult(sub {$oIni->set($strSection, $strKey, "${strSubKey}2", $strValue)}, true, 'set subkey 2');
|
||||
|
||||
$self->testResult(sub {$oIni->remove($strSection, $strKey, $strSubKey)}, true, ' remove subkey');
|
||||
$self->testResult(sub {$oIni->test($strSection, $strKey, $strSubKey)}, false, ' test subkey');
|
||||
$self->testResult(sub {$oIni->test($strSection, $strKey)}, true, ' test key');
|
||||
$self->testResult(sub {$oIni->test($strSection)}, true, ' test section');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin("Ini->test()"))
|
||||
{
|
||||
my $oIni = new pgBackRest::Common::Ini($strTestFile, {bLoad => false});
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oIni->test($strSection, $strKey)}, false, 'test undefined key');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oIni->set($strSection, $strKey, undef, $strValue)}, true, 'define key');
|
||||
|
||||
$self->testResult(sub {$oIni->test($strSection, $strKey)}, true, 'test key exists');
|
||||
|
||||
$self->testResult(sub {$oIni->test($strSection, $strKey, undef, $strValue)}, true, 'test key value');
|
||||
|
||||
$self->testResult(sub {$oIni->test($strSection, $strKey, undef, BOGUS)}, false, 'test key invalid value');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin("Ini->boolSet() & Ini->boolGet() & Ini->boolTest()"))
|
||||
{
|
||||
my $oIni = new pgBackRest::Common::Ini($strTestFile, {bLoad => false});
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oIni->boolTest($strSection, $strKey)}, false, 'test bool on undefined key');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oIni->boolGet($strSection, $strKey, undef, false, false)}, false, 'get bool default false value');
|
||||
$self->testResult(sub {$oIni->boolGet($strSection, $strKey, undef, false, true)}, true, 'get bool default true value');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oIni->boolSet($strSection, $strKey, undef, undef)}, true, 'set bool false (undef) value');
|
||||
$self->testResult(sub {$oIni->boolGet($strSection, $strKey)}, false, ' check bool false value');
|
||||
|
||||
$self->testResult(sub {$oIni->boolTest($strSection, $strKey, undef, false)}, true, 'test bool on false key');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oIni->boolSet($strSection, $strKey, undef, false)}, false, 'set bool false value');
|
||||
$self->testResult(sub {$oIni->boolGet($strSection, $strKey)}, false, ' check value');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oIni->boolSet($strSection, $strKey, undef, true)}, true, 'set bool false value');
|
||||
$self->testResult(sub {$oIni->boolGet($strSection, $strKey)}, true, ' check value');
|
||||
|
||||
$self->testResult(sub {$oIni->boolTest($strSection, $strKey, undef, true)}, true, 'test bool on true key');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin("Ini->numericSet() & Ini->numericGet() & Ini->numericTest()"))
|
||||
{
|
||||
my $oIni = new pgBackRest::Common::Ini($strTestFile, {bLoad => false});
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oIni->numericSet($strSection, $strKey)}, true, 'set numeric undef value');
|
||||
$self->testResult(sub {$oIni->test($strSection, $strKey)}, false, 'test numeric undef value');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oIni->numericGet($strSection, $strKey, undef, false, 1000)}, 1000, 'get numeric default value');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oIni->numericSet($strSection, $strKey, undef, 0)}, true, 'set numeric 0 value');
|
||||
$self->testResult(sub {$oIni->numericGet($strSection, $strKey)}, 0, ' check value');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oIni->numericSet($strSection, $strKey, undef, 0)}, false, 'set numeric 0 value again');
|
||||
$self->testResult(sub {$oIni->numericGet($strSection, $strKey)}, 0, ' check value');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oIni->numericSet($strSection, $strKey, undef, -100)}, true, 'set numeric -100 value');
|
||||
$self->testResult(sub {$oIni->numericGet($strSection, $strKey)}, -100, ' check value');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin("Ini->keys()"))
|
||||
{
|
||||
my $oIni = new pgBackRest::Common::Ini($strTestFile, {bLoad => false});
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oIni->keys($strSection)}, '[undef]', 'section undefined');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oIni->set($strSection, 'a', undef, $strValue);
|
||||
$oIni->set($strSection, 'c', undef, $strValue);
|
||||
$oIni->set($strSection, 'b', undef, $strValue);
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oIni->keys($strSection)}, '(a, b, c)', 'sort forward (default)');
|
||||
|
||||
$self->testResult(sub {$oIni->keys($strSection, INI_SORT_FORWARD)}, '(a, b, c)', 'sort forward');
|
||||
|
||||
$self->testResult(sub {$oIni->keys($strSection, INI_SORT_REVERSE)}, '(c, b, a)', 'sort reverse');
|
||||
|
||||
$self->testResult(sub {sort($oIni->keys($strSection, INI_SORT_NONE))}, '(a, b, c)', 'sort none');
|
||||
|
||||
$self->testException(sub {sort($oIni->keys($strSection, BOGUS))}, ERROR_ASSERT, "invalid strSortOrder '" . BOGUS . "'");
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
Reference in New Issue
Block a user