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