#################################################################################################################################### # Unit tests for Manifest module #################################################################################################################################### package pgBackRestTest::Module::Manifest::ManifestAllPerlTest; use parent 'pgBackRestTest::Env::HostEnvTest'; #################################################################################################################################### # Perl includes #################################################################################################################################### use strict; use warnings FATAL => qw(all); use Carp qw(confess); use File::Basename qw(dirname); use Storable qw(dclone); use pgBackRest::Backup::Common; use pgBackRest::Common::Exception; use pgBackRest::Common::Ini; use pgBackRest::Common::Log; use pgBackRest::Common::String; use pgBackRest::Common::Wait; use pgBackRest::Config::Config; use pgBackRest::DbVersion; use pgBackRest::Manifest; use pgBackRest::Protocol::Helper; use pgBackRest::Protocol::Storage::Helper; use pgBackRest::Storage::Helper; use pgBackRest::Version; use pgBackRestTest::Common::ContainerTest; use pgBackRestTest::Common::ExecuteTest; use pgBackRestTest::Common::FileTest; use pgBackRestTest::Common::RunTest; use pgBackRestTest::Env::Host::HostBackupTest; #################################################################################################################################### # Issues / Improvements # # While working on the unit tests a number of possible issues/improvements have come up. Issues are documented in the tests where # they are relevant with an INVESTIGATE tag. General improvements are listed here to be addressed later: # # 1. Assignment of required values to the manifest is haphazard. Db version is in the constructor but the rest is assigned in # Backup.pm. These should probably all be passed in the constructor. It may be like it is now in part because of test needs # but that should be changed if so. # # 2. Improve validate function to check that all values that are collected actually got set. Some things are being checked now, # but others like backup-lsn-start, backup-wal-start, etc. are not. Include all options like option-compress, etc. and db info # like db-id, system-id, etc. Basically, validate should check everything in the manifest before it is saved (for the last time # since intermediate saves may be missing data) and make sure nothing is missing or extraneous. Also check the contents of # values, i.e. make sure that checksum is really a 40-character hex string. # # 3. In fileAdd() the mode should be based on a mask (remove execute bit) of the dir mode, rather than a constant. i.e. dir mode # 0700 should become 0600, dir mode 0750 should become 0640, etc. #################################################################################################################################### #################################################################################################################################### # Constants #################################################################################################################################### use constant MODE_0750 => '0750'; use constant MODE_0700 => '0700'; use constant MODE_0644 => '0644'; use constant MODE_0600 => '0600'; use constant PGCONTROL_SIZE => 8192; #################################################################################################################################### # initModule #################################################################################################################################### sub initModule { my $self = shift; $self->{strDbPath} = $self->testPath() . "/db"; $self->{strRepoPath} = $self->testPath() . "/repo"; $self->{strArchivePath} = "$self->{strRepoPath}/archive/" . $self->stanza(); $self->{strBackupPath} = "$self->{strRepoPath}/backup/" . $self->stanza(); $self->{strSpoolPath} = "$self->{strArchivePath}/out"; $self->{strExpectedManifest} = $self->testPath() . "/expected.manifest"; $self->{strActualManifest} = $self->testPath() . "/actual.manifest"; } #################################################################################################################################### # initTest #################################################################################################################################### sub initTest { my $self = shift; # Create archive info path storageTest()->pathCreate($self->{strArchivePath}, {bIgnoreExists => true, bCreateParent => true}); # Create backup info path storageTest()->pathCreate($self->{strBackupPath}, {bIgnoreExists => true, bCreateParent => true}); # Create pg_control global path storageTest()->pathCreate($self->{strDbPath} . '/' . DB_PATH_GLOBAL, {bCreateParent => true}); } #################################################################################################################################### # manifestCompare #################################################################################################################################### sub manifestCompare { my $self = shift; my $oManifestExpected = shift; my $oManifestActual = shift; # Remove manifest files if exist storageTest()->remove($self->{strExpectedManifest}, {bIgnoreMissing => true}); storageTest()->remove($self->{strActualManifest}, {bIgnoreMissing => true}); # Section backup. Confirm the copy-start timestamp is set for the actual manifest then copy it to the expected so files can # be compared if ($oManifestActual->test(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_TIMESTAMP_COPY_START)) { $oManifestExpected->set(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_TIMESTAMP_COPY_START, undef, $oManifestActual->get(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_TIMESTAMP_COPY_START)); } else { return MANIFEST_KEY_TIMESTAMP_COPY_START . " not set in actual manifest"; } storageTest()->put($self->{strActualManifest}, iniRender($oManifestActual->{oContent})); storageTest()->put($self->{strExpectedManifest}, iniRender($oManifestExpected->{oContent})); return executeTest("diff " . $self->{strExpectedManifest} . " " . $self->{strActualManifest}); } #################################################################################################################################### # run #################################################################################################################################### sub run { my $self = shift; $self->optionTestSet(CFGOPT_STANZA, $self->stanza()); $self->optionTestSet(CFGOPT_REPO_PATH, $self->{strRepoPath}); $self->optionTestSet(CFGOPT_PG_PATH, $self->{strDbPath}); $self->configTestLoad(CFGCMD_ARCHIVE_PUSH); my $strBackupLabel = backupLabelFormat(CFGOPTVAL_BACKUP_TYPE_FULL, undef, 1482000000); my $strBackupPath = storageRepo->pathGet(STORAGE_REPO_BACKUP . "/${strBackupLabel}"); my $strBackupManifestFile = "$strBackupPath/" . FILE_MANIFEST; my $iDbCatalogVersion = 201409291; my $lTime = time() - 10000; my $strTest = 'test'; my $oManifestBase = new pgBackRest::Common::Ini($self->{strExpectedManifest}, {bLoad => false}); # Section: backup:db $oManifestBase->set(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_DB_VERSION, undef, PG_VERSION_94); # Section: target:path my $hDefault = {}; $oManifestBase->set(MANIFEST_SECTION_TARGET_PATH, MANIFEST_TARGET_PGDATA, undef, $hDefault); $oManifestBase->set(MANIFEST_SECTION_TARGET_PATH, MANIFEST_PATH_GLOBAL, undef, $hDefault); # Section: target:path:default $oManifestBase->set(MANIFEST_SECTION_TARGET_PATH . ":default", MANIFEST_SUBKEY_MODE, undef, MODE_0750); $oManifestBase->set(MANIFEST_SECTION_TARGET_PATH . ":default", MANIFEST_SUBKEY_GROUP, undef, TEST_GROUP); $oManifestBase->set(MANIFEST_SECTION_TARGET_PATH . ":default", MANIFEST_SUBKEY_USER, undef, TEST_USER); # Section backup:target $oManifestBase->set(MANIFEST_SECTION_BACKUP_TARGET, MANIFEST_TARGET_PGDATA, MANIFEST_SUBKEY_TYPE, MANIFEST_VALUE_PATH); $oManifestBase->set(MANIFEST_SECTION_BACKUP_TARGET, MANIFEST_TARGET_PGDATA, MANIFEST_SUBKEY_PATH, $self->{strDbPath}); ################################################################################################################################ if ($self->begin('new()')) { # Missing DB version #--------------------------------------------------------------------------------------------------------------------------- $self->testException(sub {(new pgBackRest::Manifest($strBackupManifestFile, {bLoad => false}))}, ERROR_ASSERT, 'strDbVersion must be provided with bLoad = false'); # Successfully instantiate #--------------------------------------------------------------------------------------------------------------------------- my $oManifest = $self->testResult(sub {(new pgBackRest::Manifest($strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94}))}, "[object]", 'manifest instantiated'); # Initialize #--------------------------------------------------------------------------------------------------------------------------- $self->testResult(sub {$oManifest->test(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_DB_VERSION, undef, PG_VERSION_94) && $oManifest->test(INI_SECTION_BACKREST, INI_KEY_FORMAT, undef, $oManifest->{iInitFormat}) && $oManifest->test(INI_SECTION_BACKREST, INI_KEY_VERSION, undef, $oManifest->{strInitVersion})}, true, ' manifest initialized'); # Attempt to save without proper path #--------------------------------------------------------------------------------------------------------------------------- $self->testException(sub {$oManifest->save()}, ERROR_PATH_MISSING, "unable to open '" . $strBackupManifestFile . "': No such file or directory"); # Create path and save #--------------------------------------------------------------------------------------------------------------------------- storageRepo()->pathCreate($strBackupPath); $self->testResult(sub {$oManifest->save()}, "[undef]", 'manifest saved'); # Load and check the saved file #--------------------------------------------------------------------------------------------------------------------------- my $oBackupManifest = $self->testResult(sub {(new pgBackRest::Manifest($strBackupManifestFile))}, "[object]", ' saved manifest loaded'); $self->testResult(sub {($oManifest->numericGet(INI_SECTION_BACKREST, INI_KEY_FORMAT) == $oBackupManifest->numericGet(INI_SECTION_BACKREST, INI_KEY_FORMAT)) && ($oManifest->get(INI_SECTION_BACKREST, INI_KEY_CHECKSUM) eq $oBackupManifest->get(INI_SECTION_BACKREST, INI_KEY_CHECKSUM))}, true, ' saved manifest equals initial manifest'); } ################################################################################################################################ if ($self->begin('build()')) { my $oManifest = new pgBackRest::Manifest($strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94}); # Build error if offline = true and no tablespace path #--------------------------------------------------------------------------------------------------------------------------- $self->testException(sub {$oManifest->build(storageDb(), $self->{strDbPath}, undef, false)}, ERROR_FILE_MISSING, "unable to stat '" . $self->{strDbPath} . "/" . MANIFEST_TARGET_PGTBLSPC . "': No such file or directory"); # bOnline = true tests - Compare the base manifest #--------------------------------------------------------------------------------------------------------------------------- $oManifest->build(storageDb(), $self->{strDbPath}, undef, true); $self->testResult(sub {$self->manifestCompare($oManifestBase, $oManifest)}, "", 'base manifest'); # Create expected manifest from base my $oManifestExpected = dclone($oManifestBase); # Add global/pg_control file and PG_VERSION file and create a directory with a different modes than default storageDb()->put(storageDb()->openWrite($self->{strDbPath} . '/' . DB_FILE_PGCONTROL, {strMode => MODE_0644, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), $self->controlGenerateContent(PG_VERSION_94)); storageDb()->put(storageDb()->openWrite($self->{strDbPath} . '/' . DB_FILE_PGVERSION, {strMode => MODE_0600, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), PG_VERSION_94); # Create base path with different mode than default storageDb()->pathCreate(DB_PATH_BASE, {strMode => MODE_0700}); # Update expected manifest $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE . ":default", MANIFEST_SUBKEY_MODE, undef, MODE_0600); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE . ":default", MANIFEST_SUBKEY_GROUP, undef, TEST_GROUP); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE . ":default", MANIFEST_SUBKEY_USER, undef, TEST_USER); $oManifestExpected->boolSet(MANIFEST_SECTION_TARGET_FILE . ":default", MANIFEST_SUBKEY_MASTER, undef, true); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_FILE_PGCONTROL, MANIFEST_SUBKEY_SIZE, PGCONTROL_SIZE); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_FILE_PGCONTROL, MANIFEST_SUBKEY_TIMESTAMP, $lTime); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_FILE_PGCONTROL, MANIFEST_SUBKEY_MODE, MODE_0644); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' .DB_FILE_PGVERSION, MANIFEST_SUBKEY_SIZE, length(&PG_VERSION_94)); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' .DB_FILE_PGVERSION, MANIFEST_SUBKEY_TIMESTAMP, $lTime); $oManifestExpected->set(MANIFEST_SECTION_TARGET_PATH, MANIFEST_PATH_BASE, MANIFEST_SUBKEY_MODE, MODE_0700); $oManifest->build(storageDb(), $self->{strDbPath}, undef, true); $self->testResult(sub {$self->manifestCompare($oManifestExpected, $oManifest)}, "", 'paths/files and different modes'); # Master = false #--------------------------------------------------------------------------------------------------------------------------- storageDb()->put(storageDb()->openWrite($self->{strDbPath} . '/' . DB_PATH_BASE . '/' . $strTest, {strMode => MODE_0600, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), $strTest); # Update expected manifest $oManifestExpected->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . DB_PATH_BASE . '/' . $strTest, MANIFEST_SUBKEY_MASTER, undef, false); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . DB_PATH_BASE . '/' . $strTest, MANIFEST_SUBKEY_SIZE, length($strTest)); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . DB_PATH_BASE . '/' . $strTest, MANIFEST_SUBKEY_TIMESTAMP, $lTime); $oManifest->build(storageDb(), $self->{strDbPath}, undef, true); $self->testResult(sub {$self->manifestCompare($oManifestExpected, $oManifest)}, "", 'master false'); # Create a pg_config path and file link my $strConfFile = '/pg_config/postgresql.conf'; my $strConfContent = "listen_addresses = *\n"; storageDb()->pathCreate('pg_config'); storageDb()->put(storageDb()->openWrite($self->{strDbPath} . $strConfFile, {strMode => MODE_0600, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), $strConfContent); # link db/pg_config/postgresql.conf.link -> ./postgresql.conf testLinkCreate($self->{strDbPath} . $strConfFile . '.link', './postgresql.conf'); # INVESTIGATE: on the command line, these links appear to be fine but in the code, a debug line prior to the recursive call to build() produces: # STRPATH BEFORE BUILD: /home/ubuntu/test/test-0/db/base, STRLEVEL PASSED: $VAR1 = 'pg_data/base/pg_config_bad'; # STRFILTER: $VAR1 = undef; # STRPATH BEFORE BUILD: /home/ubuntu/test/test-0/db/pg_config, STRLEVEL PASSED: $VAR1 = 'pg_data/base/pg_config_bad/postgresql.conf.link'; # STRFILTER: $VAR1 = undef; # STRPATH BEFORE BUILD: /home/ubuntu/test/test-0/db/base/base, STRLEVEL PASSED: $VAR1 = 'pg_data/base/postgresql.conf'; # STRFILTER: $VAR1 = undef; # # and right here throws: 'unable to stat '/home/ubuntu/test/test-0/db/base/pg_config/postgresql.conf': No such file or directory' # -- note the extra "base" here - it should just be /home/ubuntu/test/test-0/db/pg_config/postgresql.conf # # link db/base/pg_config_bad -> ../../db/pg_config # testLinkCreate($self->{strDbPath} . '/'. DB_PATH_BASE . '/pg_config_bad', '../../db/pg_config'); # # link db/base/postgresql.conf -> ../pg_config/postgresql.conf # testLinkCreate($self->{strDbPath} . '/'. DB_PATH_BASE . '/postgresql.conf', '..' . $strConfFile); # $self->testException(sub {$oManifest->build(storageDb(), $self->{strDbPath}, undef, true)}, ERROR_LINK_DESTINATION, # 'TEST THIS'); # INVESTIGATE: Even though the below code creates a duplicate link, this error occurs (note the pg_config/pg_config): # 'unable to stat '/home/ubuntu/test/test-0/db/pg_config/pg_config/./postgresql.conf': No such file or directory' # ubuntu@pgbackrest-test:~$ ls -l /home/ubuntu/test/test-0/db/pg_config/ # total 4 # -rw------- 1 ubuntu ubuntu 21 Nov 9 17:07 postgresql.conf # lrwxrwxrwx 1 ubuntu ubuntu 17 Nov 9 19:53 postgresql.conf.bad.link -> ./postgresql.conf # lrwxrwxrwx 1 ubuntu ubuntu 17 Nov 9 19:53 postgresql.conf.link -> ./postgresql.conf # # This link will cause errors because it points to the same location as above # testLinkCreate($self->{strDbPath} . $strConfFile . '.bad.link', './postgresql.conf'); # # $self->testException(sub {$oManifest->build(storageDb(), $self->{strDbPath}, undef, true)}, ERROR_LINK_DESTINATION, # 'TEST ERROR'); # testFileRemove($self->{strDbPath} . $strConfFile . '.link.bad'); # Update expected manifest $oManifestExpected->set(MANIFEST_SECTION_TARGET_PATH, MANIFEST_PATH_BASE, MANIFEST_SUBKEY_MODE, MODE_0700); $oManifestExpected->set(MANIFEST_SECTION_TARGET_PATH, MANIFEST_TARGET_PGDATA . '/pg_config', undef, $hDefault); # Section backup:target $oManifestExpected->set(MANIFEST_SECTION_BACKUP_TARGET, MANIFEST_TARGET_PGDATA . $strConfFile . '.link', MANIFEST_SUBKEY_FILE, 'postgresql.conf'); $oManifestExpected->set(MANIFEST_SECTION_BACKUP_TARGET, MANIFEST_TARGET_PGDATA . $strConfFile . '.link', MANIFEST_SUBKEY_PATH, '.'); $oManifestExpected->set(MANIFEST_SECTION_BACKUP_TARGET, MANIFEST_TARGET_PGDATA . $strConfFile . '.link', MANIFEST_SUBKEY_TYPE, MANIFEST_VALUE_LINK); # Section target:file $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strConfFile, MANIFEST_SUBKEY_SIZE, length($strConfContent)); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strConfFile, MANIFEST_SUBKEY_TIMESTAMP, $lTime); # Section target:link $oManifestExpected->set(MANIFEST_SECTION_TARGET_LINK, MANIFEST_TARGET_PGDATA . $strConfFile . '.link', MANIFEST_SUBKEY_DESTINATION, './postgresql.conf'); # Section target:link:default $oManifestExpected->set(MANIFEST_SECTION_TARGET_LINK . ":default", MANIFEST_SUBKEY_GROUP, undef, TEST_GROUP); $oManifestExpected->set(MANIFEST_SECTION_TARGET_LINK . ":default", MANIFEST_SUBKEY_USER, undef, TEST_USER); $oManifest->build(storageDb(), $self->{strDbPath}, undef, true); $self->testResult(sub {$self->manifestCompare($oManifestExpected, $oManifest)}, "", 'link'); # Test skip files/directories #--------------------------------------------------------------------------------------------------------------------------- # Create files to skip storageDb()->put(storageDb()->openWrite($self->{strDbPath} . '/' . DB_FILE_POSTGRESQLAUTOCONFTMP ), ''); storageDb()->put(storageDb()->openWrite($self->{strDbPath} . '/' . DB_FILE_BACKUPLABELOLD), ''); storageDb()->put(storageDb()->openWrite($self->{strDbPath} . '/' . DB_FILE_POSTMASTEROPTS), ''); storageDb()->put(storageDb()->openWrite($self->{strDbPath} . '/' . DB_FILE_POSTMASTERPID), ''); storageDb()->put(storageDb()->openWrite($self->{strDbPath} . '/' . DB_FILE_RECOVERYCONF), ''); storageDb()->put(storageDb()->openWrite($self->{strDbPath} . '/' . DB_FILE_RECOVERYDONE), ''); # Create directories to skip. Add a bogus file to them for test coverage. storageDb()->pathCreate(DB_FILE_PREFIX_TMP); storageDb()->pathCreate('pg_xlog'); storageDb()->put(storageDb()->openWrite($self->{strDbPath} . '/pg_xlog/' . BOGUS, {strMode => MODE_0644, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), ''); storageDb()->pathCreate(DB_PATH_PGDYNSHMEM); storageDb()->put(storageDb()->openWrite($self->{strDbPath} . '/' . DB_PATH_PGDYNSHMEM . '/' . BOGUS, {strMode => MODE_0600, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), ''); storageDb()->pathCreate(DB_PATH_PGNOTIFY); storageDb()->put(storageDb()->openWrite($self->{strDbPath} . '/' . DB_PATH_PGNOTIFY . '/' . BOGUS, {strMode => MODE_0600, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), ''); storageDb()->pathCreate(DB_PATH_PGREPLSLOT); storageDb()->put(storageDb()->openWrite($self->{strDbPath} . '/' . DB_PATH_PGREPLSLOT . '/' . BOGUS, {strMode => MODE_0600, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), ''); storageDb()->pathCreate(DB_PATH_PGSERIAL); storageDb()->put(storageDb()->openWrite($self->{strDbPath} . '/' . DB_PATH_PGSERIAL . '/' . BOGUS, {strMode => MODE_0600, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), ''); storageDb()->pathCreate(DB_PATH_PGSNAPSHOTS); storageDb()->put(storageDb()->openWrite($self->{strDbPath} . '/' . DB_PATH_PGSNAPSHOTS . '/' . BOGUS, {strMode => MODE_0600, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), ''); storageDb()->pathCreate(DB_PATH_PGSTATTMP); storageDb()->put(storageDb()->openWrite($self->{strDbPath} . '/' . DB_PATH_PGSTATTMP . '/' . BOGUS, {strMode => MODE_0600, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), ''); storageDb()->pathCreate(DB_PATH_PGSUBTRANS); storageDb()->put(storageDb()->openWrite($self->{strDbPath} . '/' . DB_PATH_PGSUBTRANS . '/' . BOGUS, {strMode => MODE_0600, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), ''); storageDb()->pathCreate(DB_FILE_PGINTERNALINIT); # Update expected manifest $oManifestExpected->set(MANIFEST_SECTION_TARGET_PATH, MANIFEST_TARGET_PGDATA . '/pg_xlog', undef, $hDefault); $oManifestExpected->set(MANIFEST_SECTION_TARGET_PATH, MANIFEST_PATH_PGDYNSHMEM, undef, $hDefault); $oManifestExpected->set(MANIFEST_SECTION_TARGET_PATH, MANIFEST_PATH_PGNOTIFY, undef, $hDefault); $oManifestExpected->set(MANIFEST_SECTION_TARGET_PATH, MANIFEST_PATH_PGREPLSLOT, undef, $hDefault); $oManifestExpected->set(MANIFEST_SECTION_TARGET_PATH, MANIFEST_PATH_PGSERIAL, undef, $hDefault); $oManifestExpected->set(MANIFEST_SECTION_TARGET_PATH, MANIFEST_PATH_PGSNAPSHOTS, undef, $hDefault); $oManifestExpected->set(MANIFEST_SECTION_TARGET_PATH, MANIFEST_PATH_PGSTATTMP, undef, $hDefault); $oManifestExpected->set(MANIFEST_SECTION_TARGET_PATH, MANIFEST_PATH_PGSUBTRANS, undef, $hDefault); $oManifest->build(storageDb(), $self->{strDbPath}, undef, true); $self->testResult(sub {$self->manifestCompare($oManifestExpected, $oManifest)}, "", 'skip directories/files'); # Unskip code path coverage #--------------------------------------------------------------------------------------------------------------------------- my $oManifestExpectedUnskip = dclone($oManifestExpected); # Change DB version to 93 $oManifest = new pgBackRest::Manifest($strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_93}); $oManifestExpectedUnskip->set(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_DB_VERSION, undef, PG_VERSION_93); # Update expected manifest $oManifestExpectedUnskip->set(MANIFEST_SECTION_TARGET_FILE . ":default", MANIFEST_SUBKEY_MODE, undef, MODE_0600); $oManifestExpectedUnskip->set(MANIFEST_SECTION_TARGET_FILE . ":default", MANIFEST_SUBKEY_GROUP, undef, TEST_GROUP); $oManifestExpectedUnskip->set(MANIFEST_SECTION_TARGET_FILE . ":default", MANIFEST_SUBKEY_USER, undef, TEST_USER); $oManifestExpectedUnskip->boolSet(MANIFEST_SECTION_TARGET_FILE . ":default", MANIFEST_SUBKEY_MASTER, undef, true); $oManifestExpectedUnskip->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_PATH_PGDYNSHMEM . '/' . BOGUS, MANIFEST_SUBKEY_SIZE, 0); $oManifestExpectedUnskip->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_PATH_PGDYNSHMEM . '/' . BOGUS, MANIFEST_SUBKEY_TIMESTAMP, $lTime); $oManifestExpectedUnskip->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_PATH_PGREPLSLOT . '/' . BOGUS, MANIFEST_SUBKEY_SIZE, 0); $oManifestExpectedUnskip->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_PATH_PGREPLSLOT . '/' . BOGUS, MANIFEST_SUBKEY_TIMESTAMP, $lTime); $oManifest->build(storageDb(), $self->{strDbPath}, undef, true); $self->testResult(sub {$self->manifestCompare($oManifestExpectedUnskip, $oManifest)}, "", 'unskip 94 directories'); # Change DB version to 91 $oManifest = new pgBackRest::Manifest($strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_91}); $oManifestExpectedUnskip->set(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_DB_VERSION, undef, PG_VERSION_91); $oManifestExpectedUnskip->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_PATH_PGSNAPSHOTS . '/' . BOGUS, MANIFEST_SUBKEY_SIZE, 0); $oManifestExpectedUnskip->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_PATH_PGSNAPSHOTS . '/' . BOGUS, MANIFEST_SUBKEY_TIMESTAMP, $lTime); $oManifest->build(storageDb(), $self->{strDbPath}, undef, true); $self->testResult(sub {$self->manifestCompare($oManifestExpectedUnskip, $oManifest)}, "", 'unskip 92 directories'); # Change DB version to 90 $oManifest = new pgBackRest::Manifest($strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_90}); $oManifestExpectedUnskip->set(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_DB_VERSION, undef, PG_VERSION_90); $oManifestExpectedUnskip->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_PATH_PGSERIAL . '/' . BOGUS, MANIFEST_SUBKEY_SIZE, 0); $oManifestExpectedUnskip->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_PATH_PGSERIAL . '/' . BOGUS, MANIFEST_SUBKEY_TIMESTAMP, $lTime); $oManifest->build(storageDb(), $self->{strDbPath}, undef, true); $self->testResult(sub {$self->manifestCompare($oManifestExpectedUnskip, $oManifest)}, "", 'unskip 91 directories'); # Change DB version to 84 $oManifest = new pgBackRest::Manifest($strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_84}); $oManifestExpectedUnskip->set(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_DB_VERSION, undef, PG_VERSION_84); $oManifestExpectedUnskip->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_PATH_PGNOTIFY . '/' . BOGUS, MANIFEST_SUBKEY_SIZE, 0); $oManifestExpectedUnskip->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_PATH_PGNOTIFY . '/' . BOGUS, MANIFEST_SUBKEY_TIMESTAMP, $lTime); $oManifest->build(storageDb(), $self->{strDbPath}, undef, true); $self->testResult(sub {$self->manifestCompare($oManifestExpectedUnskip, $oManifest)}, "", 'unskip 90 directories'); # Change DB version to 83 $oManifest = new pgBackRest::Manifest($strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_83}); $oManifestExpectedUnskip->set(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_DB_VERSION, undef, PG_VERSION_83); $oManifestExpectedUnskip->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_PATH_PGSTATTMP . '/' . BOGUS, MANIFEST_SUBKEY_SIZE, 0); $oManifestExpectedUnskip->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_PATH_PGSTATTMP . '/' . BOGUS, MANIFEST_SUBKEY_TIMESTAMP, $lTime); $oManifest->build(storageDb(), $self->{strDbPath}, undef, true); $self->testResult(sub {$self->manifestCompare($oManifestExpectedUnskip, $oManifest)}, "", 'unskip 84 directories'); # Reset Manifest for next tests $oManifest = new pgBackRest::Manifest($strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94}); $oManifest->build(storageDb(), $self->{strDbPath}, undef, true); $self->testResult(sub {$self->manifestCompare($oManifestExpected, $oManifest)}, "", 'manifest reset'); # Tablespaces #--------------------------------------------------------------------------------------------------------------------------- # Create pg_tblspc path my $strTblSpcPath = $self->{strDbPath} . '/' . DB_PATH_PGTBLSPC; storageDb()->pathCreate($strTblSpcPath, {bCreateParent => true}); # Create a directory in pg_tblspc storageDb()->pathCreate("$strTblSpcPath/" . BOGUS, {strMode => '0700'}); $self->testException(sub {$oManifest->build(storageDb(), $self->{strDbPath}, undef, true)}, ERROR_LINK_EXPECTED, MANIFEST_TARGET_PGTBLSPC . "/" . BOGUS . " is not a symlink - " . DB_PATH_PGTBLSPC . " should contain only symlinks"); testPathRemove("${strTblSpcPath}/" . BOGUS); my $strTblspcId = '99999'; # Invalid relative tablespace is ../ testLinkCreate("${strTblSpcPath}/${strTblspcId}", '../'); $self->testException(sub {$oManifest->build(storageDb(), $self->{strDbPath}, undef, true)}, ERROR_TABLESPACE_IN_PGDATA, 'tablespace symlink ../ destination must not be in $PGDATA'); testFileRemove("${strTblSpcPath}/${strTblspcId}"); # Invalid relative tablespace is .. testLinkCreate("${strTblSpcPath}/${strTblspcId}", '..'); $self->testException(sub {$oManifest->build(storageDb(), $self->{strDbPath}, undef, true)}, ERROR_TABLESPACE_IN_PGDATA, 'tablespace symlink .. destination must not be in $PGDATA'); testFileRemove("${strTblSpcPath}/${strTblspcId}"); # Invalid relative tablespace is ../base - a subdirectory of $PGDATA testLinkCreate("${strTblSpcPath}/${strTblspcId}", '../base'); $self->testException(sub {$oManifest->build(storageDb(), $self->{strDbPath}, undef, true)}, ERROR_TABLESPACE_IN_PGDATA, 'tablespace symlink ../base destination must not be in $PGDATA'); testFileRemove("${strTblSpcPath}/${strTblspcId}"); # Create the catalog key for the tablespace construction $oManifest->set(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_CATALOG, undef, $iDbCatalogVersion); # Invalid absolute tablespace is $self->{strDbPath} . /base # INVESTIGATE: But this should fail because the link points to a directory in pg_data but instead it passes the # index($hManifest->{$strName}{link_destination}, '/') != 0 and then fails later. It WILL fail "destination must not be in # $PGDATA" if an ending slash is added - so maybe the comment in Manifest.pm "# Make sure that DB_PATH_PGTBLSPC contains # only absolute links that do not point inside PGDATA" is not exactly correct? testLinkCreate("${strTblSpcPath}/${strTblspcId}", $self->{strDbPath} . '/base'); $self->testException(sub {$oManifest->build(storageDb(), $self->{strDbPath}, undef, true)}, ERROR_ASSERT, "tablespace with oid ${strTblspcId} not found in tablespace map\n" . "HINT: was a tablespace created or dropped during the backup?"); testFileRemove("${strTblSpcPath}/${strTblspcId}"); # Invalid relative tablespace is ../../BOGUS - which is not in $PGDATA and does not exist testLinkCreate("${strTblSpcPath}/${strTblspcId}", '../../' . BOGUS); $self->testException(sub {$oManifest->build(storageDb(), $self->{strDbPath}, undef, true)}, ERROR_ASSERT, "tablespace with oid ${strTblspcId} not found in tablespace map\n" . "HINT: was a tablespace created or dropped during the backup?"); testFileRemove("${strTblSpcPath}/${strTblspcId}"); # Create tablespace directory outside PGDATA my $strTablespace = 'tablespace'; storageTest()->pathCreate($strTablespace); my $strIntermediateLink = $self->{strDbPath} . "/intermediate_link"; # Create a link to a link testLinkCreate($strIntermediateLink, $self->testPath() . '/' . $strTablespace); testLinkCreate("${strTblSpcPath}/${strTblspcId}", $strIntermediateLink); $self->testException(sub {$oManifest->build(storageDb(), $self->{strDbPath}, undef, false)}, ERROR_LINK_DESTINATION, "link '${strTblSpcPath}/${strTblspcId}' -> '$strIntermediateLink' cannot reference another link"); testFileRemove($self->{strDbPath} . "/intermediate_link"); testFileRemove("${strTblSpcPath}/${strTblspcId}"); # Reload the manifest otherwise it will contain invalid data from the above exception tests $oManifest = new pgBackRest::Manifest($strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94}); # Set the required db catalog version for tablespaces $oManifest->numericSet(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_CATALOG, undef, $iDbCatalogVersion); $oManifestExpected->numericSet(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_CATALOG, undef, $iDbCatalogVersion); # Create a valid symlink pg_tblspc/1 to tablespace/ts1/1 directory my $strTablespaceOid = '1'; my $strTablespaceName = "ts${strTablespaceOid}"; storageTest()->pathCreate("${strTablespace}/${strTablespaceName}/${strTablespaceOid}", {bCreateParent => true}); my $strTablespacePath = storageTest()->pathGet("${strTablespace}/${strTablespaceName}/${strTablespaceOid}"); testLinkCreate("${strTblSpcPath}/${strTablespaceOid}", $strTablespacePath); # Create the tablespace info in expected manifest my $strMfTs = MANIFEST_TARGET_PGTBLSPC . "/" . $strTablespaceOid; $oManifestExpected->set(MANIFEST_SECTION_BACKUP_TARGET, $strMfTs, MANIFEST_SUBKEY_PATH, $strTablespacePath); $oManifestExpected->set(MANIFEST_SECTION_BACKUP_TARGET, $strMfTs, MANIFEST_SUBKEY_TABLESPACE_ID, $strTablespaceOid); $oManifestExpected->set(MANIFEST_SECTION_BACKUP_TARGET, $strMfTs, MANIFEST_SUBKEY_TABLESPACE_NAME, $strTablespaceName); $oManifestExpected->set(MANIFEST_SECTION_BACKUP_TARGET, $strMfTs, MANIFEST_SUBKEY_TYPE, MANIFEST_VALUE_LINK); $oManifestExpected->set(MANIFEST_SECTION_TARGET_LINK, MANIFEST_TARGET_PGDATA . "/${strMfTs}", MANIFEST_SUBKEY_DESTINATION, $strTablespacePath); $oManifestExpected->set(MANIFEST_SECTION_TARGET_PATH, MANIFEST_TARGET_PGTBLSPC, undef, $hDefault); $oManifestExpected->set(MANIFEST_SECTION_TARGET_PATH, MANIFEST_PATH_PGTBLSPC, undef, $hDefault); $oManifestExpected->set(MANIFEST_SECTION_TARGET_PATH, $strMfTs, undef, $hDefault); # In offline mode, do not skip the db WAL path $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_FILE_PGCONTROL, MANIFEST_SUBKEY_MODE, MODE_0644); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/pg_xlog/' . BOGUS, MANIFEST_SUBKEY_MODE, MODE_0644); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/pg_xlog/' . BOGUS, MANIFEST_SUBKEY_SIZE, 0); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/pg_xlog/' . BOGUS, MANIFEST_SUBKEY_TIMESTAMP, $lTime); $oManifest->build(storageDb(), $self->{strDbPath}, undef, false); $self->testResult(sub {$self->manifestCompare($oManifestExpected, $oManifest)}, "", 'offline with valid tablespace - do not skip database WAL directory'); # Create tablespace and database maps my $hTablespaceMap = {}; $hTablespaceMap->{$strTablespaceOid} = $strTablespaceName; my $hDatabaseMap = {}; $hDatabaseMap->{&BOGUS}{&MANIFEST_KEY_DB_ID} = 12345; $hDatabaseMap->{&BOGUS}{&MANIFEST_KEY_DB_LAST_SYSTEM_ID} = 67890; $oManifestExpected->numericSet(MANIFEST_SECTION_DB, BOGUS, MANIFEST_KEY_DB_ID, $hDatabaseMap->{&BOGUS}{&MANIFEST_KEY_DB_ID}); $oManifestExpected->numericSet(MANIFEST_SECTION_DB, BOGUS, MANIFEST_KEY_DB_LAST_SYSTEM_ID, $hDatabaseMap->{&BOGUS}{&MANIFEST_KEY_DB_LAST_SYSTEM_ID}); $oManifest->build(storageDb(), $self->{strDbPath}, undef, false, $hTablespaceMap, $hDatabaseMap); $self->testResult(sub {$self->manifestCompare($oManifestExpected, $oManifest)}, "", 'offline passing tablespace map and database map'); # Reload the manifest with version < 9.0 #--------------------------------------------------------------------------------------------------------------------------- $oManifest = new pgBackRest::Manifest($strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_84}); # Catalog not stored in < 9.0 $oManifestExpected->remove(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_CATALOG); $oManifestExpected->set(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_DB_VERSION, undef, PG_VERSION_84); # Add unskip directories $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_PATH_PGDYNSHMEM . '/' . BOGUS, MANIFEST_SUBKEY_SIZE, 0); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_PATH_PGDYNSHMEM . '/' . BOGUS, MANIFEST_SUBKEY_TIMESTAMP, $lTime); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_PATH_PGREPLSLOT . '/' . BOGUS, MANIFEST_SUBKEY_SIZE, 0); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_PATH_PGREPLSLOT . '/' . BOGUS, MANIFEST_SUBKEY_TIMESTAMP, $lTime); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_PATH_PGSNAPSHOTS . '/' . BOGUS, MANIFEST_SUBKEY_SIZE, 0); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_PATH_PGSNAPSHOTS . '/' . BOGUS, MANIFEST_SUBKEY_TIMESTAMP, $lTime); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_PATH_PGSERIAL . '/' . BOGUS, MANIFEST_SUBKEY_SIZE, 0); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_PATH_PGSERIAL . '/' . BOGUS, MANIFEST_SUBKEY_TIMESTAMP, $lTime); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_PATH_PGNOTIFY . '/' . BOGUS, MANIFEST_SUBKEY_SIZE, 0); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_PATH_PGNOTIFY . '/' . BOGUS, MANIFEST_SUBKEY_TIMESTAMP, $lTime); $oManifest->build(storageDb(), $self->{strDbPath}, undef, false, $hTablespaceMap, $hDatabaseMap); $self->testResult(sub {$self->manifestCompare($oManifestExpected, $oManifest)}, "", 'tablespace with version < 9.0'); # Undefined user/group #--------------------------------------------------------------------------------------------------------------------------- executeTest("sudo chgrp 777 " . $self->{strDbPath} . '/pg_xlog/' . BOGUS); executeTest("sudo chown 777 " . $self->{strDbPath} . '/pg_xlog/' . BOGUS); $oManifestExpected->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/pg_xlog/' . BOGUS, MANIFEST_SUBKEY_GROUP, false); $oManifestExpected->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/pg_xlog/' . BOGUS, MANIFEST_SUBKEY_USER, false); $oManifest->build(storageDb(), $self->{strDbPath}, undef, false); $self->testResult(sub {$self->manifestCompare($oManifestExpected, $oManifest)}, "", 'undefined user/group'); # Reset the group / owner executeTest("sudo chgrp " . TEST_GROUP . " " . $self->{strDbPath} . '/pg_xlog/' . BOGUS); executeTest("sudo chown " . TEST_USER . " " . $self->{strDbPath} . '/pg_xlog/' . BOGUS); } ################################################################################################################################ if ($self->begin('get/set')) { my $oManifest = new pgBackRest::Manifest($strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94}); # SubKey required but has not been set #--------------------------------------------------------------------------------------------------------------------------- $self->testException(sub {$oManifest->boolGet(MANIFEST_SECTION_TARGET_FILE, BOGUS, MANIFEST_SUBKEY_CHECKSUM_PAGE)}, ERROR_ASSERT, "strSection '" . MANIFEST_SECTION_TARGET_FILE . "', strKey '" . BOGUS . "', strSubKey '" . MANIFEST_SUBKEY_CHECKSUM_PAGE . "' is required but not defined"); # SubKey not required and not set #--------------------------------------------------------------------------------------------------------------------------- $self->testResult(sub {$oManifest->boolGet(MANIFEST_SECTION_TARGET_FILE, BOGUS, MANIFEST_SUBKEY_CHECKSUM_PAGE, false)}, false, 'boolGet() - false'); # Set and get a boolean value #--------------------------------------------------------------------------------------------------------------------------- $oManifest->boolSet(MANIFEST_SECTION_TARGET_FILE, BOGUS, MANIFEST_SUBKEY_CHECKSUM_PAGE, true); $self->testResult(sub {$oManifest->boolGet(MANIFEST_SECTION_TARGET_FILE, BOGUS, MANIFEST_SUBKEY_CHECKSUM_PAGE)}, true, 'boolGet() - true'); # Get default boolean value #--------------------------------------------------------------------------------------------------------------------------- $self->testResult(sub {$oManifest->boolGet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_COMPRESS, undef, false, true)}, true, 'boolGet() - default true'); # Get but don't return a default boolean value even if there is supposed to be one #--------------------------------------------------------------------------------------------------------------------------- $self->testResult(sub {$oManifest->boolGet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_COMPRESS, undef, false, false)}, false, 'boolGet() - default false'); # Get default numeric value #--------------------------------------------------------------------------------------------------------------------------- $self->testResult(sub {$oManifest->numericGet(MANIFEST_SECTION_TARGET_FILE, BOGUS, MANIFEST_SUBKEY_SIZE, false, 0)}, 0, 'numericGet() - default 0'); # Coverage for $self->SUPER::get("${strSection}:default" #--------------------------------------------------------------------------------------------------------------------------- $self->testResult(sub {$oManifest->get(MANIFEST_SECTION_TARGET_FILE, BOGUS, MANIFEST_SUBKEY_USER, false)}, "[undef]", 'get() - default section'); # Get the correct path for the control file in the DB #--------------------------------------------------------------------------------------------------------------------------- $oManifest->set(MANIFEST_SECTION_BACKUP_TARGET, MANIFEST_TARGET_PGDATA, MANIFEST_SUBKEY_PATH, $self->{strDbPath}); $self->testResult(sub {$oManifest->dbPathGet($oManifest->get(MANIFEST_SECTION_BACKUP_TARGET, MANIFEST_TARGET_PGDATA, MANIFEST_SUBKEY_PATH), MANIFEST_FILE_PGCONTROL)}, $self->{strDbPath} . "/" . DB_FILE_PGCONTROL, 'dbPathGet() - control file'); # Get filename - no path passed #--------------------------------------------------------------------------------------------------------------------------- $self->testResult(sub {$oManifest->dbPathGet(undef, BOGUS)}, BOGUS, 'dbPathGet() - filename'); # repoPathGet - no tablespace #--------------------------------------------------------------------------------------------------------------------------- $self->testResult(sub {$oManifest->repoPathGet(MANIFEST_TARGET_PGDATA, DB_FILE_PGCONTROL)}, MANIFEST_TARGET_PGDATA . "/" . DB_FILE_PGCONTROL, 'repoPathGet() - pg_control'); # repoPathGet - tablespace - no subpath #--------------------------------------------------------------------------------------------------------------------------- my $strTablespaceId = "1"; my $strTablespace = MANIFEST_TARGET_PGTBLSPC . "/" . $strTablespaceId; my $strTablespaceName = "ts" . $strTablespaceId; $oManifest->set(MANIFEST_SECTION_BACKUP_TARGET, $strTablespace, MANIFEST_SUBKEY_PATH, $self->{strDbPath} . "/tablespace/" . $strTablespaceName); $self->testResult(sub {$oManifest->repoPathGet($strTablespace)}, $strTablespace, 'repoPathGet() - tablespace - no tablepace-id nor subpath'); # repoPathGet - fully qualified tablespace target #--------------------------------------------------------------------------------------------------------------------------- # Set the catalog for the DB since that is what is expected to be returned $oManifest->numericSet(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_CATALOG, undef, $iDbCatalogVersion); $self->testResult(sub {$oManifest->tablespacePathGet()}, "PG_" . PG_VERSION_94 . "_" . $iDbCatalogVersion, 'tablespacePathGet()'); $oManifest->set(MANIFEST_SECTION_BACKUP_TARGET, $strTablespace, MANIFEST_SUBKEY_TABLESPACE_ID, $strTablespaceId); $oManifest->set(MANIFEST_SECTION_BACKUP_TARGET, $strTablespace, MANIFEST_SUBKEY_TABLESPACE_NAME, $strTablespaceName); $oManifest->set(MANIFEST_SECTION_BACKUP_TARGET, $strTablespace, MANIFEST_SUBKEY_TYPE, MANIFEST_VALUE_LINK); $self->testResult(sub {$oManifest->repoPathGet($strTablespace, BOGUS)}, $strTablespace . "/PG_" . PG_VERSION_94 . "_" . $iDbCatalogVersion . "/" . BOGUS, 'repoPathGet() - tablespace valid with subpath'); # Set the DB version to < 9.0 - there is no special sudirectory in earlier PG versions $oManifest->set(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_DB_VERSION, undef, PG_VERSION_84); $self->testResult(sub {$oManifest->repoPathGet($strTablespace, BOGUS)}, $strTablespace . "/" . BOGUS, 'repoPathGet() - tablespace in 8.4 valid with subpath'); $oManifest->set(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_DB_VERSION, undef, PG_VERSION_94); # isTargetLink #--------------------------------------------------------------------------------------------------------------------------- $self->testResult(sub {$oManifest->isTargetLink(MANIFEST_TARGET_PGDATA)}, false, "isTargetLink - false"); $self->testResult(sub {$oManifest->isTargetLink($strTablespace)}, true, "isTargetLink - true"); # isTargetLink #--------------------------------------------------------------------------------------------------------------------------- $self->testResult(sub {$oManifest->isTargetFile(MANIFEST_TARGET_PGDATA)}, false, "isTargetFile - false"); $oManifest->set(MANIFEST_SECTION_BACKUP_TARGET, MANIFEST_TARGET_PGDATA, MANIFEST_SUBKEY_FILE, BOGUS); $self->testResult(sub {$oManifest->isTargetFile(MANIFEST_TARGET_PGDATA)}, true, "isTargetFile - true"); } ################################################################################################################################ if ($self->begin('isTarget - exceptions')) { my $oManifest = new pgBackRest::Manifest($strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94}); # Target not defined #--------------------------------------------------------------------------------------------------------------------------- $self->testException(sub {$oManifest->isTargetValid()}, ERROR_ASSERT, 'target is not defined'); $self->testException(sub {$oManifest->isTargetFile()}, ERROR_ASSERT, 'target is not defined'); $self->testException(sub {$oManifest->isTargetLink()}, ERROR_ASSERT, 'target is not defined'); $self->testException(sub {$oManifest->isTargetTablespace()}, ERROR_ASSERT, 'target is not defined'); # Target not valid #--------------------------------------------------------------------------------------------------------------------------- $self->testException(sub {$oManifest->isTargetValid(BOGUS, true)}, ERROR_ASSERT, BOGUS . ' is not a valid target'); $self->testResult(sub {$oManifest->isTargetValid(BOGUS, false)}, false, 'isTargetValid - bError = false, return false'); $self->testResult(sub {$oManifest->isTargetValid(BOGUS)}, false, 'isTargetValid - bError = undef, false'); } ################################################################################################################################ if ($self->begin('dbVerion(), xactPath(), walPath()')) { # dbVersion, xactPath and walPath - PG < 10 #--------------------------------------------------------------------------------------------------------------------------- my $oManifest = new pgBackRest::Manifest($strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94}); $self->testResult(sub {$oManifest->dbVersion()}, PG_VERSION_94, 'dbVersion < 10'); $self->testResult(sub {$oManifest->xactPath()}, 'pg_clog', ' xactPath - pg_clog'); $self->testResult(sub {$oManifest->walPath()}, 'pg_xlog', ' walPath - pg_xlog'); # dbVersion, xactPath and walPath - PG >= 10 #--------------------------------------------------------------------------------------------------------------------------- $oManifest = new pgBackRest::Manifest($strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_10}); $self->testResult(sub {$oManifest->dbVersion()}, PG_VERSION_10, 'dbVersion >= 10'); $self->testResult(sub {$oManifest->xactPath()}, 'pg_xact', ' xactPath - pg_xact'); $self->testResult(sub {$oManifest->walPath()}, 'pg_wal', ' walPath - pg_wal'); } ################################################################################################################################ if ($self->begin('validate()')) { my $oManifest = new pgBackRest::Manifest($strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94}); # Set a target:file with only a timestamp - fail size not set #--------------------------------------------------------------------------------------------------------------------------- $oManifest->numericSet(MANIFEST_SECTION_TARGET_FILE, BOGUS, MANIFEST_SUBKEY_TIMESTAMP, 1509384645); $self->testException(sub {$oManifest->validate()}, ERROR_ASSERT, "manifest subvalue 'size' not set for file '" . BOGUS . "'"); # Set target:file size - fail checksum not set #--------------------------------------------------------------------------------------------------------------------------- $oManifest->numericSet(MANIFEST_SECTION_TARGET_FILE, BOGUS, MANIFEST_SUBKEY_SIZE, 1); $self->testException(sub {$oManifest->validate()}, ERROR_ASSERT, "manifest subvalue 'checksum' not set for file '" . BOGUS . "'"); # Set target:file checksum - validate passes when size > 0 and checksum set #--------------------------------------------------------------------------------------------------------------------------- $oManifest->numericSet(MANIFEST_SECTION_TARGET_FILE, BOGUS, MANIFEST_SUBKEY_CHECKSUM, 0); $self->testResult(sub {$oManifest->validate()}, "[undef]", 'manifest validated - size 1, checksum 0'); # Set target:file size to 0 - validate passes when size 0 #--------------------------------------------------------------------------------------------------------------------------- $oManifest->numericSet(MANIFEST_SECTION_TARGET_FILE, BOGUS, MANIFEST_SUBKEY_SIZE, 0); $self->testResult(sub {$oManifest->validate()}, "[undef]", 'manifest validated - size 0'); } ################################################################################################################################ if ($self->begin('future file and last manifest')) { my $oManifest = new pgBackRest::Manifest($strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94}); # Create expected manifest from base my $oManifestExpected = dclone($oManifestBase); # Future timestamp on file #--------------------------------------------------------------------------------------------------------------------------- storageDb()->put(storageDb()->openWrite($self->{strDbPath} . '/' . $strTest, {strMode => MODE_0600, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime + 20000}), $strTest); # Update expected manifest $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE . ":default", MANIFEST_SUBKEY_MODE, undef, MODE_0600); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE . ":default", MANIFEST_SUBKEY_GROUP, undef, TEST_GROUP); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE . ":default", MANIFEST_SUBKEY_USER, undef, TEST_USER); $oManifestExpected->boolSet(MANIFEST_SECTION_TARGET_FILE . ":default", MANIFEST_SUBKEY_MASTER, undef, true); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTest, MANIFEST_SUBKEY_SIZE, length($strTest)); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTest, MANIFEST_SUBKEY_TIMESTAMP, $lTime + 20000); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTest, MANIFEST_SUBKEY_FUTURE, 'y'); $self->testResult(sub {$oManifest->build(storageDb(), $self->{strDbPath}, undef, true)}, "[undef]", 'future timestamp warning', {strLogExpect => "WARN: some files have timestamps in the future - they will be copied to prevent possible race conditions"}); $self->testResult(sub {$self->manifestCompare($oManifestExpected, $oManifest)}, "", 'manifest future subkey=y'); # Future timestamp in last manifest #--------------------------------------------------------------------------------------------------------------------------- my $oLastManifest = dclone($oManifestExpected); # Set a backup label $oLastManifest->set(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_LABEL, undef, BOGUS); $oManifestExpected->set(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_PRIOR, undef, BOGUS); # Remove the file and recreate it without it being in the future storageTest()->remove($self->{strDbPath} . '/' . $strTest); storageDb()->put(storageDb()->openWrite($self->{strDbPath} . '/' . $strTest, {strMode => MODE_0600, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), $strTest); # Remove the future subkey from the expected manifest and reset the timestamp $oManifestExpected->remove(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTest, MANIFEST_SUBKEY_FUTURE); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTest, MANIFEST_SUBKEY_TIMESTAMP, $lTime); # Create a new manifest $oManifest = new pgBackRest::Manifest($strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94}); $self->testResult(sub {$oManifest->build(storageDb(), $self->{strDbPath}, $oLastManifest, true)}, "[undef]", 'last manifest future timestamp warning', {strLogExpect => "WARN: some files have timestamps in the future - they will be copied to prevent possible race conditions"}); $self->testResult(sub {$self->manifestCompare($oManifestExpected, $oManifest)}, "", 'last manifest future subkey=y, new manifest future subkey removed'); # File info in last manifest same as current #--------------------------------------------------------------------------------------------------------------------------- $oLastManifest->remove(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTest, MANIFEST_SUBKEY_FUTURE); $oLastManifest->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTest, MANIFEST_SUBKEY_TIMESTAMP, $lTime); # Update reference in expected manifest $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTest, MANIFEST_SUBKEY_REFERENCE, BOGUS); # Check reference $oManifest->build(storageDb(), $self->{strDbPath}, $oLastManifest, true); $self->testResult(sub {$self->manifestCompare($oManifestExpected, $oManifest)}, "", 'reference set to prior backup label'); # Create a new file reference my $strTestNew = $strTest . 'new'; storageDb()->put(storageDb()->openWrite($self->{strDbPath} . '/' . $strTestNew, {strMode => MODE_0600, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), $strTestNew); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTestNew, MANIFEST_SUBKEY_SIZE, length($strTestNew)); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTestNew, MANIFEST_SUBKEY_TIMESTAMP, $lTime); $oLastManifest->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTestNew, MANIFEST_SUBKEY_SIZE, length($strTestNew)); $oLastManifest->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTestNew, MANIFEST_SUBKEY_TIMESTAMP, $lTime); # Set a reference, checksum, repo size, master and page checksum in the last manifest my $strCheckSum = '1234567890'; my $lRepoSize = 10000; $oLastManifest->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTestNew, MANIFEST_SUBKEY_REFERENCE, BOGUS . BOGUS); $oLastManifest->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTestNew, MANIFEST_SUBKEY_CHECKSUM, $strCheckSum); $oLastManifest->numericSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTestNew, MANIFEST_SUBKEY_REPO_SIZE, $lRepoSize); $oLastManifest->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTestNew, MANIFEST_SUBKEY_MASTER, false); $oLastManifest->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTestNew, MANIFEST_SUBKEY_CHECKSUM_PAGE, true); # Update expected manifest $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTestNew, MANIFEST_SUBKEY_REFERENCE, BOGUS . BOGUS); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTestNew, MANIFEST_SUBKEY_CHECKSUM, $strCheckSum); $oManifestExpected->numericSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTestNew, MANIFEST_SUBKEY_REPO_SIZE, $lRepoSize); $oManifestExpected->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTestNew, MANIFEST_SUBKEY_CHECKSUM_PAGE, true); # Default "master" is flipping because it's not something we read from disk $oManifestExpected->boolSet(MANIFEST_SECTION_TARGET_FILE . ":default", MANIFEST_SUBKEY_MASTER, undef, false); $oManifestExpected->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTest, MANIFEST_SUBKEY_MASTER, true); $oManifest->build(storageDb(), $self->{strDbPath}, $oLastManifest, true); $self->testResult(sub {$self->manifestCompare($oManifestExpected, $oManifest)}, "", 'updates from last manifest'); # MANIFEST_SUBKEY_CHECKSUM_PAGE = false and MANIFEST_SUBKEY_CHECKSUM_PAGE_ERROR set/not set #--------------------------------------------------------------------------------------------------------------------------- $oLastManifest->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTestNew, MANIFEST_SUBKEY_CHECKSUM_PAGE, false); $oManifestExpected->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTestNew, MANIFEST_SUBKEY_CHECKSUM_PAGE, false); $oManifest->build(storageDb(), $self->{strDbPath}, $oLastManifest, true); $self->testResult(sub {$self->manifestCompare($oManifestExpected, $oManifest)}, "", 'checksum-page false, checksum-page-error not set'); my @iyChecksumPageError = (1); $oLastManifest->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTestNew, MANIFEST_SUBKEY_CHECKSUM_PAGE_ERROR, \@iyChecksumPageError); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTestNew, MANIFEST_SUBKEY_CHECKSUM_PAGE_ERROR, \@iyChecksumPageError); $oManifest->build(storageDb(), $self->{strDbPath}, $oLastManifest, true); $self->testResult(sub {$self->manifestCompare($oManifestExpected, $oManifest)}, "", 'checksum-page false, checksum-page-error set'); } ################################################################################################################################ if ($self->begin('fileAdd()')) { my $oManifest = new pgBackRest::Manifest($strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94}); my $oManifestExpected = dclone($oManifestBase); $oManifest->build(storageDb(), $self->{strDbPath}, undef, true); # Add a file after building manifest my $lTimeTest = $lTime + 10; storageDb()->put(storageDb()->openWrite($self->{strDbPath} . '/' . $strTest, {strMode => MODE_0644, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTimeTest}), $strTest); $oManifest->fileAdd($strTest, $lTimeTest, 0, 0, true); # Update expected manifest $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, $strTest, MANIFEST_SUBKEY_MODE, MODE_0600); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, $strTest, MANIFEST_SUBKEY_USER, TEST_USER); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, $strTest, MANIFEST_SUBKEY_GROUP, TEST_GROUP); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, $strTest, MANIFEST_SUBKEY_TIMESTAMP, $lTimeTest); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, $strTest, MANIFEST_SUBKEY_SIZE, 0); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, $strTest, MANIFEST_SUBKEY_CHECKSUM, 0); $oManifestExpected->boolSet(MANIFEST_SECTION_TARGET_FILE, $strTest, MANIFEST_SUBKEY_MASTER, true); $self->testResult(sub {$self->manifestCompare($oManifestExpected, $oManifest)}, "", 'file added to manifest'); # Remove the file user, mode and group from the actual and expected manifest $oManifestExpected->remove(MANIFEST_SECTION_TARGET_FILE, $strTest, MANIFEST_SUBKEY_MODE); $oManifestExpected->remove(MANIFEST_SECTION_TARGET_FILE, $strTest, MANIFEST_SUBKEY_USER); $oManifestExpected->remove(MANIFEST_SECTION_TARGET_FILE, $strTest, MANIFEST_SUBKEY_GROUP); $oManifest->remove(MANIFEST_SECTION_TARGET_FILE, $strTest, MANIFEST_SUBKEY_MODE); $oManifest->remove(MANIFEST_SECTION_TARGET_FILE, $strTest, MANIFEST_SUBKEY_USER); $oManifest->remove(MANIFEST_SECTION_TARGET_FILE, $strTest, MANIFEST_SUBKEY_GROUP); # Add a target:file:default section to the manifests with a mode other than 0600 $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE . ":default", MANIFEST_SUBKEY_MODE, undef, MODE_0750); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE . ":default", MANIFEST_SUBKEY_GROUP, undef, TEST_GROUP); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE . ":default", MANIFEST_SUBKEY_USER, undef, TEST_USER); $oManifest->set(MANIFEST_SECTION_TARGET_FILE . ":default", MANIFEST_SUBKEY_MODE, undef, MODE_0750); $oManifest->set(MANIFEST_SECTION_TARGET_FILE . ":default", MANIFEST_SUBKEY_GROUP, undef, TEST_GROUP); $oManifest->set(MANIFEST_SECTION_TARGET_FILE . ":default", MANIFEST_SUBKEY_USER, undef, TEST_USER); # Set the expected mode to 0600 $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, $strTest, MANIFEST_SUBKEY_MODE, MODE_0600); $oManifest->fileAdd($strTest, $lTimeTest, 0, 0, true); $self->testResult(sub {$self->manifestCompare($oManifestExpected, $oManifest)}, "", 'file added to manifest - file:default values set'); # Remove the file mode from the manifests and change the default so it need not be set for the file $oManifest->remove(MANIFEST_SECTION_TARGET_FILE, $strTest, MANIFEST_SUBKEY_MODE); $oManifest->set(MANIFEST_SECTION_TARGET_FILE . ":default", MANIFEST_SUBKEY_MODE, undef, MODE_0600); $oManifestExpected->remove(MANIFEST_SECTION_TARGET_FILE, $strTest, MANIFEST_SUBKEY_MODE); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE . ":default", MANIFEST_SUBKEY_MODE, undef, MODE_0600); $oManifest->fileAdd($strTest, $lTimeTest, 0, 0, true); $self->testResult(sub {$self->manifestCompare($oManifestExpected, $oManifest)}, "", 'file added to manifest - default mode set 0600'); } ################################################################################################################################ if ($self->begin('isChecksumPage()')) { my $strFile = BOGUS; $self->testResult(sub {isChecksumPage($strFile)}, false, "file '${strFile}' isChecksumPage=false"); $strFile = MANIFEST_TARGET_PGDATA . '/' . DB_PATH_BASE . '/' . DB_FILE_PGVERSION; $self->testResult(sub {isChecksumPage($strFile)}, false, "file '${strFile}' isChecksumPage=false"); $strFile = MANIFEST_TARGET_PGDATA . '/' . DB_PATH_BASE . '/' . DB_FILE_PGINTERNALINIT; $self->testResult(sub {isChecksumPage($strFile)}, false, "file '${strFile}' isChecksumPage=false"); $strFile = MANIFEST_TARGET_PGDATA . '/' . DB_PATH_BASE. '/' . DB_FILE_PGFILENODEMAP; $self->testResult(sub {isChecksumPage($strFile)}, false, "file '${strFile}' isChecksumPage=false"); $strFile = MANIFEST_TARGET_PGTBLSPC . '/' . DB_FILE_PGFILENODEMAP; $self->testResult(sub {isChecksumPage($strFile)}, false, "file '${strFile}' isChecksumPage=false"); $strFile = MANIFEST_TARGET_PGTBLSPC . '/' . DB_FILE_PGINTERNALINIT; $self->testResult(sub {isChecksumPage($strFile)}, false, "file '${strFile}' isChecksumPage=false"); $strFile = MANIFEST_TARGET_PGTBLSPC . '/' . DB_FILE_PGVERSION; $self->testResult(sub {isChecksumPage($strFile)}, false, "file '${strFile}' isChecksumPage=false"); $strFile = MANIFEST_TARGET_PGDATA . '/' . DB_PATH_GLOBAL. '/' . DB_FILE_PGFILENODEMAP; $self->testResult(sub {isChecksumPage($strFile)}, false, "file '${strFile}' isChecksumPage=false"); $strFile = MANIFEST_TARGET_PGDATA . '/' . DB_PATH_GLOBAL. '/' . DB_FILE_PGINTERNALINIT; $self->testResult(sub {isChecksumPage($strFile)}, false, "file '${strFile}' isChecksumPage=false"); $strFile = MANIFEST_TARGET_PGDATA . '/' . DB_PATH_GLOBAL. '/' . DB_FILE_PGVERSION; $self->testResult(sub {isChecksumPage($strFile)}, false, "file '${strFile}' isChecksumPage=false"); $strFile = MANIFEST_TARGET_PGDATA . '/' . DB_PATH_GLOBAL. '/' . DB_FILE_PGCONTROL; $self->testResult(sub {isChecksumPage($strFile)}, false, "file '${strFile}' isChecksumPage=false"); $strFile = MANIFEST_TARGET_PGDATA . '/' . DB_FILE_PGCONTROL; $self->testResult(sub {isChecksumPage($strFile)}, false, "file '${strFile}' isChecksumPage=false"); $strFile = MANIFEST_TARGET_PGDATA . '/' . DB_PATH_BASE . '/' . BOGUS; $self->testResult(sub {isChecksumPage($strFile)}, true, "file '${strFile}' isChecksumPage=true"); $strFile = MANIFEST_TARGET_PGDATA . '/' . DB_PATH_GLOBAL . '/' . BOGUS; $self->testResult(sub {isChecksumPage($strFile)}, true, "file '${strFile}' isChecksumPage=true"); } } 1;