1
0
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:
David Steele
2017-06-09 17:51:41 -04:00
parent 7e982f05f5
commit de7fc37f88
183 changed files with 17880 additions and 14734 deletions

View 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;

View 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;

View 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;

View 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;

View 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;