You've already forked pgbackrest
mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-06-14 23:44:58 +02:00
pgBackRest is now pure C.
Remove embedded Perl from the distributed binary. This includes code, configure, Makefile, and packages. The distributed binary is now pure C. Remove storagePathEnforceSet() from the C Storage object which allowed Perl to write outside of the storage base directory. Update mock/all and real/all integration tests to use storageLocal() where they were violating this rule. Remove "c" option that allowed the remote to tell if it was being called from C or Perl. Code to convert options to JSON for passing to Perl (perl/config.c) has been moved to LibC since it is still required for Perl integration tests. Update build and installation instructions in the user guide. Remove all Perl unit tests. Remove obsolete Perl code. In particular this included all the Perl protocol code which required modifications to the Perl storage, manifest, and db objects that are still required for integration testing but only run locally. Any remaining Perl code is required for testing, documentation, or code generation. Rename perlReq to binReq in define.yaml to indicate that the binary is required for a test. This had been the actual meaning for quite some time but the key was never renamed.
This commit is contained in:
@ -1,62 +0,0 @@
|
||||
####################################################################################################################################
|
||||
# Test Binary to String Encode/Decode
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Module::Common::CommonEncodePerlTest;
|
||||
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::LibC qw(:encode);
|
||||
use pgBackRest::Version;
|
||||
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
|
||||
####################################################################################################################################
|
||||
# run
|
||||
####################################################################################################################################
|
||||
sub run
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin("encodeToStrBase64() and decodeToBinBase64()"))
|
||||
{
|
||||
my $strData = 'string_to_encode';
|
||||
my $strEncodedData = 'c3RyaW5nX3RvX2VuY29kZQ==';
|
||||
|
||||
$self->testResult(sub {encodeToStr(ENCODE_TYPE_BASE64, $strData)}, $strEncodedData, 'encode string');
|
||||
$self->testResult(sub {decodeToBin(ENCODE_TYPE_BASE64, $strEncodedData)}, $strData, 'decode string');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $tData =
|
||||
pack('C', 1) . pack('C', 2) . pack('C', 3) . pack('C', 4) . pack('C', 5) . pack('C', 4) . pack('C', 3) . pack('C', 2);
|
||||
my $tEncodedData = 'AQIDBAUEAwI=';
|
||||
|
||||
$self->testResult(sub {encodeToStr(ENCODE_TYPE_BASE64, $tData)}, $tEncodedData, 'encode binary');
|
||||
$self->testResult(sub {decodeToBin(ENCODE_TYPE_BASE64, $tEncodedData)}, $tData, 'decode binary');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$tData .= pack('C', 1);
|
||||
$tEncodedData = 'AQIDBAUEAwIB';
|
||||
|
||||
$self->testResult(sub {encodeToStr(ENCODE_TYPE_BASE64, $tData)}, $tEncodedData, 'encode binary');
|
||||
$self->testResult(sub {decodeToBin(ENCODE_TYPE_BASE64, $tEncodedData)}, $tData, 'decode binary');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testException(sub {encodeToStr(99999, '')}, ERROR_ASSERT, 'invalid encode type 99999');
|
||||
$self->testException(
|
||||
sub {decodeToBin(ENCODE_TYPE_BASE64, "XX")}, ERROR_FORMAT, 'base64 size 2 is not evenly divisible by 4');
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
@ -1,533 +0,0 @@
|
||||
####################################################################################################################################
|
||||
# Unit tests for Ini module
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Module::Common::CommonIniPerlTest;
|
||||
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::Config::Config;
|
||||
use pgBackRest::Storage::Base;
|
||||
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]\n" .
|
||||
"backrest-format=" . (defined($iFormat) ? $iFormat : $oIni->get(INI_SECTION_BACKREST, INI_KEY_FORMAT)) . "\n" .
|
||||
"backrest-version=\"" . (defined($iVersion) ? $iVersion : $oIni->get(INI_SECTION_BACKREST, INI_KEY_VERSION)) . "\"\n" .
|
||||
"\n" .
|
||||
"[backrest]\n" .
|
||||
"backrest-checksum=\"" .
|
||||
(defined($strChecksum) ? $strChecksum : $oIni->get(INI_SECTION_BACKREST, INI_KEY_CHECKSUM)) . "\"\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()"))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {(new pgBackRest::Common::Ini($strTestFile, {bIgnoreMissing => true}))->exists()}, false, 'ignore missing');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $oIni = new pgBackRest::Common::Ini(
|
||||
$strTestFile, {bLoad => false, iInitFormat => 4, strInitVersion => '1.01'});
|
||||
|
||||
$self->testResult($oIni->exists(), false, 'file does not exist');
|
||||
|
||||
$oIni->saveCopy();
|
||||
|
||||
$self->testResult($oIni->exists(), false, 'file does not exist after saveCopy()');
|
||||
|
||||
$self->testResult(
|
||||
sub {${storageTest()->get($strTestFile . INI_COPY_EXT)}},
|
||||
$self->iniHeader(undef, 4, '1.01', '488e5ca1a018cd7cd6d4e15150548f39f493dacd'),
|
||||
'empty with synthetic format and version');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oIni = new pgBackRest::Common::Ini($strTestFile, {bLoad => false});
|
||||
$oIni->saveCopy();
|
||||
|
||||
$self->testResult(
|
||||
sub {${storageTest()->get($strTestFile . INI_COPY_EXT)}},
|
||||
$self->iniHeader(undef, REPOSITORY_FORMAT, PROJECT_VERSION, $oIni->hash()),
|
||||
'empty with default format and version');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {storageTest()->list($self->testPath())},
|
||||
'test.ini.copy',
|
||||
'only copy is saved');
|
||||
|
||||
$oIni->save();
|
||||
|
||||
$self->testResult(
|
||||
sub {storageTest()->list($self->testPath())},
|
||||
'(test.ini, test.ini.copy)',
|
||||
'both versions are saved');
|
||||
|
||||
$self->testException(
|
||||
sub {$oIni->saveCopy()}, ERROR_ASSERT,
|
||||
"cannot save copy only when '${strTestFile}' exists");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {new pgBackRest::Common::Ini($strTestFile)}, '[object]', 'normal load');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $hIni = iniParse(${storageTest()->get($strTestFile)});
|
||||
$hIni->{&INI_SECTION_BACKREST}{&INI_KEY_CHECKSUM} = BOGUS;
|
||||
storageTest()->put($strTestFile, iniRender($hIni));
|
||||
storageTest()->put($strTestFileCopy, iniRender($hIni));
|
||||
|
||||
$self->testException(
|
||||
sub {new pgBackRest::Common::Ini($strTestFile)}, ERROR_FILE_MISSING,
|
||||
"unable to open ${strTestFile} or ${strTestFile}" . INI_COPY_EXT);
|
||||
# "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();
|
||||
storageTest()->put($strTestFile, iniRender($hIni));
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oIni->numericSet(INI_SECTION_BACKREST, INI_KEY_FORMAT, undef, REPOSITORY_FORMAT - 1);
|
||||
$oIni->save();
|
||||
|
||||
$self->testException(
|
||||
sub {new pgBackRest::Common::Ini($strTestFile)}, ERROR_FILE_MISSING,
|
||||
"unable to open ${strTestFile} or ${strTestFile}" . INI_COPY_EXT);
|
||||
# "invalid format in '${strTestFile}', expected " . REPOSITORY_FORMAT . ' but found ' . (REPOSITORY_FORMAT - 1));
|
||||
|
||||
$oIni->numericSet(INI_SECTION_BACKREST, INI_KEY_FORMAT, undef, REPOSITORY_FORMAT);
|
||||
$oIni->save();
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oIni->set(INI_SECTION_BACKREST, INI_KEY_VERSION, undef, '1.01');
|
||||
$oIni->save();
|
||||
|
||||
$self->testResult(
|
||||
sub {${storageTest()->get($strTestFile . INI_COPY_EXT)}},
|
||||
$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)}, PROJECT_VERSION, 'version is updated on load');
|
||||
$oIni->save();
|
||||
|
||||
$self->testResult(
|
||||
sub {${storageTest()->get($strTestFile . INI_COPY_EXT)}},
|
||||
$self->iniHeader($oIni, undef, PROJECT_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 => ${storageTest()->get($strTestFile)}})},
|
||||
'[object]', 'new() passing content as a string');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
executeTest("rm -rf ${strTestFile}*");
|
||||
|
||||
$self->testException(
|
||||
sub {new pgBackRest::Common::Ini($strTestFile)}, ERROR_FILE_MISSING,
|
||||
"unable to open ${strTestFile} or ${strTestFile}" . INI_COPY_EXT);
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
storageTest()->put($strTestFileCopy, BOGUS);
|
||||
|
||||
$self->testException(
|
||||
sub {new pgBackRest::Common::Ini($strTestFile)}, ERROR_FILE_MISSING,
|
||||
"unable to open ${strTestFile} or ${strTestFile}" . INI_COPY_EXT);
|
||||
# "key/value pair 'bogus' found outside of a section");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $oIniSource = new pgBackRest::Common::Ini($strTestFile, {bLoad => false});
|
||||
|
||||
storageTest()->put($strTestFileCopy, iniRender($oIniSource->{oContent}));
|
||||
|
||||
$self->testException(
|
||||
sub {new pgBackRest::Common::Ini($strTestFile)}, ERROR_FILE_MISSING,
|
||||
"unable to open ${strTestFile} or ${strTestFile}" . INI_COPY_EXT);
|
||||
# "invalid checksum in '${strTestFileCopy}', expected '" .
|
||||
# $oIniSource->hash() . "' but found [undef]");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oIniSource = new pgBackRest::Common::Ini($strTestFile, {bLoad => false});
|
||||
$oIniSource->save();
|
||||
|
||||
storageTest()->put($strTestFile, BOGUS);
|
||||
|
||||
# main invalid, copy ok
|
||||
$self->testResult(sub {new pgBackRest::Common::Ini($strTestFile)}, '[object]', 'invalid main - load copy');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
storageTest()->remove($strTestFileCopy);
|
||||
|
||||
storageTest()->put($strTestFile, "[section]\n" . BOGUS);
|
||||
|
||||
# main invalid, copy missing
|
||||
$self->testException
|
||||
(sub {new pgBackRest::Common::Ini($strTestFile)}, ERROR_FILE_MISSING,
|
||||
"unable to open ${strTestFile} or ${strTestFile}" . INI_COPY_EXT);
|
||||
#"unable to find '=' in 'bogus'");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
storageTest()->put($strTestFile, iniRender($oIniSource->{oContent}));
|
||||
|
||||
$self->testResult(sub {new pgBackRest::Common::Ini($strTestFile)}, '[object]', 'main ok, copy missing');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
storageTest()->put($strTestFileCopy, BOGUS);
|
||||
|
||||
# main ok, copy invalid
|
||||
$self->testResult(sub {new pgBackRest::Common::Ini($strTestFile)}, '[object]', 'main ok, copy invalid');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
storageTest()->put($strTestFile, BOGUS);
|
||||
|
||||
# main invalid, copy invalid
|
||||
$self->testException(
|
||||
sub {new pgBackRest::Common::Ini($strTestFile)}, ERROR_FILE_MISSING,
|
||||
"unable to open ${strTestFile} or ${strTestFile}" . INI_COPY_EXT);
|
||||
# "key/value pair 'bogus' found outside of a section");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
storageTest()->put($strTestFile, iniRender($hIni));
|
||||
$hIni->{&INI_SECTION_BACKREST}{&INI_KEY_CHECKSUM} = BOGUS;
|
||||
storageTest()->put($strTestFileCopy, iniRender($hIni));
|
||||
|
||||
$self->testResult(sub {new pgBackRest::Common::Ini($strTestFile)}, '[object]', 'invalid copy header - load main');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$hIni->{&INI_SECTION_BACKREST}{&INI_KEY_CHECKSUM} = $oIni->hash();
|
||||
storageTest()->put($strTestFileCopy, iniRender($hIni));
|
||||
$hIni->{&INI_SECTION_BACKREST}{&INI_KEY_CHECKSUM} = BOGUS;
|
||||
storageTest()->put($strTestFile, iniRender($hIni));
|
||||
|
||||
$self->testResult(sub {new pgBackRest::Common::Ini($strTestFile)}, '[object]', 'invalid main header - load copy');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
# Prepend encryption Magic signature to copy (main invalid) to simulate encryption
|
||||
executeTest('echo "' . CIPHER_MAGIC . '$(cat ' . $strTestFileCopy . ')" > ' . $strTestFileCopy);
|
||||
|
||||
$self->testException(sub {new pgBackRest::Common::Ini($strTestFile)}, ERROR_CRYPTO,
|
||||
"unable to parse '$strTestFileCopy'" .
|
||||
"\nHINT: is or was the repo encrypted?");
|
||||
|
||||
# Prepend encryption Magic signature to main to simulate encryption
|
||||
executeTest('echo "' . CIPHER_MAGIC . '$(cat ' . $strTestFile . ')" > ' . $strTestFile);
|
||||
|
||||
$self->testException(sub {new pgBackRest::Common::Ini($strTestFile)}, ERROR_CRYPTO,
|
||||
"unable to parse '$strTestFile'" .
|
||||
"\nHINT: is or was the repo encrypted?");
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
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;
|
@ -1,259 +0,0 @@
|
||||
####################################################################################################################################
|
||||
# Tests for Common::Io::Buffered module
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Module::Common::CommonIoBufferedPerlTest;
|
||||
use parent 'pgBackRestTest::Common::RunTest';
|
||||
|
||||
####################################################################################################################################
|
||||
# Perl includes
|
||||
####################################################################################################################################
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
use IO::Socket::UNIX;
|
||||
use Time::HiRes qw(usleep);
|
||||
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Io::Buffered;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::Wait;
|
||||
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
|
||||
####################################################################################################################################
|
||||
# socketServer
|
||||
####################################################################################################################################
|
||||
sub socketServer
|
||||
{
|
||||
my $self = shift;
|
||||
my $strSocketFile = shift;
|
||||
my $fnServer = shift;
|
||||
|
||||
# Fork off the server
|
||||
if (fork() == 0)
|
||||
{
|
||||
# Open the domain socket
|
||||
my $oSocketServer = IO::Socket::UNIX->new(Type => SOCK_STREAM(), Local => $strSocketFile, Listen => 1);
|
||||
&log(INFO, " * socket server open");
|
||||
|
||||
# Wait for a connection and create IO object
|
||||
my $oConnection = $oSocketServer->accept();
|
||||
my $oIoHandle = new pgBackRest::Common::Io::Handle('socket server', $oConnection, $oConnection);
|
||||
&log(INFO, " * socket server connected");
|
||||
|
||||
# Run server function
|
||||
$fnServer->($oIoHandle);
|
||||
|
||||
# Shutdown server
|
||||
$oSocketServer->close();
|
||||
&log(INFO, " * socket server closed");
|
||||
unlink($strSocketFile);
|
||||
exit 0;
|
||||
}
|
||||
|
||||
# Wait for client socket
|
||||
my $oWait = waitInit(5);
|
||||
while (!-e $strSocketFile && waitMore($oWait)) {};
|
||||
|
||||
# Open the client socket
|
||||
my $oClient = IO::Socket::UNIX->new(Type => SOCK_STREAM(), Peer => $strSocketFile);
|
||||
|
||||
if (!defined($oClient))
|
||||
{
|
||||
logErrorResult(ERROR_FILE_OPEN, 'unable to open client socket', $OS_ERROR);
|
||||
}
|
||||
|
||||
&log(INFO, " * socket client connected");
|
||||
|
||||
return $oClient;
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# run
|
||||
####################################################################################################################################
|
||||
sub run
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Test data
|
||||
my $strSocketFile = $self->testPath() . qw{/} . 'domain.socket';
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('new() & timeout() & bufferMax()'))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $oIoBuffered = $self->testResult(
|
||||
sub {new pgBackRest::Common::Io::Buffered(
|
||||
new pgBackRest::Common::Io::Handle('test'), 10, 2048)}, '[object]', 'new - no handles');
|
||||
|
||||
$self->testResult(sub {$oIoBuffered->timeout()}, 10, ' check timeout');
|
||||
$self->testResult(sub {$oIoBuffered->bufferMax()}, 2048, ' check buffer max');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('readLine() & writeLine()'))
|
||||
{
|
||||
my $oClient = $self->socketServer($strSocketFile, sub
|
||||
{
|
||||
my $oIoHandle = shift;
|
||||
|
||||
my $tResponse = '';
|
||||
my $tData;
|
||||
|
||||
# Ack after timeout
|
||||
while (length($tResponse) != 1) {$oIoHandle->read(\$tResponse, 1)};
|
||||
|
||||
# Write 8 char line
|
||||
$tResponse = '';
|
||||
$tData = "12345678\n";
|
||||
$oIoHandle->write(\$tData);
|
||||
while (length($tResponse) != 1) {$oIoHandle->read(\$tResponse, 1)};
|
||||
|
||||
# Write 3 lines
|
||||
$tResponse = '';
|
||||
$tData = "1\n2\n345678\n";
|
||||
$oIoHandle->write(\$tData);
|
||||
while (length($tResponse) != 1) {$oIoHandle->read(\$tResponse, 1)};
|
||||
|
||||
# Write blank line
|
||||
$tResponse = '';
|
||||
$tData = "\n";
|
||||
$oIoHandle->write(\$tData);
|
||||
while (length($tResponse) != 1) {$oIoHandle->read(\$tResponse, 1)};
|
||||
|
||||
# Write char with no linefeed
|
||||
$tResponse = '';
|
||||
$tData = "A";
|
||||
$oIoHandle->write(\$tData);
|
||||
while (length($tResponse) != 1) {$oIoHandle->read(\$tResponse, 1)};
|
||||
|
||||
# Write linefeed
|
||||
$tResponse = '';
|
||||
$tData = "\n";
|
||||
$oIoHandle->write(\$tData);
|
||||
while (length($tResponse) != 1) {$oIoHandle->read(\$tResponse, 1)};
|
||||
});
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $oIoBuffered = $self->testResult(
|
||||
sub {new pgBackRest::Common::Io::Buffered(
|
||||
new pgBackRest::Common::Io::Handle('socket client', $oClient, $oClient), 1, 4)}, '[object]', 'open');
|
||||
|
||||
$self->testException(
|
||||
sub {$oIoBuffered->readLine()}, ERROR_FILE_READ, 'unable to read line after 1 second(s) from socket client');
|
||||
|
||||
$oIoBuffered->writeLine();
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oIoBuffered->readLine()}, '12345678', 'read 8 char line');
|
||||
$oIoBuffered->writeLine();
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oIoBuffered->readLine()}, '1', 'read 1 char line');
|
||||
$self->testResult(sub {$oIoBuffered->readLine()}, '2', 'read 1 char line');
|
||||
$self->testResult(sub {$oIoBuffered->readLine()}, '345678', 'read 6 char line');
|
||||
$oIoBuffered->writeLine();
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oIoBuffered->readLine()}, '', 'read blank line');
|
||||
$oIoBuffered->writeLine();
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oIoBuffered->readLine(undef, false)}, undef, 'read ignoring error');
|
||||
|
||||
$self->testException(
|
||||
sub {$oIoBuffered->readLine(undef, true)}, ERROR_FILE_READ,
|
||||
'unable to read line after 1 second(s) from socket client');
|
||||
|
||||
# Clear buffer so EOF tests pass
|
||||
$oIoBuffered->writeLine();
|
||||
$oIoBuffered->readLine();
|
||||
$oIoBuffered->writeLine();
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testException(sub {$oIoBuffered->readLine()}, ERROR_FILE_READ, 'unexpected EOF reading line from socket client');
|
||||
|
||||
$self->testException(
|
||||
sub {$oIoBuffered->readLine(false)}, ERROR_FILE_READ, 'unexpected EOF reading line from socket client');
|
||||
|
||||
$self->testResult(sub {$oIoBuffered->readLine(true)}, undef, 'ignore EOF');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('read'))
|
||||
{
|
||||
my $tBuffer;
|
||||
|
||||
my $oClient = $self->socketServer($strSocketFile, sub
|
||||
{
|
||||
my $oIoHandle = shift;
|
||||
|
||||
my $tResponse = '';
|
||||
my $tData;
|
||||
|
||||
# Ack after timeout
|
||||
while (length($tResponse) != 1) {$oIoHandle->read(\$tResponse, 1)};
|
||||
|
||||
# Write mixed buffer
|
||||
$tResponse = '';
|
||||
$tData = "123\n123\n1";
|
||||
$oIoHandle->write(\$tData);
|
||||
while (length($tResponse) != 1) {$oIoHandle->read(\$tResponse, 1)};
|
||||
|
||||
# Write buffer
|
||||
$tResponse = '';
|
||||
$tData = "23456789";
|
||||
$oIoHandle->write(\$tData);
|
||||
|
||||
# Wait before writing the rest to force client to loop
|
||||
usleep(500);
|
||||
$tData = "0";
|
||||
$oIoHandle->write(\$tData);
|
||||
while (length($tResponse) != 1) {$oIoHandle->read(\$tResponse, 1)};
|
||||
});
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $oIoBuffered = $self->testResult(
|
||||
sub {new pgBackRest::Common::Io::Buffered(
|
||||
new pgBackRest::Common::Io::Handle('socket client', $oClient, $oClient), 1, 8)}, '[object]', 'open');
|
||||
|
||||
$self->testException(
|
||||
sub {$oIoBuffered->read(\$tBuffer, 1, true)}, ERROR_FILE_READ,
|
||||
'unable to read 1 byte(s) after 1 second(s) from socket client');
|
||||
|
||||
$self->testResult(sub {$oIoBuffered->read(\$tBuffer, 1)}, 0, ' read 0 char buffer');
|
||||
|
||||
$oIoBuffered->writeLine();
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oIoBuffered->readLine()}, '123', ' read 3 char line');
|
||||
|
||||
undef($tBuffer);
|
||||
$self->testResult(sub {$oIoBuffered->read(\$tBuffer, 1)}, 1, ' read 1 char buffer');
|
||||
$self->testResult(sub {$tBuffer}, '1', ' check 1 char buffer');
|
||||
|
||||
$self->testResult(sub {$oIoBuffered->read(\$tBuffer, 3)}, 3, ' read 3 char buffer');
|
||||
$self->testResult(sub {$tBuffer}, "123\n", ' check 3 char buffer');
|
||||
|
||||
$oIoBuffered->writeLine();
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
undef($tBuffer);
|
||||
$self->testResult(sub {$oIoBuffered->read(\$tBuffer, 10)}, 10, ' read 10 char buffer');
|
||||
$self->testResult(sub {$tBuffer}, '1234567890', ' check 10 char buffer');
|
||||
|
||||
$oIoBuffered->writeLine();
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oIoBuffered->read(\$tBuffer, 5)}, 0, ' expect EOF');
|
||||
|
||||
$self->testException(
|
||||
sub {$oIoBuffered->read(\$tBuffer, 5, true)}, ERROR_FILE_READ,
|
||||
'unable to read 5 byte(s) due to EOF from socket client');
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
@ -1,209 +0,0 @@
|
||||
####################################################################################################################################
|
||||
# Tests for Common::Io::Handle module
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Module::Common::CommonIoHandlePerlTest;
|
||||
use parent 'pgBackRestTest::Common::RunTest';
|
||||
|
||||
####################################################################################################################################
|
||||
# Perl includes
|
||||
####################################################################################################################################
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
use Fcntl qw(O_RDONLY O_WRONLY O_CREAT O_TRUNC O_NONBLOCK);
|
||||
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Io::Base;
|
||||
use pgBackRest::Common::Io::Handle;
|
||||
use pgBackRest::Common::Log;
|
||||
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
|
||||
####################################################################################################################################
|
||||
# run
|
||||
####################################################################################################################################
|
||||
sub run
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Test data
|
||||
my $strFile = $self->testPath() . qw{/} . 'file.txt';
|
||||
my $strFileContent = 'TESTDATA';
|
||||
my $iFileLength = length($strFileContent);
|
||||
my $iFileLengthHalf = int($iFileLength / 2);
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('new() & handleRead() & handleReadSet() & handleWrite() & handleWriteSet()'))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $oIoHandle = $self->testResult(
|
||||
sub {new pgBackRest::Common::Io::Handle('test', undef, undef)}, '[object]', 'new - no handles');
|
||||
|
||||
$self->testResult(sub {$oIoHandle->id()}, 'test', ' check error msg');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {$oIoHandle->handleReadSet(1)}, 1, ' set read handle');
|
||||
$self->testResult(sub {$oIoHandle->handleRead()}, 1, ' check read handle');
|
||||
$self->testResult(sub {$oIoHandle->handleWrite()}, undef, ' check write handle');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {$oIoHandle->handleWriteSet(2)}, 2, ' set write handle');
|
||||
$self->testResult(sub {$oIoHandle->handleRead()}, 1, ' check read handle');
|
||||
$self->testResult(sub {$oIoHandle->handleWrite()}, 2, ' check write handle');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oIoHandle = $self->testResult(
|
||||
sub {new pgBackRest::Common::Io::Handle('test', 1, undef)}, '[object]', 'new - read handle');
|
||||
|
||||
$self->testResult(sub {$oIoHandle->handleRead()}, 1, ' check read handle');
|
||||
$self->testResult(sub {$oIoHandle->handleWrite()}, undef, ' check write handle');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oIoHandle = $self->testResult(
|
||||
sub {new pgBackRest::Common::Io::Handle('test', undef, 2)}, '[object]', 'new - write handle');
|
||||
|
||||
$self->testResult(sub {$oIoHandle->handleRead()}, undef, ' check read handle');
|
||||
$self->testResult(sub {$oIoHandle->handleWrite()}, 2, ' check write handle');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oIoHandle = $self->testResult(
|
||||
sub {new pgBackRest::Common::Io::Handle('test', 1, 2)}, '[object]', 'new - read/write handle');
|
||||
|
||||
$self->testResult(sub {$oIoHandle->handleRead()}, 1, ' check read handle');
|
||||
$self->testResult(sub {$oIoHandle->handleWrite()}, 2, ' check write handle');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('read()'))
|
||||
{
|
||||
my $tContent;
|
||||
my $fhRead;
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
executeTest("echo -n '${strFileContent}' | tee ${strFile}");
|
||||
|
||||
sysopen($fhRead, $strFile, O_RDONLY)
|
||||
or confess &log(ERROR, "unable to open '${strFile}'");
|
||||
|
||||
my $oIoHandle = $self->testResult(sub {new pgBackRest::Common::Io::Handle("'$strFile'", $fhRead)}, '[object]', 'open');
|
||||
$self->testException(
|
||||
sub {$oIoHandle->read(\$tContent, -1)}, ERROR_FILE_READ, "unable to read from '${strFile}': Negative length");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$tContent = undef;
|
||||
|
||||
sysopen($fhRead, $strFile, O_RDONLY)
|
||||
or confess &log(ERROR, "unable to open '${strFile}'");
|
||||
|
||||
$oIoHandle = $self->testResult(sub {new pgBackRest::Common::Io::Handle("'$strFile'", $fhRead)}, '[object]', 'open');
|
||||
|
||||
$self->testResult(sub {$oIoHandle->read(\$tContent, $iFileLengthHalf)}, $iFileLengthHalf, ' read part 1');
|
||||
$self->testResult($tContent, substr($strFileContent, 0, $iFileLengthHalf), ' check read');
|
||||
|
||||
$self->testResult(sub {$oIoHandle->eof()}, false, ' not eof');
|
||||
|
||||
$self->testResult(
|
||||
sub {$oIoHandle->read(
|
||||
\$tContent, $iFileLength - $iFileLengthHalf)}, $iFileLength - $iFileLengthHalf, ' read part 2');
|
||||
$self->testResult($tContent, $strFileContent, ' check read');
|
||||
|
||||
$self->testResult(sub {$oIoHandle->read(\$tContent, 1)}, 0, ' zero read');
|
||||
$self->testResult(sub {$oIoHandle->eof()}, true, ' eof');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('write()'))
|
||||
{
|
||||
my $tContent;
|
||||
my $fhRead;
|
||||
my $fhWrite;
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
sysopen($fhWrite, $strFile, O_WRONLY | O_CREAT | O_TRUNC)
|
||||
or confess &log(ERROR, "unable to open '${strFile}'");
|
||||
|
||||
my $oIoHandle = $self->testResult(
|
||||
sub {new pgBackRest::Common::Io::Handle("'$strFile'", undef, $fhWrite)}, '[object]', 'open write');
|
||||
|
||||
$self->testException(
|
||||
sub {$oIoHandle->write(undef)}, ERROR_FILE_WRITE,
|
||||
"unable to write to '${strFile}': Can't use an undefined value as a SCALAR reference");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$tContent = substr($strFileContent, 0, $iFileLengthHalf);
|
||||
$self->testResult(sub {$oIoHandle->write(\$tContent)}, $iFileLengthHalf, ' write part 1');
|
||||
$self->testResult(sub {$oIoHandle->size()}, $iFileLengthHalf, ' check part 1 size');
|
||||
|
||||
$tContent = substr($strFileContent, $iFileLengthHalf);
|
||||
$self->testResult(sub {$oIoHandle->write(\$tContent)}, $iFileLength - $iFileLengthHalf, ' write part 2');
|
||||
$self->testResult(sub {$oIoHandle->size()}, $iFileLength, ' check part 2 size');
|
||||
$self->testResult(sub {$oIoHandle->close()}, true, ' close');
|
||||
|
||||
sysopen($fhRead, $strFile, O_RDONLY)
|
||||
or confess &log(ERROR, "unable to open '${strFile}'");
|
||||
|
||||
$oIoHandle = $self->testResult(sub {new pgBackRest::Common::Io::Handle("'$strFile'", $fhRead)}, '[object]', 'open read');
|
||||
|
||||
$tContent = undef;
|
||||
$self->testResult(sub {$oIoHandle->read(\$tContent, $iFileLength)}, $iFileLength, ' read');
|
||||
$self->testResult($tContent, $strFileContent, ' check write content');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('result() & resultSet()'))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $oIoHandle = $self->testResult(
|
||||
sub {new pgBackRest::Common::Io::Handle('test', undef, undef)}, '[object]', 'new - no handles');
|
||||
|
||||
$self->testResult(sub {$oIoHandle->resultSet('Module::1', 1)}, 1, ' set int result');
|
||||
$self->testResult(sub {$oIoHandle->resultSet('Module::2', {value => 2})}, '{value => 2}', ' set hash result');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oIoHandle->result('Module::1')}, 1, ' check int result');
|
||||
$self->testResult(sub {$oIoHandle->result('Module::2')}, '{value => 2}', ' check hash result');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oIoHandle->{rhResult}}, '{Module::1 => 1, Module::2 => {value => 2}}', ' check all results');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('className()'))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $oIoHandle = $self->testResult(
|
||||
sub {new pgBackRest::Common::Io::Handle('test', undef, undef)}, '[object]', 'new - no handles');
|
||||
|
||||
$self->testResult(sub {$oIoHandle->className()}, COMMON_IO_HANDLE, ' check class name');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('close()'))
|
||||
{
|
||||
my $tContent;
|
||||
my $fhRead;
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
executeTest("echo -n '${strFileContent}' | tee ${strFile}");
|
||||
|
||||
sysopen($fhRead, $strFile, O_RDONLY)
|
||||
or confess &log(ERROR, "unable to open '${strFile}'");
|
||||
|
||||
my $oIoHandle = $self->testResult(sub {new pgBackRest::Common::Io::Handle("'$strFile'", $fhRead)}, '[object]', 'open read');
|
||||
$self->testResult(sub {$oIoHandle->read(\$tContent, $iFileLengthHalf)}, $iFileLengthHalf, ' read');
|
||||
$self->testResult(sub {$oIoHandle->close()}, true, ' close');
|
||||
$self->testResult(sub {$oIoHandle->close()}, true, ' close again');
|
||||
|
||||
$self->testResult(sub {$oIoHandle->result(COMMON_IO_HANDLE)}, $iFileLengthHalf, ' check result');
|
||||
|
||||
# Destroy and to make sure close runs again
|
||||
undef($oIoHandle);
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
@ -1,72 +0,0 @@
|
||||
####################################################################################################################################
|
||||
# Tests for Common::Io::Process module
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Module::Common::CommonIoProcessPerlTest;
|
||||
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::Io::Buffered;
|
||||
use pgBackRest::Common::Io::Process;
|
||||
use pgBackRest::Common::Log;
|
||||
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
|
||||
####################################################################################################################################
|
||||
# run
|
||||
####################################################################################################################################
|
||||
sub run
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Test data
|
||||
my $strFile = $self->testPath() . qw{/} . 'file.txt';
|
||||
my $strFileContent = 'TESTDATA';
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('new() & processId()'))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $oIoProcess = $self->testResult(sub {
|
||||
new pgBackRest::Common::Io::Process(
|
||||
new pgBackRest::Common::Io::Buffered(
|
||||
new pgBackRest::Common::Io::Handle('test'), 1, 32), "echo '${strFileContent}'")}, '[object]', 'new - echo');
|
||||
$self->testResult(sub {defined($oIoProcess->processId())}, true, ' process id defined');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('close() and error when stderr has data'))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $oIoProcess =
|
||||
new pgBackRest::Common::Io::Process(
|
||||
new pgBackRest::Common::Io::Buffered(
|
||||
new pgBackRest::Common::Io::Handle('test'), 1, 32), "echo '${strFileContent}' 1>&2");
|
||||
|
||||
$self->testException(
|
||||
sub {$oIoProcess->close()}, ERROR_FILE_READ, 'test terminated unexpectedly [000]: TESTDATA');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('close() & error()'))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $oIoProcess =
|
||||
new pgBackRest::Common::Io::Process(
|
||||
new pgBackRest::Common::Io::Buffered(
|
||||
new pgBackRest::Common::Io::Handle('test'), 1, 32), "echo '${strFileContent}'");
|
||||
$oIoProcess->close();
|
||||
$self->testException(
|
||||
sub {$oIoProcess->error()}, ERROR_ASSERT, 'cannot call error() after process has been closed');
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
@ -1,46 +0,0 @@
|
||||
####################################################################################################################################
|
||||
# CommonLogTest.pm - Unit tests for Log module
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Module::Common::CommonLogPerlTest;
|
||||
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::Version;
|
||||
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
|
||||
####################################################################################################################################
|
||||
# run
|
||||
####################################################################################################################################
|
||||
sub run
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin("log()"))
|
||||
{
|
||||
logWarnOnErrorEnable();
|
||||
$self->testResult(sub {&log(ERROR, "my test log", 27)}, "[object]", 'log error as warning',
|
||||
{strLogExpect => "WARN: [027]: my test log"});
|
||||
|
||||
$self->testResult(sub {&log(INFO, "my test log")}, "my test log", 'log info as info',
|
||||
{strLogLevel => INFO, strLogExpect => "INFO: my test log"});
|
||||
|
||||
logWarnOnErrorDisable();
|
||||
$self->testResult(sub {&log(ERROR, "my test log", 27)}, "[object]", 'log error',
|
||||
{strLogExpect => "ERROR: [027]: my test log"});
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
@ -1,249 +0,0 @@
|
||||
####################################################################################################################################
|
||||
# Unit tests for ArchiveInfo
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Module::Info::InfoInfoArchivePerlTest;
|
||||
use parent 'pgBackRestTest::Env::HostEnvTest';
|
||||
|
||||
####################################################################################################################################
|
||||
# Perl includes
|
||||
####################################################################################################################################
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
use File::Basename qw(dirname);
|
||||
use Storable qw(dclone);
|
||||
|
||||
use pgBackRest::Archive::Info;
|
||||
use pgBackRest::Backup::Info;
|
||||
use pgBackRest::Common::Cipher;
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Ini;
|
||||
use pgBackRest::Common::Lock;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Config::Config;
|
||||
use pgBackRest::DbVersion;
|
||||
use pgBackRest::InfoCommon;
|
||||
use pgBackRest::Manifest;
|
||||
use pgBackRest::Protocol::Storage::Helper;
|
||||
use pgBackRest::Storage::Base;
|
||||
|
||||
use pgBackRestTest::Env::HostEnvTest;
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
|
||||
####################################################################################################################################
|
||||
# initModule
|
||||
####################################################################################################################################
|
||||
sub initModule
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
$self->{strRepoPath} = $self->testPath() . '/repo';
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# initTest
|
||||
####################################################################################################################################
|
||||
sub initTest
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Clear cache from the previous test
|
||||
storageRepoCacheClear();
|
||||
|
||||
# Load options
|
||||
$self->configTestClear();
|
||||
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
|
||||
$self->optionTestSet(CFGOPT_REPO_PATH, $self->testPath() . '/repo');
|
||||
$self->configTestLoad(CFGCMD_ARCHIVE_PUSH);
|
||||
|
||||
# Create backup info path
|
||||
storageRepo()->pathCreate(STORAGE_REPO_BACKUP, {bCreateParent => true});
|
||||
|
||||
# Create archive info path
|
||||
storageRepo()->pathCreate(STORAGE_REPO_ARCHIVE, {bCreateParent => true});
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# run
|
||||
####################################################################################################################################
|
||||
sub run
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
my $strArchiveTestFile = $self->dataPath() . '/backup.wal1_';
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin("Archive::Info::new()"))
|
||||
{
|
||||
$self->testException(sub {new pgBackRest::Archive::Info(storageRepo()->pathGet(STORAGE_REPO_ARCHIVE))}, ERROR_FILE_MISSING,
|
||||
ARCHIVE_INFO_FILE . " does not exist but is required to push/get WAL segments\n" .
|
||||
"HINT: is archive_command configured in postgresql.conf?\n" .
|
||||
"HINT: has a stanza-create been performed?\n" .
|
||||
"HINT: use --no-archive-check to disable archive checks during backup if you have an alternate archiving scheme.");
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin("Archive::Info::reconstruct()"))
|
||||
{
|
||||
my $tWalContent = $self->walGenerateContent(PG_VERSION_94);
|
||||
my $strWalChecksum = $self->walGenerateContentChecksum(PG_VERSION_94);
|
||||
|
||||
my $oArchiveInfo = new pgBackRest::Archive::Info(storageRepo()->pathGet(STORAGE_REPO_ARCHIVE), false,
|
||||
{bLoad => false, bIgnoreMissing => true});
|
||||
|
||||
storageRepo()->pathCreate(STORAGE_REPO_ARCHIVE . "/" . PG_VERSION_94 . "-1/0000000100000001", {bCreateParent => true});
|
||||
my $strArchiveFile = storageRepo()->pathGet(STORAGE_REPO_ARCHIVE . "/" . PG_VERSION_94 . "-1/0000000100000001/") .
|
||||
"000000010000000100000001-${strWalChecksum}";
|
||||
storageTest()->put($strArchiveFile, $tWalContent);
|
||||
|
||||
$self->testResult(sub {$oArchiveInfo->reconstruct(PG_VERSION_94, $self->dbSysId(PG_VERSION_94))}, "[undef]", 'reconstruct');
|
||||
$self->testResult(sub {$oArchiveInfo->check(PG_VERSION_94, $self->dbSysId(PG_VERSION_94), false)}, PG_VERSION_94 . "-1",
|
||||
' check reconstruct');
|
||||
|
||||
# Attempt to reconstruct from an encypted archived WAL for an unencrypted repo
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
# Prepend encryption Magic signature to simulate encryption
|
||||
executeTest('echo "' . CIPHER_MAGIC . '" > ' . $strArchiveFile);
|
||||
|
||||
$self->testException(sub {$oArchiveInfo->reconstruct(PG_VERSION_94, $self->dbSysId(PG_VERSION_94))}, ERROR_CRYPTO,
|
||||
"encryption incompatible for '$strArchiveFile'" .
|
||||
"\nHINT: is or was the repo encrypted?");
|
||||
|
||||
executeTest('rm ' . $strArchiveFile);
|
||||
|
||||
# Attempt to reconstruct from an encypted archived WAL with an encrypted repo
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
storageRepoCacheClear();
|
||||
$self->optionTestSet(CFGOPT_REPO_CIPHER_TYPE, CFGOPTVAL_REPO_CIPHER_TYPE_AES_256_CBC);
|
||||
$self->optionTestSet(CFGOPT_REPO_CIPHER_PASS, 'x');
|
||||
$self->configTestLoad(CFGCMD_ARCHIVE_PUSH);
|
||||
|
||||
# Instantiate an archive.info object with a sub passphrase for the archived WAL
|
||||
my $strCipherPassSub = 'y';
|
||||
$oArchiveInfo = new pgBackRest::Archive::Info(storageRepo()->pathGet(STORAGE_REPO_ARCHIVE), false,
|
||||
{bLoad => false, bIgnoreMissing => true, strCipherPassSub => $strCipherPassSub});
|
||||
|
||||
# Create an encrypted archived WAL
|
||||
storageRepo()->put($strArchiveFile, $tWalContent, {strCipherPass => $strCipherPassSub});
|
||||
|
||||
$self->testResult(sub {$oArchiveInfo->reconstruct(PG_VERSION_94, $self->dbSysId(PG_VERSION_94))}, "[undef]", 'reconstruct');
|
||||
$self->testResult(sub {$oArchiveInfo->check(PG_VERSION_94, $self->dbSysId(PG_VERSION_94), false)}, PG_VERSION_94 . "-1",
|
||||
' check reconstruction from encrypted archive');
|
||||
|
||||
$oArchiveInfo->save();
|
||||
|
||||
# Confirm encrypted
|
||||
$self->testResult(sub {storageRepo()->encrypted(storageRepo()->pathGet(STORAGE_REPO_ARCHIVE) . '/'
|
||||
. ARCHIVE_INFO_FILE) && ($oArchiveInfo->cipherPassSub() eq $strCipherPassSub)}, true,
|
||||
' new archive info encrypted');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin("Archive::Info::archiveIdList(), check(), archiveId()"))
|
||||
{
|
||||
my @stryArchiveId;
|
||||
my $oArchiveInfo = new pgBackRest::Archive::Info(storageRepo()->pathGet(STORAGE_REPO_ARCHIVE), false,
|
||||
{bLoad => false, bIgnoreMissing => true});
|
||||
|
||||
$oArchiveInfo->create(PG_VERSION_92, $self->dbSysId(PG_VERSION_92), false);
|
||||
$oArchiveInfo->dbSectionSet(PG_VERSION_93, $self->dbSysId(PG_VERSION_93), $oArchiveInfo->dbHistoryIdGet(false) + 1);
|
||||
$oArchiveInfo->dbSectionSet(PG_VERSION_94, $self->dbSysId(PG_VERSION_94), $oArchiveInfo->dbHistoryIdGet(false) + 10);
|
||||
$oArchiveInfo->dbSectionSet(PG_VERSION_93, $self->dbSysId(PG_VERSION_93), $oArchiveInfo->dbHistoryIdGet(false) + 1);
|
||||
$oArchiveInfo->save();
|
||||
|
||||
# Check gets only the latest DB and returns only that archiveId
|
||||
push(@stryArchiveId, $oArchiveInfo->check(PG_VERSION_93, $self->dbSysId(PG_VERSION_93)));
|
||||
$self->testResult(sub {(@stryArchiveId == 1) && ($stryArchiveId[0] eq PG_VERSION_93 . "-13")}, true,
|
||||
'check - return only newest archiveId');
|
||||
|
||||
$self->testResult(sub {$oArchiveInfo->archiveId(
|
||||
{strDbVersion => PG_VERSION_93, ullDbSysId => $self->dbSysId(PG_VERSION_93)})},
|
||||
PG_VERSION_93 . "-13", 'archiveId - return only newest archiveId for multiple histories');
|
||||
|
||||
$self->testException(
|
||||
sub {$oArchiveInfo->archiveId({strDbVersion => PG_VERSION_94, ullDbSysId => BOGUS})}, ERROR_ARCHIVE_MISMATCH,
|
||||
"unable to retrieve the archive id for database version '" . PG_VERSION_94 . "' and system-id '" . BOGUS . "'");
|
||||
|
||||
$self->testException(sub {$oArchiveInfo->check(PG_VERSION_94, $self->dbSysId(PG_VERSION_94))}, ERROR_ARCHIVE_MISMATCH,
|
||||
"WAL segment version " . PG_VERSION_94 . " does not match archive version " . PG_VERSION_93 .
|
||||
"\nWAL segment system-id " . $self->dbSysId(PG_VERSION_94) . " does not match archive system-id " .
|
||||
$self->dbSysId(PG_VERSION_93) . "\nHINT: are you archiving to the correct stanza?");
|
||||
|
||||
@stryArchiveId = $oArchiveInfo->archiveIdList(PG_VERSION_93, $self->dbSysId(PG_VERSION_93));
|
||||
$self->testResult(sub {(@stryArchiveId == 2) && ($stryArchiveId[0] eq PG_VERSION_93 . "-13") &&
|
||||
($stryArchiveId[1] eq PG_VERSION_93 . "-2")}, true, 'archiveIdList - returns multiple archiveId - newest first');
|
||||
|
||||
@stryArchiveId = $oArchiveInfo->archiveIdList(PG_VERSION_94, $self->dbSysId(PG_VERSION_94));
|
||||
$self->testResult(sub {(@stryArchiveId == 1) && ($stryArchiveId[0] eq PG_VERSION_94 . "-12")}, true,
|
||||
'archiveIdList - returns older archiveId');
|
||||
|
||||
$self->testException(
|
||||
sub {$oArchiveInfo->archiveIdList(PG_VERSION_95, $self->dbSysId(PG_VERSION_94))}, ERROR_ARCHIVE_MISMATCH,
|
||||
"unable to retrieve the archive id for database version '" . PG_VERSION_95 . "' and system-id '" .
|
||||
$self->dbSysId(PG_VERSION_94) . "'");
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin("encryption"))
|
||||
{
|
||||
# Create an unencrypted archive.info file
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $oArchiveInfo = new pgBackRest::Archive::Info(storageRepo()->pathGet(STORAGE_REPO_ARCHIVE), false,
|
||||
{bLoad => false, bIgnoreMissing => true});
|
||||
$oArchiveInfo->create(PG_VERSION_94, $self->dbSysId(PG_VERSION_94), true);
|
||||
|
||||
# Confirm unencrypted
|
||||
$self->testResult(sub {storageRepo()->encrypted(storageRepo()->pathGet(STORAGE_REPO_ARCHIVE) . '/'
|
||||
. ARCHIVE_INFO_FILE)}, false, ' new archive info unencrypted');
|
||||
|
||||
my $strFile = $oArchiveInfo->{strFileName};
|
||||
|
||||
# Prepend encryption Magic signature to simulate encryption
|
||||
executeTest('echo "' . CIPHER_MAGIC . '$(cat ' . $strFile . ')" > ' . $strFile);
|
||||
|
||||
$self->testException(sub {new pgBackRest::Archive::Info(storageRepo()->pathGet(STORAGE_REPO_ARCHIVE))}, ERROR_CRYPTO,
|
||||
"unable to parse '$strFile'" .
|
||||
"\nHINT: is or was the repo encrypted?");
|
||||
|
||||
# Remove the archive info files
|
||||
executeTest('rm ' . $oArchiveInfo->{strFileName} . '*');
|
||||
|
||||
# Create an encrypted storage and archive.info file
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $strCipherPass = 'x';
|
||||
$self->configTestClear();
|
||||
$self->optionTestSet(CFGOPT_REPO_CIPHER_TYPE, CFGOPTVAL_REPO_CIPHER_TYPE_AES_256_CBC);
|
||||
$self->optionTestSet(CFGOPT_REPO_CIPHER_PASS, $strCipherPass);
|
||||
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
|
||||
$self->optionTestSet(CFGOPT_REPO_PATH, $self->testPath() . '/repo');
|
||||
$self->configTestLoad(CFGCMD_ARCHIVE_PUSH);
|
||||
|
||||
# Clear the storage repo settings
|
||||
storageRepoCacheClear();
|
||||
|
||||
# Create an encrypted storage and generate an encryption sub passphrase to store in the file
|
||||
my $strCipherPassSub = cipherPassGen();
|
||||
|
||||
# Error on encrypted repo but no passphrase passed to store in the file
|
||||
$self->testException(sub {new pgBackRest::Archive::Info(storageRepo()->pathGet(STORAGE_REPO_ARCHIVE), false,
|
||||
{bLoad => false, bIgnoreMissing => true})}, ERROR_ASSERT,
|
||||
'a user passphrase and sub passphrase are both required when encrypting');
|
||||
|
||||
# Create an encrypted archiveInfo file
|
||||
$oArchiveInfo = new pgBackRest::Archive::Info(storageRepo()->pathGet(STORAGE_REPO_ARCHIVE), false,
|
||||
{bLoad => false, bIgnoreMissing => true, strCipherPassSub => $strCipherPassSub});
|
||||
$oArchiveInfo->create(PG_VERSION_94, $self->dbSysId(PG_VERSION_94), true);
|
||||
|
||||
# Confirm encrypted
|
||||
$self->testResult(sub {storageRepo()->encrypted(storageRepo()->pathGet(STORAGE_REPO_ARCHIVE) . '/'
|
||||
. ARCHIVE_INFO_FILE)}, true, ' new archive info encrypted');
|
||||
|
||||
$self->testResult(sub {$oArchiveInfo->test(INI_SECTION_CIPHER, INI_KEY_CIPHER_PASS, undef, $strCipherPassSub)},
|
||||
true, ' generated passphrase stored');
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
@ -1,262 +0,0 @@
|
||||
####################################################################################################################################
|
||||
# Unit tests for BackupInfo
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Module::Info::InfoInfoBackupPerlTest;
|
||||
use parent 'pgBackRestTest::Env::HostEnvTest';
|
||||
|
||||
####################################################################################################################################
|
||||
# Perl includes
|
||||
####################################################################################################################################
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
use File::Basename qw(dirname);
|
||||
use Storable qw(dclone);
|
||||
|
||||
use pgBackRest::Archive::Info;
|
||||
use pgBackRest::Backup::Info;
|
||||
use pgBackRest::Common::Cipher;
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Lock;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Config::Config;
|
||||
use pgBackRest::DbVersion;
|
||||
use pgBackRest::InfoCommon;
|
||||
use pgBackRest::Manifest;
|
||||
use pgBackRest::Protocol::Storage::Helper;
|
||||
use pgBackRest::Storage::Base;
|
||||
|
||||
use pgBackRestTest::Env::HostEnvTest;
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
|
||||
####################################################################################################################################
|
||||
# initModule
|
||||
####################################################################################################################################
|
||||
sub initModule
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
$self->{strRepoPath} = $self->testPath() . '/repo';
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# initTest
|
||||
####################################################################################################################################
|
||||
sub initTest
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Load options
|
||||
$self->configTestClear();
|
||||
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
|
||||
$self->optionTestSet(CFGOPT_REPO_PATH, $self->testPath() . '/repo');
|
||||
$self->configTestLoad(CFGCMD_ARCHIVE_PUSH);
|
||||
|
||||
# Create backup info path
|
||||
storageRepo()->pathCreate(STORAGE_REPO_BACKUP, {bCreateParent => true});
|
||||
|
||||
# Create archive info path
|
||||
storageRepo()->pathCreate(STORAGE_REPO_ARCHIVE, {bCreateParent => true});
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# run
|
||||
####################################################################################################################################
|
||||
sub run
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
my $i93ControlVersion = 937;
|
||||
my $i93CatalogVersion = 201306121;
|
||||
my $i94ControlVersion = 942;
|
||||
my $i94CatalogVersion = 201409291;
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin("BackupInfo::check() && BackupInfo::confirmDb()"))
|
||||
{
|
||||
my $oBackupInfo = new pgBackRest::Backup::Info(storageRepo()->pathGet(STORAGE_REPO_BACKUP), false, false,
|
||||
{bIgnoreMissing => true});
|
||||
$oBackupInfo->create(PG_VERSION_93, $self->dbSysId(PG_VERSION_93), $i93ControlVersion, $i93CatalogVersion, true);
|
||||
|
||||
# All DB section matches
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oBackupInfo->check(
|
||||
PG_VERSION_93, $i93ControlVersion, $i93CatalogVersion, $self->dbSysId(PG_VERSION_93), false)}, 1, 'db section matches');
|
||||
|
||||
# DB section version mismatch
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testException(sub {$oBackupInfo->check(PG_VERSION_94, $i93ControlVersion, $i93CatalogVersion,
|
||||
$self->dbSysId(PG_VERSION_93))}, ERROR_BACKUP_MISMATCH,
|
||||
"database version = " . &PG_VERSION_94 . ", system-id " . $self->dbSysId(PG_VERSION_93) .
|
||||
" does not match backup version = " . &PG_VERSION_93 . ", " . "system-id = " . $self->dbSysId(PG_VERSION_93) .
|
||||
"\nHINT: is this the correct stanza?");
|
||||
|
||||
# DB section system-id mismatch
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testException(
|
||||
sub {$oBackupInfo->check(PG_VERSION_93, $i93ControlVersion, $i93CatalogVersion, $self->dbSysId(PG_VERSION_94))},
|
||||
ERROR_BACKUP_MISMATCH,
|
||||
"database version = " . &PG_VERSION_93 . ", system-id " . $self->dbSysId(PG_VERSION_94) .
|
||||
" does not match backup version = " . &PG_VERSION_93 . ", " . "system-id = " . $self->dbSysId(PG_VERSION_93) .
|
||||
"\nHINT: is this the correct stanza?");
|
||||
|
||||
# DB section control version mismatch
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testException(sub {$oBackupInfo->check(PG_VERSION_93, 123, $i93CatalogVersion, $self->dbSysId(PG_VERSION_93))},
|
||||
ERROR_BACKUP_MISMATCH, "database control-version = 123, catalog-version $i93CatalogVersion " .
|
||||
"does not match backup control-version = $i93ControlVersion, catalog-version = $i93CatalogVersion" .
|
||||
"\nHINT: this may be a symptom of database or repository corruption!");
|
||||
|
||||
# DB section catalog version mismatch
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testException(sub {$oBackupInfo->check(PG_VERSION_93, $i93ControlVersion, 123456789, $self->dbSysId(PG_VERSION_93))},
|
||||
ERROR_BACKUP_MISMATCH, "database control-version = $i93ControlVersion, catalog-version 123456789 " .
|
||||
"does not match backup control-version = $i93ControlVersion, catalog-version = $i93CatalogVersion" .
|
||||
"\nHINT: this may be a symptom of database or repository corruption!");
|
||||
|
||||
my $strBackupLabel = "20170403-175647F";
|
||||
|
||||
$oBackupInfo->set(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_HISTORY_ID,
|
||||
$oBackupInfo->get(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_HISTORY_ID));
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oBackupInfo->confirmDb($strBackupLabel, PG_VERSION_93, $self->dbSysId(PG_VERSION_93))}, true,
|
||||
'backup db matches');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oBackupInfo->confirmDb($strBackupLabel, PG_VERSION_94, $self->dbSysId(PG_VERSION_93))}, false,
|
||||
'backup db wrong version');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oBackupInfo->confirmDb($strBackupLabel, PG_VERSION_93, $self->dbSysId(PG_VERSION_94))}, false,
|
||||
'backup db wrong system-id');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin("BackupInfo::backupArchiveDbHistoryId()"))
|
||||
{
|
||||
my $oBackupInfo = new pgBackRest::Backup::Info(storageRepo()->pathGet(STORAGE_REPO_BACKUP), false, false,
|
||||
{bIgnoreMissing => true});
|
||||
$oBackupInfo->create(PG_VERSION_93, $self->dbSysId(PG_VERSION_93), $i93ControlVersion, $i93CatalogVersion, true);
|
||||
|
||||
my $oArchiveInfo = new pgBackRest::Archive::Info(storageRepo()->pathGet(STORAGE_REPO_ARCHIVE), false,
|
||||
{bLoad => false, bIgnoreMissing => true});
|
||||
$oArchiveInfo->create(PG_VERSION_93, $self->dbSysId(PG_VERSION_93), true);
|
||||
|
||||
# Map archiveId to Backup history id
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $strArchiveId = $oArchiveInfo->archiveId({strDbVersion => PG_VERSION_93, ullDbSysId => $self->dbSysId(PG_VERSION_93)});
|
||||
$self->testResult(sub {$oBackupInfo->backupArchiveDbHistoryId($strArchiveId,
|
||||
storageRepo()->pathGet(STORAGE_REPO_ARCHIVE))}, 1, 'backupArchiveDbHistoryId found');
|
||||
|
||||
# Unable to map archiveId to Backup history id
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$strArchiveId = &PG_VERSION_94 . "-2";
|
||||
$self->testResult(sub {$oBackupInfo->backupArchiveDbHistoryId($strArchiveId,
|
||||
storageRepo()->pathGet(STORAGE_REPO_ARCHIVE))}, "[undef]", 'backupArchiveDbHistoryId not found');
|
||||
|
||||
# Same version but different ullsystemid so continue looking until find match
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
# Update db section and db history sections
|
||||
my $iHistoryId = $oBackupInfo->dbHistoryIdGet(true)+1;
|
||||
$oBackupInfo->dbSectionSet(
|
||||
PG_VERSION_94, $i94ControlVersion, $i94CatalogVersion, $self->dbSysId(PG_VERSION_93), $iHistoryId);
|
||||
$oArchiveInfo->dbSectionSet(PG_VERSION_94, $self->dbSysId(PG_VERSION_93), $iHistoryId);
|
||||
|
||||
$oBackupInfo->save();
|
||||
$oArchiveInfo->save();
|
||||
|
||||
$strArchiveId = &PG_VERSION_94 . "-" . $iHistoryId;
|
||||
$self->testResult(sub {$oBackupInfo->backupArchiveDbHistoryId($strArchiveId,
|
||||
storageRepo()->pathGet(STORAGE_REPO_ARCHIVE))}, $iHistoryId, 'same db version but different system-id');
|
||||
|
||||
# Different version but same ullsystemid
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$iHistoryId = $oBackupInfo->dbHistoryIdGet(false)+1;
|
||||
$oBackupInfo->dbSectionSet(
|
||||
PG_VERSION_94, $i93ControlVersion, $i93CatalogVersion, $self->dbSysId(PG_VERSION_94), $iHistoryId);
|
||||
$oArchiveInfo->dbSectionSet(PG_VERSION_94, $self->dbSysId(PG_VERSION_94), $iHistoryId);
|
||||
|
||||
$oBackupInfo->save();
|
||||
$oArchiveInfo->save();
|
||||
|
||||
$strArchiveId = &PG_VERSION_93 . "-" . $iHistoryId;
|
||||
$self->testResult(sub {$oBackupInfo->backupArchiveDbHistoryId($strArchiveId,
|
||||
storageRepo()->pathGet(STORAGE_REPO_ARCHIVE))}, "[undef]", 'same db system-id but different version');
|
||||
|
||||
# First and last version and ullsystemid same in backup.info but only 1st in archive info - return last
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$iHistoryId = $oBackupInfo->dbHistoryIdGet(true)+1;
|
||||
$oBackupInfo->dbSectionSet(
|
||||
PG_VERSION_93, $i93ControlVersion, $i93CatalogVersion, $self->dbSysId(PG_VERSION_93), $iHistoryId);
|
||||
|
||||
$oBackupInfo->save();
|
||||
|
||||
$strArchiveId = &PG_VERSION_93 . "-1";
|
||||
$self->testResult(sub {$oBackupInfo->backupArchiveDbHistoryId($strArchiveId,
|
||||
storageRepo()->pathGet(STORAGE_REPO_ARCHIVE))}, $iHistoryId, 'duplicate 1st and last version/sysid - last chosen');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin("encryption"))
|
||||
{
|
||||
# Create a backupInfo file
|
||||
my $oBackupInfo = new pgBackRest::Backup::Info(storageRepo()->pathGet(STORAGE_REPO_BACKUP), false, false,
|
||||
{bIgnoreMissing => true});
|
||||
$oBackupInfo->create(PG_VERSION_93, $self->dbSysId(PG_VERSION_93), $i93ControlVersion, $i93CatalogVersion, true);
|
||||
|
||||
my $strFile = $oBackupInfo->{strFileName};
|
||||
|
||||
# Prepend encryption Magic signature to simulate encryption
|
||||
executeTest('echo "' . CIPHER_MAGIC . '$(cat ' . $strFile . ')" > ' . $strFile);
|
||||
|
||||
$self->testException(sub {new pgBackRest::Backup::Info(storageRepo()->pathGet(STORAGE_REPO_BACKUP))}, ERROR_CRYPTO,
|
||||
"unable to parse '$strFile'" .
|
||||
"\nHINT: is or was the repo encrypted?");
|
||||
|
||||
# Create encrypted files, change the passphrase and attempt to load - ensure flush error returned as parse error
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
# Remove the backup info files
|
||||
executeTest('rm ' . $oBackupInfo->{strFileName} . '*');
|
||||
|
||||
# Clear the storage repo settings and change the passphrase
|
||||
storageRepoCacheClear();
|
||||
|
||||
my $strCipherPass = 'x';
|
||||
$self->configTestClear();
|
||||
$self->optionTestSet(CFGOPT_REPO_CIPHER_TYPE, CFGOPTVAL_REPO_CIPHER_TYPE_AES_256_CBC);
|
||||
$self->optionTestSet(CFGOPT_REPO_CIPHER_PASS, $strCipherPass);
|
||||
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
|
||||
$self->optionTestSet(CFGOPT_REPO_PATH, $self->testPath() . '/repo');
|
||||
$self->configTestLoad(CFGCMD_ARCHIVE_PUSH);
|
||||
|
||||
# Confirm exception when not passing a sub passphrase
|
||||
$self->testException(sub {new pgBackRest::Backup::Info(storageRepo()->pathGet(STORAGE_REPO_BACKUP), false, false,
|
||||
{bIgnoreMissing => true})}, ERROR_ASSERT,
|
||||
'a user passphrase and sub passphrase are both required when encrypting');
|
||||
|
||||
my $strCipherPassSub = cipherPassGen();
|
||||
|
||||
# Create encrypted files
|
||||
$oBackupInfo = new pgBackRest::Backup::Info(storageRepo()->pathGet(STORAGE_REPO_BACKUP), false, false,
|
||||
{bIgnoreMissing => true, strCipherPassSub => $strCipherPassSub});
|
||||
$oBackupInfo->create(PG_VERSION_93, $self->dbSysId(PG_VERSION_93), $i93ControlVersion, $i93CatalogVersion, true);
|
||||
|
||||
# Clear the storage repo settings and change the passphrase
|
||||
storageRepoCacheClear();
|
||||
$self->optionTestSet(CFGOPT_REPO_CIPHER_TYPE, CFGOPTVAL_REPO_CIPHER_TYPE_AES_256_CBC);
|
||||
$self->optionTestSet(CFGOPT_REPO_CIPHER_PASS, BOGUS);
|
||||
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
|
||||
$self->optionTestSet(CFGOPT_REPO_PATH, $self->testPath() . '/repo');
|
||||
$self->configTestLoad(CFGCMD_ARCHIVE_PUSH);
|
||||
|
||||
$self->testException(sub {new pgBackRest::Backup::Info(storageRepo()->pathGet(STORAGE_REPO_BACKUP))}, ERROR_CRYPTO,
|
||||
"unable to parse '" . $oBackupInfo->{strFileName} . "'" .
|
||||
"\nHINT: is or was the repo encrypted?");
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
File diff suppressed because it is too large
Load Diff
@ -26,6 +26,7 @@ use pgBackRest::InfoCommon;
|
||||
use pgBackRest::LibC qw(:checksum);
|
||||
use pgBackRest::Manifest;
|
||||
use pgBackRest::Protocol::Storage::Helper;
|
||||
use pgBackRest::Storage::Helper;
|
||||
use pgBackRest::Version;
|
||||
|
||||
use pgBackRestTest::Common::ContainerTest;
|
||||
@ -142,7 +143,7 @@ sub run
|
||||
'184473f470864e067ee3a22e64b47b0a1c356f29', $lTime, undef, true);
|
||||
|
||||
# Load sample page
|
||||
my $tBasePage = ${storageTest()->get($self->dataPath() . '/page.bin')};
|
||||
my $tBasePage = ${storageLocal()->get($self->dataPath() . '/page.bin')};
|
||||
my $iBasePageChecksum = 0x1B99;
|
||||
|
||||
# Create base path
|
||||
|
@ -1,135 +0,0 @@
|
||||
####################################################################################################################################
|
||||
# Tests for Protocol::Common::Minion module
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Module::Protocol::ProtocolCommonMinionPerlTest;
|
||||
use parent 'pgBackRestTest::Common::RunTest';
|
||||
|
||||
####################################################################################################################################
|
||||
# Perl includes
|
||||
####################################################################################################################################
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
use IO::Socket::UNIX;
|
||||
use Time::HiRes qw(usleep);
|
||||
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Io::Buffered;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::Wait;
|
||||
use pgBackRest::LibC qw(:config);
|
||||
use pgBackRest::Protocol::Base::Minion;
|
||||
use pgBackRest::Version;
|
||||
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
|
||||
####################################################################################################################################
|
||||
# socketServer
|
||||
####################################################################################################################################
|
||||
sub socketServer
|
||||
{
|
||||
my $self = shift;
|
||||
my $strSocketFile = shift;
|
||||
my $fnServer = shift;
|
||||
|
||||
# Fork off the server
|
||||
if (fork() == 0)
|
||||
{
|
||||
# Open the domain socket
|
||||
my $oSocketServer = IO::Socket::UNIX->new(Type => SOCK_STREAM(), Local => $strSocketFile, Listen => 1);
|
||||
&log(INFO, " * socket server open");
|
||||
|
||||
# Wait for a connection and create IO object
|
||||
my $oConnection = $oSocketServer->accept();
|
||||
my $oIoHandle = new pgBackRest::Common::Io::Handle('socket server', $oConnection, $oConnection);
|
||||
&log(INFO, " * socket server connected");
|
||||
|
||||
# Run server function
|
||||
$fnServer->($oIoHandle);
|
||||
|
||||
# Shutdown server
|
||||
$oSocketServer->close();
|
||||
&log(INFO, " * socket server closed");
|
||||
unlink($strSocketFile);
|
||||
exit 0;
|
||||
}
|
||||
|
||||
# Wait for client socket
|
||||
my $oWait = waitInit(5);
|
||||
while (!-e $strSocketFile && waitMore($oWait)) {};
|
||||
|
||||
# Open the client socket
|
||||
my $oClient = IO::Socket::UNIX->new(Type => SOCK_STREAM(), Peer => $strSocketFile);
|
||||
|
||||
if (!defined($oClient))
|
||||
{
|
||||
logErrorResult(ERROR_FILE_OPEN, 'unable to open client socket', $OS_ERROR);
|
||||
}
|
||||
|
||||
&log(INFO, " * socket client connected");
|
||||
|
||||
return $oClient;
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# run
|
||||
####################################################################################################################################
|
||||
sub run
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Test data
|
||||
my $strSocketFile = $self->testPath() . qw{/} . 'domain.socket';
|
||||
|
||||
################################################################################################################################
|
||||
# if ($self->begin('new() & timeout() & bufferMax()'))
|
||||
# {
|
||||
# #---------------------------------------------------------------------------------------------------------------------------
|
||||
# my $oIoBuffered = $self->testResult(
|
||||
# sub {new pgBackRest::Common::Io::Buffered(
|
||||
# new pgBackRest::Common::Io::Handle('test'), 10, 2048)}, '[object]', 'new - no handles');
|
||||
#
|
||||
# $self->testResult(sub {$oIoBuffered->timeout()}, 10, ' check timeout');
|
||||
# $self->testResult(sub {$oIoBuffered->bufferMax()}, 2048, ' check buffer max');
|
||||
# }
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('process()'))
|
||||
{
|
||||
my $oClient = $self->socketServer($strSocketFile, sub
|
||||
{
|
||||
my $oIoHandle = shift;
|
||||
|
||||
my $oMinion = new pgBackRest::Protocol::Base::Minion('test', new pgBackRest::Common::Io::Buffered($oIoHandle, 5, 4096));
|
||||
|
||||
# Use bogus lock path to ensure a lock is not taken for the archive-get command
|
||||
$oMinion->process($self->testPath(), cfgCommandName(CFGCMD_ARCHIVE_GET), "test", 0);
|
||||
});
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $oIoBuffered = $self->testResult(
|
||||
sub {new pgBackRest::Common::Io::Buffered(
|
||||
new pgBackRest::Common::Io::Handle('socket client', $oClient, $oClient), 5, 4096)}, '[object]', 'open');
|
||||
|
||||
$self->testResult(
|
||||
sub {$oIoBuffered->readLine()},
|
||||
'{"name":"' . PROJECT_NAME . '","service":"test","version":"' . PROJECT_VERSION . '"}', 'read greeting');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {$oIoBuffered->writeLine('{"cmd":"noop"}')}, 15, 'write noop');
|
||||
$self->testResult(
|
||||
sub {$oIoBuffered->readLine()}, '{"out":[]}', 'read output');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {$oIoBuffered->writeLine('{"cmd":"exit"}')}, 15, 'write exit');
|
||||
$self->testResult(
|
||||
sub {$oIoBuffered->readLine(true)}, undef, 'read EOF');
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
@ -1,155 +0,0 @@
|
||||
####################################################################################################################################
|
||||
# Protocol Helper Tests
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Module::Protocol::ProtocolHelperPerlTest;
|
||||
use parent 'pgBackRestTest::Env::ConfigEnvTest';
|
||||
|
||||
####################################################################################################################################
|
||||
# Perl includes
|
||||
####################################################################################################################################
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
use File::Basename qw(dirname);
|
||||
use Storable qw(dclone);
|
||||
|
||||
use pgBackRest::Archive::Common;
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Config::Config;
|
||||
use pgBackRest::Protocol::Helper;
|
||||
use pgBackRest::Protocol::Storage::Helper;
|
||||
use pgBackRest::Storage::Helper;
|
||||
use pgBackRest::Version;
|
||||
|
||||
use pgBackRestTest::Env::HostEnvTest;
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Env::Host::HostBackupTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
|
||||
####################################################################################################################################
|
||||
# initModule
|
||||
####################################################################################################################################
|
||||
sub initModule
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
$self->{strDbPath} = $self->testPath() . '/db';
|
||||
$self->{strRepoPath} = $self->testPath() . '/repo';
|
||||
$self->{strArchivePath} = "$self->{strRepoPath}/archive/" . $self->stanza();
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# initTest
|
||||
####################################################################################################################################
|
||||
sub initTest
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Create archive info
|
||||
storageTest()->pathCreate($self->{strArchivePath}, {bIgnoreExists => true, bCreateParent => true});
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# initOption
|
||||
####################################################################################################################################
|
||||
sub initOption
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
$self->configTestClear();
|
||||
|
||||
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
|
||||
$self->optionTestSet(CFGOPT_PG_PATH, $self->{strDbPath});
|
||||
$self->optionTestSet(CFGOPT_REPO_PATH, $self->{strRepoPath});
|
||||
$self->optionTestSet(CFGOPT_LOG_PATH, $self->testPath());
|
||||
$self->optionTestSetBool(CFGOPT_COMPRESS, false);
|
||||
|
||||
$self->optionTestSet(CFGOPT_DB_TIMEOUT, 5);
|
||||
$self->optionTestSet(CFGOPT_PROTOCOL_TIMEOUT, 6);
|
||||
$self->optionTestSet(CFGOPT_ARCHIVE_TIMEOUT, 3);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# run
|
||||
####################################################################################################################################
|
||||
sub run
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('protocolParam()'))
|
||||
{
|
||||
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
|
||||
$self->optionTestSet(cfgOptionIdFromIndex(CFGOPT_PG_HOST, 1), 'pg-host-1');
|
||||
$self->optionTestSet(cfgOptionIdFromIndex(CFGOPT_PG_PATH, 1), '/db1');
|
||||
$self->optionTestSet(cfgOptionIdFromIndex(CFGOPT_PG_PORT, 1), '1111');
|
||||
$self->optionTestSet(cfgOptionIdFromIndex(CFGOPT_PG_HOST_CMD, 1), 'pgbackrest1');
|
||||
$self->optionTestSet(cfgOptionIdFromIndex(CFGOPT_PG_HOST, 2), 'pg-host-2');
|
||||
$self->optionTestSet(cfgOptionIdFromIndex(CFGOPT_PG_PATH, 2), '/db2');
|
||||
$self->optionTestSet(cfgOptionIdFromIndex(CFGOPT_PG_PORT, 2), '2222');
|
||||
$self->optionTestSet(cfgOptionIdFromIndex(CFGOPT_PG_HOST_CMD, 2), 'pgbackrest2');
|
||||
$self->optionTestSet(cfgOptionIdFromIndex(CFGOPT_PG_HOST_CONFIG, 2), '/config2');
|
||||
$self->optionTestSet(cfgOptionIdFromIndex(CFGOPT_PG_HOST_CONFIG_INCLUDE_PATH, 2), '/config-include2');
|
||||
$self->optionTestSet(cfgOptionIdFromIndex(CFGOPT_PG_HOST_CONFIG_PATH, 2), '/config-path2');
|
||||
$self->configTestLoad(CFGCMD_BACKUP);
|
||||
|
||||
$self->testResult(
|
||||
sub {pgBackRest::Protocol::Helper::protocolParam(cfgCommandName(CFGCMD_BACKUP), CFGOPTVAL_REMOTE_TYPE_DB, 2)},
|
||||
'(pg-host-2, postgres, [undef], pgbackrest2 --buffer-size=4194304 --command=backup --compress-level=6' .
|
||||
' --compress-level-network=3 --config=/config2 --config-include-path=/config-include2 --config-path=/config-path2' .
|
||||
' --log-level-file=off --pg1-path=/db2 --pg1-port=2222 --process=0 --protocol-timeout=1830 --stanza=db --type=db' .
|
||||
' remote)',
|
||||
'more than one backup db host');
|
||||
|
||||
# --------------------------------------------------------------------------------------------------------------------------
|
||||
$self->configTestClear();
|
||||
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
|
||||
$self->optionTestSet(cfgOptionIdFromIndex(CFGOPT_PG_PATH, 1), '/db1');
|
||||
$self->optionTestSet(CFGOPT_REPO_HOST, 'repo-host');
|
||||
$self->optionTestSet(CFGOPT_REPO_PATH, '/repo');
|
||||
$self->optionTestSet(CFGOPT_REPO_HOST_CMD, 'pgbackrest-repo');
|
||||
$self->optionTestSet(CFGOPT_REPO_HOST_CONFIG, '/config-repo');
|
||||
$self->optionTestSet(CFGOPT_REPO_HOST_CONFIG_INCLUDE_PATH, '/config-include-repo');
|
||||
$self->optionTestSet(CFGOPT_REPO_HOST_CONFIG_PATH, '/config-path-repo');
|
||||
$self->configTestLoad(CFGCMD_RESTORE);
|
||||
|
||||
$self->testResult(
|
||||
sub {pgBackRest::Protocol::Helper::protocolParam(cfgCommandName(CFGCMD_RESTORE), CFGOPTVAL_REMOTE_TYPE_BACKUP)},
|
||||
'(repo-host, pgbackrest, [undef], pgbackrest-repo --buffer-size=4194304 --command=restore --compress-level=6' .
|
||||
' --compress-level-network=3 --config=/config-repo --config-include-path=/config-include-repo' .
|
||||
' --config-path=/config-path-repo --log-level-file=off --pg1-path=/db1 --process=0 --protocol-timeout=1830' .
|
||||
' --repo1-path=/repo --stanza=db --type=backup remote)',
|
||||
'config params to repo host');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin("Protocol::Helper"))
|
||||
{
|
||||
$self->initOption();
|
||||
$self->optionTestSet(CFGOPT_REPO_HOST, 'localhost');
|
||||
$self->optionTestSet(CFGOPT_REPO_HOST_USER, $self->pgUser());
|
||||
$self->configTestLoad(CFGCMD_ARCHIVE_PUSH);
|
||||
|
||||
$self->testResult(
|
||||
sub {protocolGet(CFGOPTVAL_REMOTE_TYPE_BACKUP, undef, {strBackRestBin => $self->backrestExe()})}, "[object]",
|
||||
'ssh default port');
|
||||
|
||||
# Destroy protocol object
|
||||
protocolDestroy();
|
||||
|
||||
$self->optionTestSet(CFGOPT_REPO_HOST_PORT, 25);
|
||||
$self->configTestLoad(CFGCMD_ARCHIVE_PUSH);
|
||||
|
||||
$self->testException(
|
||||
sub {protocolGet(CFGOPTVAL_REMOTE_TYPE_BACKUP, undef, {strBackRestBin => $self->backrestExe()})}, ERROR_FILE_READ,
|
||||
"remote process on 'localhost' terminated unexpectedly: ssh: connect to host localhost port 25:");
|
||||
|
||||
# Destroy protocol object
|
||||
protocolDestroy();
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
@ -25,6 +25,7 @@ use pgBackRest::Config::Config;
|
||||
use pgBackRest::InfoCommon;
|
||||
use pgBackRest::Manifest;
|
||||
use pgBackRest::Protocol::Storage::Helper;
|
||||
use pgBackRest::Storage::Helper;
|
||||
use pgBackRest::Version;
|
||||
|
||||
use pgBackRestTest::Common::ContainerTest;
|
||||
@ -319,7 +320,7 @@ sub run
|
||||
'fail on backup info file missing from non-empty dir', {iExpectedExitStatus => ERROR_PATH_NOT_EMPTY});
|
||||
|
||||
# Change the database version by copying a new pg_control file to a new pg-path to use for db mismatch test
|
||||
storageDb()->pathCreate(
|
||||
storageLocal()->pathCreate(
|
||||
$oHostDbMaster->dbPath() . '/testbase/' . DB_PATH_GLOBAL,
|
||||
{strMode => '0700', bIgnoreExists => true, bCreateParent => true});
|
||||
$self->controlGenerate(
|
||||
@ -769,7 +770,7 @@ sub run
|
||||
# Version <= 8.4 always places a PG_VERSION file in the tablespace
|
||||
if ($oHostDbMaster->pgVersion() <= PG_VERSION_84)
|
||||
{
|
||||
if (!storageDb()->exists("${strTablespacePath}/" . DB_FILE_PGVERSION))
|
||||
if (!storageLocal()->exists("${strTablespacePath}/" . DB_FILE_PGVERSION))
|
||||
{
|
||||
confess &log(ASSERT, "unable to find '" . DB_FILE_PGVERSION . "' in tablespace path '${strTablespacePath}'");
|
||||
}
|
||||
@ -787,14 +788,14 @@ sub run
|
||||
'/PG_' . $oHostDbMaster->pgVersion() . qw{_} . $oBackupInfo->get(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_CATALOG);
|
||||
|
||||
# Check that path exists
|
||||
if (!storageDb()->pathExists($strTablespacePath))
|
||||
if (!storageLocal()->pathExists($strTablespacePath))
|
||||
{
|
||||
confess &log(ASSERT, "unable to find tablespace path '${strTablespacePath}'");
|
||||
}
|
||||
}
|
||||
|
||||
# Make sure there are some files in the tablespace path (exclude PG_VERSION if <= 8.4 since that was tested above)
|
||||
if (grep(!/^PG\_VERSION$/i, storageDb()->list($strTablespacePath)) == 0)
|
||||
if (grep(!/^PG\_VERSION$/i, storageLocal()->list($strTablespacePath)) == 0)
|
||||
{
|
||||
confess &log(ASSERT, "no files found in tablespace path '${strTablespacePath}'");
|
||||
}
|
||||
@ -864,7 +865,7 @@ sub run
|
||||
# Save recovery file to test so we can use it in the next test
|
||||
$strRecoveryFile = $oHostDbMaster->pgVersion() >= PG_VERSION_12 ? 'postgresql.auto.conf' : DB_FILE_RECOVERYCONF;
|
||||
|
||||
storageDb()->copy(
|
||||
storageLocal()->copy(
|
||||
$oHostDbMaster->dbBasePath() . qw{/} . $strRecoveryFile, $self->testPath() . qw{/} . $strRecoveryFile);
|
||||
|
||||
$oHostDbMaster->clusterStart();
|
||||
@ -886,7 +887,7 @@ sub run
|
||||
executeTest('rm -rf ' . $oHostDbMaster->tablespacePath(1) . "/*");
|
||||
|
||||
# Restore recovery file that was saved in last test
|
||||
storageDb()->move($self->testPath . "/${strRecoveryFile}", $oHostDbMaster->dbBasePath() . "/${strRecoveryFile}");
|
||||
storageLocal()->move($self->testPath . "/${strRecoveryFile}", $oHostDbMaster->dbBasePath() . "/${strRecoveryFile}");
|
||||
|
||||
# Also touch recovery.signal when required
|
||||
if ($oHostDbMaster->pgVersion() >= PG_VERSION_12)
|
||||
|
@ -1,116 +0,0 @@
|
||||
####################################################################################################################################
|
||||
# StorageHelperTest.pm - Tests for Storage::Helper module.
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Module::Storage::StorageHelperPerlTest;
|
||||
use parent 'pgBackRestTest::Env::ConfigEnvTest';
|
||||
|
||||
####################################################################################################################################
|
||||
# Perl includes
|
||||
####################################################################################################################################
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
use Storable qw(dclone);
|
||||
|
||||
use pgBackRest::Config::Config;
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Protocol::Storage::Helper;
|
||||
use pgBackRest::Storage::Helper;
|
||||
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Env::Host::HostBackupTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
|
||||
####################################################################################################################################
|
||||
# initTest - initialization before each test
|
||||
####################################################################################################################################
|
||||
sub initTest
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
storageTest()->pathCreate('db');
|
||||
storageTest()->pathCreate('repo');
|
||||
storageTest()->pathCreate('spool');
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# run
|
||||
####################################################################################################################################
|
||||
sub run
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Define test file
|
||||
my $strFile = 'file.txt';
|
||||
my $strFileCopy = 'file.txt.copy';
|
||||
my $strFileContent = 'TESTDATA';
|
||||
my $iFileSize = length($strFileContent);
|
||||
|
||||
# Setup parameters
|
||||
$self->optionTestSet(CFGOPT_PG_PATH, $self->testPath() . '/db');
|
||||
$self->optionTestSet(CFGOPT_REPO_PATH, $self->testPath() . '/repo');
|
||||
$self->optionTestSet(CFGOPT_SPOOL_PATH, $self->testPath() . '/spool');
|
||||
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
|
||||
$self->optionTestSetBool(CFGOPT_ARCHIVE_ASYNC, true);
|
||||
|
||||
$self->configTestLoad(CFGCMD_ARCHIVE_PUSH);
|
||||
|
||||
#-------------------------------------------------------------------------------------------------------------------------------
|
||||
if ($self->begin("storageLocal()"))
|
||||
{
|
||||
$self->testResult(sub {storageLocal($self->testPath())->put("/tmp/${strFile}", $strFileContent)}, $iFileSize, 'put');
|
||||
$self->testResult(sub {${storageTest()->get("/tmp/${strFile}")}}, $strFileContent, ' check put');
|
||||
|
||||
$self->testResult(
|
||||
sub {storageLocal($self->testPath())->put("/tmp/${strFile}", $strFileContent)}, $iFileSize, 'put cache storage');
|
||||
$self->testResult(sub {${storageTest()->get("/tmp/${strFile}")}}, $strFileContent, ' check put');
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------------------------------------------------------------
|
||||
if ($self->begin("storageDb()"))
|
||||
{
|
||||
$self->testResult(sub {storageDb()->put($strFile, $strFileContent)}, $iFileSize, 'put');
|
||||
$self->testResult(sub {${storageTest()->get("db/${strFile}")}}, $strFileContent, ' check put');
|
||||
|
||||
$self->testResult(sub {storageDb()->put($strFileCopy, $strFileContent)}, $iFileSize, 'put cached storage');
|
||||
$self->testResult(sub {${storageTest()->get("db/${strFileCopy}")}}, $strFileContent, ' check put');
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------------------------------------------------------------
|
||||
if ($self->begin("storageRepo()"))
|
||||
{
|
||||
$self->testResult(sub {storageRepo()->put($strFile, $strFileContent)}, $iFileSize, 'put');
|
||||
$self->testResult(sub {${storageTest()->get("repo/${strFile}")}}, $strFileContent, ' check put');
|
||||
|
||||
$self->testResult(sub {storageRepo()->put($strFileCopy, $strFileContent)}, $iFileSize, 'put cached storage');
|
||||
$self->testResult(sub {${storageTest()->get("repo/${strFileCopy}")}}, $strFileContent, ' check put');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {storageRepo()->pathGet(STORAGE_REPO_ARCHIVE)}, $self->testPath() . '/repo/archive/db', 'check archive path');
|
||||
$self->testResult(
|
||||
sub {storageRepo()->pathGet(STORAGE_REPO_ARCHIVE . '/9.3-1/000000010000000100000001')},
|
||||
$self->testPath() . '/repo/archive/db/9.3-1/0000000100000001/000000010000000100000001', 'check repo WAL file');
|
||||
$self->testResult(
|
||||
sub {storageRepo()->pathGet(STORAGE_REPO_ARCHIVE . '/9.3-1/0000000100000001')},
|
||||
$self->testPath() . '/repo/archive/db/9.3-1/0000000100000001', 'check repo WAL path');
|
||||
$self->testResult(
|
||||
sub {storageRepo()->pathGet(STORAGE_REPO_ARCHIVE . '/9.3-1/0000000100000001')},
|
||||
$self->testPath() . '/repo/archive/db/9.3-1/0000000100000001', 'check repo WAL major path');
|
||||
$self->testResult(
|
||||
sub {storageRepo()->pathGet(STORAGE_REPO_ARCHIVE . '/9.3-1')},
|
||||
$self->testPath() . '/repo/archive/db/9.3-1', 'check repo archive id path');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {storageRepo()->pathGet(STORAGE_REPO_BACKUP)}, $self->testPath() . '/repo/backup/db', 'check backup path');
|
||||
$self->testResult(
|
||||
sub {storageRepo()->pathGet(STORAGE_REPO_BACKUP . '/file')}, $self->testPath() . '/repo/backup/db/file',
|
||||
'check backup file');
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
@ -1,351 +0,0 @@
|
||||
####################################################################################################################################
|
||||
# Tests for Storage::Local module
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Module::Storage::StoragePerlTest;
|
||||
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::Config::Config;
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::LibC qw(:crypto);
|
||||
use pgBackRest::Storage::Base;
|
||||
|
||||
use pgBackRestTest::Common::ContainerTest;
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
use pgBackRestTest::Env::Host::HostBackupTest;
|
||||
|
||||
####################################################################################################################################
|
||||
# run
|
||||
####################################################################################################################################
|
||||
sub run
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Define test file
|
||||
my $strFile = $self->testPath() . '/file.txt';
|
||||
my $strFileCopy = $self->testPath() . '/file.txt.copy';
|
||||
my $strFileHash = 'bbbcf2c59433f68f22376cd2439d6cd309378df6';
|
||||
my $strFileContent = 'TESTDATA';
|
||||
my $iFileSize = length($strFileContent);
|
||||
|
||||
# Create local storage
|
||||
$self->{oStorageLocal} = new pgBackRest::Storage::Storage('<LOCAL>');
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin("pathGet()"))
|
||||
{
|
||||
$self->testResult(sub {$self->storageLocal()->pathGet('file')}, '/file', 'relative path');
|
||||
$self->testResult(sub {$self->storageLocal()->pathGet('/file2')}, '/file2', 'absolute path');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('put()'))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->put($self->storageLocal()->openWrite($strFile))}, 0, 'put empty');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->put($strFile)}, 0, 'put empty (all defaults)');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->put($self->storageLocal()->openWrite($strFile), $strFileContent)}, $iFileSize, 'put');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->put($self->storageLocal()->openWrite($strFile), \$strFileContent)}, $iFileSize,
|
||||
'put reference');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('get()'))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->get($self->storageLocal()->openRead($strFile, {bIgnoreMissing => true}))}, undef,
|
||||
'get missing');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->storageLocal()->put($strFile);
|
||||
$self->testResult(sub {${$self->storageLocal()->get($strFile)}}, undef, 'get empty');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->storageLocal()->put($strFile, $strFileContent);
|
||||
$self->testResult(sub {${$self->storageLocal()->get($strFile)}}, $strFileContent, 'get');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {${$self->storageLocal()->get($self->storageLocal()->openRead($strFile))}}, $strFileContent, 'get from io');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('hashSize()'))
|
||||
{
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->put($strFile, $strFileContent)}, 8, 'put');
|
||||
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->hashSize($strFile)},
|
||||
qw{(} . cryptoHashOne('sha1', $strFileContent) . ', ' . $iFileSize . qw{)}, ' check hash/size');
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->hashSize(BOGUS, {bIgnoreMissing => true})}, "([undef], [undef])",
|
||||
' check missing hash/size');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('copy()'))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testException(
|
||||
sub {$self->storageLocal()->copy($self->storageLocal()->openRead($strFile), $strFileCopy)}, ERROR_FILE_MISSING,
|
||||
"unable to open missing file '${strFile}' for read");
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->exists($strFileCopy)}, false, ' destination does not exist');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->copy(
|
||||
$self->storageLocal()->openRead($strFile, {bIgnoreMissing => true}),
|
||||
$self->storageLocal()->openWrite($strFileCopy))},
|
||||
false, 'missing source io');
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->exists($strFileCopy)}, false, ' destination does not exist');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testException(
|
||||
sub {$self->storageLocal()->copy($self->storageLocal()->openRead($strFile), $strFileCopy)}, ERROR_FILE_MISSING,
|
||||
"unable to open missing file '${strFile}' for read");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->storageLocal()->put($strFile, $strFileContent);
|
||||
|
||||
$self->testResult(sub {$self->storageLocal()->copy($strFile, $strFileCopy)}, true, 'copy filename->filename');
|
||||
$self->testResult(sub {${$self->storageLocal()->get($strFileCopy)}}, $strFileContent, ' check copy');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->storageLocal()->remove($strFileCopy);
|
||||
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->copy($self->storageLocal()->openRead($strFile), $strFileCopy)}, true, 'copy io->filename');
|
||||
$self->testResult(sub {${$self->storageLocal()->get($strFileCopy)}}, $strFileContent, ' check copy');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->storageLocal()->remove($strFileCopy);
|
||||
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->copy(
|
||||
$self->storageLocal()->openRead($strFile), $self->storageLocal()->openWrite($strFileCopy))},
|
||||
true, 'copy io->io');
|
||||
$self->testResult(sub {${$self->storageLocal()->get($strFileCopy)}}, $strFileContent, ' check copy');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('exists()'))
|
||||
{
|
||||
$self->storageLocal()->put($self->testPath() . "/test.file");
|
||||
|
||||
$self->testResult(sub {$self->storageLocal()->exists($self->testPath() . "/test.file")}, true, 'existing file');
|
||||
$self->testResult(sub {$self->storageLocal()->exists($self->testPath() . "/test.missing")}, false, 'missing file');
|
||||
$self->testResult(sub {$self->storageLocal()->exists($self->testPath())}, false, 'path');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('info()'))
|
||||
{
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->info($self->testPath())},
|
||||
"{group => " . $self->group() . ", mode => 0770, type => d, user => " . $self->pgUser() . "}",
|
||||
'stat dir successfully');
|
||||
|
||||
$self->testException(sub {$self->storageLocal()->info(BOGUS)}, ERROR_FILE_OPEN,
|
||||
"unable to get info for missing path/file '/bogus'");
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin("manifest() and list()"))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testException(
|
||||
sub {$self->storageLocal()->manifest($self->testPath() . '/missing')},
|
||||
ERROR_PATH_MISSING, "unable to list file info for missing path '" . $self->testPath() . "/missing'");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
# Setup test data
|
||||
executeTest('mkdir -m 750 ' . $self->testPath() . '/sub1');
|
||||
executeTest('mkdir -m 750 ' . $self->testPath() . '/sub1/sub2');
|
||||
executeTest('mkdir -m 750 ' . $self->testPath() . '/sub2');
|
||||
|
||||
executeTest("echo 'TESTDATA' > " . $self->testPath() . '/test.txt');
|
||||
utime(1111111111, 1111111111, $self->testPath() . '/test.txt');
|
||||
executeTest('chmod 1640 ' . $self->testPath() . '/test.txt');
|
||||
|
||||
executeTest("echo 'TESTDATA_' > ". $self->testPath() . '/sub1/test-sub1.txt');
|
||||
utime(1111111112, 1111111112, $self->testPath() . '/sub1/test-sub1.txt');
|
||||
executeTest('chmod 0640 ' . $self->testPath() . '/sub1/test-sub1.txt');
|
||||
|
||||
executeTest("echo 'TESTDATA_' > ". $self->testPath() . '/sub1/.test-sub1.txt');
|
||||
utime(1111111112, 1111111112, $self->testPath() . '/sub1/.test-sub1.txt');
|
||||
executeTest('chmod 0640 ' . $self->testPath() . '/sub1/.test-sub1.txt');
|
||||
|
||||
executeTest("echo 'TESTDATA__' > " . $self->testPath() . '/sub1/sub2/test-sub2.txt');
|
||||
utime(1111111113, 1111111113, $self->testPath() . '/sub1/sub2/test-sub2.txt');
|
||||
executeTest('chmod 0646 ' . $self->testPath() . '/sub1/sub2/test-sub2.txt');
|
||||
|
||||
executeTest('mkfifo -m 606 ' . $self->testPath() . '/sub1/apipe');
|
||||
|
||||
executeTest('ln ' . $self->testPath() . '/test.txt ' . $self->testPath() . '/sub1/test-hardlink.txt');
|
||||
executeTest('ln ' . $self->testPath() . '/test.txt ' . $self->testPath() . '/sub1/sub2/test-hardlink.txt');
|
||||
|
||||
executeTest('ln -s .. ' . $self->testPath() . '/sub1/test');
|
||||
executeTest('chmod 0700 ' . $self->testPath() . '/sub1/test');
|
||||
executeTest('ln -s ../.. ' . $self->testPath() . '/sub1/sub2/test');
|
||||
executeTest('chmod 0750 ' . $self->testPath() . '/sub1/sub2/test');
|
||||
|
||||
executeTest('chmod 0770 ' . $self->testPath());
|
||||
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->manifest($self->testPath())},
|
||||
'{. => {group => ' . $self->group() . ', mode => 0770, type => d, user => ' . $self->pgUser() . '}, ' .
|
||||
'sub1 => {group => ' . $self->group() . ', mode => 0750, type => d, user => ' . $self->pgUser() . '}, ' .
|
||||
'sub1/.test-sub1.txt => ' .
|
||||
'{group => ' . $self->group() . ', mode => 0640, modification_time => 1111111112, size => 10, type => f, user => ' .
|
||||
$self->pgUser() . '}, ' .
|
||||
'sub1/apipe => {group => ' . $self->group() . ', mode => 0606, type => s, user => ' . $self->pgUser() . '}, ' .
|
||||
'sub1/sub2 => {group => ' . $self->group() . ', mode => 0750, type => d, user => ' . $self->pgUser() . '}, ' .
|
||||
'sub1/sub2/test => {group => ' . $self->group() . ', link_destination => ../.., type => l, user => ' .
|
||||
$self->pgUser() . '}, ' .
|
||||
'sub1/sub2/test-hardlink.txt => ' .
|
||||
'{group => ' . $self->group() . ', mode => 0640, modification_time => 1111111111, size => 9, type => f, user => ' .
|
||||
$self->pgUser() . '}, ' .
|
||||
'sub1/sub2/test-sub2.txt => ' .
|
||||
'{group => ' . $self->group() . ', mode => 0646, modification_time => 1111111113, size => 11, type => f, user => ' .
|
||||
$self->pgUser() . '}, ' .
|
||||
'sub1/test => {group => ' . $self->group() . ', link_destination => .., type => l, user => ' . $self->pgUser() . '}, ' .
|
||||
'sub1/test-hardlink.txt => ' .
|
||||
'{group => ' . $self->group() . ', mode => 0640, modification_time => 1111111111, size => 9, type => f, user => ' .
|
||||
$self->pgUser() . '}, ' .
|
||||
'sub1/test-sub1.txt => ' .
|
||||
'{group => ' . $self->group() . ', mode => 0640, modification_time => 1111111112, size => 10, type => f, user => ' .
|
||||
$self->pgUser() . '}, ' .
|
||||
'sub2 => {group => ' . $self->group() . ', mode => 0750, type => d, user => ' . $self->pgUser() . '}, ' .
|
||||
'test.txt => ' .
|
||||
'{group => ' . $self->group() . ', mode => 0640, modification_time => 1111111111, size => 9, type => f, user => ' .
|
||||
$self->pgUser() . '}}',
|
||||
'complete manifest');
|
||||
|
||||
$self->testResult(sub {$self->storageLocal()->list($self->testPath())}, "(sub1, sub2, test.txt)", "list");
|
||||
$self->testResult(sub {$self->storageLocal()->list($self->testPath(), {strExpression => "2\$"})}, "sub2", "list");
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->list($self->testPath(), {strSortOrder => 'reverse'})}, "(test.txt, sub2, sub1)",
|
||||
"list reverse");
|
||||
$self->testResult(sub {$self->storageLocal()->list($self->testPath() . "/sub2")}, "[undef]", "list empty");
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->list($self->testPath() . "/sub99", {bIgnoreMissing => true})}, "[undef]", "list missing");
|
||||
$self->testException(
|
||||
sub {$self->storageLocal()->list($self->testPath() . "/sub99")}, ERROR_PATH_MISSING,
|
||||
"unable to list files for missing path '" . $self->testPath() . "/sub99'");
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('move()'))
|
||||
{
|
||||
my $strFileCopy = "${strFile}.copy";
|
||||
my $strFileSub = $self->testPath() . '/sub/file.txt';
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testException(
|
||||
sub {$self->storageLocal()->move($strFile, $strFileCopy)}, ERROR_FILE_MOVE,
|
||||
"unable to move '${strFile}' to '${strFile}.copy': No such file or directory");
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('owner()'))
|
||||
{
|
||||
my $strFile = $self->testPath() . "/test.txt";
|
||||
|
||||
$self->testException(
|
||||
sub {$self->storageLocal()->owner($strFile, 'root')}, ERROR_FILE_MISSING,
|
||||
"unable to stat '${strFile}': No such file or directory");
|
||||
|
||||
executeTest("touch ${strFile}");
|
||||
|
||||
$self->testException(
|
||||
sub {$self->storageLocal()->owner($strFile, BOGUS)}, ERROR_FILE_OWNER,
|
||||
"unable to set ownership for '${strFile}' because user 'bogus' does not exist");
|
||||
$self->testException(
|
||||
sub {$self->storageLocal()->owner($strFile, undef, BOGUS)}, ERROR_FILE_OWNER,
|
||||
"unable to set ownership for '${strFile}' because group 'bogus' does not exist");
|
||||
|
||||
$self->testResult(sub {$self->storageLocal()->owner($strFile)}, undef, "no ownership changes");
|
||||
$self->testResult(sub {$self->storageLocal()->owner($strFile, TEST_USER)}, undef, "same user");
|
||||
$self->testResult(sub {$self->storageLocal()->owner($strFile, undef, TEST_GROUP)}, undef, "same group");
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->owner($strFile, TEST_USER, TEST_GROUP)}, undef,
|
||||
"same user, group");
|
||||
|
||||
$self->testException(
|
||||
sub {$self->storageLocal()->owner($strFile, 'root', undef)}, ERROR_FILE_OWNER,
|
||||
"unable to set ownership for '${strFile}': Operation not permitted");
|
||||
$self->testException(
|
||||
sub {$self->storageLocal()->owner($strFile, undef, 'root')}, ERROR_FILE_OWNER,
|
||||
"unable to set ownership for '${strFile}': Operation not permitted");
|
||||
|
||||
executeTest("sudo chown :root ${strFile}");
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->owner($strFile, undef, TEST_GROUP)}, undef, "change group back from root");
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('pathCreate()'))
|
||||
{
|
||||
my $strTestPath = $self->testPath() . "/" . BOGUS;
|
||||
|
||||
$self->testResult(sub {$self->storageLocal()->pathCreate($strTestPath)}, "[undef]",
|
||||
"test creation of path " . $strTestPath);
|
||||
|
||||
$self->testException(sub {$self->storageLocal()->pathCreate($strTestPath)}, ERROR_PATH_CREATE,
|
||||
"unable to create path '". $strTestPath. "'");
|
||||
|
||||
$self->testResult(sub {$self->storageLocal()->pathCreate($strTestPath, {bIgnoreExists => true})}, "[undef]",
|
||||
"ignore path exists");
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('pathExists()'))
|
||||
{
|
||||
$self->storageLocal()->put($self->testPath() . "/test.file");
|
||||
|
||||
$self->testResult(sub {$self->storageLocal()->pathExists($self->testPath() . "/test.file")}, false, 'existing file');
|
||||
$self->testResult(sub {$self->storageLocal()->pathExists($self->testPath() . "/test.missing")}, false, 'missing file');
|
||||
$self->testResult(sub {$self->storageLocal()->pathExists($self->testPath())}, true, 'path');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('pathSync()'))
|
||||
{
|
||||
$self->testResult(sub {$self->storageLocal()->pathSync($self->testPath())}, "[undef]", "test path sync");
|
||||
}
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Getters
|
||||
####################################################################################################################################
|
||||
# sub host {return '127.0.0.1'}
|
||||
# sub pathLocal {return shift->{strPathLocal}};
|
||||
# sub pathRemote {return shift->{strPathRemote}};
|
||||
sub storageLocal {return shift->{oStorageLocal}};
|
||||
# sub storageEncrypt {return shift->{oStorageEncrypt}};
|
||||
# sub storageRemote {return shift->{oStorageRemote}};
|
||||
|
||||
1;
|
Reference in New Issue
Block a user