mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2024-12-14 10:13:05 +02:00
b0947fdaa8
Reported by Stephen Frost.
131 lines
4.9 KiB
Perl
131 lines
4.9 KiB
Perl
####################################################################################################################################
|
|
# pgBackRest-LibC.t - Unit tests for the LibC module
|
|
####################################################################################################################################
|
|
use strict;
|
|
use warnings;
|
|
use Carp;
|
|
use English '-no_match_vars';
|
|
|
|
use Fcntl qw(O_RDONLY);
|
|
|
|
# Set number of tests
|
|
use Test::More tests => 10;
|
|
|
|
# Make sure the module loads without errors
|
|
BEGIN {use_ok('pgBackRest::LibC')};
|
|
|
|
# Load the module dynamically so it does not interfere with the test above
|
|
require pgBackRest::LibC;
|
|
pgBackRest::LibC->import(qw(:debug :checksum));
|
|
|
|
# UVSIZE determines the pointer and long long int size. This needs to be 8 to indicate 64-bit types are available.
|
|
ok (&UVSIZE == 8, 'UVSIZE == 8');
|
|
|
|
sub pageBuild
|
|
{
|
|
my $tPageSource = shift;
|
|
my $iWalId = shift;
|
|
my $iWalOffset = shift;
|
|
my $iBlockNo = shift;
|
|
|
|
my $tPage = pack('I', $iWalId) . pack('I', $iWalOffset) . substr($tPageSource, 8);
|
|
my $iChecksum = pageChecksum($tPage, $iBlockNo, length($tPage));
|
|
|
|
return substr($tPage, 0, 8) . pack('S', $iChecksum) . substr($tPage, 10);
|
|
}
|
|
|
|
# Test page-level checksums
|
|
{
|
|
my $strPageFile = 't/data/page.bin';
|
|
my $iPageSize = 8192;
|
|
my $iPageChecksum = 0x1B99;
|
|
|
|
# Load the block into a buffer
|
|
sysopen(my $hFile, $strPageFile, O_RDONLY)
|
|
or confess "unable to open ${strPageFile}";
|
|
|
|
sysread($hFile, my $tBuffer, $iPageSize) == $iPageSize
|
|
or confess "unable to read 8192 bytes from ${strPageFile}";
|
|
|
|
close ($hFile);
|
|
|
|
# Test the checksum
|
|
my $iPageChecksumTest = pageChecksum($tBuffer, 0, $iPageSize);
|
|
|
|
ok (
|
|
$iPageChecksumTest == $iPageChecksum,
|
|
'page checksum test (' . sprintf('%X', $iPageChecksumTest) .
|
|
') == page checksum (' . sprintf('%X', $iPageChecksum) . ')');
|
|
|
|
# Test the checksum on a different block no
|
|
$iPageChecksumTest = pageChecksum($tBuffer, 1, $iPageSize);
|
|
my $iPageChecksumBlockNo = $iPageChecksum + 1;
|
|
|
|
ok (
|
|
$iPageChecksumTest == $iPageChecksumBlockNo,
|
|
'page checksum test (' . sprintf('%X', $iPageChecksumTest) .
|
|
') == page checksum blockno (' . sprintf('%X', $iPageChecksumBlockNo) . ')');
|
|
|
|
# Now munge the block and make sure the checksum changes
|
|
$iPageChecksumTest = pageChecksum(pack('I', 1024) . substr($tBuffer, 4), 0, $iPageSize);
|
|
my $iPageChecksumMunge = 0xFCFF;
|
|
|
|
ok (
|
|
$iPageChecksumTest == $iPageChecksumMunge,
|
|
'page checksum test (' . sprintf('%X', $iPageChecksumTest) .
|
|
') == page checksum munge (' . sprintf('%X', $iPageChecksumMunge) . ')');
|
|
|
|
# Pass a valid page buffer
|
|
my $tBufferMulti =
|
|
$tBuffer .
|
|
substr($tBuffer, 0, 8) . pack('S', $iPageChecksum + 1) . substr($tBuffer, 10) .
|
|
substr($tBuffer, 0, 8) . pack('S', $iPageChecksum - 2) . substr($tBuffer, 10) .
|
|
substr($tBuffer, 0, 8) . pack('S', $iPageChecksum - 1) . substr($tBuffer, 10) .
|
|
substr($tBuffer, 0, 8) . pack('S', $iPageChecksum + 4) . substr($tBuffer, 10) .
|
|
substr($tBuffer, 0, 8) . pack('S', $iPageChecksum + 5) . substr($tBuffer, 10) .
|
|
substr($tBuffer, 0, 8) . pack('S', $iPageChecksum + 2) . substr($tBuffer, 10) .
|
|
substr($tBuffer, 0, 8) . pack('S', $iPageChecksum + 3) . substr($tBuffer, 10);
|
|
|
|
ok (pageChecksumBufferTest($tBufferMulti, length($tBufferMulti), 0, $iPageSize, 0xFFFF, 0xFFFF), 'pass valid page buffer');
|
|
|
|
# Allow page with an invalid checksum because LSN >= ignore LSN
|
|
$tBufferMulti =
|
|
pageBuild($tBuffer, 0, 0, 0) .
|
|
pageBuild($tBuffer, 0xFFFF, 0xFFFE, 0) .
|
|
pageBuild($tBuffer, 0, 0, 2);
|
|
|
|
ok (pageChecksumBufferTest($tBufferMulti, length($tBufferMulti), 0, $iPageSize, 0xFFFF, 0xFFFE), 'skip invalid checksum');
|
|
|
|
# Reject an invalid page buffer (second block will error because the checksum will not contain the correct block no)
|
|
ok (!pageChecksumBufferTest($tBufferMulti, length($tBufferMulti), 0, $iPageSize, 0xFFFF, 0xFFFF), 'reject invalid page buffer');
|
|
|
|
# Find the rejected page in the buffer
|
|
my $iRejectedBlockNo = -1;
|
|
my $iExpectedBlockNo = 1;
|
|
|
|
for (my $iIndex = 0; $iIndex < length($tBufferMulti) / $iPageSize; $iIndex++)
|
|
{
|
|
if (!pageChecksumTest(substr($tBufferMulti, $iIndex * $iPageSize, $iPageSize), $iIndex, $iPageSize, 0xFFFF, 0xFFFF))
|
|
{
|
|
$iRejectedBlockNo = $iIndex;
|
|
}
|
|
}
|
|
|
|
ok ($iRejectedBlockNo == $iExpectedBlockNo, "rejected blockno ${iRejectedBlockNo} equals expected ${iExpectedBlockNo}");
|
|
|
|
# Reject an misaligned page buffer
|
|
$tBufferMulti =
|
|
pageBuild($tBuffer, 0, 0, 0) .
|
|
substr(pageBuild($tBuffer, 0, 0, 1), 1);
|
|
|
|
eval
|
|
{
|
|
pageChecksumBufferTest($tBufferMulti, length($tBufferMulti), 0, $iPageSize, 0xFFFF, 0xFFFF);
|
|
ok (0, 'misaligned test should have failed');
|
|
}
|
|
or do
|
|
{
|
|
ok (1, 'misaligned test failed');
|
|
};
|
|
}
|