#################################################################################################################################### # 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 $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); $oManifestBase->numericSet(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_CATALOG, undef, $self->dbCatalogVersion(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 and DB Catalog version #--------------------------------------------------------------------------------------------------------------------------- $self->testException(sub {(new pgBackRest::Manifest($strBackupManifestFile, {bLoad => false}))}, ERROR_ASSERT, 'strDbVersion and iDbCatalogVersion must be provided with bLoad = false'); # Missing DB version #--------------------------------------------------------------------------------------------------------------------------- $self->testException(sub {(new pgBackRest::Manifest($strBackupManifestFile, {bLoad => false, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_94)}))}, ERROR_ASSERT, 'strDbVersion and iDbCatalogVersion must be provided with bLoad = false'); # Missing DB Catalog version #--------------------------------------------------------------------------------------------------------------------------- $self->testException(sub {(new pgBackRest::Manifest($strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94}))}, ERROR_ASSERT, 'strDbVersion and iDbCatalogVersion must be provided with bLoad = false'); # Successfully instantiate #--------------------------------------------------------------------------------------------------------------------------- my $oManifest = $self->testResult(sub {(new pgBackRest::Manifest($strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94, iDbCatalogVersion => $self->dbCatalogVersion(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, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_94)}); # Build error if offline = true and no tablespace path #--------------------------------------------------------------------------------------------------------------------------- $self->testException(sub {$oManifest->build(storageDb(), $self->{strDbPath}, undef, false, false)}, ERROR_FILE_MISSING, "unable to stat '" . $self->{strDbPath} . "/" . MANIFEST_TARGET_PGTBLSPC . "': No such file or directory"); # bOnline = true tests #--------------------------------------------------------------------------------------------------------------------------- $oManifest = new pgBackRest::Manifest( $strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_94)}); # 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 = new pgBackRest::Manifest( $strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_94)}); $oManifest->build(storageDb(), $self->{strDbPath}, undef, true, false); $self->testResult(sub {$self->manifestCompare($oManifestExpected, $oManifest)}, "", 'paths/files and different modes'); $self->testException( sub {$oManifest->build(storageDb(), $self->{strDbPath}, undef, true, false)}, ERROR_ASSERT, 'manifest has already been built'); # Master = false (what can be copied from a standby vs the master) #--------------------------------------------------------------------------------------------------------------------------- my $strOidFile = '11111'; storageDb()->put(storageDb()->openWrite($self->{strDbPath} . '/' . DB_PATH_BASE . '/' . $strOidFile, {strMode => MODE_0600, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), $strOidFile); # Update expected manifest $oManifestExpected->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . DB_PATH_BASE . '/' . $strOidFile, MANIFEST_SUBKEY_MASTER, undef, false); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . DB_PATH_BASE . '/' . $strOidFile, MANIFEST_SUBKEY_SIZE, length($strOidFile)); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . DB_PATH_BASE . '/' . $strOidFile, MANIFEST_SUBKEY_TIMESTAMP, $lTime); $oManifest = new pgBackRest::Manifest( $strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_94)}); $oManifest->build(storageDb(), $self->{strDbPath}, undef, true, false); $self->testResult(sub {$self->manifestCompare($oManifestExpected, $oManifest)}, "", 'master false'); # Create pg_config path and postgresql.conf file my $strConfFile = '/postgresql.conf'; my $strConfContent = "listen_addresses = *\n"; storageTest()->pathCreate('pg_config'); storageTest()->put(storageTest()->openWrite($self->testPath() . '/pg_config' . $strConfFile, {strMode => MODE_0600, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), $strConfContent); # link db/postgresql.conf -> pg_config/postgresql.conf testLinkCreate($self->{strDbPath} . $strConfFile, $self->testPath() . '/pg_config' . $strConfFile); # 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); # Section backup:target $oManifestExpected->set( MANIFEST_SECTION_BACKUP_TARGET, MANIFEST_TARGET_PGDATA . $strConfFile, MANIFEST_SUBKEY_FILE, 'postgresql.conf'); $oManifestExpected->set( MANIFEST_SECTION_BACKUP_TARGET, MANIFEST_TARGET_PGDATA . $strConfFile, MANIFEST_SUBKEY_PATH, $self->testPath() . '/pg_config'); $oManifestExpected->set( MANIFEST_SECTION_BACKUP_TARGET, MANIFEST_TARGET_PGDATA . $strConfFile, 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 . '/postgresql.conf', MANIFEST_SUBKEY_TIMESTAMP, $lTime); # Section target:link $oManifestExpected->set(MANIFEST_SECTION_TARGET_LINK, MANIFEST_TARGET_PGDATA . '/postgresql.conf', MANIFEST_SUBKEY_DESTINATION, $self->testPath() . '/pg_config' . $strConfFile); # 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); # Create an unreadable file and path in pg_config to test that we are only reading the files we need to executeTest( "sudo touch " . $self->testPath() . "/pg_config/do_not_read.txt" . " && sudo mkdir -m 700 " . $self->testPath() . "/pg_config/do_not_read"); $oManifest = new pgBackRest::Manifest( $strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_94)}); $oManifest->build(storageDb(), $self->{strDbPath}, undef, true, false); $self->testResult(sub {$self->manifestCompare($oManifestExpected, $oManifest)}, "", 'link'); # Create a link loop and expect an error #--------------------------------------------------------------------------------------------------------------------------- testLinkCreate($self->{strDbPath} . '/pgdata', $self->{strDbPath}); $oManifest = new pgBackRest::Manifest( $strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_94)}); $self->testException( sub {$oManifest->build(storageDb(), $self->{strDbPath}, undef, true, false)}, ERROR_FORMAT, 'recursion in manifest build exceeds depth of 16: pg_data/pgdata/pgdata/pgdata/pgdata/pgdata/pgdata/pgdata/pgdata/' . "pgdata/pgdata/pgdata/pgdata/pgdata/pgdata/pgdata/pgdata\n" . 'HINT: is there a link loop in $PGDATA?'); testFileRemove($self->{strDbPath} . '/pgdata'); # 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 temp table files in a data directory - these will be skipped my $strDbDataDirBasePath = "/" . DB_PATH_BASE . "/12134"; my $strDbDataDir = $self->{strDbPath} . $strDbDataDirBasePath; storageDb()->pathCreate($strDbDataDir); my $strTempFileOid = '/t123_456'; storageDb()->put(storageDb()->openWrite($strDbDataDir . $strTempFileOid, {strMode => MODE_0600, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), ''); storageDb()->put(storageDb()->openWrite($strDbDataDir . $strTempFileOid . '.1', {strMode => MODE_0600, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), ''); storageDb()->put(storageDb()->openWrite($strDbDataDir . $strTempFileOid . '_fsm', {strMode => MODE_0600, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), ''); storageDb()->put(storageDb()->openWrite($strDbDataDir . $strTempFileOid . '_vm.12', {strMode => MODE_0600, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), ''); # Create unlogged files to skip my $strUnlogFileOid = '/12345'; my $strUnlogFile = $strDbDataDir . $strUnlogFileOid; storageDb()->put(storageDb()->openWrite($strUnlogFile . '_init', {strMode => MODE_0600, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), ''); # will not be skipped storageDb()->put(storageDb()->openWrite($strUnlogFile . '_init.1', {strMode => MODE_0600, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), ''); # will not be skipped storageDb()->put(storageDb()->openWrite($strUnlogFile . '_vm.1_vm', {strMode => MODE_0600, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), ''); # will not be skipped storageDb()->put(storageDb()->openWrite($strUnlogFile, {strMode => MODE_0600, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), ''); storageDb()->put(storageDb()->openWrite($strUnlogFile . '.11', {strMode => MODE_0600, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), ''); storageDb()->put(storageDb()->openWrite($strUnlogFile . '_fsm.1', {strMode => MODE_0600, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), ''); storageDb()->put(storageDb()->openWrite($strUnlogFile . '_vm', {strMode => MODE_0600, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), ''); # Create an OID file and instead of OID_init file create a directory - the OID file and directory will NOT be skipped my $strNotUnlogFileOid = '/54321'; my $strNotUnlogFile = $strDbDataDir . $strNotUnlogFileOid; storageDb()->put(storageDb()->openWrite($strNotUnlogFile, {strMode => MODE_0600, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), ''); storageDb()->pathCreate($strNotUnlogFile . '_init'); # Create a temp-looking file not in the database directory - this will not be skipped my $strTempNoSkip = '/' . DB_PATH_BASE . '/t111_111'; storageDb()->put(storageDb()->openWrite($self->{strDbPath} . $strTempNoSkip, {strMode => MODE_0600, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), ''); # 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 with files and paths that will not be skipped $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); $oManifestExpected->set(MANIFEST_SECTION_TARGET_PATH, MANIFEST_TARGET_PGDATA . $strDbDataDirBasePath, undef, $hDefault); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strTempNoSkip, MANIFEST_SUBKEY_SIZE, 0); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strTempNoSkip, MANIFEST_SUBKEY_TIMESTAMP, $lTime); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strDbDataDirBasePath . $strUnlogFileOid . '_init', MANIFEST_SUBKEY_SIZE, 0); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strDbDataDirBasePath . $strUnlogFileOid . '_init', MANIFEST_SUBKEY_TIMESTAMP, $lTime); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strDbDataDirBasePath . $strUnlogFileOid . '_init.1', MANIFEST_SUBKEY_SIZE, 0); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strDbDataDirBasePath . $strUnlogFileOid . '_init.1', MANIFEST_SUBKEY_TIMESTAMP, $lTime); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strDbDataDirBasePath . $strUnlogFileOid . '_vm.1_vm', MANIFEST_SUBKEY_SIZE, 0); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strDbDataDirBasePath . $strUnlogFileOid . '_vm.1_vm', MANIFEST_SUBKEY_TIMESTAMP, $lTime); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strDbDataDirBasePath . $strNotUnlogFileOid, MANIFEST_SUBKEY_SIZE, 0); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strDbDataDirBasePath . $strNotUnlogFileOid, MANIFEST_SUBKEY_TIMESTAMP, $lTime); $oManifestExpected->set(MANIFEST_SECTION_TARGET_PATH, MANIFEST_TARGET_PGDATA . $strDbDataDirBasePath . $strNotUnlogFileOid . '_init', undef, $hDefault); # The number of files that can be retrieved from the standby has increased so default for [target:file:default] "master" # setting is now expected to be false and the files that must be copied from the master will individually change to true $oManifestExpected->boolSet(MANIFEST_SECTION_TARGET_FILE . ":default", MANIFEST_SUBKEY_MASTER, undef, false); $oManifestExpected->remove(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . "/" . DB_PATH_BASE . "/" . $strOidFile, MANIFEST_SUBKEY_MASTER); $oManifestExpected->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . DB_FILE_PGVERSION, MANIFEST_SUBKEY_MASTER, true); $oManifestExpected->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strConfFile, MANIFEST_SUBKEY_MASTER, true); $oManifestExpected->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_FILE_PGCONTROL, MANIFEST_SUBKEY_MASTER, true); $oManifest = new pgBackRest::Manifest( $strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_94)}); $oManifest->build(storageDb(), $self->{strDbPath}, undef, true, false); $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, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_93)}); $oManifestExpectedUnskip->set(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_DB_VERSION, undef, PG_VERSION_93); $oManifestExpectedUnskip->numericSet(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_CATALOG, undef, $self->dbCatalogVersion(PG_VERSION_93)); # Update expected manifest $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->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_PATH_PGDYNSHMEM . '/' . BOGUS, MANIFEST_SUBKEY_MASTER, true); $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); $oManifestExpectedUnskip->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_PATH_PGREPLSLOT . '/' . BOGUS, MANIFEST_SUBKEY_MASTER, true); $oManifest = new pgBackRest::Manifest( $strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_93, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_93)}); $oManifest->build(storageDb(), $self->{strDbPath}, undef, true, false); $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, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_91)}); $oManifestExpectedUnskip->set(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_DB_VERSION, undef, PG_VERSION_91); $oManifestExpectedUnskip->numericSet(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_CATALOG, undef, $self->dbCatalogVersion(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); $oManifestExpectedUnskip->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_PATH_PGSNAPSHOTS . '/' . BOGUS, MANIFEST_SUBKEY_MASTER, true); $oManifest = new pgBackRest::Manifest( $strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_91, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_91)}); $oManifest->build(storageDb(), $self->{strDbPath}, undef, true, false); $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, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_90)}); $oManifestExpectedUnskip->set(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_DB_VERSION, undef, PG_VERSION_90); $oManifestExpectedUnskip->numericSet(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_CATALOG, undef, $self->dbCatalogVersion(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); # Any file that has a pattern for unlogged tables will not be skipped. $oManifestExpectedUnskip->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strDbDataDirBasePath . $strUnlogFileOid, MANIFEST_SUBKEY_SIZE, 0); $oManifestExpectedUnskip->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strDbDataDirBasePath . $strUnlogFileOid, MANIFEST_SUBKEY_TIMESTAMP, $lTime); $oManifestExpectedUnskip->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strDbDataDirBasePath . $strUnlogFileOid . '.11', MANIFEST_SUBKEY_SIZE, 0); $oManifestExpectedUnskip->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strDbDataDirBasePath . $strUnlogFileOid . '.11', MANIFEST_SUBKEY_TIMESTAMP, $lTime); $oManifestExpectedUnskip->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strDbDataDirBasePath . $strUnlogFileOid . '_fsm.1', MANIFEST_SUBKEY_SIZE, 0); $oManifestExpectedUnskip->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strDbDataDirBasePath . $strUnlogFileOid . '_fsm.1', MANIFEST_SUBKEY_TIMESTAMP, $lTime); $oManifestExpectedUnskip->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strDbDataDirBasePath . $strUnlogFileOid . '_vm', MANIFEST_SUBKEY_SIZE, 0); $oManifestExpectedUnskip->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strDbDataDirBasePath . $strUnlogFileOid . '_vm', MANIFEST_SUBKEY_TIMESTAMP, $lTime); # The number of files that can be retrieved from the standby has increased so default for [target:file:default] "master" # setting is now expected to be false and the files that must be copied from the master will individually change to true $oManifestExpectedUnskip->boolSet(MANIFEST_SECTION_TARGET_FILE . ":default", MANIFEST_SUBKEY_MASTER, undef, false); $oManifestExpectedUnskip->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . "/" . DB_FILE_PGVERSION, MANIFEST_SUBKEY_MASTER, true); $oManifestExpectedUnskip->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_FILE_PGCONTROL, MANIFEST_SUBKEY_MASTER, true); $oManifestExpectedUnskip->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strConfFile, MANIFEST_SUBKEY_MASTER, true); $oManifestExpectedUnskip->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_PATH_PGDYNSHMEM . '/' . BOGUS, MANIFEST_SUBKEY_MASTER, true); $oManifestExpectedUnskip->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_PATH_PGREPLSLOT . '/' . BOGUS, MANIFEST_SUBKEY_MASTER, true); $oManifestExpectedUnskip->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_PATH_PGSNAPSHOTS . '/' . BOGUS, MANIFEST_SUBKEY_MASTER, true); $oManifestExpectedUnskip->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_PATH_PGSERIAL . '/' . BOGUS, MANIFEST_SUBKEY_MASTER, true); $oManifestExpectedUnskip->remove(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . DB_PATH_BASE . '/' . $strOidFile, MANIFEST_SUBKEY_MASTER); $oManifestExpectedUnskip->remove(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strDbDataDirBasePath . $strUnlogFileOid . '_init', MANIFEST_SUBKEY_MASTER); $oManifestExpectedUnskip->remove(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strDbDataDirBasePath . $strUnlogFileOid . '_init.1', MANIFEST_SUBKEY_MASTER); $oManifestExpectedUnskip->remove(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strDbDataDirBasePath . $strUnlogFileOid . '_vm.1_vm', MANIFEST_SUBKEY_MASTER); $oManifestExpectedUnskip->remove(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strTempNoSkip, MANIFEST_SUBKEY_MASTER); $oManifest = new pgBackRest::Manifest( $strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_90, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_90)}); $oManifest->build(storageDb(), $self->{strDbPath}, undef, true, false); $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, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_84)}); $oManifestExpectedUnskip->set(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_DB_VERSION, undef, PG_VERSION_84); $oManifestExpectedUnskip->numericSet(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_CATALOG, undef, $self->dbCatalogVersion(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); $oManifestExpectedUnskip->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_PATH_PGNOTIFY . '/' . BOGUS, MANIFEST_SUBKEY_MASTER, true); # Files that look like "temp" object files will no longer be skipped $oManifestExpectedUnskip->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strDbDataDirBasePath . $strTempFileOid, MANIFEST_SUBKEY_SIZE, 0); $oManifestExpectedUnskip->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strDbDataDirBasePath . $strTempFileOid, MANIFEST_SUBKEY_TIMESTAMP, $lTime); $oManifestExpectedUnskip->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strDbDataDirBasePath . $strTempFileOid . '.1', MANIFEST_SUBKEY_SIZE, 0); $oManifestExpectedUnskip->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strDbDataDirBasePath . $strTempFileOid . '.1', MANIFEST_SUBKEY_TIMESTAMP, $lTime); $oManifestExpectedUnskip->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strDbDataDirBasePath . $strTempFileOid . '_fsm', MANIFEST_SUBKEY_SIZE, 0); $oManifestExpectedUnskip->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strDbDataDirBasePath . $strTempFileOid . '_fsm', MANIFEST_SUBKEY_TIMESTAMP, $lTime); $oManifestExpectedUnskip->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strDbDataDirBasePath . $strTempFileOid . '_vm.12', MANIFEST_SUBKEY_SIZE, 0); $oManifestExpectedUnskip->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strDbDataDirBasePath . $strTempFileOid . '_vm.12', MANIFEST_SUBKEY_TIMESTAMP, $lTime); $oManifest = new pgBackRest::Manifest( $strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_84, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_84)}); $oManifest->build(storageDb(), $self->{strDbPath}, undef, true, false); $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, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_83)}); $oManifestExpectedUnskip->set(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_DB_VERSION, undef, PG_VERSION_83); $oManifestExpectedUnskip->numericSet(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_CATALOG, undef, $self->dbCatalogVersion(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); $oManifestExpectedUnskip->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_PATH_PGSTATTMP . '/' . BOGUS, MANIFEST_SUBKEY_MASTER, true); $oManifest = new pgBackRest::Manifest( $strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_83, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_83)}); $oManifest->build(storageDb(), $self->{strDbPath}, undef, true, false); $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, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_94)}); # Remove files and expect manifest entries not necessary for the rest of the tests testPathRemove($strDbDataDir); $oManifestExpected->remove(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strDbDataDirBasePath . $strUnlogFileOid . '_init.1'); $oManifestExpected->remove(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strDbDataDirBasePath . $strUnlogFileOid . '_init'); $oManifestExpected->remove(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strDbDataDirBasePath . $strUnlogFileOid . '_vm.1_vm'); $oManifestExpected->remove(MANIFEST_SECTION_TARGET_PATH, MANIFEST_TARGET_PGDATA . $strDbDataDirBasePath); $oManifestExpected->boolSet(MANIFEST_SECTION_TARGET_FILE . ":default", MANIFEST_SUBKEY_MASTER, undef, true); $oManifestExpected->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . DB_PATH_BASE . '/' . $strOidFile, MANIFEST_SUBKEY_MASTER, false); $oManifestExpected->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strTempNoSkip, MANIFEST_SUBKEY_MASTER, false); $oManifestExpected->remove(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . "/" . DB_FILE_PGVERSION, MANIFEST_SUBKEY_MASTER); $oManifestExpected->remove(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strConfFile, MANIFEST_SUBKEY_MASTER); $oManifestExpected->remove(MANIFEST_SECTION_TARGET_FILE, MANIFEST_FILE_PGCONTROL, MANIFEST_SUBKEY_MASTER); $oManifestExpected->remove(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strDbDataDirBasePath . $strNotUnlogFileOid); $oManifestExpected->remove(MANIFEST_SECTION_TARGET_PATH, MANIFEST_TARGET_PGDATA . $strDbDataDirBasePath . $strNotUnlogFileOid . '_init'); $oManifest = new pgBackRest::Manifest( $strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_94)}); $oManifest->build(storageDb(), $self->{strDbPath}, undef, true, false); $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'}); $oManifest = new pgBackRest::Manifest( $strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_94)}); $self->testException(sub {$oManifest->build(storageDb(), $self->{strDbPath}, undef, true, false)}, 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}", '../'); $oManifest = new pgBackRest::Manifest( $strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_94)}); $self->testException(sub {$oManifest->build(storageDb(), $self->{strDbPath}, undef, true, false)}, ERROR_TABLESPACE_IN_PGDATA, 'tablespace symlink ../ destination must not be in $PGDATA'); testFileRemove("${strTblSpcPath}/${strTblspcId}"); # Invalid relative tablespace is .. testLinkCreate("${strTblSpcPath}/${strTblspcId}", '..'); $oManifest = new pgBackRest::Manifest( $strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_94)}); $self->testException(sub {$oManifest->build(storageDb(), $self->{strDbPath}, undef, true, false)}, 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'); $oManifest = new pgBackRest::Manifest( $strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_94)}); $self->testException(sub {$oManifest->build(storageDb(), $self->{strDbPath}, undef, true, false)}, ERROR_TABLESPACE_IN_PGDATA, 'tablespace symlink ../base destination must not be in $PGDATA'); testFileRemove("${strTblSpcPath}/${strTblspcId}"); # Invalid absolute tablespace is $self->{strDbPath} . /base testLinkCreate("${strTblSpcPath}/${strTblspcId}", $self->{strDbPath} . '/base'); $oManifest = new pgBackRest::Manifest( $strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_94)}); $self->testException( sub {$oManifest->build(storageDb(), $self->{strDbPath}, undef, true, false)}, ERROR_TABLESPACE_IN_PGDATA, "tablespace symlink $self->{strDbPath}/base destination must not be in \$PGDATA"); testFileRemove("${strTblSpcPath}/${strTblspcId}"); # Invalid relative tablespace is ../../BOGUS - which is not in $PGDATA and does not exist testLinkCreate("${strTblSpcPath}/${strTblspcId}", '../../' . BOGUS); $oManifest = new pgBackRest::Manifest( $strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_94)}); $self->testException(sub {$oManifest->build(storageDb(), $self->{strDbPath}, undef, true, false)}, 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->testPath() . "/intermediate_link"; # Create a link to a link testLinkCreate($strIntermediateLink, $self->testPath() . '/' . $strTablespace); testLinkCreate("${strTblSpcPath}/${strTblspcId}", $strIntermediateLink); $oManifest = new pgBackRest::Manifest( $strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_94)}); $self->testException(sub {$oManifest->build(storageDb(), $self->{strDbPath}, undef, false, false)}, ERROR_LINK_DESTINATION, "link '${strTblSpcPath}/${strTblspcId}' -> '$strIntermediateLink' cannot reference another link"); testFileRemove($strIntermediateLink); 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, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_94)}); # 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 directory PG would create when the sql CREATE TABLESPACE is run my $strTblspcVersion = 'PG_9.4_201409291'; my $strTblspcDir = $strTblspcVersion . '/11'; storageTest()->pathCreate("$strTablespacePath/$strTblspcDir", {bCreateParent => true}); # Create a file and path that will error if read executeTest("sudo touch ${strTablespacePath}/do_not_read.txt && sudo mkdir -m 700 ${strTablespacePath}/do_not_read"); # Create unlogged and temp files storageDb()->put(storageDb()->openWrite($strTablespacePath . '/' . $strTblspcDir . $strUnlogFileOid . '_init', {strMode => MODE_0600, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), ''); storageDb()->put(storageDb()->openWrite($strTablespacePath . '/' . $strTblspcDir . $strUnlogFileOid, {strMode => MODE_0600, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), ''); storageDb()->put(storageDb()->openWrite($strTablespacePath . '/' . $strTblspcDir . $strTempFileOid, {strMode => MODE_0600, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), ''); storageDb()->put(storageDb()->openWrite($strTablespacePath . '/' . $strTblspcDir . '/' . $strOidFile, {strMode => MODE_0600, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), ''); # The number of files that can be retrieved from the standby has increased so default for [target:file:default] "master" # setting is now expected to be false and the files that must be copied from the master will individually change to true $oManifestExpected->boolSet(MANIFEST_SECTION_TARGET_FILE . ":default", MANIFEST_SUBKEY_MASTER, undef, false); $oManifestExpected->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . DB_FILE_PGVERSION, MANIFEST_SUBKEY_MASTER, true); $oManifestExpected->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strConfFile, MANIFEST_SUBKEY_MASTER, true); $oManifestExpected->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_FILE_PGCONTROL, MANIFEST_SUBKEY_MASTER, true); $oManifestExpected->remove(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . "/" . DB_PATH_BASE . "/" . $strOidFile, MANIFEST_SUBKEY_MASTER); $oManifestExpected->remove(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strTempNoSkip, MANIFEST_SUBKEY_MASTER); # 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); $oManifestExpected->set(MANIFEST_SECTION_TARGET_PATH, $strMfTs . '/' . $strTblspcVersion, undef, $hDefault); $oManifestExpected->set(MANIFEST_SECTION_TARGET_PATH, $strMfTs . '/' . $strTblspcDir, undef, $hDefault); # Don't skip unlog init file or normal oid files $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, $strMfTs . '/' . $strTblspcDir . $strUnlogFileOid . '_init', MANIFEST_SUBKEY_SIZE, 0); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, $strMfTs . '/' . $strTblspcDir . $strUnlogFileOid . '_init', MANIFEST_SUBKEY_TIMESTAMP, $lTime); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, $strMfTs . '/' . $strTblspcDir . '/' . $strOidFile, MANIFEST_SUBKEY_SIZE, 0); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, $strMfTs . '/' . $strTblspcDir . '/' . $strOidFile, MANIFEST_SUBKEY_TIMESTAMP, $lTime); # 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); $oManifestExpected->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/pg_xlog/' . BOGUS, MANIFEST_SUBKEY_MASTER, true); $oManifest = new pgBackRest::Manifest( $strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_94)}); $oManifest->build(storageDb(), $self->{strDbPath}, undef, false, false); $self->testResult(sub {$self->manifestCompare($oManifestExpected, $oManifest)}, "", 'offline with valid tablespace - do not skip database WAL directory and only copy unlogged init file'); # 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 = new pgBackRest::Manifest( $strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_94)}); $oManifest->build(storageDb(), $self->{strDbPath}, undef, false, false, $hTablespaceMap, $hDatabaseMap); $self->testResult(sub {$self->manifestCompare($oManifestExpected, $oManifest)}, "", 'offline passing tablespace map and database map'); # Remove the unreadable file and path because they will not work with tests for PG < 9.0 executeTest("sudo rm ${strTablespacePath}/do_not_read.txt && sudo rmdir ${strTablespacePath}/do_not_read"); # Exclusions #--------------------------------------------------------------------------------------------------------------------------- # Excluded links storageDb()->linkCreate('/dev/null', 'postgresql.auto.conf'); storageDb()->linkCreate('/etc/hosts', 'hosts'); # Exclude log files but not directory storageDb()->pathCreate('pg_log'); storageDb()->put(storageDb()->openWrite('pg_log/logfile'), 'EXCLUDE'); $oManifestExpected->set(MANIFEST_SECTION_TARGET_PATH, MANIFEST_TARGET_PGDATA . '/pg_log', undef, $hDefault); # Exclude directory and all contents storageDb()->pathCreate('global/exclude'); storageDb()->put(storageDb()->openWrite('global/exclude/exclude.txt'), 'EXCLUDE'); # Test exclusions against the ideal manifest $oManifest = new pgBackRest::Manifest( $strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_94)}); $oManifest->build( storageDb(), $self->{strDbPath}, undef, false, false, $hTablespaceMap, $hDatabaseMap, {'postgresql.auto.conf' => true, 'hosts' => true, 'pg_log/' => true, 'global/exclude' => true}); $self->testResult(sub {$self->manifestCompare($oManifestExpected, $oManifest)}, "", 'check exclusions'); # Remove excluded files so we don't have to pass exclusions to the rest of the tests storageDb()->remove('postgresql.auto.conf'); storageDb()->remove('hosts'); storageDb()->remove('pg_log/logfile'); storageDb()->remove('global/exclude', {bRecurse => true}); # Reload the manifest with version < 9.0 #--------------------------------------------------------------------------------------------------------------------------- $oManifest = new pgBackRest::Manifest( $strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_84, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_84)}); # Catalog not stored in < 9.0 $oManifestExpected->set(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_DB_VERSION, undef, PG_VERSION_84); $oManifestExpected->numericSet(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_CATALOG, undef, $self->dbCatalogVersion(PG_VERSION_84)); # The number of files that can be retrieved from the standby has been superseded so [target:file:default] "master" # setting is now expected to be true and the files that must be copied from the master will individually change to false $oManifestExpected->boolSet(MANIFEST_SECTION_TARGET_FILE . ":default", MANIFEST_SUBKEY_MASTER, undef, true); $oManifestExpected->remove(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . "/" . DB_FILE_PGVERSION, MANIFEST_SUBKEY_MASTER); $oManifestExpected->remove(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strConfFile, MANIFEST_SUBKEY_MASTER); $oManifestExpected->remove(MANIFEST_SECTION_TARGET_FILE, MANIFEST_FILE_PGCONTROL, MANIFEST_SUBKEY_MASTER); $oManifestExpected->remove(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/pg_xlog/' . BOGUS, MANIFEST_SUBKEY_MASTER); $oManifestExpected->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . DB_PATH_BASE . '/' . $strOidFile, MANIFEST_SUBKEY_MASTER, false); $oManifestExpected->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . $strTempNoSkip, MANIFEST_SUBKEY_MASTER, false); $oManifestExpected->boolSet(MANIFEST_SECTION_TARGET_FILE, $strMfTs . '/' . $strTblspcDir . $strUnlogFileOid . '_init', MANIFEST_SUBKEY_MASTER, false); $oManifestExpected->boolSet(MANIFEST_SECTION_TARGET_FILE, $strMfTs . '/' . $strTblspcDir . '/' . $strOidFile, MANIFEST_SUBKEY_MASTER, false); # 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); # Add unskip of temp and unlog file patterns $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, $strMfTs . '/' . $strTblspcDir . $strUnlogFileOid, MANIFEST_SUBKEY_SIZE, 0); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, $strMfTs . '/' . $strTblspcDir . $strUnlogFileOid, MANIFEST_SUBKEY_TIMESTAMP, $lTime); $oManifestExpected->boolSet(MANIFEST_SECTION_TARGET_FILE, $strMfTs . '/' . $strTblspcDir . $strUnlogFileOid, MANIFEST_SUBKEY_MASTER, false); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, $strMfTs . '/' . $strTblspcDir . $strTempFileOid, MANIFEST_SUBKEY_SIZE, 0); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, $strMfTs . '/' . $strTblspcDir . $strTempFileOid, MANIFEST_SUBKEY_TIMESTAMP, $lTime); $oManifestExpected->boolSet(MANIFEST_SECTION_TARGET_FILE, $strMfTs . '/' . $strTblspcDir . $strTempFileOid, MANIFEST_SUBKEY_MASTER, false); $oManifest->build(storageDb(), $self->{strDbPath}, undef, false, false, $hTablespaceMap, $hDatabaseMap); $self->testResult(sub {$self->manifestCompare($oManifestExpected, $oManifest)}, "", 'tablespace with version < 9.0'); $oManifestExpected->remove(MANIFEST_SECTION_DB); # 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 = new pgBackRest::Manifest( $strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_84, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_84)}); $oManifest->build(storageDb(), $self->{strDbPath}, undef, false, 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, iDbCatalogVersion => $self->dbCatalogVersion(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 #--------------------------------------------------------------------------------------------------------------------------- $self->testResult(sub {$oManifest->tablespacePathGet()}, "PG_" . PG_VERSION_94 . "_" . $self->dbCatalogVersion(PG_VERSION_94), '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 . "_" . $self->dbCatalogVersion(PG_VERSION_94) . "/" . 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, iDbCatalogVersion => $self->dbCatalogVersion(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, iDbCatalogVersion => $self->dbCatalogVersion(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, iDbCatalogVersion => $self->dbCatalogVersion(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, iDbCatalogVersion => $self->dbCatalogVersion(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, iDbCatalogVersion => $self->dbCatalogVersion(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, false)}, true, 'future timestamp warning, enable delta checksum', {strLogExpect => "WARN: file " . MANIFEST_TARGET_PGDATA . "/$strTest has timestamp in the future, enabling delta checksum\n" . "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, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_94)}); # Last manifest is passed with online option=false, but passing true as current online status to invoke warning delta # being enabled $oLastManifest->boolSet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_ONLINE, undef, false); $self->testResult(sub {$oManifest->build(storageDb(), $self->{strDbPath}, $oLastManifest, true, false)}, true, 'last manifest future timestamp warning - delta enabled for online mismatch', {strLogExpect => "WARN: the online option has changed since the last backup, enabling delta checksum\n" . "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'); # Set online in last manifest to avoid delta warning being displayed in the rest of the tests $oLastManifest->boolSet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_ONLINE, undef, true); # 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); $oLastManifest->boolSet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_ONLINE, undef, true); # Update reference in expected manifest $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTest, MANIFEST_SUBKEY_REFERENCE, BOGUS); # Check reference $oManifest = new pgBackRest::Manifest( $strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_94)}); $self->testResult(sub {$oManifest->build(storageDb(), $self->{strDbPath}, $oLastManifest, true, false)}, false, 'delta is not enabled'); $self->testResult(sub {$self->manifestCompare($oManifestExpected, $oManifest)}, "", ' reference set to prior backup label'); # Zero-sized file and size of file changed but timestamp did not #--------------------------------------------------------------------------------------------------------------------------- # Create a new file reference and a zero-sized file reference my $strTestNew = $strTest . 'new'; my $strZeroFile = 'zero-file'; storageDb()->put(storageDb()->openWrite($self->{strDbPath} . '/' . $strTestNew, {strMode => MODE_0600, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), $strTestNew); storageDb()->put(storageDb()->openWrite($self->{strDbPath} . '/' . $strZeroFile, {strMode => MODE_0600, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), ''); # Change the size on a file storageDb()->put(storageDb()->openWrite($self->{strDbPath} . '/' . $strTest, {strMode => MODE_0600, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), $strTest . 'more'); # 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_SIZE, length($strTestNew)); $oLastManifest->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_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); $oLastManifest->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strZeroFile, MANIFEST_SUBKEY_SIZE, 0); $oLastManifest->numericSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strZeroFile, MANIFEST_SUBKEY_REPO_SIZE, $lRepoSize); $oLastManifest->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strZeroFile, MANIFEST_SUBKEY_MASTER, false); $oLastManifest->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strZeroFile, MANIFEST_SUBKEY_CHECKSUM_PAGE, true); # Update expected manifest $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); $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); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strZeroFile, MANIFEST_SUBKEY_SIZE, 0); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strZeroFile, MANIFEST_SUBKEY_TIMESTAMP, $lTime); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strZeroFile, MANIFEST_SUBKEY_REFERENCE, BOGUS); $oManifestExpected->numericSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strZeroFile, MANIFEST_SUBKEY_REPO_SIZE, $lRepoSize); $oManifestExpected->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strZeroFile, MANIFEST_SUBKEY_CHECKSUM_PAGE, true); # Remove the reference for strTest since the size has changed $oManifestExpected->remove(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTest, MANIFEST_SUBKEY_REFERENCE); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTest, MANIFEST_SUBKEY_SIZE, length($strTest . 'more')); # 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 = new pgBackRest::Manifest( $strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_94)}); $self->testResult(sub {$oManifest->build(storageDb(), $self->{strDbPath}, $oLastManifest, true, false)}, true, 'timestamp same, contents different, delta is enabled', {strLogExpect => "WARN: file " . MANIFEST_TARGET_PGDATA . "/$strTest timestamp in the past or size changed but timestamp did not, enabling delta checksum"}); $self->testResult(sub {$self->manifestCompare($oManifestExpected, $oManifest)}, "", ' updates from last manifest'); # new timestamp less than last manifest timestamp for referenced file #--------------------------------------------------------------------------------------------------------------------------- $oLastManifest->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTest, MANIFEST_SUBKEY_TIMESTAMP, $lTime + 100); $oManifestExpected->remove(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTest, MANIFEST_SUBKEY_REFERENCE); $oManifest = new pgBackRest::Manifest( $strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_94)}); $self->testResult(sub {$oManifest->build(storageDb(), $self->{strDbPath}, $oLastManifest, true, false)}, true, 'time in past, delta enabled', {strLogExpect => "WARN: file " . MANIFEST_TARGET_PGDATA . "/$strTest timestamp in the past or size changed but timestamp did not, enabling delta checksum"}); $self->testResult(sub {$self->manifestCompare($oManifestExpected, $oManifest)}, "", ' manifest compare'); # Reset the timestamp $oLastManifest->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTest, MANIFEST_SUBKEY_TIMESTAMP, $lTime + 0); # Timestamp in the lastManifest is different than built manifest (size and content the same) #--------------------------------------------------------------------------------------------------------------------------- # pass delta=true - expected manifest will use the timestamp set for the file on disk ($lTime) $oLastManifest->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTestNew, MANIFEST_SUBKEY_TIMESTAMP, $lTime - 10); $oLastManifest->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strZeroFile, MANIFEST_SUBKEY_TIMESTAMP, $lTime - 10); # Add a file not in the last manifest storageDb()->put(storageDb()->openWrite($self->{strDbPath} . '/' . $strTest . '2', {strMode => MODE_0600, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), $strTest); # Update expected manifest $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTest . '2', MANIFEST_SUBKEY_SIZE, length($strTest)); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTest . '2', MANIFEST_SUBKEY_TIMESTAMP, $lTime + 0); $oManifestExpected->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTest . '2', MANIFEST_SUBKEY_MASTER, true); $oManifest = new pgBackRest::Manifest( $strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_94)}); $oManifest->build(storageDb(), $self->{strDbPath}, $oLastManifest, true, true); $self->testResult(sub {$self->manifestCompare($oManifestExpected, $oManifest)}, "", 'delta true, size same, timestamp different'); # With different timestamp in last manifest pass delta=false - the references to the prior backup will be removed for the # non-zero file but the zero file will still have a reference $oManifestExpected->remove(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTestNew, MANIFEST_SUBKEY_REFERENCE); $oManifestExpected->remove(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTestNew, MANIFEST_SUBKEY_CHECKSUM); $oManifestExpected->remove(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTestNew, MANIFEST_SUBKEY_REPO_SIZE); $oManifestExpected->remove(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTestNew, MANIFEST_SUBKEY_CHECKSUM_PAGE); # Update the size in the last manifest to match the current and add the reference to the expected manifest $oLastManifest->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTest, MANIFEST_SUBKEY_SIZE, length($strTest . 'more')); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTest, MANIFEST_SUBKEY_REFERENCE, BOGUS); # Default "master" is flipping because it's not something we read from disk $oManifestExpected->boolSet(MANIFEST_SECTION_TARGET_FILE . ":default", MANIFEST_SUBKEY_MASTER, undef, true); $oManifestExpected->remove(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTest, MANIFEST_SUBKEY_MASTER); $oManifestExpected->remove(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strTest . '2', MANIFEST_SUBKEY_MASTER); $oManifestExpected->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strZeroFile, MANIFEST_SUBKEY_MASTER, false); $oManifest = new pgBackRest::Manifest( $strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_94)}); $oManifest->build(storageDb(), $self->{strDbPath}, $oLastManifest, true, false); $self->testResult(sub {$self->manifestCompare($oManifestExpected, $oManifest)}, "", 'delta false, size same, timestamp different'); # MANIFEST_SUBKEY_CHECKSUM_PAGE = false and MANIFEST_SUBKEY_CHECKSUM_PAGE_ERROR set/not set from last manifest #--------------------------------------------------------------------------------------------------------------------------- $oLastManifest->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strZeroFile, MANIFEST_SUBKEY_CHECKSUM_PAGE, false); $oManifestExpected->boolSet(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strZeroFile, MANIFEST_SUBKEY_CHECKSUM_PAGE, false); $oManifest = new pgBackRest::Manifest( $strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_94)}); $oManifest->build(storageDb(), $self->{strDbPath}, $oLastManifest, true, false); $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 . '/' . $strZeroFile, MANIFEST_SUBKEY_CHECKSUM_PAGE_ERROR, \@iyChecksumPageError); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . $strZeroFile, MANIFEST_SUBKEY_CHECKSUM_PAGE_ERROR, \@iyChecksumPageError); $oManifest = new pgBackRest::Manifest( $strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_94)}); $oManifest->build(storageDb(), $self->{strDbPath}, $oLastManifest, true, false); $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, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_94)}); my $oManifestExpected = dclone($oManifestBase); # Add a bogus file - all traces to be removed after the manifest has been built to simulate an inital manifest and avoid # missing files error storageDb()->put(storageDb()->openWrite($self->{strDbPath} . '/' . BOGUS, {strMode => MODE_0750, strUser => TEST_USER, strGroup => TEST_GROUP, lTimestamp => $lTime}), ''); $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); $oManifestExpected->boolSet(MANIFEST_SECTION_TARGET_FILE . ":default", MANIFEST_SUBKEY_MASTER, undef, true); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . BOGUS, MANIFEST_SUBKEY_SIZE, 0); $oManifestExpected->set(MANIFEST_SECTION_TARGET_FILE, MANIFEST_TARGET_PGDATA . '/' . BOGUS, MANIFEST_SUBKEY_TIMESTAMP, $lTime); $oManifest->build(storageDb(), $self->{strDbPath}, undef, true, false); # Remove the initial file and reset the manifest portions relating to the file for the following tests storageDb()->remove($self->{strDbPath} . '/' . BOGUS); $oManifestExpected->remove(MANIFEST_SECTION_TARGET_FILE); $oManifestExpected->remove(MANIFEST_SECTION_TARGET_FILE . ":default"); $oManifest->remove(MANIFEST_SECTION_TARGET_FILE); $oManifest->remove(MANIFEST_SECTION_TARGET_FILE . ":default"); $self->testResult(sub {$self->manifestCompare($oManifestExpected, $oManifest)}, "", 'build initial manifest'); # 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"); } ################################################################################################################################ if ($self->begin('checkDelta()')) { my $oManifest = new pgBackRest::Manifest($strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_94)}); $self->testResult(sub {$oManifest->checkDelta('test', false, "000000010000000000000000", "000000020000000000000000")}, true, "timeline switch, delta enabled", {strLogExpect => "WARN: a timeline switch has occurred since the test backup, enabling delta checksum"}); $self->testResult(sub {$oManifest->checkDelta('last', false, "000000010000000000000000", "000000010000000000000000")}, true, "online option changed, delta enabled", {strLogExpect => "WARN: the online option has changed since the last backup, enabling delta checksum"}); $self->testResult(sub {$oManifest->checkDelta('test', true, "000000010000000000000000", undef)}, false, "no last timeline, online same, delta not enabled"); $self->testResult(sub {$oManifest->checkDelta('test', false, undef, "000000010000000000000000")}, true, "no current timeline, online not same, delta enabled"); $self->testResult(sub {$oManifest->checkDelta('test', true, undef, undef)}, false, "no timelines, online same, delta not enabled"); } ################################################################################################################################ if ($self->begin('checkDeltaFile()')) { # Additional tests to cover checkDeltaFile not covered by build tests my $oManifest = new pgBackRest::Manifest($strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_94)}); my $strFile = MANIFEST_TARGET_PGDATA . '/' . BOGUS; my @stryFileList = ($strFile . '1'); push(@stryFileList, $strFile); $self->testResult(sub {$oManifest->checkDeltaFile(\@stryFileList, undef, undef)}, false, "no prior manifest, no time begin, delta not enabled"); my $oManifestPrior = new pgBackRest::Manifest($strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_94)}); $oManifest->numericSet(MANIFEST_SECTION_TARGET_FILE, $strFile . '1', MANIFEST_SUBKEY_TIMESTAMP, $lTime); $oManifest->numericSet(MANIFEST_SECTION_TARGET_FILE, $strFile . '1', MANIFEST_SUBKEY_SIZE, 0); $oManifest->numericSet(MANIFEST_SECTION_TARGET_FILE, $strFile, MANIFEST_SUBKEY_TIMESTAMP, $lTime); $oManifest->numericSet(MANIFEST_SECTION_TARGET_FILE, $strFile, MANIFEST_SUBKEY_SIZE, 0); $oManifestPrior->numericSet(MANIFEST_SECTION_TARGET_FILE, $strFile . '1', MANIFEST_SUBKEY_TIMESTAMP, $lTime); $oManifestPrior->numericSet(MANIFEST_SECTION_TARGET_FILE, $strFile . '1', MANIFEST_SUBKEY_SIZE, 0); $oManifestPrior->numericSet(MANIFEST_SECTION_TARGET_FILE, $strFile, MANIFEST_SUBKEY_TIMESTAMP, $lTime); $oManifestPrior->numericSet(MANIFEST_SECTION_TARGET_FILE, $strFile, MANIFEST_SUBKEY_SIZE, 0); $oManifestPrior->set(MANIFEST_SECTION_TARGET_FILE, $strFile, MANIFEST_SUBKEY_FUTURE, 'y'); $self->testResult(sub {$oManifest->checkDeltaFile(\@stryFileList, $oManifestPrior, $lTime)}, true, "prior manifest, time begin same, prior future is set, delta enabled", {strLogExpect => "WARN: file $strFile has timestamp in the future, enabling delta checksum"}); $oManifestPrior->remove(MANIFEST_SECTION_TARGET_FILE, $strFile, MANIFEST_SUBKEY_FUTURE); $self->testResult(sub {$oManifest->checkDeltaFile(\@stryFileList, $oManifestPrior)}, false, "simulate aborted manifest, delta not enabled"); } } 1;