You've already forked pgbackrest
mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-12-23 23:51:07 +02:00
Storage and IO layer refactor:
Refactor storage layer to allow for new repository filesystems using drivers. (Reviewed by Cynthia Shang.) Refactor IO layer to allow for new compression formats, checksum types, and other capabilities using filters. (Reviewed by Cynthia Shang.)
This commit is contained in:
197
test/lib/pgBackRestTest/Module/Storage/StorageFilterGzipTest.pm
Normal file
197
test/lib/pgBackRestTest/Module/Storage/StorageFilterGzipTest.pm
Normal file
@@ -0,0 +1,197 @@
|
||||
####################################################################################################################################
|
||||
# StorageFilterGzipTest.pm - Tests for Storage::Filter::Gzip module.
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Module::Storage::StorageFilterGzipTest;
|
||||
use parent 'pgBackRestTest::Common::RunTest';
|
||||
|
||||
####################################################################################################################################
|
||||
# Perl includes
|
||||
####################################################################################################################################
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
use Compress::Raw::Zlib qw(Z_OK Z_BUF_ERROR Z_DATA_ERROR);
|
||||
use Digest::SHA qw(sha1_hex);
|
||||
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Storage::Base;
|
||||
use pgBackRest::Storage::Filter::Gzip;
|
||||
use pgBackRest::Storage::Posix::Driver;
|
||||
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
|
||||
####################################################################################################################################
|
||||
# run
|
||||
####################################################################################################################################
|
||||
sub run
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Test data
|
||||
my $strFile = $self->testPath() . qw{/} . 'file.txt';
|
||||
my $strFileGz = "${strFile}.gz";
|
||||
my $strFileContent = 'TESTDATA';
|
||||
my $iFileLength = length($strFileContent);
|
||||
my $oDriver = new pgBackRest::Storage::Posix::Driver();
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('errorCheck()'))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $oGzipIo = $self->testResult(
|
||||
sub {new pgBackRest::Storage::Filter::Gzip($oDriver->openWrite($strFileGz))}, '[object]', 'new write');
|
||||
|
||||
$oGzipIo->{bWrite} = true;
|
||||
$self->testException(sub {$oGzipIo->errorCheck(Z_DATA_ERROR)}, ERROR_FILE_WRITE, "unable to deflate '${strFileGz}'");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oGzipIo->errorCheck(Z_OK)}, Z_OK, 'Z_OK');
|
||||
$self->testResult(sub {$oGzipIo->errorCheck(Z_BUF_ERROR)}, Z_OK, 'Z_BUF_ERROR');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oGzipIo->{bWrite} = false;
|
||||
$oGzipIo->{strCompressType} = STORAGE_DECOMPRESS;
|
||||
$self->testException(sub {$oGzipIo->errorCheck(Z_DATA_ERROR)}, ERROR_FILE_READ, "unable to inflate '${strFileGz}'");
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('write()'))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $oGzipIo = $self->testResult(
|
||||
sub {new pgBackRest::Storage::Filter::Gzip($oDriver->openWrite($strFileGz))}, '[object]', 'new write compress');
|
||||
|
||||
my $tBuffer = substr($strFileContent, 0, 2);
|
||||
$self->testResult(sub {$oGzipIo->write(\$tBuffer)}, 2, ' write 2 bytes');
|
||||
$tBuffer = substr($strFileContent, 2, 2);
|
||||
$self->testResult(sub {$oGzipIo->write(\$tBuffer)}, 2, ' write 2 bytes');
|
||||
$tBuffer = substr($strFileContent, 4, 2);
|
||||
$self->testResult(sub {$oGzipIo->write(\$tBuffer)}, 2, ' write 2 bytes');
|
||||
$tBuffer = substr($strFileContent, 6, 2);
|
||||
$self->testResult(sub {$oGzipIo->write(\$tBuffer)}, 2, ' write 2 bytes');
|
||||
$tBuffer = '';
|
||||
$self->testResult(sub {$oGzipIo->write(\$tBuffer)}, 0, ' write 0 bytes');
|
||||
|
||||
$self->testResult(sub {$oGzipIo->close()}, true, ' close');
|
||||
|
||||
executeTest("gzip -d ${strFileGz}");
|
||||
$self->testResult(sub {${storageTest()->get($strFile)}}, $strFileContent, ' check content');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
executeTest("gzip ${strFile}");
|
||||
my $tFile = ${storageTest()->get($strFileGz)};
|
||||
|
||||
$oGzipIo = $self->testResult(
|
||||
sub {new pgBackRest::Storage::Filter::Gzip(
|
||||
$oDriver->openWrite($strFile), {strCompressType => STORAGE_DECOMPRESS})}, '[object]', 'new write decompress');
|
||||
|
||||
$tBuffer = substr($tFile, 0, 10);
|
||||
$self->testResult(sub {$oGzipIo->write(\$tBuffer)}, 10, ' write bytes');
|
||||
$tBuffer = substr($tFile, 10);
|
||||
$self->testResult(sub {$oGzipIo->write(\$tBuffer)}, length($tFile) - 10, ' write bytes');
|
||||
$self->testResult(sub {$oGzipIo->close()}, true, ' close');
|
||||
|
||||
$self->testResult(sub {${storageTest()->get($strFile)}}, $strFileContent, ' check content');
|
||||
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('read()'))
|
||||
{
|
||||
my $tBuffer;
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $oGzipIo = $self->testResult(
|
||||
sub {new pgBackRest::Storage::Filter::Gzip($oDriver->openWrite($strFileGz), {bWantGzip => false})},
|
||||
'[object]', 'new write compress');
|
||||
$self->testResult(sub {$oGzipIo->write(\$strFileContent, $iFileLength)}, $iFileLength, ' write');
|
||||
$self->testResult(sub {$oGzipIo->close()}, true, ' close');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oGzipIo = $self->testResult(
|
||||
sub {new pgBackRest::Storage::Filter::Gzip(
|
||||
$oDriver->openRead($strFileGz), {bWantGzip => false, strCompressType => STORAGE_DECOMPRESS})},
|
||||
'[object]', 'new read decompress');
|
||||
|
||||
$self->testResult(sub {$oGzipIo->read(\$tBuffer, 4)}, 4, ' read 4 bytes');
|
||||
$self->testResult(sub {$oGzipIo->read(\$tBuffer, 2)}, 2, ' read 2 bytes');
|
||||
$self->testResult(sub {$oGzipIo->read(\$tBuffer, 2)}, 2, ' read 2 bytes');
|
||||
$self->testResult(sub {$oGzipIo->read(\$tBuffer, 2)}, 0, ' read 0 bytes');
|
||||
$self->testResult(sub {$oGzipIo->read(\$tBuffer, 2)}, 0, ' read 0 bytes');
|
||||
|
||||
$self->testResult(sub {$oGzipIo->close()}, true, ' close');
|
||||
$self->testResult($tBuffer, $strFileContent, ' check content');
|
||||
|
||||
storageTest()->remove($strFileGz);
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$tBuffer = 'AA';
|
||||
storageTest()->put($strFile, $strFileContent);
|
||||
|
||||
$oGzipIo = $self->testResult(
|
||||
sub {new pgBackRest::Storage::Filter::Gzip($oDriver->openRead($strFile))},
|
||||
'[object]', 'new read compress');
|
||||
$self->testResult(sub {$oGzipIo->read(\$tBuffer, 2)}, 10, ' read 10 bytes (request 2)');
|
||||
$self->testResult(sub {$oGzipIo->read(\$tBuffer, 2)}, 18, ' read 18 bytes (request 2)');
|
||||
$self->testResult(sub {$oGzipIo->read(\$tBuffer, 2)}, 0, ' read 0 bytes (request 2)');
|
||||
$self->testResult(sub {$oGzipIo->close()}, true, ' close');
|
||||
|
||||
$self->testResult(sub {storageTest()->put($strFileGz, substr($tBuffer, 2))}, 28, ' put content');
|
||||
executeTest("gzip -df ${strFileGz}");
|
||||
$self->testResult(sub {${storageTest()->get($strFile)}}, $strFileContent, ' check content');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$tBuffer = undef;
|
||||
|
||||
executeTest('cat ' . $self->dataPath() . "/filecopy.archive2.bin | gzip -c > ${strFileGz}");
|
||||
|
||||
$oGzipIo = $self->testResult(
|
||||
sub {new pgBackRest::Storage::Filter::Gzip(
|
||||
$oDriver->openRead($strFileGz), {lCompressBufferMax => 4096, strCompressType => STORAGE_DECOMPRESS})},
|
||||
'[object]', 'new read decompress');
|
||||
|
||||
$self->testResult(sub {$oGzipIo->read(\$tBuffer, 8388608)}, 8388608, ' read 8388608 bytes');
|
||||
$self->testResult(sub {$oGzipIo->read(\$tBuffer, 4194304)}, 4194304, ' read 4194304 bytes');
|
||||
$self->testResult(sub {$oGzipIo->read(\$tBuffer, 4194304)}, 4194304, ' read 4194304 bytes');
|
||||
$self->testResult(sub {$oGzipIo->read(\$tBuffer, 1)}, 0, ' read 0 bytes');
|
||||
|
||||
$self->testResult(sub {$oGzipIo->close()}, true, ' close');
|
||||
$self->testResult(sha1_hex($tBuffer), '1c7e00fd09b9dd11fc2966590b3e3274645dd031', ' check content');
|
||||
|
||||
storageTest()->remove($strFileGz);
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$tBuffer = undef;
|
||||
|
||||
executeTest('cp ' . $self->dataPath() . "/filecopy.archive2.bin ${strFile}");
|
||||
|
||||
$oGzipIo = $self->testResult(
|
||||
sub {new pgBackRest::Storage::Filter::Gzip($oDriver->openRead($strFile), {strCompressType => STORAGE_COMPRESS})},
|
||||
'[object]', 'new read compress');
|
||||
|
||||
$self->testResult(sub {$oGzipIo->read(\$tBuffer, 2000000) > 0}, true, ' read bytes');
|
||||
$self->testResult(sub {$oGzipIo->read(\$tBuffer, 2000000) > 0}, true, ' read bytes');
|
||||
$self->testResult(sub {$oGzipIo->close()}, true, ' close');
|
||||
|
||||
$self->testResult(sub {storageTest()->put($strFileGz, $tBuffer) > 0}, true, ' put content');
|
||||
executeTest("gzip -df ${strFileGz}");
|
||||
$self->testResult(
|
||||
sub {sha1_hex(${storageTest()->get($strFile)})}, '1c7e00fd09b9dd11fc2966590b3e3274645dd031', ' check content');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
storageTest()->put($strFileGz, $strFileContent);
|
||||
|
||||
$oGzipIo = $self->testResult(
|
||||
sub {new pgBackRest::Storage::Filter::Gzip($oDriver->openRead($strFileGz), {strCompressType => STORAGE_DECOMPRESS})},
|
||||
'[object]', 'new read decompress');
|
||||
|
||||
$self->testException(
|
||||
sub {$oGzipIo->read(\$tBuffer, 1)}, ERROR_FILE_READ, "unable to inflate '${strFileGz}': incorrect header check");
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
105
test/lib/pgBackRestTest/Module/Storage/StorageFilterShaTest.pm
Normal file
105
test/lib/pgBackRestTest/Module/Storage/StorageFilterShaTest.pm
Normal file
@@ -0,0 +1,105 @@
|
||||
####################################################################################################################################
|
||||
# StorageFilterShaTest.pm - Tests for StorageFilterSha module.
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Module::Storage::StorageFilterShaTest;
|
||||
use parent 'pgBackRestTest::Common::RunTest';
|
||||
|
||||
####################################################################################################################################
|
||||
# Perl includes
|
||||
####################################################################################################################################
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
use Digest::SHA qw(sha1_hex);
|
||||
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Storage::Base;
|
||||
use pgBackRest::Storage::Filter::Sha;
|
||||
use pgBackRest::Storage::Posix::Driver;
|
||||
|
||||
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 $oDriver = new pgBackRest::Storage::Posix::Driver();
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('read()'))
|
||||
{
|
||||
my $tBuffer;
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
executeTest("echo -n '${strFileContent}' | tee ${strFile}");
|
||||
|
||||
my $oFileIo = $self->testResult(sub {$oDriver->openRead($strFile)}, '[object]', 'open read');
|
||||
my $oShaIo = $self->testResult(sub {new pgBackRest::Storage::Filter::Sha($oFileIo)}, '[object]', 'new read');
|
||||
|
||||
$self->testResult(sub {$oShaIo->read(\$tBuffer, 2, undef)}, 2, 'read 2 bytes');
|
||||
$self->testResult(sub {$oShaIo->read(\$tBuffer, 2, 2)}, 2, 'read 2 bytes');
|
||||
$self->testResult(sub {$oShaIo->read(\$tBuffer, 2, 4)}, 2, 'read 2 bytes');
|
||||
$self->testResult(sub {$oShaIo->read(\$tBuffer, 2, 6)}, 2, 'read 2 bytes');
|
||||
$self->testResult(sub {$oShaIo->read(\$tBuffer, 2, 8)}, 0, 'read 0 bytes');
|
||||
|
||||
$self->testResult(sub {$oShaIo->close()}, true, 'close');
|
||||
my $strSha = $self->testResult(
|
||||
sub {$oShaIo->result(STORAGE_FILTER_SHA)}, sha1_hex($strFileContent), 'check hash against original content');
|
||||
$self->testResult($strSha, sha1_hex($tBuffer), 'check hash against buffer');
|
||||
$self->testResult(sub {${storageTest()->get($strFile)}}, $strFileContent, 'check content');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$tBuffer = undef;
|
||||
|
||||
$oFileIo = $self->testResult(
|
||||
sub {$oDriver->openRead($self->dataPath() . '/filecopy.archive2.bin')}, '[object]', 'open read');
|
||||
$oShaIo = $self->testResult(sub {new pgBackRest::Storage::Filter::Sha($oFileIo)}, '[object]', 'new read');
|
||||
|
||||
$self->testResult(sub {$oShaIo->read(\$tBuffer, 8388608)}, 8388608, ' read 8388608 bytes');
|
||||
$self->testResult(sub {$oShaIo->read(\$tBuffer, 4194304)}, 4194304, ' read 4194304 bytes');
|
||||
$self->testResult(sub {$oShaIo->read(\$tBuffer, 4194304)}, 4194304, ' read 4194304 bytes');
|
||||
$self->testResult(sub {$oShaIo->read(\$tBuffer, 1)}, 0, ' read 0 bytes');
|
||||
|
||||
$self->testResult(sub {$oShaIo->close()}, true, ' close');
|
||||
$self->testResult($oShaIo->result(STORAGE_FILTER_SHA), '1c7e00fd09b9dd11fc2966590b3e3274645dd031', ' check hash');
|
||||
$self->testResult(sha1_hex($tBuffer), '1c7e00fd09b9dd11fc2966590b3e3274645dd031', ' check content');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('write()'))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $oFileIo = $self->testResult(sub {$oDriver->openWrite($strFile, {bAtomic => true})}, '[object]', 'open write');
|
||||
my $oShaIo = $self->testResult(
|
||||
sub {new pgBackRest::Storage::Filter::Sha($oFileIo)}, '[object]', 'new');
|
||||
|
||||
my $tBuffer = substr($strFileContent, 0, 2);
|
||||
$self->testResult(sub {$oShaIo->write(\$tBuffer)}, 2, 'write 2 bytes');
|
||||
$tBuffer = substr($strFileContent, 2, 2);
|
||||
$self->testResult(sub {$oShaIo->write(\$tBuffer)}, 2, 'write 2 bytes');
|
||||
$tBuffer = substr($strFileContent, 4, 2);
|
||||
$self->testResult(sub {$oShaIo->write(\$tBuffer)}, 2, 'write 2 bytes');
|
||||
$tBuffer = substr($strFileContent, 6, 2);
|
||||
$self->testResult(sub {$oShaIo->write(\$tBuffer)}, 2, 'write 2 bytes');
|
||||
$tBuffer = '';
|
||||
$self->testResult(sub {$oShaIo->write(\$tBuffer)}, 0, 'write 0 bytes');
|
||||
|
||||
$self->testResult(sub {$oShaIo->close()}, true, 'close');
|
||||
my $strSha = $self->testResult(
|
||||
sub {$oShaIo->result(STORAGE_FILTER_SHA)}, sha1_hex($strFileContent), 'check hash against original content');
|
||||
$self->testResult(sub {${storageTest()->get($strFile)}}, $strFileContent, 'check content');
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
147
test/lib/pgBackRestTest/Module/Storage/StorageHelperTest.pm
Normal file
147
test/lib/pgBackRestTest/Module/Storage/StorageHelperTest.pm
Normal file
@@ -0,0 +1,147 @@
|
||||
####################################################################################################################################
|
||||
# StorageHelperTest.pm - Tests for Storage::Helper module.
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Module::Storage::StorageHelperTest;
|
||||
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
|
||||
my $oOption = {};
|
||||
$self->optionSetTest($oOption, OPTION_DB_PATH, $self->testPath() . '/db');
|
||||
$self->optionSetTest($oOption, OPTION_REPO_PATH, $self->testPath() . '/repo');
|
||||
$self->optionSetTest($oOption, OPTION_SPOOL_PATH, $self->testPath() . '/spool');
|
||||
$self->optionSetTest($oOption, OPTION_STANZA, $self->stanza());
|
||||
$self->optionBoolSetTest($oOption, OPTION_ARCHIVE_ASYNC, true);
|
||||
|
||||
#-------------------------------------------------------------------------------------------------------------------------------
|
||||
if ($self->begin("storageLocal()"))
|
||||
{
|
||||
$self->testResult(sub {$self->configLoadExpect(dclone($oOption), CMD_ARCHIVE_PUSH)}, '', 'config load');
|
||||
|
||||
$self->testResult(sub {storageLocal($self->testPath())->put($strFile, $strFileContent)}, $iFileSize, 'put');
|
||||
$self->testResult(sub {${storageTest()->get($strFile)}}, $strFileContent, ' check put');
|
||||
|
||||
$self->testResult(sub {storageLocal($self->testPath())->put($strFile, $strFileContent)}, $iFileSize, 'put cache storage');
|
||||
$self->testResult(sub {${storageTest()->get($strFile)}}, $strFileContent, ' check put');
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------------------------------------------------------------
|
||||
if ($self->begin("storageDb()"))
|
||||
{
|
||||
$self->testResult(sub {$self->configLoadExpect(dclone($oOption), CMD_ARCHIVE_PUSH)}, '', 'config load');
|
||||
|
||||
$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 {$self->configLoadExpect(dclone($oOption), CMD_ARCHIVE_PUSH)}, '', 'config load');
|
||||
|
||||
$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');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
# Insert a bogus rule to generate an error
|
||||
storageRepo()->{hRule}{'<BOGUS>'} =
|
||||
{
|
||||
fnRule => storageRepo()->{hRule}{&STORAGE_REPO_ARCHIVE}{fnRule},
|
||||
};
|
||||
|
||||
$self->testException(sub {storageRepo()->pathGet('<BOGUS>')}, ERROR_ASSERT, 'invalid <REPO> storage rule <BOGUS>');
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------------------------------------------------------------
|
||||
if ($self->begin("storageSpool()"))
|
||||
{
|
||||
$self->testResult(sub {$self->configLoadExpect(dclone($oOption), CMD_ARCHIVE_PUSH)}, '', 'config load');
|
||||
|
||||
$self->testResult(sub {storageSpool()->put($strFile, $strFileContent)}, $iFileSize, 'put');
|
||||
$self->testResult(sub {${storageTest()->get("spool/${strFile}")}}, $strFileContent, ' check put');
|
||||
|
||||
$self->testResult(sub {storageSpool()->put($strFileCopy, $strFileContent)}, $iFileSize, 'put cached storage');
|
||||
$self->testResult(sub {${storageTest()->get("spool/${strFileCopy}")}}, $strFileContent, ' check put');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {storageSpool()->pathGet(STORAGE_SPOOL_ARCHIVE_OUT)}, $self->testPath() . '/spool/archive/db/out',
|
||||
'check archive out path');
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
363
test/lib/pgBackRestTest/Module/Storage/StorageLocalTest.pm
Normal file
363
test/lib/pgBackRestTest/Module/Storage/StorageLocalTest.pm
Normal file
@@ -0,0 +1,363 @@
|
||||
####################################################################################################################################
|
||||
# StorageLocalTest.pm - Tests for Storage::Local module
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Module::Storage::StorageLocalTest;
|
||||
use parent 'pgBackRestTest::Common::RunTest';
|
||||
|
||||
####################################################################################################################################
|
||||
# Perl includes
|
||||
####################################################################################################################################
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
use Digest::SHA qw(sha1_hex);
|
||||
|
||||
use pgBackRest::Config::Config;
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Storage::Filter::Sha;
|
||||
use pgBackRest::Storage::Local;
|
||||
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Env::Host::HostBackupTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
|
||||
####################################################################################################################################
|
||||
# initModule - common objects and variables used by all tests.
|
||||
####################################################################################################################################
|
||||
sub initModule
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Local path
|
||||
$self->{strPathLocal} = $self->testPath() . '/local';
|
||||
|
||||
# Create the dynamic rule
|
||||
my $fnRule = sub
|
||||
{
|
||||
my $strRule = shift;
|
||||
my $strFile = shift;
|
||||
my $xData = shift;
|
||||
|
||||
if ($strRule eq '<fn-rule-1>')
|
||||
{
|
||||
return "fn-rule-1/${xData}" . (defined($strFile) ? "/${strFile}" : '');
|
||||
}
|
||||
else
|
||||
{
|
||||
return 'fn-rule-2/' . (defined($strFile) ? "${strFile}/${strFile}" : 'no-file');
|
||||
}
|
||||
};
|
||||
|
||||
# Create the rule hash
|
||||
my $hRule =
|
||||
{
|
||||
'<static-rule>' => 'static-rule-path',
|
||||
'<fn-rule-1>' =>
|
||||
{
|
||||
fnRule => $fnRule,
|
||||
xData => 'test',
|
||||
},
|
||||
'<fn-rule-2>' =>
|
||||
{
|
||||
fnRule => $fnRule,
|
||||
},
|
||||
};
|
||||
|
||||
# Create local storage
|
||||
$self->{oStorageLocal} = new pgBackRest::Storage::Local(
|
||||
$self->pathLocal(), new pgBackRest::Storage::Posix::Driver(), {hRule => $hRule, bAllowTemp => false});
|
||||
|
||||
# Remote path
|
||||
$self->{strPathRemote} = $self->testPath() . '/remote';
|
||||
|
||||
# Create the repo path so the remote won't complain that it's missing
|
||||
mkdir($self->pathRemote())
|
||||
or confess &log(ERROR, "unable to create repo directory '" . $self->pathRemote() . qw{'});
|
||||
|
||||
# Remove repo path now that the remote is created
|
||||
rmdir($self->{strPathRemote})
|
||||
or confess &log(ERROR, "unable to remove repo directory '" . $self->pathRemote() . qw{'});
|
||||
|
||||
# Create remote storage
|
||||
$self->{oStorageRemote} = new pgBackRest::Storage::Local(
|
||||
$self->pathRemote(), new pgBackRest::Storage::Posix::Driver(), {hRule => $hRule});
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# initTest - initialization before each test
|
||||
####################################################################################################################################
|
||||
sub initTest
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
executeTest(
|
||||
'ssh ' . $self->backrestUser() . '\@' . $self->host() . ' mkdir -m 700 ' . $self->pathRemote(), {bSuppressStdErr => true});
|
||||
|
||||
executeTest('mkdir -m 700 ' . $self->pathLocal());
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# run
|
||||
####################################################################################################################################
|
||||
sub run
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Define test file
|
||||
my $strFile = 'file.txt';
|
||||
my $strFileCopy = 'file.txt.copy';
|
||||
# my $strFileHash = 'bbbcf2c59433f68f22376cd2439d6cd309378df6';
|
||||
my $strFileContent = 'TESTDATA';
|
||||
my $iFileSize = length($strFileContent);
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
if ($self->begin("pathGet()"))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testException(
|
||||
sub {$self->storageLocal()->pathGet('<static-rule>/test', {bTemp => true})},
|
||||
ERROR_ASSERT, "temp file not supported for storage '" . $self->storageLocal()->pathBase() . "'");
|
||||
$self->testException(
|
||||
sub {$self->storageRemote()->pathGet('<static-rule>', {bTemp => true})},
|
||||
ERROR_ASSERT, 'file part must be defined when temp file specified');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {$self->storageRemote()->pathGet('/file', {bTemp => true})}, "/file.tmp", 'absolute path temp');
|
||||
$self->testResult(sub {$self->storageRemote()->pathGet('/file')}, "/file", 'absolute path file');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->pathGet('file')}, $self->storageLocal()->pathBase() . '/file', 'relative path');
|
||||
$self->testResult(
|
||||
sub {$self->storageRemote()->pathGet('file', {bTemp => true})},
|
||||
$self->storageRemote()->pathBase() . '/file.tmp', 'relative path temp');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testException(
|
||||
sub {$self->storageLocal()->pathGet('<static-rule/file')}, ERROR_ASSERT, "found < but not > in '<static-rule/file'");
|
||||
|
||||
$self->testException(
|
||||
sub {$self->storageLocal()->pathGet('<bogus-rule>')}, ERROR_ASSERT, "storage rule '<bogus-rule>' does not exist");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->pathGet('<static-rule>/file')},
|
||||
$self->storageLocal()->pathBase() . '/static-rule-path/file', 'static rule file');
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->pathGet('<static-rule>')},
|
||||
$self->storageLocal()->pathBase() . '/static-rule-path', 'static rule path');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->pathGet('<fn-rule-1>/file')},
|
||||
$self->storageLocal()->pathBase() . '/fn-rule-1/test/file', 'function rule 1 file');
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->pathGet('<fn-rule-2>/file')},
|
||||
$self->storageLocal()->pathBase() . '/fn-rule-2/file/file', 'function rule 2 file');
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->pathGet('<fn-rule-1>')},
|
||||
$self->storageLocal()->pathBase() . '/fn-rule-1/test', 'function rule 1 path');
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->pathGet('<fn-rule-2>')},
|
||||
$self->storageLocal()->pathBase() . '/fn-rule-2/no-file', 'function rule 2 no file');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('openWrite()'))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $oFileIo = $self->testResult(sub {$self->storageLocal()->openWrite($strFile)}, '[object]', 'open write');
|
||||
|
||||
$self->testResult(sub {$oFileIo->write(\$strFileContent, length($strFileContent))}, $iFileSize, "write $iFileSize bytes");
|
||||
$self->testResult(sub {$oFileIo->close()}, true, 'close');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
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('openRead()'))
|
||||
{
|
||||
my $tContent;
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->openRead($strFile, {bIgnoreMissing => true})}, undef, 'ignore missing');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testException(
|
||||
sub {$self->storageLocal()->openRead($strFile)}, ERROR_FILE_MISSING,
|
||||
"unable to open '" . $self->storageLocal()->pathBase() . "/${strFile}': No such file or directory");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
executeTest('sudo touch ' . $self->pathLocal() . "/${strFile} && sudo chmod 700 " . $self->pathLocal() . "/${strFile}");
|
||||
|
||||
$self->testException(
|
||||
sub {$self->storageLocal()->openRead($strFile)}, ERROR_FILE_OPEN,
|
||||
"unable to open '" . $self->storageLocal()->pathBase() . "/${strFile}': Permission denied");
|
||||
|
||||
executeTest('sudo rm ' . $self->pathLocal() . "/${strFile}");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->storageLocal()->put($self->storageLocal()->openWrite($strFile), $strFileContent);
|
||||
|
||||
my $oFileIo = $self->testResult(sub {$self->storageLocal()->openRead($strFile)}, '[object]', 'open read');
|
||||
|
||||
$self->testResult(sub {$oFileIo->read(\$tContent, $iFileSize)}, $iFileSize, "read $iFileSize bytes");
|
||||
$self->testResult($tContent, $strFileContent, ' check read');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oFileIo = $self->testResult(
|
||||
sub {$self->storageLocal()->openRead($strFile, {rhyFilter => [{strClass => STORAGE_FILTER_SHA}]})}, '[object]',
|
||||
'open read + checksum');
|
||||
|
||||
undef($tContent);
|
||||
$self->testResult(sub {$oFileIo->read(\$tContent, $iFileSize)}, $iFileSize, "read $iFileSize bytes");
|
||||
$self->testResult(sub {$oFileIo->close()}, true, 'close');
|
||||
$self->testResult($tContent, $strFileContent, ' check read');
|
||||
$self->testResult($oFileIo->result(STORAGE_FILTER_SHA), sha1_hex($strFileContent), ' check hash');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('get()'))
|
||||
{
|
||||
my $tBuffer;
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$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()'))
|
||||
{
|
||||
my $tBuffer;
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->put($strFile, $strFileContent)}, 8, 'put');
|
||||
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->hashSize($strFile)},
|
||||
qw{(} . sha1_hex($strFileContent) . ', ' . $iFileSize . qw{)}, ' check hash/size');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('copy()'))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testException(
|
||||
sub {$self->storageLocal()->copy($self->storageLocal()->openRead($strFile), $strFileCopy)}, ERROR_FILE_MISSING,
|
||||
"unable to open '" . $self->storageLocal()->pathBase() . "/${strFile}': No such file or directory");
|
||||
$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 '" . $self->storageLocal()->pathBase() . "/${strFile}': No such file or directory");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$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('info()'))
|
||||
{
|
||||
$self->testResult(sub {$self->storageLocal()->info($self->{strPathLocal})}, "[object]", 'stat dir successfully');
|
||||
|
||||
$self->testException(sub {$self->storageLocal()->info($strFile)}, ERROR_FILE_MISSING,
|
||||
"unable to stat '". $self->{strPathLocal} . "/" . $strFile ."': No such file or directory");
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('pathCreate()'))
|
||||
{
|
||||
my $strTestPath = $self->{strPathLocal} . "/" . BOGUS;
|
||||
|
||||
$self->testResult(sub {$self->storageLocal()->pathCreate($strTestPath)}, "[undef]",
|
||||
"test creation of path " . $strTestPath);
|
||||
|
||||
$self->testException(sub {$self->storageLocal()->pathCreate($strTestPath)}, ERROR_PATH_EXISTS,
|
||||
"unable to create path '". $strTestPath. "' because it already exists");
|
||||
|
||||
$self->testResult(sub {$self->storageLocal()->pathCreate($strTestPath, {bIgnoreExists => true})}, "[undef]",
|
||||
"ignore path exists");
|
||||
}
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Getters
|
||||
####################################################################################################################################
|
||||
sub host {return '127.0.0.1'}
|
||||
sub pathLocal {return shift->{strPathLocal}};
|
||||
sub pathRemote {return shift->{strPathRemote}};
|
||||
sub protocolLocal {return shift->{oProtocolLocal}};
|
||||
sub protocolRemote {return shift->{oProtocolRemote}};
|
||||
sub storageLocal {return shift->{oStorageLocal}};
|
||||
sub storageRemote {return shift->{oStorageRemote}};
|
||||
|
||||
1;
|
||||
389
test/lib/pgBackRestTest/Module/Storage/StoragePosixTest.pm
Normal file
389
test/lib/pgBackRestTest/Module/Storage/StoragePosixTest.pm
Normal file
@@ -0,0 +1,389 @@
|
||||
####################################################################################################################################
|
||||
# Posix Driver Tests
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Module::Storage::StoragePosixTest;
|
||||
use parent 'pgBackRestTest::Common::RunTest';
|
||||
|
||||
####################################################################################################################################
|
||||
# Perl includes
|
||||
####################################################################################################################################
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
use File::Basename qw(basename dirname);
|
||||
use IO::Socket::UNIX;
|
||||
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Storage::Posix::Driver;
|
||||
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
|
||||
####################################################################################################################################
|
||||
# run
|
||||
####################################################################################################################################
|
||||
sub run
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Test data
|
||||
my $strFile = $self->testPath() . '/file.txt';
|
||||
my $strFileContent = 'TESTDATA';
|
||||
my $iFileLength = length($strFileContent);
|
||||
my $iFileLengthHalf = int($iFileLength / 2);
|
||||
|
||||
# Test driver
|
||||
my $oPosix = new pgBackRest::Storage::Posix::Driver();
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('exists()'))
|
||||
{
|
||||
my $strPathSub = $self->testPath() . '/sub';
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {$oPosix->exists($strFile)}, false, 'file');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
executeTest("sudo mkdir ${strPathSub} && sudo chmod 700 ${strPathSub}");
|
||||
|
||||
$self->testResult(
|
||||
sub {$oPosix->pathExists($strPathSub)}, true, 'path');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testException(
|
||||
sub {$oPosix->exists("${strPathSub}/file")}, ERROR_FILE_EXISTS,
|
||||
"unable to test if file '${strPathSub}/file' exists: Permission denied");
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin("manifestList()"))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my @stryFile = ('.', 'test.txt');
|
||||
|
||||
$self->testResult(
|
||||
sub {$oPosix->manifestList($self->testPath(), \@stryFile)},
|
||||
'{. => {group => ' . $self->group() . ', mode => 0770, type => d, user => ' . $self->pgUser() . '}}',
|
||||
'skip missing file');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin("manifestStat()"))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $strFile = $self->testPath() . '/test.txt';
|
||||
|
||||
$self->testResult(sub {$oPosix->manifestStat($strFile)}, '[undef]', 'ignore missing file');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
storageTest()->put($strFile, "TEST");
|
||||
utime(1111111111, 1111111111, $strFile);
|
||||
executeTest('chmod 1640 ' . $strFile);
|
||||
|
||||
$self->testResult(
|
||||
sub {$oPosix->manifestStat($strFile)},
|
||||
'{group => ' . $self->group() .
|
||||
', mode => 1640, modification_time => 1111111111, size => 4, type => f, user => ' . $self->pgUser() . '}',
|
||||
'stat file');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $strSocketFile = $self->testPath() . '/test.socket';
|
||||
|
||||
# Create a socket to test invalid files
|
||||
my $oSocket = IO::Socket::UNIX->new(Type => SOCK_STREAM(), Local => $strSocketFile, Listen => 1);
|
||||
|
||||
$self->testException(
|
||||
sub {$oPosix->manifestStat($strSocketFile)}, ERROR_FILE_INVALID,
|
||||
"${strSocketFile} is not of type directory, file, or link");
|
||||
|
||||
# Cleanup socket
|
||||
$oSocket->close();
|
||||
storageTest()->remove($strSocketFile);
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $strTestPath = $self->testPath() . '/public_dir';
|
||||
storageTest()->pathCreate($strTestPath, {strMode => '0750'});
|
||||
|
||||
$self->testResult(
|
||||
sub {$oPosix->manifestStat($strTestPath)},
|
||||
'{group => ' . $self->group() . ', mode => 0750, type => d, user => ' . $self->pgUser() . '}',
|
||||
'stat directory');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $strTestLink = $self->testPath() . '/public_dir_link';
|
||||
|
||||
symlink($strTestPath, $strTestLink)
|
||||
or confess &log(ERROR, "unable to create symlink from ${strTestPath} to ${strTestLink}");
|
||||
|
||||
$self->testResult(
|
||||
sub {$oPosix->manifestStat($strTestLink)},
|
||||
'{group => ' . $self->group() . ", link_destination => ${strTestPath}, type => l, user => " . $self->pgUser() . '}',
|
||||
'stat link');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin("manifestRecurse()"))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $strTestPath = $self->testPath() . '/public_dir';
|
||||
my $strTestFile = "${strTestPath}/test.txt";
|
||||
|
||||
$self->testException(
|
||||
sub {my $hManifest = {}; $oPosix->manifestRecurse($strTestFile, undef, 0, $hManifest); $hManifest},
|
||||
ERROR_FILE_MISSING, "unable to stat '${strTestFile}': No such file or directory");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
storageTest()->pathCreate($strTestPath, {strMode => '0750'});
|
||||
|
||||
$self->testResult(
|
||||
sub {my $hManifest = {}; $oPosix->manifestRecurse($strTestPath, undef, 0, $hManifest); $hManifest},
|
||||
'{. => {group => ' . $self->group() . ', mode => 0750, type => d, user => ' . $self->pgUser() . '}}',
|
||||
'empty directory manifest');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
storageTest()->put($strTestFile, "TEST");
|
||||
utime(1111111111, 1111111111, $strTestFile);
|
||||
executeTest('chmod 0750 ' . $strTestFile);
|
||||
|
||||
storageTest()->pathCreate("${strTestPath}/sub", {strMode => '0750'});
|
||||
|
||||
$self->testResult(
|
||||
sub {my $hManifest = {}; $oPosix->manifestRecurse(
|
||||
$self->testPath(), basename($strTestPath), 1, $hManifest); $hManifest},
|
||||
'{public_dir => {group => ' . $self->group() . ', mode => 0750, type => d, user => ' . $self->pgUser() . '}, ' .
|
||||
'public_dir/sub => {group => ' . $self->group() . ', mode => 0750, type => d, user => ' . $self->pgUser() . '}, ' .
|
||||
'public_dir/' . basename($strTestFile) . ' => {group => ' . $self->group() .
|
||||
', mode => 0750, modification_time => 1111111111, size => 4, type => f, user => ' . $self->pgUser() . '}}',
|
||||
'directory and file manifest');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {my $hManifest = {}; $oPosix->manifestRecurse($strTestFile, undef, 0, $hManifest); $hManifest},
|
||||
'{' . basename($strTestFile) . ' => {group => ' . $self->group() .
|
||||
', mode => 0750, modification_time => 1111111111, size => 4, type => f, user => ' . $self->pgUser() . '}}',
|
||||
'single file manifest');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin("manifest()"))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $strMissingFile = $self->testPath() . '/missing';
|
||||
|
||||
$self->testException(
|
||||
sub {$oPosix->manifest($strMissingFile)},
|
||||
ERROR_FILE_MISSING, "unable to stat '${strMissingFile}': No such file or directory");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
# Setup test data
|
||||
executeTest('mkdir -m 750 ' . $self->testPath() . '/sub1');
|
||||
executeTest('mkdir -m 750 ' . $self->testPath() . '/sub1/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/sub2/test-sub2.txt');
|
||||
utime(1111111113, 1111111113, $self->testPath() . '/sub1/sub2/test-sub2.txt');
|
||||
executeTest('chmod 0646 ' . $self->testPath() . '/sub1/test-sub1.txt');
|
||||
|
||||
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 {$oPosix->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/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 => 1640, modification_time => 1111111111, size => 9, type => f, user => ' .
|
||||
$self->pgUser() . '}, ' .
|
||||
'sub1/sub2/test-sub2.txt => ' .
|
||||
'{group => ' . $self->group() . ', mode => 0666, 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 => 1640, modification_time => 1111111111, size => 9, type => f, user => ' .
|
||||
$self->pgUser() . '}, ' .
|
||||
'sub1/test-sub1.txt => ' .
|
||||
'{group => ' . $self->group() . ', mode => 0646, modification_time => 1111111112, size => 10, type => f, user => ' .
|
||||
$self->pgUser() . '}, ' .
|
||||
'test.txt => ' .
|
||||
'{group => ' . $self->group() . ', mode => 1640, modification_time => 1111111111, size => 9, type => f, user => ' .
|
||||
$self->pgUser() . '}}',
|
||||
'complete manifest');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('openRead() & Posix::FileRead'))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testException(
|
||||
sub {$oPosix->openRead($strFile)}, ERROR_FILE_MISSING, "unable to open '${strFile}': No such file or directory");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
executeTest("echo -n '${strFileContent}' | tee ${strFile}");
|
||||
|
||||
$self->testResult(
|
||||
sub {$oPosix->openRead($strFile)}, '[object]', 'open read');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('openWrite() & Posix::FileWrite'))
|
||||
{
|
||||
my $tContent = $strFileContent;
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
executeTest("echo -n '${strFileContent}' | tee ${strFile}");
|
||||
executeTest("chmod 600 ${strFile} && sudo chown root:root ${strFile}");
|
||||
|
||||
$self->testException(
|
||||
sub {new pgBackRest::Storage::Posix::FileRead($oPosix, $strFile)}, ERROR_FILE_OPEN,
|
||||
"unable to open '${strFile}': Permission denied");
|
||||
|
||||
executeTest("sudo rm -rf ${strFile}");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $oPosixIo = $self->testResult(
|
||||
sub {new pgBackRest::Storage::Posix::FileWrite($oPosix, $strFile)}, '[object]', 'open');
|
||||
|
||||
$tContent = substr($strFileContent, 0, $iFileLengthHalf);
|
||||
$self->testResult(
|
||||
sub {$oPosixIo->write(\$tContent)}, $iFileLengthHalf, 'write part 1');
|
||||
|
||||
$tContent = substr($strFileContent, $iFileLengthHalf);
|
||||
$self->testResult(
|
||||
sub {$oPosixIo->write(\$tContent)}, $iFileLength - $iFileLengthHalf,
|
||||
'write part 2');
|
||||
$oPosixIo->close();
|
||||
|
||||
$tContent = undef;
|
||||
$self->testResult(
|
||||
sub {(new pgBackRest::Storage::Posix::FileRead($oPosix, $strFile))->read(\$tContent, $iFileLength)},
|
||||
$iFileLength, 'check write content length');
|
||||
$self->testResult($tContent, $strFileContent, 'check write content');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oPosixIo = $self->testResult(
|
||||
sub {new pgBackRest::Storage::Posix::FileWrite(
|
||||
$oPosix, "${strFile}.atomic", {bAtomic => true, strMode => '0666', lTimestamp => time(), bSync => false})},
|
||||
'[object]', 'open');
|
||||
|
||||
$self->testResult(sub {$oPosixIo->write(\$tContent, $iFileLength)}, $iFileLength, 'write');
|
||||
$self->testResult(sub {$oPosixIo->close()}, true, 'close');
|
||||
|
||||
$self->testResult(sub {${storageTest()->get("${strFile}.atomic")}}, $strFileContent, 'check content');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oPosixIo = $self->testResult(
|
||||
sub {new pgBackRest::Storage::Posix::FileWrite($oPosix, $strFile)}, '[object]', 'open');
|
||||
|
||||
$self->testResult(sub {$oPosixIo->close()}, true, 'close');
|
||||
|
||||
undef($oPosixIo);
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oPosixIo = $self->testResult(
|
||||
sub {new pgBackRest::Storage::Posix::FileWrite($oPosix, $strFile, {lTimestamp => time()})}, '[object]', 'open');
|
||||
$self->testResult(sub {$oPosixIo->write(\$strFileContent, $iFileLength)}, $iFileLength, 'write');
|
||||
executeTest("rm -f $strFile");
|
||||
|
||||
$self->testException(
|
||||
sub {$oPosixIo->close()}, ERROR_FILE_WRITE, "unable to set time for '${strFile}': No such file or directory");
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('pathCreate()'))
|
||||
{
|
||||
my $strPathParent = $self->testPath() . '/parent';
|
||||
my $strPathSub = "${strPathParent}/sub1/sub2";
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oPosix->pathCreate($strPathParent)}, undef, 'parent path');
|
||||
$self->testResult(
|
||||
sub {$oPosix->pathExists($strPathParent)}, true, ' check path');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testException(
|
||||
sub {$oPosix->pathCreate($strPathParent)}, ERROR_PATH_EXISTS,
|
||||
"unable to create path '${strPathParent}' because it already exists");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {$oPosix->pathCreate($strPathParent, {bIgnoreExists => true})}, undef, 'path already exists');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
executeTest("sudo chown root:root ${strPathParent} && sudo chmod 700 ${strPathParent}");
|
||||
|
||||
$self->testException(
|
||||
sub {$oPosix->pathCreate($strPathSub)}, ERROR_PATH_CREATE,
|
||||
"unable to create path '${strPathSub}': Permission denied");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
executeTest("rmdir ${strPathParent}");
|
||||
|
||||
$self->testException(
|
||||
sub {$oPosix->pathCreate($strPathSub)}, ERROR_PATH_MISSING,
|
||||
"unable to create path '${strPathSub}' because parent does not exist");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {$oPosix->pathCreate($strPathSub, {bCreateParent => true})}, undef, 'path with parents');
|
||||
$self->testResult(
|
||||
sub {$oPosix->pathExists($strPathSub)}, true, ' check path');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('move()'))
|
||||
{
|
||||
my $strFileCopy = "${strFile}.copy";
|
||||
my $strFileSub = $self->testPath() . '/sub/file.txt';
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testException(
|
||||
sub {$oPosix->move($strFile, $strFileCopy)}, ERROR_FILE_MISSING,
|
||||
"unable to move '${strFile}' because it is missing");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {storageTest()->put($strFile, $strFileContent)}, $iFileLength, 'put');
|
||||
$self->testResult(
|
||||
sub {$oPosix->move($strFile, $strFileCopy)}, undef, 'simple move');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testException(
|
||||
sub {$oPosix->move($strFileCopy, $strFileSub)}, ERROR_PATH_MISSING,
|
||||
"unable to move '${strFileCopy}' to missing path '" . dirname($strFileSub) . "'");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
executeTest('sudo mkdir ' . dirname($strFileSub) . ' && sudo chmod 700 ' . dirname($strFileSub));
|
||||
|
||||
$self->testException(
|
||||
sub {$oPosix->move($strFileCopy, $strFileSub)}, ERROR_FILE_MOVE,
|
||||
"unable to move '${strFileCopy}' to '${strFileSub}': Permission denied");
|
||||
|
||||
executeTest('sudo rmdir ' . dirname($strFileSub));
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {$oPosix->move($strFileCopy, $strFileSub, {bCreatePath => true})}, undef, 'create parent path');
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
Reference in New Issue
Block a user