You've already forked pgbackrest
mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-11-29 22:28:02 +02:00
Storage and IO layer refactor:
Refactor storage layer to allow for new repository filesystems using drivers. (Reviewed by Cynthia Shang.) Refactor IO layer to allow for new compression formats, checksum types, and other capabilities using filters. (Reviewed by Cynthia Shang.)
This commit is contained in:
@@ -15,7 +15,6 @@ use English '-no_match_vars';
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Ini;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::FileCommon;
|
||||
use pgBackRest::Version;
|
||||
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
@@ -100,56 +99,77 @@ sub run
|
||||
################################################################################################################################
|
||||
if ($self->begin("Ini->new()"))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {(new pgBackRest::Common::Ini($strTestFile, {bIgnoreMissing => true}))->exists()}, false, 'ignore missing');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $oIni = new pgBackRest::Common::Ini(
|
||||
$strTestFile, {bLoad => false, iInitFormat => 4, strInitVersion => '1.01'});
|
||||
|
||||
$self->testResult($oIni->exists(), false, 'file does not exist');
|
||||
|
||||
$oIni->save();
|
||||
$oIni->saveCopy();
|
||||
|
||||
$self->testResult($oIni->exists(), false, 'file does not exist after saveCopy()');
|
||||
|
||||
$self->testResult(
|
||||
sub {fileStringRead($strTestFile)},
|
||||
sub {${storageTest()->get($strTestFile . INI_COPY_EXT)}},
|
||||
$self->iniHeader(undef, 4, '1.01', '488e5ca1a018cd7cd6d4e15150548f39f493dacd'),
|
||||
'empty with synthetic format and version');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
fileStringWrite($strTestFile);
|
||||
$self->testException(sub {new pgBackRest::Common::Ini($strTestFile)}, ERROR_CONFIG, 'no key/value pairs found');
|
||||
$oIni = new pgBackRest::Common::Ini($strTestFile, {bLoad => false});
|
||||
$oIni->saveCopy();
|
||||
|
||||
$self->testResult(
|
||||
sub {${storageTest()->get($strTestFile . INI_COPY_EXT)}},
|
||||
$self->iniHeader(undef, BACKREST_FORMAT, BACKREST_VERSION, $oIni->hash()),
|
||||
'empty with default format and version');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oIni = new pgBackRest::Common::Ini($strTestFile, {bLoad => false});
|
||||
$self->testResult(
|
||||
sub {storageTest()->list($self->testPath())},
|
||||
'test.ini.copy',
|
||||
'only copy is saved');
|
||||
|
||||
$oIni->save();
|
||||
|
||||
$self->testResult(
|
||||
sub {fileStringRead($strTestFile)},
|
||||
$self->iniHeader(undef, BACKREST_FORMAT, BACKREST_VERSION, $oIni->hash()),
|
||||
'empty with default format and version');
|
||||
sub {storageTest()->list($self->testPath())},
|
||||
'(test.ini, test.ini.copy)',
|
||||
'both versions are saved');
|
||||
|
||||
$self->testException(
|
||||
sub {$oIni->saveCopy()}, ERROR_ASSERT,
|
||||
"cannot save copy only when '${strTestFile}' exists");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {new pgBackRest::Common::Ini($strTestFile)}, '[object]', 'normal load');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $hIni = iniParse(fileStringRead($strTestFile));
|
||||
my $hIni = iniParse(${storageTest()->get($strTestFile)});
|
||||
$hIni->{&INI_SECTION_BACKREST}{&INI_KEY_CHECKSUM} = BOGUS;
|
||||
fileStringWrite($strTestFile, iniRender($hIni));
|
||||
fileStringWrite($strTestFileCopy, iniRender($hIni));
|
||||
storageTest()->put($strTestFile, iniRender($hIni));
|
||||
storageTest()->put($strTestFileCopy, iniRender($hIni));
|
||||
|
||||
$self->testException(
|
||||
sub {new pgBackRest::Common::Ini($strTestFile)}, ERROR_CHECKSUM,
|
||||
"invalid checksum in '${strTestFile}', expected '" .
|
||||
$oIni->get(INI_SECTION_BACKREST, INI_KEY_CHECKSUM) . "' but found 'bogus'");
|
||||
sub {new pgBackRest::Common::Ini($strTestFile)}, ERROR_FILE_MISSING,
|
||||
"unable to open ${strTestFile} or ${strTestFile}" . INI_COPY_EXT);
|
||||
# "invalid checksum in '${strTestFile}', expected '" .
|
||||
# $oIni->get(INI_SECTION_BACKREST, INI_KEY_CHECKSUM) . "' but found 'bogus'");
|
||||
|
||||
$hIni->{&INI_SECTION_BACKREST}{&INI_KEY_CHECKSUM} = $oIni->hash();
|
||||
fileStringWrite($strTestFile, iniRender($hIni));
|
||||
storageTest()->put($strTestFile, iniRender($hIni));
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oIni->numericSet(INI_SECTION_BACKREST, INI_KEY_FORMAT, undef, BACKREST_FORMAT - 1);
|
||||
$oIni->save();
|
||||
|
||||
$self->testException(
|
||||
sub {new pgBackRest::Common::Ini($strTestFile)}, ERROR_FORMAT,
|
||||
"invalid format in '${strTestFile}', expected " . BACKREST_FORMAT . ' but found ' . (BACKREST_FORMAT - 1));
|
||||
sub {new pgBackRest::Common::Ini($strTestFile)}, ERROR_FILE_MISSING,
|
||||
"unable to open ${strTestFile} or ${strTestFile}" . INI_COPY_EXT);
|
||||
# "invalid format in '${strTestFile}', expected " . BACKREST_FORMAT . ' but found ' . (BACKREST_FORMAT - 1));
|
||||
|
||||
$oIni->numericSet(INI_SECTION_BACKREST, INI_KEY_FORMAT, undef, BACKREST_FORMAT);
|
||||
$oIni->save();
|
||||
@@ -159,17 +179,17 @@ sub run
|
||||
$oIni->save();
|
||||
|
||||
$self->testResult(
|
||||
sub {fileStringRead($strTestFile)},
|
||||
sub {${storageTest()->get($strTestFile . INI_COPY_EXT)}},
|
||||
$self->iniHeader($oIni, undef, '1.01'),
|
||||
'verify old version was written');
|
||||
|
||||
$oIni = new pgBackRest::Common::Ini($strTestFile);
|
||||
|
||||
$self->testResult(sub {$oIni->get(INI_SECTION_BACKREST, INI_KEY_VERSION)}, BACKREST_VERSION, 'version is updated on load');
|
||||
$self->testResult(sub {$oIni->save()}, true, 'save changes');
|
||||
$oIni->save();
|
||||
|
||||
$self->testResult(
|
||||
sub {fileStringRead($strTestFile)},
|
||||
sub {${storageTest()->get($strTestFile . INI_COPY_EXT)}},
|
||||
$self->iniHeader($oIni, undef, BACKREST_VERSION),
|
||||
'verify version is updated on load');
|
||||
|
||||
@@ -177,65 +197,89 @@ sub run
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {new pgBackRest::Common::Ini($strTestFile, {bLoad => false, strContent => fileStringRead($strTestFile)})},
|
||||
sub {new pgBackRest::Common::Ini($strTestFile, {bLoad => false, strContent => ${storageTest()->get($strTestFile)}})},
|
||||
'[object]', 'new() passing content as a string');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
executeTest("rm -rf ${strTestFile}*");
|
||||
|
||||
$self->testException(
|
||||
sub {new pgBackRest::Common::Ini($strTestFile)}, ERROR_UNKNOWN,
|
||||
"unable to open ${strTestFile}");
|
||||
sub {new pgBackRest::Common::Ini($strTestFile)}, ERROR_FILE_MISSING,
|
||||
"unable to open ${strTestFile} or ${strTestFile}" . INI_COPY_EXT);
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
fileStringWrite($strTestFileCopy, BOGUS);
|
||||
storageTest()->put($strTestFileCopy, BOGUS);
|
||||
|
||||
$self->testException(
|
||||
sub {new pgBackRest::Common::Ini($strTestFileCopy)}, ERROR_CONFIG,
|
||||
"key/value pair 'bogus' found outside of a section");
|
||||
sub {new pgBackRest::Common::Ini($strTestFile)}, ERROR_FILE_MISSING,
|
||||
"unable to open ${strTestFile} or ${strTestFile}" . INI_COPY_EXT);
|
||||
# "key/value pair 'bogus' found outside of a section");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oIni = new pgBackRest::Common::Ini($strTestFile, {bLoad => false});
|
||||
my $oIniSource = new pgBackRest::Common::Ini($strTestFile, {bLoad => false});
|
||||
|
||||
fileStringWrite($strTestFileCopy, iniRender($oIni->{oContent}));
|
||||
storageTest()->put($strTestFileCopy, iniRender($oIniSource->{oContent}));
|
||||
|
||||
$self->testException(
|
||||
sub {new pgBackRest::Common::Ini($strTestFileCopy)}, ERROR_CHECKSUM,
|
||||
"invalid checksum in '${strTestFileCopy}', expected '" .
|
||||
$oIni->hash() . "' but found [undef]");
|
||||
sub {new pgBackRest::Common::Ini($strTestFile)}, ERROR_FILE_MISSING,
|
||||
"unable to open ${strTestFile} or ${strTestFile}" . INI_COPY_EXT);
|
||||
# "invalid checksum in '${strTestFileCopy}', expected '" .
|
||||
# $oIniSource->hash() . "' but found [undef]");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oIni = new pgBackRest::Common::Ini($strTestFile, {bLoad => false});
|
||||
$oIni->{oContent}->{&INI_SECTION_BACKREST}{&INI_KEY_FORMAT} = 0;
|
||||
$oIniSource = new pgBackRest::Common::Ini($strTestFile, {bLoad => false});
|
||||
$oIniSource->save();
|
||||
|
||||
$self->testResult(
|
||||
sub {$oIni->headerCheck({bIgnoreInvalid => true})}, false,
|
||||
'ignore invalid header');
|
||||
storageTest()->put($strTestFile, BOGUS);
|
||||
|
||||
# main invalid, copy ok
|
||||
$self->testResult(sub {new pgBackRest::Common::Ini($strTestFile)}, '[object]', 'invalid main - load copy');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
fileRemove($strTestFileCopy);
|
||||
storageTest()->remove($strTestFileCopy);
|
||||
|
||||
fileStringWrite($strTestFile, "[section]\n" . BOGUS);
|
||||
storageTest()->put($strTestFile, "[section]\n" . BOGUS);
|
||||
|
||||
$self->testException(sub {new pgBackRest::Common::Ini($strTestFile)}, ERROR_CONFIG, "unable to find '=' in 'bogus'");
|
||||
# main invalid, copy missing
|
||||
$self->testException
|
||||
(sub {new pgBackRest::Common::Ini($strTestFile)}, ERROR_FILE_MISSING,
|
||||
"unable to open ${strTestFile} or ${strTestFile}" . INI_COPY_EXT);
|
||||
#"unable to find '=' in 'bogus'");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {iniParse("[section]\n" . BOGUS, {bIgnoreInvalid => true})}, undef, 'ignore invalid content');
|
||||
storageTest()->put($strTestFile, iniRender($oIniSource->{oContent}));
|
||||
|
||||
$self->testResult(sub {new pgBackRest::Common::Ini($strTestFile)}, '[object]', 'main ok, copy missing');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
fileStringWrite($strTestFile, BOGUS);
|
||||
storageTest()->put($strTestFileCopy, BOGUS);
|
||||
|
||||
# main ok, copy invalid
|
||||
$self->testResult(sub {new pgBackRest::Common::Ini($strTestFile)}, '[object]', 'main ok, copy invalid');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
storageTest()->put($strTestFile, BOGUS);
|
||||
|
||||
# main invalid, copy invalid
|
||||
$self->testException(
|
||||
sub {new pgBackRest::Common::Ini($strTestFile)}, ERROR_CONFIG, "key/value pair 'bogus' found outside of a section");
|
||||
sub {new pgBackRest::Common::Ini($strTestFile)}, ERROR_FILE_MISSING,
|
||||
"unable to open ${strTestFile} or ${strTestFile}" . INI_COPY_EXT);
|
||||
# "key/value pair 'bogus' found outside of a section");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
fileStringWrite($strTestFile, iniRender($hIni));
|
||||
storageTest()->put($strTestFile, iniRender($hIni));
|
||||
$hIni->{&INI_SECTION_BACKREST}{&INI_KEY_CHECKSUM} = BOGUS;
|
||||
fileStringWrite($strTestFileCopy, iniRender($hIni));
|
||||
storageTest()->put($strTestFileCopy, iniRender($hIni));
|
||||
|
||||
$self->testResult(sub {new pgBackRest::Common::Ini($strTestFile)}, '[object]', 'invalid header - load main');
|
||||
$self->testResult(sub {new pgBackRest::Common::Ini($strTestFile)}, '[object]', 'invalid copy header - load main');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$hIni->{&INI_SECTION_BACKREST}{&INI_KEY_CHECKSUM} = $oIni->hash();
|
||||
storageTest()->put($strTestFileCopy, iniRender($hIni));
|
||||
$hIni->{&INI_SECTION_BACKREST}{&INI_KEY_CHECKSUM} = BOGUS;
|
||||
storageTest()->put($strTestFile, iniRender($hIni));
|
||||
|
||||
$self->testResult(sub {new pgBackRest::Common::Ini($strTestFile)}, '[object]', 'invalid main header - load copy');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
|
||||
259
test/lib/pgBackRestTest/Module/Common/CommonIoBufferedTest.pm
Normal file
259
test/lib/pgBackRestTest/Module/Common/CommonIoBufferedTest.pm
Normal file
@@ -0,0 +1,259 @@
|
||||
####################################################################################################################################
|
||||
# CommonIoBufferedTest.pm - tests for Common::Io::Buffered module
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Module::Common::CommonIoBufferedTest;
|
||||
use parent 'pgBackRestTest::Common::RunTest';
|
||||
|
||||
####################################################################################################################################
|
||||
# Perl includes
|
||||
####################################################################################################################################
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
use IO::Socket::UNIX;
|
||||
use Time::HiRes qw(usleep);
|
||||
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Io::Buffered;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::Wait;
|
||||
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
|
||||
####################################################################################################################################
|
||||
# socketServer
|
||||
####################################################################################################################################
|
||||
sub socketServer
|
||||
{
|
||||
my $self = shift;
|
||||
my $strSocketFile = shift;
|
||||
my $fnServer = shift;
|
||||
|
||||
# Fork off the server
|
||||
if (fork() == 0)
|
||||
{
|
||||
# Open the domain socket
|
||||
my $oSocketServer = IO::Socket::UNIX->new(Type => SOCK_STREAM(), Local => $strSocketFile, Listen => 1);
|
||||
&log(INFO, " * socket server open");
|
||||
|
||||
# Wait for a connection and create IO object
|
||||
my $oConnection = $oSocketServer->accept();
|
||||
my $oIoHandle = new pgBackRest::Common::Io::Handle('socket server', $oConnection, $oConnection);
|
||||
&log(INFO, " * socket server connected");
|
||||
|
||||
# Run server function
|
||||
$fnServer->($oIoHandle);
|
||||
|
||||
# Shutdown server
|
||||
$oSocketServer->close();
|
||||
&log(INFO, " * socket server closed");
|
||||
unlink($strSocketFile);
|
||||
exit 0;
|
||||
}
|
||||
|
||||
# Wait for client socket
|
||||
my $oWait = waitInit(5);
|
||||
while (!-e $strSocketFile && waitMore($oWait)) {};
|
||||
|
||||
# Open the client socket
|
||||
my $oClient = IO::Socket::UNIX->new(Type => SOCK_STREAM(), Peer => $strSocketFile);
|
||||
|
||||
if (!defined($oClient))
|
||||
{
|
||||
logErrorResult(ERROR_FILE_OPEN, 'unable to open client socket', $OS_ERROR);
|
||||
}
|
||||
|
||||
&log(INFO, " * socket client connected");
|
||||
|
||||
return $oClient;
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# run
|
||||
####################################################################################################################################
|
||||
sub run
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Test data
|
||||
my $strSocketFile = $self->testPath() . qw{/} . 'domain.socket';
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('new() & timeout() & bufferMax()'))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $oIoBuffered = $self->testResult(
|
||||
sub {new pgBackRest::Common::Io::Buffered(
|
||||
new pgBackRest::Common::Io::Handle('test'), 10, 2048)}, '[object]', 'new - no handles');
|
||||
|
||||
$self->testResult(sub {$oIoBuffered->timeout()}, 10, ' check timeout');
|
||||
$self->testResult(sub {$oIoBuffered->bufferMax()}, 2048, ' check buffer max');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('readLine() & writeLine()'))
|
||||
{
|
||||
my $oClient = $self->socketServer($strSocketFile, sub
|
||||
{
|
||||
my $oIoHandle = shift;
|
||||
|
||||
my $tResponse = '';
|
||||
my $tData;
|
||||
|
||||
# Ack after timeout
|
||||
while (length($tResponse) != 1) {$oIoHandle->read(\$tResponse, 1)};
|
||||
|
||||
# Write 8 char line
|
||||
$tResponse = '';
|
||||
$tData = "12345678\n";
|
||||
$oIoHandle->write(\$tData);
|
||||
while (length($tResponse) != 1) {$oIoHandle->read(\$tResponse, 1)};
|
||||
|
||||
# Write 3 lines
|
||||
$tResponse = '';
|
||||
$tData = "1\n2\n345678\n";
|
||||
$oIoHandle->write(\$tData);
|
||||
while (length($tResponse) != 1) {$oIoHandle->read(\$tResponse, 1)};
|
||||
|
||||
# Write blank line
|
||||
$tResponse = '';
|
||||
$tData = "\n";
|
||||
$oIoHandle->write(\$tData);
|
||||
while (length($tResponse) != 1) {$oIoHandle->read(\$tResponse, 1)};
|
||||
|
||||
# Write char with no linefeed
|
||||
$tResponse = '';
|
||||
$tData = "A";
|
||||
$oIoHandle->write(\$tData);
|
||||
while (length($tResponse) != 1) {$oIoHandle->read(\$tResponse, 1)};
|
||||
|
||||
# Write linefeed
|
||||
$tResponse = '';
|
||||
$tData = "\n";
|
||||
$oIoHandle->write(\$tData);
|
||||
while (length($tResponse) != 1) {$oIoHandle->read(\$tResponse, 1)};
|
||||
});
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $oIoBuffered = $self->testResult(
|
||||
sub {new pgBackRest::Common::Io::Buffered(
|
||||
new pgBackRest::Common::Io::Handle('socket client', $oClient, $oClient), 1, 4)}, '[object]', 'open');
|
||||
|
||||
$self->testException(
|
||||
sub {$oIoBuffered->readLine()}, ERROR_FILE_READ, 'unable to read line after 1 second(s) from socket client');
|
||||
|
||||
$oIoBuffered->writeLine();
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oIoBuffered->readLine()}, '12345678', 'read 8 char line');
|
||||
$oIoBuffered->writeLine();
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oIoBuffered->readLine()}, '1', 'read 1 char line');
|
||||
$self->testResult(sub {$oIoBuffered->readLine()}, '2', 'read 1 char line');
|
||||
$self->testResult(sub {$oIoBuffered->readLine()}, '345678', 'read 6 char line');
|
||||
$oIoBuffered->writeLine();
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oIoBuffered->readLine()}, '', 'read blank line');
|
||||
$oIoBuffered->writeLine();
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oIoBuffered->readLine(undef, false)}, undef, 'read ignoring error');
|
||||
|
||||
$self->testException(
|
||||
sub {$oIoBuffered->readLine(undef, true)}, ERROR_FILE_READ,
|
||||
'unable to read line after 1 second(s) from socket client');
|
||||
|
||||
# Clear buffer so EOF tests pass
|
||||
$oIoBuffered->writeLine();
|
||||
$oIoBuffered->readLine();
|
||||
$oIoBuffered->writeLine();
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testException(sub {$oIoBuffered->readLine()}, ERROR_FILE_READ, 'unexpected EOF reading line from socket client');
|
||||
|
||||
$self->testException(
|
||||
sub {$oIoBuffered->readLine(false)}, ERROR_FILE_READ, 'unexpected EOF reading line from socket client');
|
||||
|
||||
$self->testResult(sub {$oIoBuffered->readLine(true)}, undef, 'ignore EOF');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('read'))
|
||||
{
|
||||
my $tBuffer;
|
||||
|
||||
my $oClient = $self->socketServer($strSocketFile, sub
|
||||
{
|
||||
my $oIoHandle = shift;
|
||||
|
||||
my $tResponse = '';
|
||||
my $tData;
|
||||
|
||||
# Ack after timeout
|
||||
while (length($tResponse) != 1) {$oIoHandle->read(\$tResponse, 1)};
|
||||
|
||||
# Write mixed buffer
|
||||
$tResponse = '';
|
||||
$tData = "123\n123\n1";
|
||||
$oIoHandle->write(\$tData);
|
||||
while (length($tResponse) != 1) {$oIoHandle->read(\$tResponse, 1)};
|
||||
|
||||
# Write buffer
|
||||
$tResponse = '';
|
||||
$tData = "23456789";
|
||||
$oIoHandle->write(\$tData);
|
||||
|
||||
# Wait before writing the rest to force client to loop
|
||||
usleep(500);
|
||||
$tData = "0";
|
||||
$oIoHandle->write(\$tData);
|
||||
while (length($tResponse) != 1) {$oIoHandle->read(\$tResponse, 1)};
|
||||
});
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $oIoBuffered = $self->testResult(
|
||||
sub {new pgBackRest::Common::Io::Buffered(
|
||||
new pgBackRest::Common::Io::Handle('socket client', $oClient, $oClient), 1, 8)}, '[object]', 'open');
|
||||
|
||||
$self->testException(
|
||||
sub {$oIoBuffered->read(\$tBuffer, 1, true)}, ERROR_FILE_READ,
|
||||
'unable to read 1 byte(s) after 1 second(s) from socket client');
|
||||
|
||||
$self->testResult(sub {$oIoBuffered->read(\$tBuffer, 1)}, 0, ' read 0 char buffer');
|
||||
|
||||
$oIoBuffered->writeLine();
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oIoBuffered->readLine()}, '123', ' read 3 char line');
|
||||
|
||||
undef($tBuffer);
|
||||
$self->testResult(sub {$oIoBuffered->read(\$tBuffer, 1)}, 1, ' read 1 char buffer');
|
||||
$self->testResult(sub {$tBuffer}, '1', ' check 1 char buffer');
|
||||
|
||||
$self->testResult(sub {$oIoBuffered->read(\$tBuffer, 3)}, 3, ' read 3 char buffer');
|
||||
$self->testResult(sub {$tBuffer}, "123\n", ' check 3 char buffer');
|
||||
|
||||
$oIoBuffered->writeLine();
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
undef($tBuffer);
|
||||
$self->testResult(sub {$oIoBuffered->read(\$tBuffer, 10)}, 10, ' read 10 char buffer');
|
||||
$self->testResult(sub {$tBuffer}, '1234567890', ' check 10 char buffer');
|
||||
|
||||
$oIoBuffered->writeLine();
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oIoBuffered->read(\$tBuffer, 5)}, 0, ' expect EOF');
|
||||
|
||||
$self->testException(
|
||||
sub {$oIoBuffered->read(\$tBuffer, 5, true)}, ERROR_FILE_READ,
|
||||
'unable to read 5 byte(s) due to EOF from socket client');
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
216
test/lib/pgBackRestTest/Module/Common/CommonIoHandleTest.pm
Normal file
216
test/lib/pgBackRestTest/Module/Common/CommonIoHandleTest.pm
Normal file
@@ -0,0 +1,216 @@
|
||||
####################################################################################################################################
|
||||
# CommonIoHandleTest.pm - tests for Common::Io::Handle module
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Module::Common::CommonIoHandleTest;
|
||||
use parent 'pgBackRestTest::Common::RunTest';
|
||||
|
||||
####################################################################################################################################
|
||||
# Perl includes
|
||||
####################################################################################################################################
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
use Fcntl qw(O_RDONLY O_WRONLY O_CREAT O_TRUNC O_NONBLOCK);
|
||||
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Io::Base;
|
||||
use pgBackRest::Common::Io::Handle;
|
||||
use pgBackRest::Common::Log;
|
||||
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
|
||||
####################################################################################################################################
|
||||
# run
|
||||
####################################################################################################################################
|
||||
sub run
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Test data
|
||||
my $strFile = $self->testPath() . qw{/} . 'file.txt';
|
||||
my $strFileContent = 'TESTDATA';
|
||||
my $iFileLength = length($strFileContent);
|
||||
my $iFileLengthHalf = int($iFileLength / 2);
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('new() & handleRead() & handleReadSet() & handleWrite() & handleWriteSet()'))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $oIoHandle = $self->testResult(
|
||||
sub {new pgBackRest::Common::Io::Handle('test', undef, undef)}, '[object]', 'new - no handles');
|
||||
|
||||
$self->testResult(sub {$oIoHandle->id()}, 'test', ' check error msg');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {$oIoHandle->handleReadSet(1)}, 1, ' set read handle');
|
||||
$self->testResult(sub {$oIoHandle->handleRead()}, 1, ' check read handle');
|
||||
$self->testResult(sub {$oIoHandle->handleWrite()}, undef, ' check write handle');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(
|
||||
sub {$oIoHandle->handleWriteSet(2)}, 2, ' set write handle');
|
||||
$self->testResult(sub {$oIoHandle->handleRead()}, 1, ' check read handle');
|
||||
$self->testResult(sub {$oIoHandle->handleWrite()}, 2, ' check write handle');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oIoHandle = $self->testResult(
|
||||
sub {new pgBackRest::Common::Io::Handle('test', 1, undef)}, '[object]', 'new - read handle');
|
||||
|
||||
$self->testResult(sub {$oIoHandle->handleRead()}, 1, ' check read handle');
|
||||
$self->testResult(sub {$oIoHandle->handleWrite()}, undef, ' check write handle');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oIoHandle = $self->testResult(
|
||||
sub {new pgBackRest::Common::Io::Handle('test', undef, 2)}, '[object]', 'new - write handle');
|
||||
|
||||
$self->testResult(sub {$oIoHandle->handleRead()}, undef, ' check read handle');
|
||||
$self->testResult(sub {$oIoHandle->handleWrite()}, 2, ' check write handle');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oIoHandle = $self->testResult(
|
||||
sub {new pgBackRest::Common::Io::Handle('test', 1, 2)}, '[object]', 'new - read/write handle');
|
||||
|
||||
$self->testResult(sub {$oIoHandle->handleRead()}, 1, ' check read handle');
|
||||
$self->testResult(sub {$oIoHandle->handleWrite()}, 2, ' check write handle');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('read()'))
|
||||
{
|
||||
my $tContent;
|
||||
my $fhRead;
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
executeTest("echo -n '${strFileContent}' | tee ${strFile}");
|
||||
|
||||
sysopen($fhRead, $strFile, O_RDONLY)
|
||||
or confess &log(ERROR, "unable to open '${strFile}'");
|
||||
|
||||
my $oIoHandle = $self->testResult(sub {new pgBackRest::Common::Io::Handle("'$strFile'", $fhRead)}, '[object]', 'open');
|
||||
$self->testException(
|
||||
sub {$oIoHandle->read(\$tContent, -1)}, ERROR_FILE_READ, "unable to read from '${strFile}': Negative length");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$tContent = undef;
|
||||
|
||||
sysopen($fhRead, $strFile, O_RDONLY)
|
||||
or confess &log(ERROR, "unable to open '${strFile}'");
|
||||
|
||||
$oIoHandle = $self->testResult(sub {new pgBackRest::Common::Io::Handle("'$strFile'", $fhRead)}, '[object]', 'open');
|
||||
|
||||
$self->testResult(sub {$oIoHandle->read(\$tContent, $iFileLengthHalf)}, $iFileLengthHalf, ' read part 1');
|
||||
$self->testResult($tContent, substr($strFileContent, 0, $iFileLengthHalf), ' check read');
|
||||
|
||||
$self->testResult(
|
||||
sub {$oIoHandle->read(
|
||||
\$tContent, $iFileLength - $iFileLengthHalf)}, $iFileLength - $iFileLengthHalf, ' read part 2');
|
||||
$self->testResult($tContent, $strFileContent, ' check read');
|
||||
|
||||
$self->testResult(sub {$oIoHandle->read(\$tContent, 1)}, 0, ' eof');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('write()'))
|
||||
{
|
||||
my $tContent;
|
||||
my $fhRead;
|
||||
my $fhWrite;
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
sysopen($fhWrite, $strFile, O_WRONLY | O_CREAT | O_TRUNC)
|
||||
or confess &log(ERROR, "unable to open '${strFile}'");
|
||||
|
||||
my $oIoHandle = $self->testResult(
|
||||
sub {new pgBackRest::Common::Io::Handle("'$strFile'", undef, $fhWrite)}, '[object]', 'open write');
|
||||
|
||||
$self->testException(
|
||||
sub {$oIoHandle->write(undef)}, ERROR_FILE_WRITE,
|
||||
"unable to write to '${strFile}': Can't use an undefined value as a SCALAR reference");
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$tContent = substr($strFileContent, 0, $iFileLengthHalf);
|
||||
$self->testResult(sub {$oIoHandle->write(\$tContent)}, $iFileLengthHalf, ' write part 1');
|
||||
$self->testResult(sub {$oIoHandle->size()}, $iFileLengthHalf, ' check part 1 size');
|
||||
|
||||
$tContent = substr($strFileContent, $iFileLengthHalf);
|
||||
$self->testResult(sub {$oIoHandle->write(\$tContent)}, $iFileLength - $iFileLengthHalf, ' write part 2');
|
||||
$self->testResult(sub {$oIoHandle->size()}, $iFileLength, ' check part 2 size');
|
||||
$self->testResult(sub {$oIoHandle->close()}, true, ' close');
|
||||
|
||||
sysopen($fhRead, $strFile, O_RDONLY)
|
||||
or confess &log(ERROR, "unable to open '${strFile}'");
|
||||
|
||||
$oIoHandle = $self->testResult(sub {new pgBackRest::Common::Io::Handle("'$strFile'", $fhRead)}, '[object]', 'open read');
|
||||
|
||||
$tContent = undef;
|
||||
$self->testResult(sub {$oIoHandle->read(\$tContent, $iFileLength)}, $iFileLength, ' read');
|
||||
$self->testResult($tContent, $strFileContent, ' check write content');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('result() & resultSet()'))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $oIoHandle = $self->testResult(
|
||||
sub {new pgBackRest::Common::Io::Handle('test', undef, undef)}, '[object]', 'new - no handles');
|
||||
|
||||
$self->testResult(sub {$oIoHandle->resultSet('Module::1', 1)}, 1, ' set int result');
|
||||
$self->testResult(sub {$oIoHandle->resultSet('Module::2', {value => 2})}, '{value => 2}', ' set hash result');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oIoHandle->result('Module::1')}, 1, ' check int result');
|
||||
$self->testResult(sub {$oIoHandle->result('Module::2')}, '{value => 2}', ' check hash result');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oIoHandle->{rhResult}}, '{Module::1 => 1, Module::2 => {value => 2}}', ' check all results');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('isA()'))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $oIoHandle = $self->testResult(
|
||||
sub {new pgBackRest::Common::Io::Handle('test', undef, undef)}, '[object]', 'new - no handles');
|
||||
|
||||
$self->testResult(
|
||||
sub {$oIoHandle->isA()}, '(' . COMMON_IO_HANDLE . ', ' . COMMON_IO_BASE . ')', ' check isA');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('className()'))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $oIoHandle = $self->testResult(
|
||||
sub {new pgBackRest::Common::Io::Handle('test', undef, undef)}, '[object]', 'new - no handles');
|
||||
|
||||
$self->testResult(sub {$oIoHandle->className()}, COMMON_IO_HANDLE, ' check class name');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('close()'))
|
||||
{
|
||||
my $tContent;
|
||||
my $fhRead;
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
executeTest("echo -n '${strFileContent}' | tee ${strFile}");
|
||||
|
||||
sysopen($fhRead, $strFile, O_RDONLY)
|
||||
or confess &log(ERROR, "unable to open '${strFile}'");
|
||||
|
||||
my $oIoHandle = $self->testResult(sub {new pgBackRest::Common::Io::Handle("'$strFile'", $fhRead)}, '[object]', 'open read');
|
||||
$self->testResult(sub {$oIoHandle->read(\$tContent, $iFileLengthHalf)}, $iFileLengthHalf, ' read');
|
||||
$self->testResult(sub {$oIoHandle->close()}, true, ' close');
|
||||
|
||||
$self->testResult(sub {$oIoHandle->result(COMMON_IO_HANDLE)}, $iFileLengthHalf, ' check result');
|
||||
|
||||
# Destroy and to make sure close runs again
|
||||
undef($oIoHandle);
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
59
test/lib/pgBackRestTest/Module/Common/CommonIoProcessTest.pm
Normal file
59
test/lib/pgBackRestTest/Module/Common/CommonIoProcessTest.pm
Normal file
@@ -0,0 +1,59 @@
|
||||
####################################################################################################################################
|
||||
# CommonIoProcessTest.pm - tests for Common::Io::Process module
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Module::Common::CommonIoProcessTest;
|
||||
use parent 'pgBackRestTest::Common::RunTest';
|
||||
|
||||
####################################################################################################################################
|
||||
# Perl includes
|
||||
####################################################################################################################################
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Io::Buffered;
|
||||
use pgBackRest::Common::Io::Process;
|
||||
use pgBackRest::Common::Log;
|
||||
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
|
||||
####################################################################################################################################
|
||||
# run
|
||||
####################################################################################################################################
|
||||
sub run
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Test data
|
||||
my $strFile = $self->testPath() . qw{/} . 'file.txt';
|
||||
my $strFileContent = 'TESTDATA';
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('new() & processId()'))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $oIoProcess = $self->testResult(sub {
|
||||
new pgBackRest::Common::Io::Process(
|
||||
new pgBackRest::Common::Io::Buffered(
|
||||
new pgBackRest::Common::Io::Handle('test'), 1, 32), "echo '${strFileContent}'")}, '[object]', 'new - echo');
|
||||
$self->testResult(sub {defined($oIoProcess->processId())}, true, ' process id defined');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin('close() & error()'))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
my $oIoProcess =
|
||||
new pgBackRest::Common::Io::Process(
|
||||
new pgBackRest::Common::Io::Buffered(
|
||||
new pgBackRest::Common::Io::Handle('test'), 1, 32), "echo '${strFileContent}'");
|
||||
$oIoProcess->close();
|
||||
$self->testException(
|
||||
sub {$oIoProcess->error()}, ERROR_ASSERT, 'cannot call error() after process has been closed');
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
Reference in New Issue
Block a user