You've already forked pgbackrest
mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-11-11 01:42:26 +03:00
Add Perl interface to C storage layer.
Maintaining the storage layer/drivers in two languages is burdensome. Since the integration tests require the Perl storage layer/drivers we'll need them even after the core code is migrated to C. Create an interface layer so the Perl code can be removed and new storage drivers/features introduced without adding Perl equivalents. The goal is to move the integration tests to C so this interface will eventually be removed. That being the case, the interface was designed for maximum compatibility to ease the transition. The result looks a bit hacky but we'll improve it as needed until it can be retired.
This commit is contained in:
@@ -1,285 +0,0 @@
|
||||
####################################################################################################################################
|
||||
# Tests for Block Cipher
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Module::Storage::StorageFilterCipherBlockPerlTest;
|
||||
use parent 'pgBackRestTest::Common::RunTest';
|
||||
|
||||
####################################################################################################################################
|
||||
# Perl includes
|
||||
####################################################################################################################################
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
use Fcntl qw(O_RDONLY);
|
||||
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::LibC qw(:random :crypto);
|
||||
use pgBackRest::Storage::Base;
|
||||
use pgBackRest::Storage::Filter::CipherBlock;
|
||||
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 $strFileEncrypt = $self->testPath() . qw{/} . 'file.enc.txt';
|
||||
my $strFileDecrypt = $self->testPath() . qw{/} . 'file.dcr.txt';
|
||||
my $strFileBin = $self->testPath() . qw{/} . 'file.bin';
|
||||
my $strFileBinEncrypt = $self->testPath() . qw{/} . 'file.enc.bin';
|
||||
my $strFileContent = 'TESTDATA';
|
||||
my $iFileLength = length($strFileContent);
|
||||
my $oDriver = new pgBackRest::Storage::Posix::Driver();
|
||||
my $tCipherPass = 'areallybadkey';
|
||||
my $strCipherType = 'aes-256-cbc';
|
||||
my $tContent;
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('new()'))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
# Create an unencrypted file
|
||||
executeTest("echo -n '${strFileContent}' | tee ${strFile}");
|
||||
|
||||
$self->testException(
|
||||
sub {new pgBackRest::Storage::Filter::CipherBlock(
|
||||
$oDriver->openRead($strFile), $strCipherType, $tCipherPass, {strMode => BOGUS})},
|
||||
ERROR_ASSERT, 'unknown cipher mode: ' . BOGUS);
|
||||
|
||||
$self->testException(
|
||||
sub {new pgBackRest::Storage::Filter::CipherBlock(
|
||||
$oDriver->openRead($strFile), BOGUS, $tCipherPass)},
|
||||
ERROR_ASSERT, "invalid cipher name '" . BOGUS . "'");
|
||||
|
||||
$self->testException(
|
||||
sub {new pgBackRest::Storage::Filter::CipherBlock(
|
||||
$oDriver->openWrite($strFile), $strCipherType, $tCipherPass, {strMode => BOGUS})},
|
||||
ERROR_ASSERT, 'unknown cipher mode: ' . BOGUS);
|
||||
|
||||
$self->testException(
|
||||
sub {new pgBackRest::Storage::Filter::CipherBlock(
|
||||
$oDriver->openWrite($strFile), BOGUS, $tCipherPass)},
|
||||
ERROR_ASSERT, "invalid cipher name '" . BOGUS . "'");
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('read() and write()'))
|
||||
{
|
||||
my $tBuffer;
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
# Create an plaintext file
|
||||
executeTest("echo -n '${strFileContent}' | tee ${strFile}");
|
||||
|
||||
# Instantiate the cipher object - default action encrypt
|
||||
my $oEncryptIo = $self->testResult(sub {new pgBackRest::Storage::Filter::CipherBlock($oDriver->openRead($strFile),
|
||||
$strCipherType, $tCipherPass)}, '[object]', 'new encrypt file');
|
||||
|
||||
$self->testResult(sub {$oEncryptIo->read(\$tBuffer, 2)}, 16, ' read 16 bytes (header)');
|
||||
$self->testResult(sub {$oEncryptIo->read(\$tBuffer, 2)}, 16, ' read 16 bytes (data)');
|
||||
$self->testResult(sub {$oEncryptIo->read(\$tBuffer, 2)}, 0, ' read 0 bytes');
|
||||
|
||||
$self->testResult(sub {$tBuffer ne $strFileContent}, true, ' data read is encrypted');
|
||||
|
||||
$self->testResult(sub {$oEncryptIo->close()}, true, ' close');
|
||||
$self->testResult(sub {$oEncryptIo->close()}, false, ' close again');
|
||||
|
||||
# tBuffer is now encrypted - test write decrypts correctly
|
||||
my $oDecryptFileIo = $self->testResult(
|
||||
sub {new pgBackRest::Storage::Filter::CipherBlock($oDriver->openWrite($strFileDecrypt),
|
||||
$strCipherType, $tCipherPass, {strMode => STORAGE_DECRYPT})},
|
||||
'[object]', ' new decrypt file');
|
||||
|
||||
$self->testResult(sub {$oDecryptFileIo->write(\$tBuffer)}, 32, ' write decrypted');
|
||||
$self->testResult(sub {$oDecryptFileIo->close()}, true, ' close');
|
||||
|
||||
$self->testResult(sub {${$self->storageTest()->get($strFileDecrypt)}}, $strFileContent, ' data written is decrypted');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$tBuffer = $strFileContent;
|
||||
my $oEncryptFileIo = $self->testResult(
|
||||
sub {new pgBackRest::Storage::Filter::CipherBlock($oDriver->openWrite($strFileEncrypt),
|
||||
$strCipherType, $tCipherPass)},
|
||||
'[object]', 'new write encrypt');
|
||||
|
||||
$tContent = '';
|
||||
$self->testResult(sub {$oEncryptFileIo->write(\$tContent)}, 0, ' attempt empty buffer write');
|
||||
|
||||
undef($tContent);
|
||||
$self->testException(
|
||||
sub {$oEncryptFileIo->write(\$tContent)}, ERROR_FILE_WRITE,
|
||||
"unable to write to '${strFileEncrypt}': Use of uninitialized value");
|
||||
|
||||
# Encrypted length is not known so use tBuffer then test that tBuffer was encrypted
|
||||
my $iWritten = $self->testResult(sub {$oEncryptFileIo->write(\$tBuffer)}, length($tBuffer), ' write encrypted');
|
||||
$self->testResult(sub {$oEncryptFileIo->close()}, true, ' close');
|
||||
|
||||
$tContent = $self->storageTest()->get($strFileDecrypt);
|
||||
$self->testResult(sub {defined($tContent) && $tContent ne $strFileContent}, true, ' data written is encrypted');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
undef($tBuffer);
|
||||
# Open encrypted file for decrypting
|
||||
$oEncryptFileIo =
|
||||
$self->testResult(
|
||||
sub {new pgBackRest::Storage::Filter::CipherBlock(
|
||||
$oDriver->openRead($strFileEncrypt), $strCipherType, $tCipherPass,
|
||||
{strMode => STORAGE_DECRYPT})},
|
||||
'[object]', 'new read encrypted file, decrypt');
|
||||
|
||||
# Try to read more than the length of the data expected to be output from the decrypt and confirm the decrypted length is
|
||||
# the same as the original decrypted content.
|
||||
$self->testResult(sub {$oEncryptFileIo->read(\$tBuffer, $iFileLength+4)}, $iFileLength, ' read all bytes');
|
||||
|
||||
# Just because length is the same does not mean content is so confirm
|
||||
$self->testResult($tBuffer, $strFileContent, ' data read is decrypted');
|
||||
$self->testResult(sub {$oEncryptFileIo->close()}, true, ' close');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
undef($tContent);
|
||||
undef($tBuffer);
|
||||
my $strFileBinHash = '1c7e00fd09b9dd11fc2966590b3e3274645dd031';
|
||||
|
||||
executeTest('cp ' . $self->dataPath() . "/filecopy.archive2.bin ${strFileBin}");
|
||||
$self->testResult(
|
||||
sub {cryptoHashOne('sha1', ${storageTest()->get($strFileBin)})}, $strFileBinHash, 'bin test - check sha1');
|
||||
|
||||
$tContent = ${storageTest()->get($strFileBin)};
|
||||
|
||||
$oEncryptFileIo = $self->testResult(
|
||||
sub {new pgBackRest::Storage::Filter::CipherBlock(
|
||||
$oDriver->openWrite($strFileBinEncrypt), $strCipherType, $tCipherPass)},
|
||||
'[object]', ' new write encrypt');
|
||||
|
||||
$self->testResult(sub {$oEncryptFileIo->write(\$tContent)}, length($tContent), ' write encrypted');
|
||||
$self->testResult(sub {$oEncryptFileIo->close()}, true, ' close');
|
||||
$self->testResult(
|
||||
sub {cryptoHashOne('sha1', ${storageTest()->get($strFileBinEncrypt)}) ne $strFileBinHash}, true,
|
||||
' check sha1 different');
|
||||
|
||||
my $oEncryptBinFileIo = $self->testResult(
|
||||
sub {new pgBackRest::Storage::Filter::CipherBlock(
|
||||
$oDriver->openRead($strFileBinEncrypt), $strCipherType, $tCipherPass,
|
||||
{strMode => STORAGE_DECRYPT})},
|
||||
'[object]', 'new read encrypted bin file');
|
||||
|
||||
$self->testResult(sub {$oEncryptBinFileIo->read(\$tBuffer, 16777216)}, 16777216, ' read 16777216 bytes');
|
||||
$self->testResult(sub {cryptoHashOne('sha1', $tBuffer)}, $strFileBinHash, ' check sha1 same as original');
|
||||
$self->testResult(sub {$oEncryptBinFileIo->close()}, true, ' close');
|
||||
|
||||
# Try to read the file with the wrong passphrase
|
||||
undef($tBuffer);
|
||||
undef($oEncryptBinFileIo);
|
||||
|
||||
$oEncryptBinFileIo = $self->testResult(
|
||||
sub {new pgBackRest::Storage::Filter::CipherBlock(
|
||||
$oDriver->openRead($strFileBinEncrypt), $strCipherType, BOGUS,
|
||||
{strMode => STORAGE_DECRYPT})},
|
||||
'[object]', 'new read Encrypted bin file with wrong passphrase');
|
||||
|
||||
$self->testResult(sub {$oEncryptBinFileIo->read(\$tBuffer, 16777216)}, 16777216, ' read all bytes');
|
||||
$self->testResult(sub {cryptoHashOne('sha1', $tBuffer) ne $strFileBinHash}, true, ' check sha1 NOT same as original');
|
||||
|
||||
# Test file against openssl to make sure they are compatible
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
undef($tBuffer);
|
||||
|
||||
$self->storageTest()->put($strFile, $strFileContent);
|
||||
|
||||
executeTest(
|
||||
"openssl enc -k ${tCipherPass} -md sha1 -aes-256-cbc -in ${strFile} -out ${strFileEncrypt}");
|
||||
|
||||
$oEncryptFileIo = $self->testResult(
|
||||
sub {new pgBackRest::Storage::Filter::CipherBlock(
|
||||
$oDriver->openRead($strFileEncrypt), $strCipherType, $tCipherPass,
|
||||
{strMode => STORAGE_DECRYPT})},
|
||||
'[object]', 'read file encrypted by openssl');
|
||||
|
||||
$self->testResult(sub {$oEncryptFileIo->read(\$tBuffer, 16)}, 8, ' read 8 bytes');
|
||||
$self->testResult(sub {$oEncryptFileIo->close()}, true, ' close');
|
||||
$self->testResult(sub {$tBuffer}, $strFileContent, ' check content same as original');
|
||||
|
||||
$self->storageTest()->remove($strFile);
|
||||
$self->storageTest()->remove($strFileEncrypt);
|
||||
|
||||
$oEncryptFileIo = $self->testResult(
|
||||
sub {new pgBackRest::Storage::Filter::CipherBlock(
|
||||
$oDriver->openWrite($strFileEncrypt), $strCipherType, $tCipherPass)},
|
||||
'[object]', 'write file to be read by openssl');
|
||||
|
||||
$self->testResult(sub {$oEncryptFileIo->write(\$tBuffer)}, 8, ' write 8 bytes');
|
||||
$self->testResult(sub {$oEncryptFileIo->close()}, true, ' close');
|
||||
|
||||
executeTest(
|
||||
"openssl enc -d -k ${tCipherPass} -md sha1 -aes-256-cbc -in ${strFileEncrypt} -out ${strFile}");
|
||||
|
||||
$self->testResult(sub {${$self->storageTest()->get($strFile)}}, $strFileContent, ' check content same as original');
|
||||
|
||||
# Test empty file against openssl to make sure they are compatible
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$tBuffer = '';
|
||||
|
||||
$self->storageTest()->put($strFile);
|
||||
|
||||
executeTest(
|
||||
"openssl enc -k ${tCipherPass} -md sha1 -aes-256-cbc -in ${strFile} -out ${strFileEncrypt}");
|
||||
|
||||
$oEncryptFileIo = $self->testResult(
|
||||
sub {new pgBackRest::Storage::Filter::CipherBlock(
|
||||
$oDriver->openRead($strFileEncrypt), $strCipherType, $tCipherPass,
|
||||
{strMode => STORAGE_DECRYPT})},
|
||||
'[object]', 'read empty file encrypted by openssl');
|
||||
|
||||
$self->testResult(sub {$oEncryptFileIo->read(\$tBuffer, 16)}, 0, ' read 0 bytes');
|
||||
$self->testResult(sub {$oEncryptFileIo->close()}, true, ' close');
|
||||
$self->testResult(sub {$tBuffer}, '', ' check content same as original');
|
||||
|
||||
$self->storageTest()->remove($strFile);
|
||||
$self->storageTest()->remove($strFileEncrypt);
|
||||
|
||||
$oEncryptFileIo = $self->testResult(
|
||||
sub {new pgBackRest::Storage::Filter::CipherBlock(
|
||||
$oDriver->openWrite($strFileEncrypt), $strCipherType, $tCipherPass)},
|
||||
'[object]', 'write file to be read by openssl');
|
||||
|
||||
$self->testResult(sub {$oEncryptFileIo->write(\$tBuffer)}, 0, ' write 0 bytes');
|
||||
$self->testResult(sub {$oEncryptFileIo->close()}, true, ' close');
|
||||
|
||||
executeTest(
|
||||
"openssl enc -d -k ${tCipherPass} -md sha1 -aes-256-cbc -in ${strFileEncrypt} -out ${strFile}");
|
||||
|
||||
$self->testResult(sub {${$self->storageTest()->get($strFile)}}, undef, ' check content same as original');
|
||||
|
||||
# Error on empty file decrypt - an empty file that has been encrypted will be 32 bytes
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
undef($tBuffer);
|
||||
$self->storageTest()->put($strFileEncrypt);
|
||||
|
||||
$oEncryptFileIo =
|
||||
$self->testResult(
|
||||
sub {new pgBackRest::Storage::Filter::CipherBlock(
|
||||
$oDriver->openRead($strFileEncrypt), $strCipherType, $tCipherPass,
|
||||
{strMode => STORAGE_DECRYPT})},
|
||||
'[object]', 'new read empty attempt decrypt');
|
||||
|
||||
$self->testException(sub {$oEncryptFileIo->read(\$tBuffer, 16)}, ERROR_CRYPTO, 'cipher header missing');
|
||||
$self->testResult(sub {$oEncryptFileIo->close()}, true, 'close');
|
||||
|
||||
# OpenSSL should error on the empty file
|
||||
executeTest(
|
||||
"openssl enc -d -k ${tCipherPass} -md sha1 -aes-256-cbc -in ${strFileEncrypt} -out ${strFile}",
|
||||
{iExpectedExitStatus => 1});
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -1,222 +0,0 @@
|
||||
####################################################################################################################################
|
||||
# Tests for Storage::Filter::Gzip module
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Module::Storage::StorageFilterGzipPerlTest;
|
||||
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 pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::LibC qw(:crypto);
|
||||
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), {lCompressBufferMax => 4})},
|
||||
'[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, iLevel => 3})},
|
||||
'[object]', 'new write compress');
|
||||
$self->testResult($oGzipIo->{iLevel}, 3, ' check level');
|
||||
$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(sub {$oGzipIo->close()}, false, ' close again');
|
||||
$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(cryptoHashOne('sha1', $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 {cryptoHashOne('sha1', ${storageTest()->get($strFile)})}, '1c7e00fd09b9dd11fc2966590b3e3274645dd031',
|
||||
' check content');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$tBuffer = undef;
|
||||
|
||||
my $oFile = $self->testResult(
|
||||
sub {storageTest()->openWrite($strFile)}, '[object]', 'open file to extend during compression');
|
||||
|
||||
$oGzipIo = $self->testResult(
|
||||
sub {new pgBackRest::Storage::Filter::Gzip($oDriver->openRead($strFile), {lCompressBufferMax => 4194304})},
|
||||
'[object]', ' new read compress');
|
||||
|
||||
$self->testResult(sub {$oFile->write(\$strFileContent)}, length($strFileContent), ' write first block');
|
||||
$self->testResult(sub {$oGzipIo->read(\$tBuffer, 2000000) > 0}, true, ' read compressed first block (compression done)');
|
||||
|
||||
$self->testResult(sub {$oFile->write(\$strFileContent)}, length($strFileContent), ' write second block');
|
||||
$self->testResult(sub {$oGzipIo->read(\$tBuffer, 2000000)}, 0, ' read compressed = 0');
|
||||
|
||||
$self->testResult(sub {storageTest()->put($strFileGz, $tBuffer) > 0}, true, ' put content');
|
||||
executeTest("gzip -df ${strFileGz}");
|
||||
$self->testResult(
|
||||
sub {${storageTest()->get($strFile)}}, $strFileContent, ' 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;
|
||||
@@ -1,107 +0,0 @@
|
||||
####################################################################################################################################
|
||||
# Tests for StorageFilterSha module
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Module::Storage::StorageFilterShaPerlTest;
|
||||
use parent 'pgBackRestTest::Common::RunTest';
|
||||
|
||||
####################################################################################################################################
|
||||
# Perl includes
|
||||
####################################################################################################################################
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::LibC qw(:crypto);
|
||||
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)}, cryptoHashOne('sha1', $strFileContent),
|
||||
'check hash against original content');
|
||||
$self->testResult($strSha, cryptoHashOne('sha1', $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(sub {$oShaIo->close()}, false, ' close again to make sure nothing bad happens');
|
||||
$self->testResult($oShaIo->result(STORAGE_FILTER_SHA), '1c7e00fd09b9dd11fc2966590b3e3274645dd031', ' check hash');
|
||||
$self->testResult(cryptoHashOne('sha1', $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)}, cryptoHashOne('sha1', $strFileContent),
|
||||
'check hash against original content');
|
||||
$self->testResult(sub {${storageTest()->get($strFile)}}, $strFileContent, 'check content');
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -61,11 +61,12 @@ sub run
|
||||
#-------------------------------------------------------------------------------------------------------------------------------
|
||||
if ($self->begin("storageLocal()"))
|
||||
{
|
||||
$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("/tmp/${strFile}", $strFileContent)}, $iFileSize, 'put');
|
||||
$self->testResult(sub {${storageTest()->get("/tmp/${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');
|
||||
$self->testResult(
|
||||
sub {storageLocal($self->testPath())->put("/tmp/${strFile}", $strFileContent)}, $iFileSize, 'put cache storage');
|
||||
$self->testResult(sub {${storageTest()->get("/tmp/${strFile}")}}, $strFileContent, ' check put');
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -109,44 +110,6 @@ sub run
|
||||
$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("storageRepo() encryption"))
|
||||
{
|
||||
my $strStanzaEncrypt = 'test-encrypt';
|
||||
$self->optionTestSet(CFGOPT_REPO_CIPHER_TYPE, CFGOPTVAL_REPO_CIPHER_TYPE_AES_256_CBC);
|
||||
$self->testException(
|
||||
sub {$self->configTestLoad(CFGCMD_ARCHIVE_PUSH)}, ERROR_OPTION_REQUIRED,
|
||||
'archive-push command requires option: repo1-cipher-pass');
|
||||
|
||||
# Set the encryption passphrase and confirm passphrase and type have been set in the storage object
|
||||
$self->optionTestSet(CFGOPT_REPO_CIPHER_PASS, 'x');
|
||||
$self->configTestLoad(CFGCMD_ARCHIVE_PUSH);
|
||||
|
||||
$self->testResult(sub {storageRepo({strStanza => $strStanzaEncrypt})->cipherType() eq
|
||||
CFGOPTVAL_REPO_CIPHER_TYPE_AES_256_CBC}, true, 'encryption type set');
|
||||
$self->testResult(sub {storageRepo({strStanza => $strStanzaEncrypt})->cipherPassUser() eq 'x'}, true,
|
||||
'encryption passphrase set');
|
||||
|
||||
# Cannot change encryption after it has been set (cached values not reset)
|
||||
$self->optionTestClear(CFGOPT_REPO_CIPHER_TYPE);
|
||||
$self->optionTestClear(CFGOPT_REPO_CIPHER_PASS);
|
||||
$self->configTestLoad(CFGCMD_ARCHIVE_PUSH);
|
||||
|
||||
$self->testResult(sub {storageRepo({strStanza => $strStanzaEncrypt})->cipherType() eq
|
||||
CFGOPTVAL_REPO_CIPHER_TYPE_AES_256_CBC}, true, 'encryption type not reset');
|
||||
$self->testResult(sub {storageRepo({strStanza => $strStanzaEncrypt})->cipherPassUser() eq 'x'}, true,
|
||||
'encryption passphrase not reset');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,475 +0,0 @@
|
||||
####################################################################################################################################
|
||||
# Tests for Storage::Local module
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Module::Storage::StorageLocalPerlTest;
|
||||
use parent 'pgBackRestTest::Common::RunTest';
|
||||
|
||||
####################################################################################################################################
|
||||
# Perl includes
|
||||
####################################################################################################################################
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
use pgBackRest::Config::Config;
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::LibC qw(:crypto);
|
||||
use pgBackRest::Storage::Filter::Sha;
|
||||
use pgBackRest::Storage::Base;
|
||||
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});
|
||||
|
||||
# Create encrypted storage
|
||||
$self->{oStorageEncrypt} = new pgBackRest::Storage::Local(
|
||||
$self->testPath(), new pgBackRest::Storage::Posix::Driver(),
|
||||
{hRule => $hRule, bAllowTemp => false, strCipherType => CFGOPTVAL_REPO_CIPHER_TYPE_AES_256_CBC});
|
||||
|
||||
# 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)}, $iFileSize, "write $iFileSize bytes");
|
||||
$self->testResult(sub {$oFileIo->close()}, true, 'close');
|
||||
|
||||
# Check that it is not encrypted
|
||||
$self->testResult(sub {$self->storageLocal()->encrypted($strFile)}, false, 'test storage not encrypted');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
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), cryptoHashOne('sha1', $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{(} . cryptoHashOne('sha1', $strFileContent) . ', ' . $iFileSize . qw{)}, ' check hash/size');
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->hashSize(BOGUS, {bIgnoreMissing => true})}, "([undef], [undef])",
|
||||
' check missing hash/size');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('copy()'))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testException(
|
||||
sub {$self->storageLocal()->copy($self->storageLocal()->openRead($strFile), $strFileCopy)}, ERROR_FILE_MISSING,
|
||||
"unable to open '" . $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");
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('encryption'))
|
||||
{
|
||||
my $strCipherPass = 'x';
|
||||
$self->testResult(sub {cryptoHashOne('sha1', $strFileContent)}, $strFileHash, 'hash check contents to be written');
|
||||
|
||||
# Error when passphrase not passed
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $oFileIo = $self->testException(sub {$self->storageEncrypt()->openWrite($strFile)},
|
||||
ERROR_ASSERT, 'tCipherPass is required in Storage::Filter::CipherBlock->new');
|
||||
|
||||
# Write an encrypted file
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oFileIo = $self->testResult(sub {$self->storageEncrypt()->openWrite($strFile, {strCipherPass => $strCipherPass})},
|
||||
'[object]', 'open write');
|
||||
|
||||
my $iWritten = $oFileIo->write(\$strFileContent);
|
||||
$self->testResult(sub {$oFileIo->close()}, true, ' close');
|
||||
|
||||
# Check that it is encrypted and valid for the repo encryption type
|
||||
$self->testResult(sub {$self->storageEncrypt()->encryptionValid($self->storageEncrypt()->encrypted($strFile))}, true,
|
||||
' test storage encrypted and valid');
|
||||
|
||||
$self->testResult(
|
||||
sub {cryptoHashOne('sha1', ${storageTest()->get($strFile)}) ne $strFileHash}, true, ' check written sha1 different');
|
||||
|
||||
# Error when passphrase not passed
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oFileIo = $self->testException(sub {$self->storageEncrypt()->openRead($strFile)},
|
||||
ERROR_ASSERT, 'tCipherPass is required in Storage::Filter::CipherBlock->new');
|
||||
|
||||
# Read it and confirm it decrypts and is same as original content
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oFileIo = $self->testResult(sub {$self->storageEncrypt()->openRead($strFile, {strCipherPass => $strCipherPass})},
|
||||
'[object]', 'open read and decrypt');
|
||||
my $strContent;
|
||||
$oFileIo->read(\$strContent, $iWritten);
|
||||
$self->testResult(sub {$oFileIo->close()}, true, ' close');
|
||||
$self->testResult($strContent, $strFileContent, ' decrypt read equal orginal contents');
|
||||
|
||||
# Copy
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {$self->storageEncrypt()->copy(
|
||||
$self->storageEncrypt()->openRead($strFile, {strCipherPass => $strCipherPass}),
|
||||
$self->storageEncrypt()->openWrite($strFileCopy, {strCipherPass => $strCipherPass}))},
|
||||
true, 'copy - decrypt/encrypt');
|
||||
|
||||
$self->testResult(
|
||||
sub {cryptoHashOne('sha1', ${$self->storageEncrypt()->get($strFileCopy, {strCipherPass => $strCipherPass})})},
|
||||
$strFileHash, ' check decrypted copy file sha1 same as original plaintext file');
|
||||
|
||||
# Write an empty encrypted file
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $strFileZero = 'file-0.txt';
|
||||
my $strZeroContent = '';
|
||||
$oFileIo = $self->testResult(
|
||||
sub {$self->storageEncrypt()->openWrite($strFileZero, {strCipherPass => $strCipherPass})}, '[object]',
|
||||
'open write for zero');
|
||||
|
||||
$self->testResult(sub {$oFileIo->write(\$strZeroContent)}, 0, ' zero written');
|
||||
$self->testResult(sub {$oFileIo->close()}, true, ' close');
|
||||
|
||||
$self->testResult(sub {$self->storageEncrypt()->encrypted($strFile)}, true, ' test empty file encrypted');
|
||||
|
||||
# Write an unencrypted file to the encrypted storage and check if the file is valid for that storage
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $strFileTest = $self->testPath() . qw{/} . 'test.file.txt';
|
||||
|
||||
# Create empty file
|
||||
executeTest("touch ${strFileTest}");
|
||||
$self->testResult(sub {$self->storageEncrypt()->encrypted($strFileTest)}, false, 'empty file so not encrypted');
|
||||
|
||||
# Add unencrypted content to the file
|
||||
executeTest("echo -n '${strFileContent}' | tee ${strFileTest}");
|
||||
$self->testResult(sub {$self->storageEncrypt()->encryptionValid($self->storageEncrypt()->encrypted($strFileTest))}, false,
|
||||
'storage encryption and unencrypted file format do not match');
|
||||
|
||||
# Unencrypted file valid in unencrypted storage
|
||||
$self->testResult(sub {$self->storageLocal()->encryptionValid($self->storageLocal()->encrypted($strFileTest))}, true,
|
||||
'unencrypted file valid in unencrypted storage');
|
||||
|
||||
# Prepend encryption Magic Signature and test encrypted file in unencrypted storage not valid
|
||||
executeTest('echo "' . CIPHER_MAGIC . '$(cat ' . $strFileTest . ')" > ' . $strFileTest);
|
||||
$self->testResult(sub {$self->storageLocal()->encryptionValid($self->storageLocal()->encrypted($strFileTest))}, false,
|
||||
'storage unencrypted and encrypted file format do not match');
|
||||
|
||||
# Test a file that does not exist
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$strFileTest = $self->testPath() . qw{/} . 'testfile';
|
||||
$self->testException(sub {$self->storageEncrypt()->encrypted($strFileTest)}, ERROR_FILE_MISSING,
|
||||
"unable to open '" . $strFileTest . "': No such file or directory");
|
||||
|
||||
$self->testResult(sub {$self->storageEncrypt()->encrypted($strFileTest, {bIgnoreMissing => true})}, true,
|
||||
'encryption for ignore missing file returns encrypted for encrypted storage');
|
||||
|
||||
$self->testResult(sub {$self->storageLocal()->encrypted($strFileTest, {bIgnoreMissing => true})}, false,
|
||||
'encryption for ignore missing file returns unencrypted for unencrypted storage');
|
||||
}
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# 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 storageEncrypt {return shift->{oStorageEncrypt}};
|
||||
sub storageRemote {return shift->{oStorageRemote}};
|
||||
|
||||
1;
|
||||
341
test/lib/pgBackRestTest/Module/Storage/StoragePerlTest.pm
Normal file
341
test/lib/pgBackRestTest/Module/Storage/StoragePerlTest.pm
Normal file
@@ -0,0 +1,341 @@
|
||||
####################################################################################################################################
|
||||
# Tests for Storage::Local module
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Module::Storage::StoragePerlTest;
|
||||
use parent 'pgBackRestTest::Common::RunTest';
|
||||
|
||||
####################################################################################################################################
|
||||
# Perl includes
|
||||
####################################################################################################################################
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
use pgBackRest::Config::Config;
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::LibC qw(:crypto);
|
||||
use pgBackRest::Storage::Base;
|
||||
|
||||
use pgBackRestTest::Common::ContainerTest;
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
use pgBackRestTest::Env::Host::HostBackupTest;
|
||||
|
||||
####################################################################################################################################
|
||||
# run
|
||||
####################################################################################################################################
|
||||
sub run
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Define test file
|
||||
my $strFile = $self->testPath() . '/file.txt';
|
||||
my $strFileCopy = $self->testPath() . '/file.txt.copy';
|
||||
my $strFileHash = 'bbbcf2c59433f68f22376cd2439d6cd309378df6';
|
||||
my $strFileContent = 'TESTDATA';
|
||||
my $iFileSize = length($strFileContent);
|
||||
|
||||
# Create local storage
|
||||
$self->{oStorageLocal} = new pgBackRest::Storage::Storage('<LOCAL>');
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin("pathGet()"))
|
||||
{
|
||||
$self->testResult(sub {$self->storageLocal()->pathGet('file')}, '/file', 'relative path');
|
||||
$self->testResult(sub {$self->storageLocal()->pathGet('/file2')}, '/file2', 'absolute path');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('put()'))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->put($self->storageLocal()->openWrite($strFile))}, 0, 'put empty');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->put($strFile)}, 0, 'put empty (all defaults)');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->put($self->storageLocal()->openWrite($strFile), $strFileContent)}, $iFileSize, 'put');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->put($self->storageLocal()->openWrite($strFile), \$strFileContent)}, $iFileSize,
|
||||
'put reference');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('get()'))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->get($self->storageLocal()->openRead($strFile, {bIgnoreMissing => true}))}, undef,
|
||||
'get missing');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->storageLocal()->put($strFile);
|
||||
$self->testResult(sub {${$self->storageLocal()->get($strFile)}}, undef, 'get empty');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->storageLocal()->put($strFile, $strFileContent);
|
||||
$self->testResult(sub {${$self->storageLocal()->get($strFile)}}, $strFileContent, 'get');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {${$self->storageLocal()->get($self->storageLocal()->openRead($strFile))}}, $strFileContent, 'get from io');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('hashSize()'))
|
||||
{
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->put($strFile, $strFileContent)}, 8, 'put');
|
||||
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->hashSize($strFile)},
|
||||
qw{(} . cryptoHashOne('sha1', $strFileContent) . ', ' . $iFileSize . qw{)}, ' check hash/size');
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->hashSize(BOGUS, {bIgnoreMissing => true})}, "([undef], [undef])",
|
||||
' check missing hash/size');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('copy()'))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testException(
|
||||
sub {$self->storageLocal()->copy($self->storageLocal()->openRead($strFile), $strFileCopy)}, ERROR_FILE_MISSING,
|
||||
"unable to open missing file '${strFile}' for read");
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->exists($strFileCopy)}, false, ' destination does not exist');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->copy(
|
||||
$self->storageLocal()->openRead($strFile, {bIgnoreMissing => true}),
|
||||
$self->storageLocal()->openWrite($strFileCopy))},
|
||||
false, 'missing source io');
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->exists($strFileCopy)}, false, ' destination does not exist');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testException(
|
||||
sub {$self->storageLocal()->copy($self->storageLocal()->openRead($strFile), $strFileCopy)}, ERROR_FILE_MISSING,
|
||||
"unable to open missing file '${strFile}' for read");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->storageLocal()->put($strFile, $strFileContent);
|
||||
|
||||
$self->testResult(sub {$self->storageLocal()->copy($strFile, $strFileCopy)}, true, 'copy filename->filename');
|
||||
$self->testResult(sub {${$self->storageLocal()->get($strFileCopy)}}, $strFileContent, ' check copy');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->storageLocal()->remove($strFileCopy);
|
||||
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->copy($self->storageLocal()->openRead($strFile), $strFileCopy)}, true, 'copy io->filename');
|
||||
$self->testResult(sub {${$self->storageLocal()->get($strFileCopy)}}, $strFileContent, ' check copy');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->storageLocal()->remove($strFileCopy);
|
||||
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->copy(
|
||||
$self->storageLocal()->openRead($strFile), $self->storageLocal()->openWrite($strFileCopy))},
|
||||
true, 'copy io->io');
|
||||
$self->testResult(sub {${$self->storageLocal()->get($strFileCopy)}}, $strFileContent, ' check copy');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('exists()'))
|
||||
{
|
||||
$self->storageLocal()->put($self->testPath() . "/test.file");
|
||||
|
||||
$self->testResult(sub {$self->storageLocal()->exists($self->testPath() . "/test.file")}, true, 'existing file');
|
||||
$self->testResult(sub {$self->storageLocal()->exists($self->testPath() . "/test.missing")}, false, 'missing file');
|
||||
$self->testResult(sub {$self->storageLocal()->exists($self->testPath())}, false, 'path');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('info()'))
|
||||
{
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->info($self->testPath())},
|
||||
"{group => " . $self->group() . ", mode => 0770, type => d, user => " . $self->pgUser() . "}",
|
||||
'stat dir successfully');
|
||||
|
||||
$self->testException(sub {$self->storageLocal()->info(BOGUS)}, ERROR_FILE_OPEN,
|
||||
"unable to get info for missing path/file '/bogus'");
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin("manifest() and list()"))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testException(
|
||||
sub {$self->storageLocal()->manifest($self->testPath() . '/missing')},
|
||||
ERROR_PATH_MISSING, "unable to list file info for missing path '" . $self->testPath() . "/missing'");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
# Setup test data
|
||||
executeTest('mkdir -m 750 ' . $self->testPath() . '/sub1');
|
||||
executeTest('mkdir -m 750 ' . $self->testPath() . '/sub1/sub2');
|
||||
executeTest('mkdir -m 750 ' . $self->testPath() . '/sub2');
|
||||
|
||||
executeTest("echo 'TESTDATA' > " . $self->testPath() . '/test.txt');
|
||||
utime(1111111111, 1111111111, $self->testPath() . '/test.txt');
|
||||
executeTest('chmod 1640 ' . $self->testPath() . '/test.txt');
|
||||
|
||||
executeTest("echo 'TESTDATA_' > ". $self->testPath() . '/sub1/test-sub1.txt');
|
||||
utime(1111111112, 1111111112, $self->testPath() . '/sub1/test-sub1.txt');
|
||||
executeTest('chmod 0640 ' . $self->testPath() . '/sub1/test-sub1.txt');
|
||||
|
||||
executeTest("echo 'TESTDATA__' > " . $self->testPath() . '/sub1/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 {$self->storageLocal()->manifest($self->testPath())},
|
||||
'{. => {group => ' . $self->group() . ', mode => 0770, type => d, user => ' . $self->pgUser() . '}, ' .
|
||||
'sub1 => {group => ' . $self->group() . ', mode => 0750, type => d, user => ' . $self->pgUser() . '}, ' .
|
||||
'sub1/sub2 => {group => ' . $self->group() . ', mode => 0750, type => d, user => ' . $self->pgUser() . '}, ' .
|
||||
'sub1/sub2/test => {group => ' . $self->group() . ', link_destination => ../.., type => l, user => ' .
|
||||
$self->pgUser() . '}, ' .
|
||||
'sub1/sub2/test-hardlink.txt => ' .
|
||||
'{group => ' . $self->group() . ', mode => 0640, modification_time => 1111111111, size => 9, type => f, user => ' .
|
||||
$self->pgUser() . '}, ' .
|
||||
'sub1/sub2/test-sub2.txt => ' .
|
||||
'{group => ' . $self->group() . ', mode => 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 => 0640, 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() . '}, ' .
|
||||
'sub2 => {group => ' . $self->group() . ', mode => 0750, type => d, user => ' . $self->pgUser() . '}, ' .
|
||||
'test.txt => ' .
|
||||
'{group => ' . $self->group() . ', mode => 0640, modification_time => 1111111111, size => 9, type => f, user => ' .
|
||||
$self->pgUser() . '}}',
|
||||
'complete manifest');
|
||||
|
||||
$self->testResult(sub {$self->storageLocal()->list($self->testPath())}, "(sub1, sub2, test.txt)", "list");
|
||||
$self->testResult(sub {$self->storageLocal()->list($self->testPath(), {strExpression => "2\$"})}, "sub2", "list");
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->list($self->testPath(), {strSortOrder => 'reverse'})}, "(test.txt, sub2, sub1)",
|
||||
"list reverse");
|
||||
$self->testResult(sub {$self->storageLocal()->list($self->testPath() . "/sub2")}, "[undef]", "list empty");
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->list($self->testPath() . "/sub99", {bIgnoreMissing => true})}, "[undef]", "list missing");
|
||||
$self->testException(
|
||||
sub {$self->storageLocal()->list($self->testPath() . "/sub99")}, ERROR_PATH_MISSING,
|
||||
"unable to list files for missing path '" . $self->testPath() . "/sub99'");
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('move()'))
|
||||
{
|
||||
my $strFileCopy = "${strFile}.copy";
|
||||
my $strFileSub = $self->testPath() . '/sub/file.txt';
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testException(
|
||||
sub {$self->storageLocal()->move($strFile, $strFileCopy)}, ERROR_FILE_MOVE,
|
||||
"unable to move '${strFile}' to '${strFile}.copy': No such file or directory");
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('owner()'))
|
||||
{
|
||||
my $strFile = $self->testPath() . "/test.txt";
|
||||
|
||||
$self->testException(
|
||||
sub {$self->storageLocal()->owner($strFile, 'root')}, ERROR_FILE_MISSING,
|
||||
"unable to stat '${strFile}': No such file or directory");
|
||||
|
||||
executeTest("touch ${strFile}");
|
||||
|
||||
$self->testException(
|
||||
sub {$self->storageLocal()->owner($strFile, BOGUS)}, ERROR_FILE_OWNER,
|
||||
"unable to set ownership for '${strFile}' because user 'bogus' does not exist");
|
||||
$self->testException(
|
||||
sub {$self->storageLocal()->owner($strFile, undef, BOGUS)}, ERROR_FILE_OWNER,
|
||||
"unable to set ownership for '${strFile}' because group 'bogus' does not exist");
|
||||
|
||||
$self->testResult(sub {$self->storageLocal()->owner($strFile)}, undef, "no ownership changes");
|
||||
$self->testResult(sub {$self->storageLocal()->owner($strFile, TEST_USER)}, undef, "same user");
|
||||
$self->testResult(sub {$self->storageLocal()->owner($strFile, undef, TEST_GROUP)}, undef, "same group");
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->owner($strFile, TEST_USER, TEST_GROUP)}, undef,
|
||||
"same user, group");
|
||||
|
||||
$self->testException(
|
||||
sub {$self->storageLocal()->owner($strFile, 'root', undef)}, ERROR_FILE_OWNER,
|
||||
"unable to set ownership for '${strFile}': Operation not permitted");
|
||||
$self->testException(
|
||||
sub {$self->storageLocal()->owner($strFile, undef, 'root')}, ERROR_FILE_OWNER,
|
||||
"unable to set ownership for '${strFile}': Operation not permitted");
|
||||
|
||||
executeTest("sudo chown :root ${strFile}");
|
||||
$self->testResult(
|
||||
sub {$self->storageLocal()->owner($strFile, undef, TEST_GROUP)}, undef, "change group back from root");
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('pathCreate()'))
|
||||
{
|
||||
my $strTestPath = $self->testPath() . "/" . BOGUS;
|
||||
|
||||
$self->testResult(sub {$self->storageLocal()->pathCreate($strTestPath)}, "[undef]",
|
||||
"test creation of path " . $strTestPath);
|
||||
|
||||
$self->testException(sub {$self->storageLocal()->pathCreate($strTestPath)}, ERROR_PATH_CREATE,
|
||||
"unable to create path '". $strTestPath. "'");
|
||||
|
||||
$self->testResult(sub {$self->storageLocal()->pathCreate($strTestPath, {bIgnoreExists => true})}, "[undef]",
|
||||
"ignore path exists");
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('pathExists()'))
|
||||
{
|
||||
$self->storageLocal()->put($self->testPath() . "/test.file");
|
||||
|
||||
$self->testResult(sub {$self->storageLocal()->pathExists($self->testPath() . "/test.file")}, false, 'existing file');
|
||||
$self->testResult(sub {$self->storageLocal()->pathExists($self->testPath() . "/test.missing")}, false, 'missing file');
|
||||
$self->testResult(sub {$self->storageLocal()->pathExists($self->testPath())}, true, 'path');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('pathSync()'))
|
||||
{
|
||||
$self->testResult(sub {$self->storageLocal()->pathSync($self->testPath())}, "[undef]", "test path sync");
|
||||
}
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Getters
|
||||
####################################################################################################################################
|
||||
# sub host {return '127.0.0.1'}
|
||||
# sub pathLocal {return shift->{strPathLocal}};
|
||||
# sub pathRemote {return shift->{strPathRemote}};
|
||||
sub storageLocal {return shift->{oStorageLocal}};
|
||||
# sub storageEncrypt {return shift->{oStorageEncrypt}};
|
||||
# sub storageRemote {return shift->{oStorageRemote}};
|
||||
|
||||
1;
|
||||
@@ -1,444 +0,0 @@
|
||||
####################################################################################################################################
|
||||
# Posix Driver Tests
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Module::Storage::StoragePosixPerlTest;
|
||||
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::ContainerTest;
|
||||
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 = undef;
|
||||
$self->testException(
|
||||
sub {$oPosixIo->write(\$tContent)}, ERROR_FILE_WRITE, "unable to write to '${strFile}': Use of uninitialized value");
|
||||
|
||||
$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);
|
||||
|
||||
# Test that a premature destroy (from error or otherwise) does not rename the file
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $strFileAbort = $self->testPath() . '/file-abort.txt';
|
||||
my $strFileAbortTmp = "${strFileAbort}.tmp";
|
||||
|
||||
$oPosixIo = $self->testResult(
|
||||
sub {new pgBackRest::Storage::Posix::FileWrite($oPosix, $strFileAbort, {bAtomic => true})}, '[object]', 'open');
|
||||
|
||||
$oPosixIo->write(\$strFileContent);
|
||||
undef($oPosixIo);
|
||||
|
||||
$self->testResult(sub {$oPosix->exists($strFileAbort)}, false, 'destination file does not exist');
|
||||
$self->testResult(sub {$oPosix->exists($strFileAbortTmp)}, true, 'destination file tmp exists');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$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('owner()'))
|
||||
{
|
||||
my $strFile = $self->testPath() . "/test.txt";
|
||||
|
||||
$self->testException(
|
||||
sub {$oPosix->owner($strFile, {strUser => 'root'})}, ERROR_FILE_MISSING,
|
||||
"unable to stat '${strFile}': No such file or directory");
|
||||
|
||||
executeTest("touch ${strFile}");
|
||||
|
||||
$self->testException(
|
||||
sub {$oPosix->owner($strFile, {strUser => BOGUS})}, ERROR_FILE_OWNER,
|
||||
"unable to set ownership for '${strFile}' because user 'bogus' does not exist");
|
||||
$self->testException(
|
||||
sub {$oPosix->owner($strFile, {strGroup => BOGUS})}, ERROR_FILE_OWNER,
|
||||
"unable to set ownership for '${strFile}' because group 'bogus' does not exist");
|
||||
|
||||
$self->testResult(sub {$oPosix->owner($strFile)}, undef, "no ownership changes");
|
||||
$self->testResult(sub {$oPosix->owner($strFile, {strUser => TEST_USER})}, undef, "same user");
|
||||
$self->testResult(sub {$oPosix->owner($strFile, {strGroup => TEST_GROUP})}, undef, "same group");
|
||||
$self->testResult(
|
||||
sub {$oPosix->owner($strFile, {strUser => TEST_USER, strGroup => TEST_GROUP})}, undef, "same user, group");
|
||||
|
||||
$self->testException(
|
||||
sub {$oPosix->owner($strFile, {strUser => 'root'})}, ERROR_FILE_OWNER,
|
||||
"unable to set ownership for '${strFile}': Operation not permitted");
|
||||
$self->testException(
|
||||
sub {$oPosix->owner($strFile, {strGroup => 'root'})}, ERROR_FILE_OWNER,
|
||||
"unable to set ownership for '${strFile}': Operation not permitted");
|
||||
|
||||
executeTest("sudo chown :root ${strFile}");
|
||||
$self->testResult(
|
||||
sub {$oPosix->owner($strFile, {strGroup => TEST_GROUP})}, undef, "change group back from root");
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
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;
|
||||
@@ -1,167 +0,0 @@
|
||||
####################################################################################################################################
|
||||
# S3 Authentication Tests
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Module::Storage::StorageS3AuthPerlTest;
|
||||
use parent 'pgBackRestTest::Common::RunTest';
|
||||
|
||||
####################################################################################################################################
|
||||
# Perl includes
|
||||
####################################################################################################################################
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
use POSIX qw(strftime);
|
||||
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::Wait;
|
||||
use pgBackRest::Storage::S3::Auth;
|
||||
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
|
||||
####################################################################################################################################
|
||||
# run
|
||||
####################################################################################################################################
|
||||
sub run
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('s3DateTime'))
|
||||
{
|
||||
$self->testResult(sub {s3DateTime(1491267845)}, '20170404T010405Z', 'format date/time');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
waitRemainder();
|
||||
$self->testResult(sub {s3DateTime()}, strftime("%Y%m%dT%H%M%SZ", gmtime()), 'format current date/time');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('s3CanonicalRequest'))
|
||||
{
|
||||
$self->testResult(
|
||||
sub {s3CanonicalRequest(
|
||||
'GET', qw(/), 'list-type=2',
|
||||
{'host' => 'bucket.s3.amazonaws.com', 'x-amz-date' => '20170606T121212Z',
|
||||
'x-amz-content-sha256' => '705636ecdedffc09f140497bcac3be1e8d069008ecc6a8029e104d6291b4e4e9'},
|
||||
'705636ecdedffc09f140497bcac3be1e8d069008ecc6a8029e104d6291b4e4e9')},
|
||||
"(GET\n/\nlist-type=2\nhost:bucket.s3.amazonaws.com\n" .
|
||||
"x-amz-content-sha256:705636ecdedffc09f140497bcac3be1e8d069008ecc6a8029e104d6291b4e4e9\n" .
|
||||
"x-amz-date:20170606T121212Z\n\nhost;x-amz-content-sha256;x-amz-date\n" .
|
||||
'705636ecdedffc09f140497bcac3be1e8d069008ecc6a8029e104d6291b4e4e9' .
|
||||
', host;x-amz-content-sha256;x-amz-date)',
|
||||
'canonical request');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testException(
|
||||
sub {s3CanonicalRequest(
|
||||
'GET', qw(/), 'list-type=2', {'Host' => 'bucket.s3.amazonaws.com'},
|
||||
'705636ecdedffc09f140497bcac3be1e8d069008ecc6a8029e104d6291b4e4e9')},
|
||||
ERROR_ASSERT, "header 'Host' must be lower case");
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('s3SigningKey'))
|
||||
{
|
||||
$self->testResult(
|
||||
sub {unpack('H*', s3SigningKey('20170412', 'us-east-1', 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY'))},
|
||||
'705636ecdedffc09f140497bcac3be1e8d069008ecc6a8029e104d6291b4e4e9', 'signing key');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {unpack('H*', s3SigningKey('20170412', 'us-east-1', 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY'))},
|
||||
'705636ecdedffc09f140497bcac3be1e8d069008ecc6a8029e104d6291b4e4e9', 'same signing key from cache');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {unpack('H*', s3SigningKey('20170505', 'us-west-1', 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY'))},
|
||||
'c1a1cb590bbc38ba789c8e5695a1ec0cd7fd44c6949f922e149005a221524c09', 'new signing key');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('s3StringToSign'))
|
||||
{
|
||||
$self->testResult(
|
||||
sub {s3StringToSign(
|
||||
'20170412T141414Z', 'us-east-1', '705636ecdedffc09f140497bcac3be1e8d069008ecc6a8029e104d6291b4e4e9')},
|
||||
"AWS4-HMAC-SHA256\n20170412T141414Z\n20170412/us-east-1/s3/aws4_request\n" .
|
||||
"705636ecdedffc09f140497bcac3be1e8d069008ecc6a8029e104d6291b4e4e9",
|
||||
'string to sign');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('s3AuthorizationHeader'))
|
||||
{
|
||||
$self->testResult(
|
||||
sub {s3AuthorizationHeader(
|
||||
'us-east-1', 'bucket.s3.amazonaws.com', 'GET', qw(/), 'list-type=2', '20170606T121212Z',
|
||||
{'authorization' => BOGUS, 'host' => 'bucket.s3.amazonaws.com', 'x-amz-date' => '20170606T121212Z'},
|
||||
'AKIAIOSFODNN7EXAMPLE', 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY', undef,
|
||||
'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855')},
|
||||
'({authorization => AWS4-HMAC-SHA256 Credential=AKIAIOSFODNN7EXAMPLE/20170606/us-east-1/s3/aws4_request,' .
|
||||
'SignedHeaders=host;x-amz-content-sha256;x-amz-date,' .
|
||||
'Signature=cb03bf1d575c1f8904dabf0e573990375340ab293ef7ad18d049fc1338fd89b3,' .
|
||||
' host => bucket.s3.amazonaws.com,' .
|
||||
' x-amz-content-sha256 => e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855,' .
|
||||
' x-amz-date => 20170606T121212Z}, ' .
|
||||
"GET\n" .
|
||||
"/\n" .
|
||||
"list-type=2\n" .
|
||||
"host:bucket.s3.amazonaws.com\n" .
|
||||
"x-amz-content-sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\n" .
|
||||
"x-amz-date:20170606T121212Z\n" .
|
||||
"\n" .
|
||||
"host;x-amz-content-sha256;x-amz-date\n" .
|
||||
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855, " .
|
||||
"host;x-amz-content-sha256;x-amz-date, " .
|
||||
"AWS4-HMAC-SHA256\n" .
|
||||
"20170606T121212Z\n" .
|
||||
"20170606/us-east-1/s3/aws4_request\n" .
|
||||
"4f2d4ee971f579e60ba6b3895e87434e17b1260f04392f02b512c1e8bada72dd)",
|
||||
'authorization header request');
|
||||
|
||||
$self->testResult(
|
||||
sub {s3AuthorizationHeader(
|
||||
'us-east-1', 'bucket.s3.amazonaws.com', 'GET', qw(/), 'list-type=2', '20170606T121212Z',
|
||||
{'authorization' => BOGUS, 'host' => 'bucket.s3.amazonaws.com', 'x-amz-date' => '20170606T121212Z'},
|
||||
'AKIAIOSFODNN7EXAMPLE', 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
|
||||
'AQoDYXdzEPT//////////wEXAMPLEtc764bNrC9SAPBSM22wDOk4x4HIZ8j4FZTwdQW' .
|
||||
'LWsKWHGBuFqwAeMicRXmxfpSPfIeoIYRqTflfKD8YUuwthAx7mSEI/qkPpKPi/kMcGd' .
|
||||
'QrmGdeehM4IC1NtBmUpp2wUE8phUZampKsburEDy0KPkyQDYwT7WZ0wq5VSXDvp75YU' .
|
||||
'9HFvlRd8Tx6q6fE8YQcHNVXAkiY9q6d+xo0rKwT38xVqr7ZD0u0iPPkUL64lIZbqBAz' .
|
||||
'+scqKmlzm8FDrypNC9Yjc8fPOLn9FX9KSYvKTr4rvx3iSIlTJabIQwj2ICCR/oLxBA==',
|
||||
'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855')},
|
||||
'({authorization => AWS4-HMAC-SHA256 Credential=AKIAIOSFODNN7EXAMPLE/20170606/us-east-1/s3/aws4_request,' .
|
||||
'SignedHeaders=host;x-amz-content-sha256;x-amz-date;x-amz-security-token,' .
|
||||
'Signature=c12565bf5d7e0ef623f76d66e09e5431aebef803f6a25a01c586525f17e474a3,' .
|
||||
' host => bucket.s3.amazonaws.com,' .
|
||||
' x-amz-content-sha256 => e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855,' .
|
||||
' x-amz-date => 20170606T121212Z, x-amz-security-token => AQoDYXdzEPT//////////wEXAMPLEtc764bNrC9SAPBSM22wDOk4x4H' .
|
||||
'IZ8j4FZTwdQWLWsKWHGBuFqwAeMicRXmxfpSPfIeoIYRqTflfKD8YUuwthAx7mSEI/qkPpKPi/kMcGdQrmGdeehM4IC1NtBmUpp2wUE8phUZ' .
|
||||
'ampKsburEDy0KPkyQDYwT7WZ0wq5VSXDvp75YU9HFvlRd8Tx6q6fE8YQcHNVXAkiY9q6d+xo0rKwT38xVqr7ZD0u0iPPkUL64lIZbqBAz+sc' .
|
||||
'qKmlzm8FDrypNC9Yjc8fPOLn9FX9KSYvKTr4rvx3iSIlTJabIQwj2ICCR/oLxBA==}, ' .
|
||||
"GET\n" .
|
||||
"/\n" .
|
||||
"list-type=2\n" .
|
||||
"host:bucket.s3.amazonaws.com\n" .
|
||||
"x-amz-content-sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\n" .
|
||||
"x-amz-date:20170606T121212Z\n" .
|
||||
"x-amz-security-token:AQoDYXdzEPT//////////wEXAMPLEtc764bNrC9SAPBSM22wDOk4x4HIZ8j4FZTwdQWLWsKWHGBuFqwAeMicRXmxfpSPfIe" .
|
||||
"oIYRqTflfKD8YUuwthAx7mSEI/qkPpKPi/kMcGdQrmGdeehM4IC1NtBmUpp2wUE8phUZampKsburEDy0KPkyQDYwT7WZ0wq5VSXDvp75YU9HFvlR" .
|
||||
"d8Tx6q6fE8YQcHNVXAkiY9q6d+xo0rKwT38xVqr7ZD0u0iPPkUL64lIZbqBAz+scqKmlzm8FDrypNC9Yjc8fPOLn9FX9KSYvKTr4rvx3iSIlTJab" .
|
||||
"IQwj2ICCR/oLxBA==\n" .
|
||||
"\n" .
|
||||
"host;x-amz-content-sha256;x-amz-date;x-amz-security-token\n" .
|
||||
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855, " .
|
||||
"host;x-amz-content-sha256;x-amz-date;x-amz-security-token, " .
|
||||
"AWS4-HMAC-SHA256\n" .
|
||||
"20170606T121212Z\n" .
|
||||
"20170606/us-east-1/s3/aws4_request\n" .
|
||||
"c171e7a68355ef4e0e6e1003d2d4a79a7b06e7424e3000ba619f5f7882a3251e)",
|
||||
'authorization header request with token');
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -1,113 +0,0 @@
|
||||
####################################################################################################################################
|
||||
# S3 SSL Certificate Tests
|
||||
#
|
||||
# Verify that SSL certificate validation works on live S3 servers.
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Module::Storage::StorageS3CertPerlTest;
|
||||
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::Common::Exception;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::Wait;
|
||||
use pgBackRest::Config::Config;
|
||||
use pgBackRest::Protocol::Storage::Helper;
|
||||
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
use pgBackRestTest::Common::VmTest;
|
||||
|
||||
####################################################################################################################################
|
||||
# run
|
||||
####################################################################################################################################
|
||||
sub run
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Use long random string so bucket lookups will fail and expose access errors
|
||||
my $strBucket = 'bnBfyKpXR8ZqQY5RXszxemRgvtmjXd4tf5HkFYhTpT9BndUCYMDy5NCCyRz';
|
||||
my $strEndpoint = 's3-us-west-2.amazonaws.com';
|
||||
my $strRegion = 'us-west-2';
|
||||
|
||||
# Options
|
||||
$self->optionTestSet(CFGOPT_REPO_TYPE, CFGOPTVAL_REPO_TYPE_S3);
|
||||
$self->optionTestSet(CFGOPT_REPO_S3_KEY, BOGUS);
|
||||
$self->optionTestSet(CFGOPT_REPO_S3_KEY_SECRET, BOGUS);
|
||||
$self->optionTestSet(CFGOPT_REPO_S3_TOKEN, BOGUS);
|
||||
$self->optionTestSet(CFGOPT_REPO_S3_BUCKET, $strBucket);
|
||||
$self->optionTestSet(CFGOPT_REPO_S3_ENDPOINT, $strEndpoint);
|
||||
$self->optionTestSet(CFGOPT_REPO_S3_REGION, $strRegion);
|
||||
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
|
||||
|
||||
$self->configTestLoad(CFGCMD_ARCHIVE_PUSH);
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('validation'))
|
||||
{
|
||||
if ($self->vm eq VM_U12)
|
||||
{
|
||||
&log(INFO, 'cannot test - certificates are no longer maintained for ' . $self->vm());
|
||||
}
|
||||
else
|
||||
{
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
if ($self->vm() eq VM_CO7)
|
||||
{
|
||||
# Tests fails on co7 because by default certs cannot be located. This logic may need to be changed in the future if
|
||||
# this bug gets fixed by Red Hat. UPDATE: The behavior changed here but it does not seems to be fixed.
|
||||
$self->testException(
|
||||
sub {storageRepo({strStanza => 'test1'})->list('/')}, ERROR_HOST_CONNECT,
|
||||
'SSL connect attempt failed with unknown error error.*certificate verify failed',
|
||||
'cert verify fails on ' . VM_CO7);
|
||||
|
||||
# It should work when verification is disabled
|
||||
$self->optionTestSetBool(CFGOPT_REPO_S3_VERIFY_TLS, false);
|
||||
$self->configTestLoad(CFGCMD_ARCHIVE_PUSH);
|
||||
|
||||
$self->testException(
|
||||
sub {storageRepo({strStanza => 'test2'})->list('/')}, ERROR_PROTOCOL, 'S3 request error \[403\] Forbidden.*',
|
||||
'connection succeeds with verification disabled, (expected) error on invalid access key');
|
||||
|
||||
$self->optionTestClear(CFGOPT_REPO_S3_VERIFY_TLS);
|
||||
$self->configTestLoad(CFGCMD_ARCHIVE_PUSH);
|
||||
}
|
||||
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
# CO7 doesn't locate certs automatically so specify the path
|
||||
if ($self->vm() eq VM_CO7)
|
||||
{
|
||||
$self->optionTestSet(CFGOPT_REPO_S3_CA_FILE, '/etc/pki/tls/certs/ca-bundle.crt');
|
||||
$self->configTestLoad(CFGCMD_ARCHIVE_PUSH);
|
||||
}
|
||||
|
||||
$self->testException(
|
||||
sub {storageRepo({strStanza => 'test3'})->list('/')}, ERROR_PROTOCOL, 'S3 request error \[403\] Forbidden.*',
|
||||
'connection succeeds, (expected) error on invalid access key');
|
||||
|
||||
if ($self->vm() eq VM_CO7)
|
||||
{
|
||||
$self->optionTestClear(CFGOPT_REPO_S3_CA_FILE);
|
||||
$self->configTestLoad(CFGCMD_ARCHIVE_PUSH);
|
||||
}
|
||||
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
$self->optionTestSet(CFGOPT_REPO_S3_CA_PATH, '/bogus');
|
||||
$self->configTestLoad(CFGCMD_ARCHIVE_PUSH);
|
||||
|
||||
$self->testException(
|
||||
sub {storageRepo({strStanza => 'test4'})->list('/')}, ERROR_HOST_CONNECT,
|
||||
$self->vm() eq VM_CO6 ? 'SSL connect attempt failed with unknown error.*certificate verify failed' : 'No such file or directory',
|
||||
'invalid ca path');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -1,219 +0,0 @@
|
||||
####################################################################################################################################
|
||||
# S3 Storage Tests
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Module::Storage::StorageS3PerlTest;
|
||||
use parent 'pgBackRestTest::Env::S3EnvTest';
|
||||
|
||||
####################################################################################################################################
|
||||
# Perl includes
|
||||
####################################################################################################################################
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::String;
|
||||
use pgBackRest::LibC qw(:crypto);
|
||||
use pgBackRest::Storage::S3::Driver;
|
||||
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
|
||||
####################################################################################################################################
|
||||
# initTest
|
||||
####################################################################################################################################
|
||||
sub initTest
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
executeTest("$self->{strS3Command} rm --recursive s3://pgbackrest-dev");
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# run
|
||||
####################################################################################################################################
|
||||
sub run
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Initialize the driver
|
||||
my $oS3 = $self->initS3();
|
||||
my $oStorage = new pgBackRest::Storage::Local('', $oS3);
|
||||
|
||||
# Test variables
|
||||
my $strFile = 'file.txt';
|
||||
my $strFileContent = 'TESTDATA';
|
||||
my $iFileLength = length($strFileContent);
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('exists()'))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oStorage->exists($strFile)}, false, 'root file does not exist');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
storageTest()->put($strFile, $strFileContent);
|
||||
executeTest("$self->{strS3Command} cp " . $self->testPath() . "/${strFile} s3://pgbackrest-dev");
|
||||
|
||||
$self->testResult(sub {$oStorage->exists($strFile)}, true, 'root file exists');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oStorage->pathExists('/path/to')}, false, 'sub path does not exist');
|
||||
$self->testResult(sub {$oStorage->exists("/path/to/${strFile}")}, false, 'sub file does not exist');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
executeTest("$self->{strS3Command} cp " . $self->testPath() . "/${strFile} s3://pgbackrest-dev/path/to/${strFile}");
|
||||
|
||||
$self->testResult(sub {$oStorage->pathExists('/path/to')}, true, 'sub path exists');
|
||||
# $oStorage->pathExists('/path/to');
|
||||
$self->testResult(sub {$oStorage->exists("/path/to/${strFile}")}, true, 'sub file exists');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('manifest()'))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oStorage->manifest('')}, '{. => {type => d}}', 'no files');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
storageTest()->put($strFile, $strFileContent);
|
||||
storageTest()->put("${strFile}2", $strFileContent . '2');
|
||||
|
||||
executeTest("$self->{strS3Command} cp " . $self->testPath() . "/${strFile} s3://pgbackrest-dev");
|
||||
executeTest("$self->{strS3Command} cp " . $self->testPath() . "/${strFile}2 s3://pgbackrest-dev/path/to/${strFile}2");
|
||||
|
||||
$self->testResult(
|
||||
sub {$oStorage->manifest('')},
|
||||
'{. => {type => d}, file.txt => {size => 8, type => f}, path => {type => d}, path/to => {type => d},' .
|
||||
' path/to/file.txt2 => {size => 9, type => f}}',
|
||||
'root path');
|
||||
$self->testResult(
|
||||
sub {$oStorage->manifest('/path/to')}, '{. => {type => d}, file.txt2 => {size => 9, type => f}}', 'sub path');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('list()'))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {$oStorage->list('')}, '[undef]', 'no files');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
storageTest()->put($strFile, $strFileContent);
|
||||
storageTest()->put("${strFile}2", $strFileContent . '2');
|
||||
|
||||
executeTest("$self->{strS3Command} cp " . $self->testPath() . "/${strFile} s3://pgbackrest-dev");
|
||||
executeTest("$self->{strS3Command} cp " . $self->testPath() . "/${strFile}2 s3://pgbackrest-dev/path/to/${strFile}2");
|
||||
|
||||
$self->testResult(sub {$oStorage->list('')}, '(file.txt, path)', 'root path');
|
||||
$self->testResult(sub {$oStorage->list('/path/to')}, 'file.txt2', 'sub path');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('remove()'))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oStorage->put($strFile, $strFileContent);
|
||||
$oStorage->put("/path/to/${strFile}2", $strFileContent);
|
||||
$oStorage->put("/path/to/${strFile}3", $strFileContent);
|
||||
$oStorage->put("/path/to/${strFile}4 \@+", $strFileContent);
|
||||
|
||||
$self->testResult(
|
||||
sub {$oStorage->manifest('/')},
|
||||
'{. => {type => d}, file.txt => {size => 8, type => f}, path => {type => d}, path/to => {type => d},' .
|
||||
' path/to/file.txt2 => {size => 8, type => f}, path/to/file.txt3 => {size => 8, type => f},' .
|
||||
' path/to/file.txt4 @+ => {size => 8, type => f}}',
|
||||
'check manifest');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oStorage->remove('/path/to', {bRecurse => true})}, true, 'remove subpath');
|
||||
|
||||
$self->testResult(
|
||||
sub {$oStorage->manifest('/')},
|
||||
'{. => {type => d}, file.txt => {size => 8, type => f}}', 'check manifest');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oStorage->remove($strFile)}, true, 'remove file');
|
||||
|
||||
$self->testResult(sub {$oStorage->manifest('/')}, '{. => {type => d}}', 'check manifest');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('info()'))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
storageTest()->put($strFile, $strFileContent);
|
||||
storageTest()->put("${strFile}2", $strFileContent . '2');
|
||||
|
||||
executeTest("$self->{strS3Command} cp " . $self->testPath() . "/${strFile} s3://pgbackrest-dev");
|
||||
executeTest("$self->{strS3Command} cp " . $self->testPath() . "/${strFile}2 s3://pgbackrest-dev");
|
||||
executeTest("$self->{strS3Command} cp " . $self->testPath() . "/${strFile}2 s3://pgbackrest-dev/path/to/${strFile}2");
|
||||
|
||||
$self->testResult(sub {$oStorage->info($strFile)->size()}, 8, 'file size');
|
||||
$self->testResult(sub {$oStorage->info("/path/to/${strFile}2")->size()}, 9, 'file 2 size');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('openRead() && S3::FileRead'))
|
||||
{
|
||||
# Create a random 1mb file
|
||||
my $strRandomFile = $self->testPath() . '/random@1mb.bin';
|
||||
executeTest("dd if=/dev/urandom of=${strRandomFile} bs=1024k count=1", {bSuppressStdErr => true});
|
||||
my $strRandom = ${storageTest()->get($strRandomFile)};
|
||||
|
||||
executeTest("$self->{strS3Command} cp ${strRandomFile} s3://pgbackrest-dev/path/to/${strFile}");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $tBuffer;
|
||||
my $oFileRead = $self->testResult(sub {$oS3->openRead("/path/to/${strFile}")}, '[object]', 'open read');
|
||||
$self->testResult(sub {$oFileRead->read(\$tBuffer, 524288)}, 524288, ' read half');
|
||||
$self->testResult(sub {$oFileRead->read(\$tBuffer, 524288)}, 524288, ' read half');
|
||||
$self->testResult(sub {$oFileRead->read(\$tBuffer, 512)}, 0, ' read 0');
|
||||
$self->testResult(length($tBuffer), 1048576, ' check length');
|
||||
$self->testResult(cryptoHashOne('sha1', $tBuffer), cryptoHashOne('sha1', $strRandom), ' check hash');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('openWrite() && S3::FileWrite'))
|
||||
{
|
||||
# Create a random 1mb file
|
||||
my $strRandomFile = $self->testPath() . '/random1mb.bin';
|
||||
executeTest("dd if=/dev/urandom of=${strRandomFile} bs=1024k count=1", {bSuppressStdErr => true});
|
||||
my $strRandom = ${storageTest()->get($strRandomFile)};
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $oFileWrite = $self->testResult(sub {$oS3->openWrite("/path/to/${strFile}")}, '[object]', 'open write');
|
||||
$self->testResult(sub {$oFileWrite->name()}, "/path/to/${strFile}", ' check filename');
|
||||
$self->testResult(sub {$oFileWrite->close()}, true, ' close without writing');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oFileWrite = $self->testResult(sub {$oS3->openWrite("/path/to/${strFile}" . '.@')}, '[object]', 'open write');
|
||||
$self->testResult(sub {$oFileWrite->write()}, 0, ' write undef');
|
||||
$self->testResult(sub {$oFileWrite->write(\$strFileContent)}, $iFileLength, ' write');
|
||||
$oFileWrite->close();
|
||||
|
||||
$self->testResult(sub {$oS3->exists("/path/to/${strFile}" . '.@')}, true, 'destination file exists');
|
||||
|
||||
# Test that a premature destroy (from error or otherwise) does not rename the file
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oFileWrite = $self->testResult(sub {$oS3->openWrite("/path/to/abort.file" . '.@')}, '[object]', 'open write');
|
||||
$self->testResult(sub {$oFileWrite->write()}, 0, ' write undef');
|
||||
$self->testResult(sub {$oFileWrite->write(\$strFileContent)}, $iFileLength, ' write');
|
||||
|
||||
undef($oFileWrite);
|
||||
$self->testResult(sub {$oS3->exists("/path/to/abort.file")}, false, 'destination file does not exist');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oFileWrite = $self->testResult(sub {$oS3->openWrite("/path/to/${strFile}")}, '[object]', 'open write');
|
||||
|
||||
for (my $iIndex = 1; $iIndex <= 17; $iIndex++)
|
||||
{
|
||||
$self->testResult(sub {$oFileWrite->write(\$strRandom)}, 1024 * 1024, ' write 1mb');
|
||||
}
|
||||
|
||||
$self->testResult(sub {$oFileWrite->close()}, true, ' close');
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -1,184 +0,0 @@
|
||||
####################################################################################################################################
|
||||
# S3 Request Tests
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Module::Storage::StorageS3RequestPerlTest;
|
||||
use parent 'pgBackRestTest::Common::RunTest';
|
||||
|
||||
####################################################################################################################################
|
||||
# Perl includes
|
||||
####################################################################################################################################
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
use IO::Socket::SSL;
|
||||
use POSIX qw(strftime);
|
||||
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Http::Client;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::Wait;
|
||||
use pgBackRest::Storage::S3::Request;
|
||||
|
||||
use pgBackRestTest::Common::ContainerTest;
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
|
||||
####################################################################################################################################
|
||||
# Port to use for testing
|
||||
####################################################################################################################################
|
||||
use constant HTTPS_TEST_PORT => 9443;
|
||||
|
||||
####################################################################################################################################
|
||||
# httpsServerResponse
|
||||
####################################################################################################################################
|
||||
sub httpsServerResponse
|
||||
{
|
||||
my $self = shift;
|
||||
my $iResponseCode = shift;
|
||||
my $strContent = shift;
|
||||
|
||||
# Write header
|
||||
$self->{oConnection}->write("HTTP/1.1 ${iResponseCode} GenericMessage\r\n");
|
||||
$self->{oConnection}->write(HTTP_HEADER_CONTENT_LENGTH . ': ' . (defined($strContent) ? length($strContent) : 0) . "\r\n");
|
||||
|
||||
# Write new line before content (even if there isn't any)
|
||||
$self->{oConnection}->write("\r\n");
|
||||
|
||||
# Write content
|
||||
if (defined($strContent))
|
||||
{
|
||||
$self->{oConnection}->write($strContent);
|
||||
}
|
||||
|
||||
# This will block until the connection is closed by the client
|
||||
$self->{oConnection}->read();
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# httpsServerAccept
|
||||
####################################################################################################################################
|
||||
sub httpsServerAccept
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Wait for a connection
|
||||
$self->{oConnection} = $self->{oSocketServer}->accept()
|
||||
or confess "failed to accept or handshake $!, $SSL_ERROR";
|
||||
&log(INFO, " * socket server connected");
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# httpsServer
|
||||
####################################################################################################################################
|
||||
sub httpsServer
|
||||
{
|
||||
my $self = shift;
|
||||
my $fnServer = shift;
|
||||
|
||||
# Fork off the server
|
||||
if (fork() == 0)
|
||||
{
|
||||
# Run server function
|
||||
$fnServer->();
|
||||
|
||||
exit 0;
|
||||
}
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Start the https testing server
|
||||
####################################################################################################################################
|
||||
sub initModule
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Open the domain socket
|
||||
$self->{oSocketServer} = IO::Socket::SSL->new(
|
||||
LocalAddr => '127.0.0.1', LocalPort => HTTPS_TEST_PORT, Listen => 1, SSL_cert_file => CERT_FAKE_SERVER,
|
||||
SSL_key_file => CERT_FAKE_SERVER_KEY)
|
||||
or confess "unable to open https server for testing: $!";
|
||||
&log(INFO, " * socket server open");
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Stop the https testing server
|
||||
####################################################################################################################################
|
||||
sub cleanModule
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Shutdown server
|
||||
$self->{oSocketServer}->close();
|
||||
&log(INFO, " * socket server closed");
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# run
|
||||
####################################################################################################################################
|
||||
sub run
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Initialize request object
|
||||
my $oS3Request = new pgBackRest::Storage::S3::Request(
|
||||
BOGUS, BOGUS, BOGUS, BOGUS, BOGUS, {strHost => '127.0.0.1', iPort => HTTPS_TEST_PORT, bVerifySsl => false});
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('success'))
|
||||
{
|
||||
$self->httpsServer(sub
|
||||
{
|
||||
$self->httpsServerAccept();
|
||||
$self->httpsServerResponse(200);
|
||||
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
$self->httpsServerAccept();
|
||||
$self->httpsServerResponse(200);
|
||||
});
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oS3Request->request(HTTP_VERB_GET)}, undef, 'successful request');
|
||||
$self->testResult(sub {$oS3Request->request(HTTP_VERB_GET)}, undef, 'successful request');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('retry'))
|
||||
{
|
||||
$self->httpsServer(sub
|
||||
{
|
||||
$self->httpsServerAccept();
|
||||
$self->httpsServerResponse(500);
|
||||
|
||||
$self->httpsServerAccept();
|
||||
$self->httpsServerResponse(500);
|
||||
|
||||
$self->httpsServerAccept();
|
||||
$self->httpsServerResponse(200);
|
||||
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
$self->httpsServerAccept();
|
||||
$self->httpsServerResponse(500);
|
||||
|
||||
$self->httpsServerAccept();
|
||||
$self->httpsServerResponse(500);
|
||||
|
||||
$self->httpsServerAccept();
|
||||
$self->httpsServerResponse(500);
|
||||
|
||||
$self->httpsServerAccept();
|
||||
$self->httpsServerResponse(500);
|
||||
|
||||
$self->httpsServerAccept();
|
||||
$self->httpsServerResponse(500);
|
||||
});
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oS3Request->request(HTTP_VERB_GET)}, undef, 'successful request after retries');
|
||||
$self->testException(
|
||||
sub {$oS3Request->request(HTTP_VERB_GET)}, ERROR_PROTOCOL, 'S3 request error after 5 tries \[500\] GenericMessage.*');
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
Reference in New Issue
Block a user