/*********************************************************************************************************************************** Test Verify Command ***********************************************************************************************************************************/ #include "common/io/bufferRead.h" #include "postgres/interface.h" #include "postgres/version.h" #include "storage/posix/storage.h" #include "common/harnessConfig.h" #include "common/harnessInfo.h" #include "common/harnessPostgres.h" #include "common/harnessPq.h" #include "common/harnessProtocol.h" /*********************************************************************************************************************************** Test Run ***********************************************************************************************************************************/ static void testRun(void) { FUNCTION_HARNESS_VOID(); // Create storage Storage *storageTest = storagePosixNewP(TEST_PATH_STR, .write = true); // Install local command handler shim static const ProtocolServerHandler testLocalHandlerList[] = {PROTOCOL_SERVER_HANDLER_VERIFY_LIST}; hrnProtocolLocalShimInstall(testLocalHandlerList, LENGTH_OF(testLocalHandlerList)); StringList *argListBase = strLstNew(); hrnCfgArgRawZ(argListBase, cfgOptStanza, "db"); hrnCfgArgRawZ(argListBase, cfgOptRepoPath, TEST_PATH "/repo"); const char *fileContents = "acefile"; uint64_t fileSize = 7; const Buffer *fileChecksum = bufNewDecode(encodingHex, STRDEF("d1cd8a7d11daa26814b93eb604e1d49ab4b43770")); #define TEST_BACKUP_DB1_94 \ "db-catalog-version=201409291\n" \ "db-control-version=942\n" \ "db-id=1\n" \ "db-system-id=" HRN_PG_SYSTEMID_94_Z "\n" \ "db-version=\"9.4\"\n" #define TEST_BACKUP_DB2_11 \ "db-catalog-version=201707211\n" \ "db-control-version=1100\n" \ "db-id=2\n" \ "db-system-id=" HRN_PG_SYSTEMID_11_Z "\n" \ "db-version=\"11\"\n" #define TEST_BACKUP_DB1_CURRENT_FULL1 \ "20181119-152138F={" \ "\"backrest-format\":5,\"backrest-version\":\"2.28dev\"," \ "\"backup-archive-start\":\"000000010000000000000002\",\"backup-archive-stop\":\"000000010000000000000002\"," \ "\"backup-info-repo-size\":2369186,\"backup-info-repo-size-delta\":2369186," \ "\"backup-info-size\":20162900,\"backup-info-size-delta\":20162900," \ "\"backup-timestamp-start\":1482182846,\"backup-timestamp-stop\":1482182861,\"backup-type\":\"full\"," \ "\"db-id\":1,\"option-archive-check\":true,\"option-archive-copy\":false,\"option-backup-standby\":false," \ "\"option-checksum-page\":true,\"option-compress\":true,\"option-hardlink\":false,\"option-online\":true}\n" #define TEST_BACKUP_DB1_CURRENT_FULL2 \ "20181119-152800F={" \ "\"backrest-format\":5,\"backrest-version\":\"2.08dev\"," \ "\"backup-info-repo-size\":2369186,\"backup-info-repo-size-delta\":2369186," \ "\"backup-info-size\":20162900,\"backup-info-size-delta\":20162900," \ "\"backup-timestamp-start\":1542640898,\"backup-timestamp-stop\":1542640911,\"backup-type\":\"full\"," \ "\"db-id\":1,\"option-archive-check\":true,\"option-archive-copy\":false,\"option-backup-standby\":false," \ "\"option-checksum-page\":true,\"option-compress\":true,\"option-hardlink\":false,\"option-online\":true}\n" #define TEST_BACKUP_DB1_CURRENT_FULL3 \ "20181119-152900F={" \ "\"backrest-format\":5,\"backrest-version\":\"2.08dev\"," \ "\"backup-archive-start\":\"000000010000000000000004\",\"backup-archive-stop\":\"000000010000000000000004\"," \ "\"backup-info-repo-size\":2369186,\"backup-info-repo-size-delta\":2369186," \ "\"backup-info-size\":20162900,\"backup-info-size-delta\":20162900," \ "\"backup-timestamp-start\":1542640898,\"backup-timestamp-stop\":1542640911,\"backup-type\":\"full\"," \ "\"db-id\":1,\"option-archive-check\":true,\"option-archive-copy\":false,\"option-backup-standby\":false," \ "\"option-checksum-page\":true,\"option-compress\":true,\"option-hardlink\":false,\"option-online\":true}\n" #define TEST_BACKUP_DB1_HISTORY \ "1={\"db-catalog-version\":201409291,\"db-control-version\":942,\"db-system-id\":" HRN_PG_SYSTEMID_94_Z "," \ "\"db-version\":\"9.4\"}" #define TEST_BACKUP_DB2_HISTORY \ "2={\"db-catalog-version\":201707211,\"db-control-version\":1100,\"db-system-id\":" HRN_PG_SYSTEMID_11_Z "," \ "\"db-version\":\"11\"}" #define TEST_BACKUP_INFO_MULTI_HISTORY_BASE \ "[backup:current]\n" \ TEST_BACKUP_DB1_CURRENT_FULL1 \ TEST_BACKUP_DB1_CURRENT_FULL2 \ TEST_BACKUP_DB1_CURRENT_FULL3 \ "\n" \ "[db]\n" \ TEST_BACKUP_DB2_11 \ "\n" \ "[db:history]\n" \ TEST_BACKUP_DB1_HISTORY \ "\n" \ TEST_BACKUP_DB2_HISTORY #define TEST_ARCHIVE_INFO_BASE \ "[db]\n" \ "db-id=1\n" \ "db-system-id=" HRN_PG_SYSTEMID_94_Z "\n" \ "db-version=\"9.4\"\n" \ "\n" \ "[db:history]\n" \ "1={\"db-id\":" HRN_PG_SYSTEMID_94_Z ",\"db-version\":\"9.4\"}" #define TEST_ARCHIVE_INFO_MULTI_HISTORY_BASE \ "[db]\n" \ "db-id=2\n" \ "db-system-id=" HRN_PG_SYSTEMID_11_Z "\n" \ "db-version=\"11\"\n" \ "\n" \ "[db:history]\n" \ "1={\"db-id\":" HRN_PG_SYSTEMID_94_Z ",\"db-version\":\"9.4\"}\n" \ "2={\"db-id\":" HRN_PG_SYSTEMID_11_Z ",\"db-version\":\"11\"}" #define TEST_MANIFEST_HEADER \ "[backup]\n" \ "backup-label=null\n" \ "backup-timestamp-copy-start=0\n" \ "backup-timestamp-start=0\n" \ "backup-timestamp-stop=0\n" \ "backup-type=\"full\"\n" #define TEST_MANIFEST_DB_94 \ "\n" \ "[backup:db]\n" \ "db-catalog-version=201409291\n" \ "db-control-version=942\n" \ "db-id=1\n" \ "db-system-id=" HRN_PG_SYSTEMID_94_Z "\n" \ "db-version=\"9.4\"\n" #define TEST_MANIFEST_OPTION_ALL \ "\n" \ "[backup:option]\n" \ "option-archive-check=false\n" \ "option-archive-copy=false\n" \ "option-checksum-page=false\n" \ "option-compress=false\n" \ "option-compress-type=\"none\"\n" \ "option-hardlink=false\n" \ "option-online=false\n" #define TEST_MANIFEST_OPTION_ARCHIVE_TRUE \ "\n" \ "[backup:option]\n" \ "option-archive-check=true\n" \ "option-archive-copy=true\n" #define TEST_MANIFEST_TARGET \ "\n" \ "[backup:target]\n" \ "pg_data={\"path\":\"/pg/base\",\"type\":\"path\"}\n" #define TEST_MANIFEST_DB \ "\n" \ "[db]\n" \ "postgres={\"db-id\":12173,\"db-last-system-id\":12168}\n" #define TEST_MANIFEST_FILE \ "\n" \ "[target:file]\n" \ "pg_data/PG_VERSION={\"checksum\":\"184473f470864e067ee3a22e64b47b0a1c356f29\",\"size\":4,\"timestamp\":1565282114}\n" #define TEST_MANIFEST_FILE_DEFAULT \ "\n" \ "[target:file:default]\n" \ "group=\"group1\"\n" \ "mode=\"0600\"\n" \ "user=\"user1\"\n" #define TEST_MANIFEST_LINK \ "\n" \ "[target:link]\n" \ "pg_data/pg_stat={\"destination\":\"../pg_stat\"}\n" #define TEST_MANIFEST_LINK_DEFAULT \ "\n" \ "[target:link:default]\n" \ "group=\"group1\"\n" \ "user=false\n" #define TEST_MANIFEST_PATH \ "\n" \ "[target:path]\n" \ "pg_data={\"user\":\"user1\"}\n" \ #define TEST_MANIFEST_PATH_DEFAULT \ "\n" \ "[target:path:default]\n" \ "group=false\n" \ "mode=\"0700\"\n" \ "user=\"user1\"\n" #define TEST_INVALID_BACKREST_INFO \ "[backrest]\n" \ "backrest-checksum=\"BOGUS\"\n" \ "backrest-format=5\n" \ "backrest-version=\"2.28\"\n" // ***************************************************************************************************************************** if (testBegin("verifyManifestFile()")) { // Load Parameters StringList *argList = strLstDup(argListBase); HRN_CFG_LOAD(cfgCmdVerify, argList); #define TEST_BACKUP_LABEL_FULL "20181119-152138F" Manifest *manifest = NULL; unsigned int jobErrorTotal = 0; VerifyBackupResult backupResult = {.backupLabel = strNewZ(TEST_BACKUP_LABEL_FULL)}; InfoPg *infoPg = NULL; TEST_ASSIGN( infoPg, infoArchivePg(infoArchiveNewLoad(ioBufferReadNew(harnessInfoChecksumZ(TEST_ARCHIVE_INFO_BASE)))), "infoPg from archive.info"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("manifest.copy exists, no manifest main, manifest db version not in history, not current db"); HRN_INFO_PUT( storageRepoWrite(), STORAGE_REPO_BACKUP "/" TEST_BACKUP_LABEL_FULL "/" BACKUP_MANIFEST_FILE, TEST_MANIFEST_HEADER "\n" "[backup:db]\n" "db-catalog-version=201608131\n" "db-control-version=960\n" "db-id=1\n" "db-system-id=" HRN_PG_SYSTEMID_94_Z "\n" // 9.4 system id is used so version will trigger error "db-version=\"9.6\"\n" TEST_MANIFEST_OPTION_ALL TEST_MANIFEST_TARGET TEST_MANIFEST_DB TEST_MANIFEST_FILE TEST_MANIFEST_FILE_DEFAULT TEST_MANIFEST_LINK TEST_MANIFEST_LINK_DEFAULT TEST_MANIFEST_PATH TEST_MANIFEST_PATH_DEFAULT, .comment = "manifest db section mismatch"); harnessLogLevelSet(logLevelDetail); backupResult.status = backupValid; TEST_ASSIGN(manifest, verifyManifestFile(&backupResult, NULL, false, infoPg, &jobErrorTotal), "verify manifest"); TEST_RESULT_PTR(manifest, NULL, "manifest not set - pg version mismatch"); TEST_RESULT_UINT(backupResult.status, backupInvalid, "manifest unusable - backup invalid"); TEST_RESULT_LOG( "P00 DETAIL: unable to open missing file '" TEST_PATH "/repo/backup/db/20181119-152138F/backup.manifest.copy'" " for read\n" "P00 INFO: '20181119-152138F' may not be recoverable - PG data (id 1, version 9.6, system-id" " " HRN_PG_SYSTEMID_94_Z ") is not in the backup.info history, skipping"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("rerun test with db-system-id invalid and no main"); HRN_STORAGE_REMOVE(storageRepoWrite(), STORAGE_REPO_BACKUP "/" TEST_BACKUP_LABEL_FULL "/" BACKUP_MANIFEST_FILE); HRN_INFO_PUT( storageRepoWrite(), STORAGE_REPO_BACKUP "/" TEST_BACKUP_LABEL_FULL "/" BACKUP_MANIFEST_FILE INFO_COPY_EXT, TEST_MANIFEST_HEADER "\n" "[backup:db]\n" "db-catalog-version=201409291\n" "db-control-version=942\n" "db-id=1\n" "db-system-id=0\n" "db-version=\"9.4\"\n" TEST_MANIFEST_OPTION_ALL TEST_MANIFEST_TARGET TEST_MANIFEST_DB TEST_MANIFEST_FILE TEST_MANIFEST_FILE_DEFAULT TEST_MANIFEST_LINK TEST_MANIFEST_LINK_DEFAULT TEST_MANIFEST_PATH TEST_MANIFEST_PATH_DEFAULT, .comment = "manifest copy - invalid system-id"); backupResult.status = backupValid; TEST_ASSIGN(manifest, verifyManifestFile(&backupResult, NULL, false, infoPg, &jobErrorTotal), "verify manifest"); TEST_RESULT_PTR(manifest, NULL, "manifest not set - pg system-id mismatch"); TEST_RESULT_UINT(backupResult.status, backupInvalid, "manifest unusable - backup invalid"); TEST_RESULT_LOG( "P00 DETAIL: unable to open missing file '" TEST_PATH "/repo/backup/db/20181119-152138F/backup.manifest' for read\n" "P00 DETAIL: 20181119-152138F/backup.manifest is missing or unusable, using copy\n" "P00 INFO: '20181119-152138F' may not be recoverable - PG data (id 1, version 9.4, system-id 0) is not in the" " backup.info history, skipping"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("rerun copy test with db-id invalid"); HRN_INFO_PUT( storageRepoWrite(), STORAGE_REPO_BACKUP "/" TEST_BACKUP_LABEL_FULL "/" BACKUP_MANIFEST_FILE INFO_COPY_EXT, TEST_MANIFEST_HEADER "\n" "[backup:db]\n" "db-catalog-version=201409291\n" "db-control-version=942\n" "db-id=0\n" "db-system-id=" HRN_PG_SYSTEMID_94_Z "\n" "db-version=\"9.4\"\n" TEST_MANIFEST_OPTION_ALL TEST_MANIFEST_TARGET TEST_MANIFEST_DB TEST_MANIFEST_FILE TEST_MANIFEST_FILE_DEFAULT TEST_MANIFEST_LINK TEST_MANIFEST_LINK_DEFAULT TEST_MANIFEST_PATH TEST_MANIFEST_PATH_DEFAULT, .comment = "manifest copy - invalid db-id"); backupResult.status = backupValid; TEST_ASSIGN(manifest, verifyManifestFile(&backupResult, NULL, false, infoPg, &jobErrorTotal), "verify manifest"); TEST_RESULT_PTR(manifest, NULL, "manifest not set - pg db-id mismatch"); TEST_RESULT_UINT(backupResult.status, backupInvalid, "manifest unusable - backup invalid"); TEST_RESULT_LOG( "P00 DETAIL: unable to open missing file '" TEST_PATH "/repo/backup/db/20181119-152138F/backup.manifest' for read\n" "P00 DETAIL: 20181119-152138F/backup.manifest is missing or unusable, using copy\n" "P00 INFO: '20181119-152138F' may not be recoverable - PG data (id 0, version 9.4, system-id" " " HRN_PG_SYSTEMID_94_Z ") is not in the backup.info history, skipping"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("missing main manifest, errored copy"); backupResult.status = backupValid; HRN_STORAGE_PUT_Z( storageRepoWrite(), TEST_PATH "/repo/" STORAGE_PATH_BACKUP "/db/" TEST_BACKUP_LABEL_FULL "/" BACKUP_MANIFEST_FILE INFO_COPY_EXT, TEST_INVALID_BACKREST_INFO, .comment = "invalid manifest copy"); TEST_ASSIGN(manifest, verifyManifestFile(&backupResult, NULL, false, infoPg, &jobErrorTotal), "verify manifest"); TEST_RESULT_UINT(backupResult.status, backupInvalid, "manifest unusable - backup invalid"); TEST_RESULT_LOG( "P00 DETAIL: unable to open missing file '" TEST_PATH "/repo/backup/db/20181119-152138F/backup.manifest' for read\n" "P00 DETAIL: invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS'" " /20181119-152138F/backup.manifest.copy"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("current backup true"); HRN_STORAGE_PUT_Z( storageRepoWrite(), TEST_PATH "/repo/" STORAGE_PATH_BACKUP "/db/" TEST_BACKUP_LABEL_FULL "/" BACKUP_MANIFEST_FILE, TEST_INVALID_BACKREST_INFO, .comment = "invalid manifest"); TEST_ASSIGN(manifest, verifyManifestFile(&backupResult, NULL, true, infoPg, &jobErrorTotal), "verify manifest"); TEST_RESULT_PTR(manifest, NULL, "manifest not set"); TEST_RESULT_UINT(backupResult.status, backupInvalid, "manifest unusable - backup invalid"); TEST_RESULT_LOG( "P00 DETAIL: invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS'" " /20181119-152138F/backup.manifest\n" "P00 DETAIL: invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS'" " /20181119-152138F/backup.manifest.copy"); // Write a valid manifest with a manifest copy that is invalid HRN_INFO_PUT( storageRepoWrite(), STORAGE_REPO_BACKUP "/" TEST_BACKUP_LABEL_FULL "/" BACKUP_MANIFEST_FILE, TEST_MANIFEST_HEADER TEST_MANIFEST_DB_94 TEST_MANIFEST_OPTION_ALL TEST_MANIFEST_TARGET TEST_MANIFEST_DB TEST_MANIFEST_FILE TEST_MANIFEST_FILE_DEFAULT TEST_MANIFEST_LINK TEST_MANIFEST_LINK_DEFAULT TEST_MANIFEST_PATH TEST_MANIFEST_PATH_DEFAULT, .comment = "valid manifest"); backupResult.status = backupValid; TEST_ASSIGN(manifest, verifyManifestFile(&backupResult, NULL, true, infoPg, &jobErrorTotal), "verify manifest"); TEST_RESULT_PTR_NE(manifest, NULL, "manifest set"); TEST_RESULT_UINT(backupResult.status, backupValid, "manifest usable"); TEST_RESULT_LOG("P00 DETAIL: backup '20181119-152138F' manifest.copy does not match manifest"); harnessLogLevelReset(); } // ***************************************************************************************************************************** if (testBegin("verifyCreateArchiveIdRange()")) { VerifyWalRange *walRangeResult = NULL; unsigned int errTotal = 0; StringList *walFileList = strLstNew(); VerifyArchiveResult archiveResult = { .archiveId = strNewZ("9.4-1"), .walRangeList = lstNewP(sizeof(VerifyWalRange), .comparator = lstComparatorStr), }; List *archiveIdResultList = lstNewP(sizeof(VerifyArchiveResult), .comparator = archiveIdComparator); lstAdd(archiveIdResultList, &archiveResult); VerifyArchiveResult *archiveIdResult = lstGetLast(archiveIdResultList); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("Single WAL"); archiveIdResult->pgWalInfo.size = HRN_PG_WAL_SEGMENT_SIZE_DEFAULT; archiveIdResult->pgWalInfo.version = PG_VERSION_94; strLstAddZ(walFileList, "000000020000000200000000-daa497dba64008db824607940609ba1cd7c6c501.gz"); TEST_RESULT_VOID(verifyCreateArchiveIdRange(archiveIdResult, walFileList, &errTotal), "create archiveId WAL range"); TEST_RESULT_UINT(errTotal, 0, "no errors"); TEST_RESULT_UINT(lstSize(((VerifyArchiveResult *)lstGet(archiveIdResultList, 0))->walRangeList), 1, "single range"); TEST_ASSIGN( walRangeResult, (VerifyWalRange *)lstGet(((VerifyArchiveResult *)lstGet(archiveIdResultList, 0))->walRangeList, 0), "get range"); TEST_RESULT_STR_Z(walRangeResult->start, "000000020000000200000000", "start range"); TEST_RESULT_STR_Z(walRangeResult->stop, "000000020000000200000000", "stop range"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("Duplicate WAL only - no range, all removed from list"); lstClear(archiveIdResult->walRangeList); // Add a duplicate strLstAddZ(walFileList, "000000020000000200000000"); TEST_RESULT_VOID(verifyCreateArchiveIdRange(archiveIdResult, walFileList, &errTotal), "create archiveId WAL range"); TEST_RESULT_UINT(errTotal, 1, "duplicate WAL error"); TEST_RESULT_UINT(strLstSize(walFileList), 0, "all WAL removed from WAL file list"); TEST_RESULT_UINT(lstSize(archiveIdResult->walRangeList), 0, "no range"); TEST_RESULT_LOG("P00 INFO: duplicate WAL '000000020000000200000000' for '9.4-1' exists, skipping"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("duplicates at beginning and end of list are removed"); errTotal = 0; strLstAddZ(walFileList, "000000020000000100000000-daa497dba64008db824607940609ba1cd7c6c501.gz"); strLstAddZ(walFileList, "000000020000000100000000"); strLstAddZ(walFileList, "000000020000000100000000-aaaaaadba64008db824607940609ba1cd7c6c501"); strLstAddZ(walFileList, "0000000200000001000000FD-daa497dba64008db824607940609ba1cd7c6c501.gz"); strLstAddZ(walFileList, "0000000200000001000000FE-a6e1a64f0813352bc2e97f116a1800377e17d2e4.gz"); strLstAddZ(walFileList, "0000000200000001000000FF-daa497dba64008db824607940609ba1cd7c6c501"); strLstAddZ(walFileList, "000000020000000200000000"); strLstAddZ(walFileList, "000000020000000200000001"); strLstAddZ(walFileList, "000000020000000200000001"); TEST_RESULT_VOID(verifyCreateArchiveIdRange(archiveIdResult, walFileList, &errTotal), "create archiveId WAL range"); TEST_RESULT_UINT(errTotal, 2, "triplicate WAL error at beginning, duplicate WAL at end"); TEST_RESULT_UINT(strLstSize(walFileList), 4, "only duplicate WAL removed from WAL list"); TEST_RESULT_UINT(lstSize(archiveIdResultList), 1, "single archiveId result"); TEST_RESULT_UINT(lstSize(archiveIdResult->walRangeList), 1, "single range"); TEST_ASSIGN( walRangeResult, (VerifyWalRange *)lstGet(((VerifyArchiveResult *)lstGet(archiveIdResultList, 0))->walRangeList, 0), "get range"); TEST_RESULT_STR_Z(walRangeResult->start, "0000000200000001000000FD", "start range"); TEST_RESULT_STR_Z(walRangeResult->stop, "000000020000000200000000", "stop range"); TEST_RESULT_LOG( "P00 INFO: duplicate WAL '000000020000000100000000' for '9.4-1' exists, skipping\n" "P00 INFO: duplicate WAL '000000020000000200000001' for '9.4-1' exists, skipping"); } // ***************************************************************************************************************************** if (testBegin("verifyPgHistory()")) { // Create backup.info InfoBackup *backupInfo = NULL; TEST_ASSIGN( backupInfo, infoBackupNewLoad(ioBufferReadNew(harnessInfoChecksumZ(TEST_BACKUP_INFO_MULTI_HISTORY_BASE))), "backup.info multi-history"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("history mismatch - missing history"); // Create archive.info - history mismatch InfoArchive *archiveInfo = NULL; TEST_ASSIGN( archiveInfo, infoArchiveNewLoad( ioBufferReadNew( harnessInfoChecksumZ( "[db]\n" "db-id=2\n" "db-system-id=" HRN_PG_SYSTEMID_11_Z "\n" "db-version=\"11\"\n" "\n" "[db:history]\n" "2={\"db-id\":" HRN_PG_SYSTEMID_11_Z ",\"db-version\":\"11\"}"))), "archive.info missing history"); TEST_ERROR( verifyPgHistory(infoArchivePg(archiveInfo), infoBackupPg(backupInfo)), FormatError, "archive and backup history lists do not match"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("history mismatch - system id"); TEST_ASSIGN( archiveInfo, infoArchiveNewLoad( ioBufferReadNew( harnessInfoChecksumZ( "[db]\n" "db-id=2\n" "db-system-id=" HRN_PG_SYSTEMID_11_Z "\n" "db-version=\"11\"\n" "\n" "[db:history]\n" "1={\"db-id\":6625592122879095777,\"db-version\":\"9.4\"}\n" "2={\"db-id\":" HRN_PG_SYSTEMID_11_Z ",\"db-version\":\"11\"}"))), "archive.info history system id mismatch"); TEST_ERROR( verifyPgHistory(infoArchivePg(archiveInfo), infoBackupPg(backupInfo)), FormatError, "archive and backup history lists do not match"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("history mismatch - version"); TEST_ASSIGN( archiveInfo, infoArchiveNewLoad( ioBufferReadNew( harnessInfoChecksumZ( "[db]\n" "db-id=2\n" "db-system-id=" HRN_PG_SYSTEMID_11_Z "\n" "db-version=\"11\"\n" "\n" "[db:history]\n" "1={\"db-id\":" HRN_PG_SYSTEMID_94_Z ",\"db-version\":\"9.5\"}\n" "2={\"db-id\":" HRN_PG_SYSTEMID_11_Z ",\"db-version\":\"11\"}"))), "archive.info history version mismatch"); TEST_ERROR( verifyPgHistory(infoArchivePg(archiveInfo), infoBackupPg(backupInfo)), FormatError, "archive and backup history lists do not match"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("history mismatch - id"); TEST_ASSIGN( archiveInfo, infoArchiveNewLoad( ioBufferReadNew( harnessInfoChecksumZ( "[db]\n" "db-id=2\n" "db-system-id=" HRN_PG_SYSTEMID_11_Z "\n" "db-version=\"11\"\n" "\n" "[db:history]\n" "3={\"db-id\":" HRN_PG_SYSTEMID_94_Z ",\"db-version\":\"9.4\"}\n" "2={\"db-id\":" HRN_PG_SYSTEMID_11_Z ",\"db-version\":\"11\"}"))), "archive.info history id mismatch"); TEST_ERROR( verifyPgHistory(infoArchivePg(archiveInfo), infoBackupPg(backupInfo)), FormatError, "archive and backup history lists do not match"); } // ***************************************************************************************************************************** if (testBegin("verifySetBackupCheckArchive(), verifyLogInvalidResult(), verifyRender()")) { // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("verifySetBackupCheckArchive()"); InfoBackup *backupInfo = NULL; InfoArchive *archiveInfo = NULL; TEST_ASSIGN( backupInfo, infoBackupNewLoad(ioBufferReadNew(harnessInfoChecksumZ(TEST_BACKUP_INFO_MULTI_HISTORY_BASE))), "backup.info multi-history"); TEST_ASSIGN( archiveInfo, infoArchiveNewLoad(ioBufferReadNew(harnessInfoChecksumZ(TEST_ARCHIVE_INFO_MULTI_HISTORY_BASE))), "archive.info multi-history"); InfoPg *pgHistory = infoArchivePg(archiveInfo); StringList *backupList = strLstNew(); strLstAddZ(backupList, "20181119-152138F"); strLstAddZ(backupList, "20181119-152900F"); StringList *archiveIdList = strLstComparatorSet(strLstNew(), archiveIdComparator); strLstAddZ(archiveIdList, "9.4-1"); strLstAddZ(archiveIdList, "11-2"); unsigned int errTotal = 0; // Add backup to end of list strLstAddZ(backupList, "20181119-153000F"); strLstAddZ(archiveIdList, "12-3"); TEST_RESULT_STR_Z( verifySetBackupCheckArchive(backupList, backupInfo, archiveIdList, pgHistory, &errTotal), "20181119-153000F", "current backup, missing archive"); TEST_RESULT_UINT(errTotal, 1, "error logged"); TEST_RESULT_LOG("P00 INFO: archiveIds '12-3' are not in the archive.info history list"); errTotal = 0; strLstAddZ(archiveIdList, "13-4"); TEST_RESULT_STR_Z( verifySetBackupCheckArchive(backupList, backupInfo, archiveIdList, pgHistory, &errTotal), "20181119-153000F", "test multiple archiveIds on disk not in archive.info"); TEST_RESULT_UINT(errTotal, 1, "error logged"); TEST_RESULT_LOG("P00 INFO: archiveIds '12-3, 13-4' are not in the archive.info history list"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("verifyLogInvalidResult() - missing file"); TEST_RESULT_UINT( verifyLogInvalidResult(STORAGE_REPO_ARCHIVE_STR, verifyFileMissing, 0, STRDEF("missingfilename")), 0, "file missing message"); TEST_RESULT_LOG("P00 WARN: file missing 'missingfilename'"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("verifyRender() - missing file, empty invalidList"); List *archiveIdResultList = lstNewP(sizeof(VerifyArchiveResult), .comparator = archiveIdComparator); List *backupResultList = lstNewP(sizeof(VerifyBackupResult), .comparator = lstComparatorStr); VerifyArchiveResult archiveIdResult = { .archiveId = strNewZ("9.6-1"), .totalWalFile = 1, .walRangeList = lstNewP(sizeof(VerifyWalRange), .comparator = lstComparatorStr), }; VerifyWalRange walRange = { .start = strNewZ("0"), .stop = strNewZ("2"), .invalidFileList = lstNewP(sizeof(VerifyInvalidFile), .comparator = lstComparatorStr), }; lstAdd(archiveIdResult.walRangeList, &walRange); lstAdd(archiveIdResultList, &archiveIdResult); TEST_RESULT_STR_Z( verifyRender(archiveIdResultList, backupResultList, cfgOptionBool(cfgOptVerbose)), "\n" " archiveId: 9.6-1, total WAL checked: 1, total valid WAL: 0", "archive: no invalid file list"); VerifyInvalidFile invalidFile = { .fileName = strNewZ("file"), .reason = verifyFileMissing, }; lstAdd(walRange.invalidFileList, &invalidFile); VerifyBackupResult backupResult = { .backupLabel = strNewZ("test-backup-label"), .status = backupInvalid, .totalFileVerify = 1, .invalidFileList = lstNewP(sizeof(VerifyInvalidFile), .comparator = lstComparatorStr), }; lstAdd(backupResult.invalidFileList, &invalidFile); lstAdd(backupResultList, &backupResult); TEST_RESULT_STR_Z( verifyRender(archiveIdResultList, backupResultList, cfgOptionBool(cfgOptVerbose)), "\n" " archiveId: 9.6-1, total WAL checked: 1, total valid WAL: 0\n" " missing: 1\n" " backup: test-backup-label, status: invalid, total files checked: 1, total valid files: 0\n" " missing: 1", "archive file missing, backup file missing, no text, no verbose"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("verifyAddInvalidWalFile() - file missing (coverage test)"); TEST_RESULT_VOID( verifyAddInvalidWalFile(archiveIdResult.walRangeList, verifyFileMissing, STRDEF("test"), STRDEF("3")), "coverage test"); } // ***************************************************************************************************************************** if (testBegin("cmdVerify() - info files")) { // Load Parameters StringList *argList = strLstDup(argListBase); HRN_CFG_LOAD(cfgCmdVerify, argList); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("backup.info invalid checksum, neither backup copy nor archive infos exist"); HRN_STORAGE_PUT_Z(storageRepoWrite(), INFO_BACKUP_PATH_FILE, TEST_INVALID_BACKREST_INFO, .comment = "invalid backup.info"); harnessLogLevelSet(logLevelDetail); // Redirect stdout to a file int stdoutSave = dup(STDOUT_FILENO); const String *stdoutFile = STRDEF(TEST_PATH "/stdout.info"); THROW_ON_SYS_ERROR(freopen(strZ(stdoutFile), "w", stdout) == NULL, FileWriteError, "unable to reopen stdout"); // Not in a test wrapper to avoid writing to stdout cmdVerify(); // Restore normal stdout dup2(stdoutSave, STDOUT_FILENO); // Check output of verify command stored in file TEST_STORAGE_GET(storageTest, strZ(stdoutFile), "", .remove = true); TEST_RESULT_LOG( "P00 DETAIL: invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS'" " /backup.info\n" "P00 DETAIL: unable to open missing file '" TEST_PATH "/repo/backup/db/backup.info.copy' for read\n" "P00 DETAIL: unable to open missing file '" TEST_PATH "/repo/archive/db/archive.info' for read\n" "P00 DETAIL: unable to open missing file '" TEST_PATH "/repo/archive/db/archive.info.copy' for read\n" "P00 INFO: stanza: db\n" " status: error\n" " No usable backup.info file\n" " No usable archive.info file"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("backup.info invalid checksum, backup.info.copy valid, archive.info not exist, archive copy checksum invalid"); HRN_STORAGE_PUT_Z( storageRepoWrite(), INFO_ARCHIVE_PATH_FILE INFO_COPY_EXT, TEST_INVALID_BACKREST_INFO, .comment = "invalid archive.info.copy"); HRN_INFO_PUT( storageRepoWrite(), INFO_BACKUP_PATH_FILE INFO_COPY_EXT, "[backup:current]\n" TEST_BACKUP_DB1_CURRENT_FULL1 "\n" "[db]\n" TEST_BACKUP_DB1_94 "\n" "[db:history]\n" TEST_BACKUP_DB1_HISTORY, .comment = "valid backup.info.copy"); // Redirect stdout to a file stdoutSave = dup(STDOUT_FILENO); stdoutFile = STRDEF(TEST_PATH "/stdout.info"); THROW_ON_SYS_ERROR(freopen(strZ(stdoutFile), "w", stdout) == NULL, FileWriteError, "unable to reopen stdout"); // Not in a test wrapper to avoid writing to stdout cmdVerify(); // Restore normal stdout dup2(stdoutSave, STDOUT_FILENO); // Check output of verify command stored in file TEST_STORAGE_GET(storageTest, strZ(stdoutFile), "", .remove = true); TEST_RESULT_LOG( "P00 DETAIL: invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS'" " /backup.info\n" "P00 DETAIL: unable to open missing file '" TEST_PATH "/repo/archive/db/archive.info' for read\n" "P00 DETAIL: invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS'" " /archive.info.copy\n" "P00 INFO: stanza: db\n" " status: error\n" " No usable archive.info file"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("backup.info and copy valid but checksum mismatch, archive.info checksum invalid, archive.info copy valid"); HRN_INFO_PUT( storageRepoWrite(), INFO_BACKUP_PATH_FILE, TEST_BACKUP_INFO_MULTI_HISTORY_BASE, .comment = "valid backup.info"); HRN_STORAGE_PUT_Z( storageRepoWrite(), INFO_ARCHIVE_PATH_FILE, TEST_INVALID_BACKREST_INFO, .comment = "invalid archive.info"); HRN_INFO_PUT( storageRepoWrite(), INFO_ARCHIVE_PATH_FILE INFO_COPY_EXT, TEST_ARCHIVE_INFO_BASE, .comment = "valid archive.info.copy"); // Redirect stdout to a file stdoutSave = dup(STDOUT_FILENO); stdoutFile = STRDEF(TEST_PATH "/stdout.info"); THROW_ON_SYS_ERROR(freopen(strZ(stdoutFile), "w", stdout) == NULL, FileWriteError, "unable to reopen stdout"); // Not in a test wrapper to avoid writing to stdout cmdVerify(); // Restore normal stdout dup2(stdoutSave, STDOUT_FILENO); // Check output of verify command stored in file TEST_STORAGE_GET(storageTest, strZ(stdoutFile), "", .remove = true); TEST_RESULT_LOG( "P00 DETAIL: backup.info.copy does not match backup.info\n" "P00 DETAIL: invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS'" " /archive.info\n" "P00 INFO: stanza: db\n" " status: error\n" " backup info file and archive info file do not match\n" " archive: id = 1, version = 9.4, system-id = 10000000000000090400\n" " backup : id = 2, version = 11, system-id = 10000000000000110000\n" " HINT: this may be a symptom of repository corruption!"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("backup.info and copy valid and checksums match, archive.info and copy valid, but checksum mismatch"); HRN_INFO_PUT( storageRepoWrite(), INFO_BACKUP_PATH_FILE INFO_COPY_EXT, TEST_BACKUP_INFO_MULTI_HISTORY_BASE, .comment = "valid backup.info.copy"); HRN_INFO_PUT( storageRepoWrite(), INFO_ARCHIVE_PATH_FILE, TEST_ARCHIVE_INFO_MULTI_HISTORY_BASE, .comment = "valid archive.info"); TEST_RESULT_VOID(cmdVerify(), "usable backup and archive info files"); TEST_RESULT_LOG( "P00 DETAIL: archive.info.copy does not match archive.info"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("backup.info valid, copy invalid, archive.info valid, copy invalid"); HRN_STORAGE_REMOVE(storageRepoWrite(), INFO_BACKUP_PATH_FILE INFO_COPY_EXT, .comment = "remove backup.info.copy"); HRN_STORAGE_REMOVE(storageRepoWrite(), INFO_ARCHIVE_PATH_FILE INFO_COPY_EXT, .comment = "remove archive.info.copy"); TEST_RESULT_VOID(cmdVerify(), "usable backup and archive info files"); TEST_RESULT_LOG( "P00 DETAIL: unable to open missing file '" TEST_PATH "/repo/backup/db/backup.info.copy' for read\n" "P00 DETAIL: unable to open missing file '" TEST_PATH "/repo/archive/db/archive.info.copy' for read"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("backup.info and copy missing, archive.info and copy valid"); hrnCfgArgRawZ(argList, cfgOptVerbose, "y"); HRN_CFG_LOAD(cfgCmdVerify, argList); HRN_STORAGE_REMOVE(storageRepoWrite(), INFO_BACKUP_PATH_FILE); HRN_INFO_PUT( storageRepoWrite(), INFO_ARCHIVE_PATH_FILE INFO_COPY_EXT, TEST_ARCHIVE_INFO_MULTI_HISTORY_BASE, .comment = "valid and matching archive.info.copy"); // Redirect stdout to a file stdoutSave = dup(STDOUT_FILENO); stdoutFile = STRDEF(TEST_PATH "/stdout.info"); THROW_ON_SYS_ERROR(freopen(strZ(stdoutFile), "w", stdout) == NULL, FileWriteError, "unable to reopen stdout"); // Not in a test wrapper to avoid writing to stdout cmdVerify(); // Restore normal stdout dup2(stdoutSave, STDOUT_FILENO); // Check output of verify command stored in file TEST_STORAGE_GET(storageTest, strZ(stdoutFile), "", .remove = true); TEST_RESULT_LOG( "P00 DETAIL: unable to open missing file '" TEST_PATH "/repo/backup/db/backup.info' for read\n" "P00 DETAIL: unable to open missing file '" TEST_PATH "/repo/backup/db/backup.info.copy' for read\n" "P00 INFO: stanza: db\n" " status: error\n" " No usable backup.info file"); harnessLogLevelReset(); } // ***************************************************************************************************************************** if (testBegin("verifyFile()")) { // Load Parameters StringList *argList = strLstDup(argListBase); HRN_CFG_LOAD(cfgCmdVerify, argList); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("zero-sized file in archive"); String *filePathName = strNewZ(STORAGE_REPO_ARCHIVE "/testfile"); HRN_STORAGE_PUT_EMPTY(storageRepoWrite(), strZ(filePathName)); TEST_RESULT_UINT( verifyFile(filePathName, 0, NULL, compressTypeNone, HASH_TYPE_SHA1_ZERO_BUF, 0, NULL), verifyOk, "file ok"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("file size invalid in archive"); HRN_STORAGE_PUT_Z(storageRepoWrite(), strZ(filePathName), fileContents); TEST_RESULT_UINT( verifyFile(filePathName, 0, NULL, compressTypeNone, fileChecksum, 0, NULL), verifySizeInvalid, "file size invalid"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("file missing in archive"); TEST_RESULT_UINT( verifyFile(strNewFmt(STORAGE_REPO_ARCHIVE "/missingFile"), 0, NULL, compressTypeNone, fileChecksum, 0, NULL), verifyFileMissing, "file missing"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("encrypted/compressed file in backup"); // Create a compressed encrypted repo file in backup filePathName = strCatZ(strNew(), STORAGE_REPO_BACKUP "/testfile"); HRN_STORAGE_PUT_Z( storageRepoWrite(), strZ(filePathName), fileContents, .compressType = compressTypeGz, .cipherType = cipherTypeAes256Cbc, .cipherPass = "pass"); strCatZ(filePathName, ".gz"); TEST_RESULT_UINT( verifyFile(filePathName, 0, NULL, compressTypeGz, fileChecksum, fileSize, STRDEF("pass")), verifyOk, "file encrypted compressed ok"); TEST_RESULT_UINT( verifyFile(filePathName, 0, NULL, compressTypeGz, bufNewDecode(encodingHex, STRDEF("aa")), fileSize, STRDEF("pass")), verifyChecksumMismatch, "file encrypted compressed checksum mismatch"); } // ***************************************************************************************************************************** if (testBegin("cmdVerify(), verifyProcess() - errors")) { // ------------------------------------------------------------------------------------------------------------------------- // Load Parameters with multi-repo StringList *argList = strLstDup(argListBase); hrnCfgArgKeyRawZ(argList, cfgOptRepoPath, 4, TEST_PATH "/repo4"); HRN_CFG_LOAD(cfgCmdVerify, argList); // Store valid archive/backup info files HRN_INFO_PUT( storageRepoWrite(), INFO_ARCHIVE_PATH_FILE, TEST_ARCHIVE_INFO_MULTI_HISTORY_BASE, .comment = "valid archive.info"); HRN_INFO_PUT( storageRepoWrite(), INFO_ARCHIVE_PATH_FILE INFO_COPY_EXT, TEST_ARCHIVE_INFO_MULTI_HISTORY_BASE, .comment = "valid archive.info.copy"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("valid info files, WAL files present, no backups"); #define TEST_NO_CURRENT_BACKUP \ "[db]\n" \ TEST_BACKUP_DB2_11 \ "\n" \ "[db:history]\n" \ TEST_BACKUP_DB1_HISTORY \ "\n" \ TEST_BACKUP_DB2_HISTORY HRN_INFO_PUT(storageRepoWrite(), INFO_BACKUP_PATH_FILE, TEST_NO_CURRENT_BACKUP, .comment = "no current backups"); HRN_INFO_PUT( storageRepoWrite(), INFO_BACKUP_PATH_FILE INFO_COPY_EXT, TEST_NO_CURRENT_BACKUP, .comment = "no current backups copy"); // Create WAL file with just header info and small WAL size Buffer *walBuffer = bufNew((size_t)(1024 * 1024)); bufUsedSet(walBuffer, bufSize(walBuffer)); memset(bufPtr(walBuffer), 0, bufSize(walBuffer)); HRN_PG_WAL_TO_BUFFER(walBuffer, PG_VERSION_11, .size = 1024 * 1024); const char *walBufferSha1 = strZ(strNewEncode(encodingHex, cryptoHashOne(hashTypeSha1, walBuffer))); HRN_STORAGE_PUT( storageRepoIdxWrite(0), zNewFmt(STORAGE_REPO_ARCHIVE "/11-2/0000000200000007/000000020000000700000FFE-%s", walBufferSha1), walBuffer, .comment = "valid WAL"); HRN_STORAGE_PUT( storageRepoIdxWrite(0), STORAGE_REPO_ARCHIVE "/11-2/0000000200000007/000000020000000700000FFE-bad817043007aa2100c44c712bcb456db705dab9", walBuffer, .comment = "duplicate WAL"); // Set log detail level to capture ranges (there should be none) harnessLogLevelSet(logLevelDetail); // Redirect stdout to a file int stdoutSave = dup(STDOUT_FILENO); const String *stdoutFile = STRDEF(TEST_PATH "/stdout.info"); THROW_ON_SYS_ERROR(freopen(strZ(stdoutFile), "w", stdout) == NULL, FileWriteError, "unable to reopen stdout"); // Not in a test wrapper to avoid writing to stdout cmdVerify(); // Restore normal stdout dup2(stdoutSave, STDOUT_FILENO); // Check output of verify command stored in file TEST_STORAGE_GET(storageTest, strZ(stdoutFile), "", .remove = true); TEST_RESULT_LOG( "P00 DETAIL: no backups exist in the repo\n" "P00 INFO: duplicate WAL '000000020000000700000FFE' for '11-2' exists, skipping\n" "P00 DETAIL: path '11-2/0000000200000007' does not contain any valid WAL to be processed\n" "P00 INFO: stanza: db\n" " status: error\n" " archiveId: 11-2, total WAL checked: 2, total valid WAL: 0"); harnessLogLevelReset(); HRN_STORAGE_REMOVE( storageRepoIdxWrite(0), STORAGE_REPO_ARCHIVE "/11-2/0000000200000007/000000020000000700000FFE-bad817043007aa2100c44c712bcb456db705dab9", .comment = "remove duplicate WAL"); HRN_STORAGE_PATH_CREATE( storageRepoIdxWrite(0), STORAGE_REPO_ARCHIVE "/9.4-1", .comment = "empty path for old archiveId"); HRN_STORAGE_PATH_CREATE( storageRepoIdxWrite(0), STORAGE_REPO_ARCHIVE "/11-2/0000000100000000", .comment = "empty timeline path"); HRN_STORAGE_PUT( storageRepoIdxWrite(0), STORAGE_REPO_ARCHIVE "/11-2/0000000200000007/000000020000000700000FFD-a6e1a64f0813352bc2e97f116a1800377e17d2e4", walBuffer, .compressType = compressTypeGz, .comment = "first WAL compressed - but checksum failure"); HRN_STORAGE_PUT( storageRepoIdxWrite(0), zNewFmt( STORAGE_REPO_ARCHIVE "/11-2/0000000200000007/000000020000000700000FFF-%s", strZ(strNewEncode(encodingHex, cryptoHashOne(hashTypeSha1, BUFSTRDEF("invalidsize"))))), BUFSTRDEF("invalidsize"), .comment = "WAL - invalid size"); HRN_STORAGE_PUT( storageRepoIdxWrite(0), zNewFmt(STORAGE_REPO_ARCHIVE "/11-2/0000000200000008/000000020000000800000000-%s", walBufferSha1), walBuffer, .comment = "WAL - continue range"); // Set log detail level to capture ranges harnessLogLevelSet(logLevelDetail); // Test verifyProcess directly TEST_RESULT_STR_Z( verifyProcess(cfgOptionBool(cfgOptVerbose)), "stanza: db\n" "status: error\n" " archiveId: 11-2, total WAL checked: 4, total valid WAL: 2\n" " checksum invalid: 1, size invalid: 1", "verifyProcess() no text, no verbose"); TEST_RESULT_LOG( "P00 DETAIL: no backups exist in the repo\n" "P00 DETAIL: archive path '9.4-1' is empty\n" "P00 DETAIL: path '11-2/0000000100000000' does not contain any valid WAL to be processed\n" "P01 INFO: invalid checksum" " '11-2/0000000200000007/000000020000000700000FFD-a6e1a64f0813352bc2e97f116a1800377e17d2e4.gz'\n" "P01 INFO: invalid size" " '11-2/0000000200000007/000000020000000700000FFF-ee161f898c9012dd0c28b3fd1e7140b9cf411306'\n" "P00 DETAIL: archiveId: 11-2, wal start: 000000020000000700000FFD, wal stop: 000000020000000800000000"); harnessLogLevelReset(); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("no text output, verbose, with verify failures"); hrnCfgArgRawZ(argList, cfgOptVerbose, "y"); HRN_CFG_LOAD(cfgCmdVerify, argList); // Verify text output, verbose, with verify failures TEST_RESULT_STR_Z( verifyProcess(cfgOptionBool(cfgOptVerbose)), "stanza: db\n" "status: error\n" " archiveId: 9.4-1, total WAL checked: 0, total valid WAL: 0\n" " archiveId: 11-2, total WAL checked: 4, total valid WAL: 2\n" " missing: 0, checksum invalid: 1, size invalid: 1, other: 0\n" " backup: none found", "verbose, with failures"); TEST_RESULT_LOG( "P01 INFO: invalid checksum" " '11-2/0000000200000007/000000020000000700000FFD-a6e1a64f0813352bc2e97f116a1800377e17d2e4.gz'\n" "P01 INFO: invalid size" " '11-2/0000000200000007/000000020000000700000FFF-ee161f898c9012dd0c28b3fd1e7140b9cf411306'"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("text output, verbose, with verify failures"); hrnCfgArgRawZ(argList, cfgOptOutput, "text"); HRN_CFG_LOAD(cfgCmdVerify, argList); // Verify text output, verbose, with verify failures TEST_RESULT_STR_Z( verifyProcess(cfgOptionBool(cfgOptVerbose)), "stanza: db\n" "status: error\n" " archiveId: 9.4-1, total WAL checked: 0, total valid WAL: 0\n" " archiveId: 11-2, total WAL checked: 4, total valid WAL: 2\n" " missing: 0, checksum invalid: 1, size invalid: 1, other: 0\n" " backup: none found", "verify text output, verbose, with verify failures"); TEST_RESULT_LOG( "P01 INFO: invalid checksum" " '11-2/0000000200000007/000000020000000700000FFD-a6e1a64f0813352bc2e97f116a1800377e17d2e4.gz'\n" "P01 INFO: invalid size" " '11-2/0000000200000007/000000020000000700000FFF-ee161f898c9012dd0c28b3fd1e7140b9cf411306'"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("valid info files, start next timeline"); // Load Parameters - single default repo argList = strLstDup(argListBase); HRN_CFG_LOAD(cfgCmdVerify, argList); HRN_STORAGE_PUT( storageRepoIdxWrite(0), zNewFmt(STORAGE_REPO_ARCHIVE "/11-2/0000000200000008/000000020000000800000002-%s", walBufferSha1), walBuffer, .comment = "WAL - starts next range"); HRN_STORAGE_PUT( storageRepoIdxWrite(0), zNewFmt(STORAGE_REPO_ARCHIVE "/11-2/0000000300000000/000000030000000000000000-%s", walBufferSha1), walBuffer, .comment = "WAL - starts next timeline"); HRN_STORAGE_PUT( storageRepoIdxWrite(0), zNewFmt(STORAGE_REPO_ARCHIVE "/11-2/0000000300000000/000000030000000000000001-%s", walBufferSha1), walBuffer, .comment = "WAL - end next timeline"); // Set log level to errors only harnessLogLevelSet(logLevelError); TEST_RESULT_BOOL(cfgOptionBool(cfgOptVerbose), false, "verbose is false"); TEST_RESULT_BOOL((cfgOptionStrId(cfgOptOutput) == CFGOPTVAL_OUTPUT_TEXT), false, "text is false"); // Redirect stdout to a file stdoutSave = dup(STDOUT_FILENO); stdoutFile = STRDEF(TEST_PATH "/stdout.info"); THROW_ON_SYS_ERROR(freopen(strZ(stdoutFile), "w", stdout) == NULL, FileWriteError, "unable to reopen stdout"); // Not in a test wrapper to avoid writing to stdout cmdVerify(); // Restore normal stdout dup2(stdoutSave, STDOUT_FILENO); // Check output of verify command stored in file TEST_STORAGE_GET(storageTest, strZ(stdoutFile), "", .remove = true); TEST_RESULT_LOG(""); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("none output, with verify failures"); hrnCfgArgRawZ(argList, cfgOptOutput, "none"); HRN_CFG_LOAD(cfgCmdVerify, argList); // Verify none output TEST_RESULT_STR_Z( verifyProcess(cfgOptionBool(cfgOptVerbose)), "stanza: db\n" "status: error\n" " archiveId: 11-2, total WAL checked: 7, total valid WAL: 5\n" " checksum invalid: 1, size invalid: 1", "verify none output"); TEST_RESULT_LOG(""); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("valid info files - various archive/backup errors"); // Load Parameters - single non-default repo argList = strLstNew(); hrnCfgArgKeyRawZ(argList, cfgOptRepoPath, 2, TEST_PATH "/repo"); hrnCfgArgRawZ(argList, cfgOptStanza, "db"); hrnCfgArgRawZ(argList, cfgOptRepo, "2"); HRN_CFG_LOAD(cfgCmdVerify, argList, .jobRetry = 1); HRN_STORAGE_PUT( storageRepoIdxWrite(0), STORAGE_REPO_ARCHIVE "/11-2/0000000200000008/000000020000000800000003-656817043007aa2100c44c712bcb456db705dab9", walBuffer, .modeFile = 0200, .comment = "WAL - file not readable"); HRN_STORAGE_PATH_CREATE( storageRepoIdxWrite(0), STORAGE_REPO_BACKUP "/20181119-152800F", .comment = "prior backup path missing manifests"); HRN_INFO_PUT( storageRepoIdxWrite(0), STORAGE_REPO_BACKUP "/20181119-152810F/" BACKUP_MANIFEST_FILE, TEST_MANIFEST_HEADER TEST_MANIFEST_DB_94 TEST_MANIFEST_OPTION_ALL TEST_MANIFEST_TARGET TEST_MANIFEST_DB, .comment = "manifest without target files"); // Create full backup with files HRN_STORAGE_PUT_Z( storageRepoIdxWrite(0), STORAGE_REPO_BACKUP "/20181119-152900F/pg_data/PG_VERSION", "BOGUS", .comment = "put checksum-error backup file"); HRN_STORAGE_PUT_EMPTY( storageRepoIdxWrite(0), STORAGE_REPO_BACKUP "/20181119-152900F/pg_data/testzero", .comment = "put zero-size backup file"); HRN_STORAGE_PUT_Z( storageRepoIdxWrite(0), STORAGE_REPO_BACKUP "/20181119-152900F/pg_data/testvalid", fileContents, .comment = "put valid file"); // Write manifests for full backup String *manifestContent = strNewFmt( "[backup]\n" "backup-label=\"20181119-152900F\"\n" "backup-timestamp-copy-start=0\n" "backup-timestamp-start=0\n" "backup-timestamp-stop=0\n" "backup-type=\"full\"\n" "\n" "[backup:db]\n" TEST_BACKUP_DB2_11 TEST_MANIFEST_OPTION_ALL TEST_MANIFEST_TARGET TEST_MANIFEST_DB TEST_MANIFEST_FILE "pg_data/testvalid={\"checksum\":\"%s\",\"size\":7,\"timestamp\":1565282114}\n" "pg_data/testzero={\"repo-size\":20,\"size\":0,\"timestamp\":1601405663}\n" TEST_MANIFEST_FILE_DEFAULT TEST_MANIFEST_LINK TEST_MANIFEST_LINK_DEFAULT TEST_MANIFEST_PATH TEST_MANIFEST_PATH_DEFAULT, strZ(strNewEncode(encodingHex, fileChecksum))); HRN_INFO_PUT( storageRepoIdxWrite(0), STORAGE_REPO_BACKUP "/20181119-152900F/" BACKUP_MANIFEST_FILE, strZ(manifestContent), .comment = "valid manifest"); HRN_INFO_PUT( storageRepoIdxWrite(0), STORAGE_REPO_BACKUP "/20181119-152900F/" BACKUP_MANIFEST_FILE INFO_COPY_EXT, strZ(manifestContent), .comment = "valid manifest copy"); // Create a manifest for the dependent that has references manifestContent = strNewFmt( "[backup]\n" "backup-label=\"20181119-152900F_20181119-152909D\"\n" "backup-timestamp-copy-start=0\n" "backup-timestamp-start=0\n" "backup-timestamp-stop=0\n" "backup-type=\"diff\"\n" "\n" "[backup:db]\n" TEST_BACKUP_DB2_11 TEST_MANIFEST_OPTION_ALL TEST_MANIFEST_TARGET TEST_MANIFEST_DB "\n" "[target:file]\n" "pg_data/PG_VERSION={\"checksum\":\"184473f470864e067ee3a22e64b47b0a1c356f29\"" ",\"reference\":\"20181119-152900F\",\"size\":4,\"timestamp\":1565282114}\n" "pg_data/testfile={\"checksum\":\"%s\",\"reference\":\"20181119-152900F\",\"size\":7,\"timestamp\":1565282114}\n" "pg_data/testfile2={\"checksum\":\"%s\",\"size\":7,\"timestamp\":1565282114}\n" "pg_data/repochk={\"checksum\":\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"rck\":\"%s\",\"repo-size\":7" ",\"size\":3,\"timestamp\":1565282114}\n" "pg_data/testmissing={\"checksum\":\"123473f470864e067ee3a22e64b47b0a1c356abc\",\"size\":7,\"timestamp\":1565282114}\n" "pg_data/testother={\"checksum\":\"%s\",\"reference\":\"UNPROCESSEDBACKUP\",\"size\":7,\"timestamp\":1565282114}\n" TEST_MANIFEST_FILE_DEFAULT TEST_MANIFEST_LINK TEST_MANIFEST_LINK_DEFAULT TEST_MANIFEST_PATH TEST_MANIFEST_PATH_DEFAULT, strZ(strNewEncode(encodingHex, fileChecksum)), strZ(strNewEncode(encodingHex, fileChecksum)), strZ(strNewEncode(encodingHex, fileChecksum)), strZ(strNewEncode(encodingHex, fileChecksum))); // Write manifests for dependent backup HRN_INFO_PUT( storageRepoIdxWrite(0), STORAGE_REPO_BACKUP "/20181119-152900F_20181119-152909D/" BACKUP_MANIFEST_FILE, strZ(manifestContent), .comment = "manifest to dependent"); HRN_INFO_PUT( storageRepoIdxWrite(0), STORAGE_REPO_BACKUP "/20181119-152900F_20181119-152909D/" BACKUP_MANIFEST_FILE INFO_COPY_EXT, strZ(manifestContent), .comment = "manifest copy to dependent"); HRN_STORAGE_PUT_Z( storageRepoIdxWrite(0), STORAGE_REPO_BACKUP "/20181119-152900F_20181119-152909D/pg_data/testfile2", fileContents, .comment = "put valid file to dependent"); HRN_STORAGE_PUT_Z( storageRepoIdxWrite(0), STORAGE_REPO_BACKUP "/20181119-152900F_20181119-152909D/pg_data/repochk", fileContents, .comment = "put valid file to dependent"); // Create an unprocessed backup label with a file that will be referenced in the dependent manifest HRN_STORAGE_PUT_Z( storageRepoIdxWrite(0), STORAGE_REPO_BACKUP "/UNPROCESSEDBACKUP/pg_data/testother", fileContents, .modeFile = 0200, .comment = "put unreadable file to unprocessed backup"); // Create in-progress backup HRN_STORAGE_PATH_CREATE( storageRepoIdxWrite(0), STORAGE_REPO_BACKUP "/20181119-153000F", .comment = "create empty backup path for newest backup so in-progress"); // Set log level to capture ranges harnessLogLevelSet(logLevelDetail); TEST_RESULT_BOOL(cfgOptionBool(cfgOptVerbose), false, "verbose is false"); TEST_RESULT_BOOL((cfgOptionStrId(cfgOptOutput) == CFGOPTVAL_OUTPUT_TEXT), false, "text is false"); // Redirect stdout to a file stdoutSave = dup(STDOUT_FILENO); stdoutFile = STRDEF(TEST_PATH "/stdout.info"); THROW_ON_SYS_ERROR(freopen(strZ(stdoutFile), "w", stdout) == NULL, FileWriteError, "unable to reopen stdout"); // Not in a test wrapper to avoid writing to stdout cmdVerify(); // Restore normal stdout dup2(stdoutSave, STDOUT_FILENO); // Check output of verify command stored in file TEST_STORAGE_GET(storageTest, strZ(stdoutFile), "", .remove = true); TEST_RESULT_LOG( "P00 DETAIL: archive path '9.4-1' is empty\n" "P00 DETAIL: path '11-2/0000000100000000' does not contain any valid WAL to be processed\n" "P01 INFO: invalid checksum" " '11-2/0000000200000007/000000020000000700000FFD-a6e1a64f0813352bc2e97f116a1800377e17d2e4.gz'\n" "P01 INFO: invalid size" " '11-2/0000000200000007/000000020000000700000FFF-ee161f898c9012dd0c28b3fd1e7140b9cf411306'\n" "P01 INFO: invalid result" " 11-2/0000000200000008/000000020000000800000003-656817043007aa2100c44c712bcb456db705dab9: [41] raised from " "local-1 shim protocol: unable to open file '" TEST_PATH "/repo/archive/db" "/11-2/0000000200000008/000000020000000800000003-656817043007aa2100c44c712bcb456db705dab9' for read:" " [13] Permission denied\n" " [RETRY DETAIL OMITTED]\n" "P00 DETAIL: unable to open missing file '" TEST_PATH "/repo/backup/db/20181119-152800F/backup.manifest' for read\n" "P00 DETAIL: unable to open missing file '" TEST_PATH "/repo/backup/db/20181119-152800F/backup.manifest.copy'" " for read\n" "P00 DETAIL: manifest missing for '20181119-152800F' - backup may have expired\n" "P00 DETAIL: unable to open missing file '" TEST_PATH "/repo/backup/db/20181119-152810F/backup.manifest.copy'" " for read\n" "P00 INFO: backup '20181119-152810F' manifest does not contain any target files to verify\n" "P01 INFO: invalid checksum '20181119-152900F/pg_data/PG_VERSION'\n" "P01 INFO: file missing '20181119-152900F_20181119-152909D/pg_data/testmissing'\n" "P00 DETAIL: unable to open missing file '" TEST_PATH "/repo/backup/db/20181119-153000F/backup.manifest' for read\n" "P00 INFO: backup '20181119-153000F' appears to be in progress, skipping\n" "P01 INFO: invalid result UNPROCESSEDBACKUP/pg_data/testother: [41] raised from local-1 shim protocol:" " unable to open file '" TEST_PATH "/repo/backup/db/UNPROCESSEDBACKUP/pg_data/testother' for read: [13]" " Permission denied\n" " [RETRY DETAIL OMITTED]\n" "P00 DETAIL: archiveId: 11-2, wal start: 000000020000000700000FFD, wal stop: 000000020000000800000000\n" "P00 DETAIL: archiveId: 11-2, wal start: 000000020000000800000002, wal stop: 000000020000000800000003\n" "P00 DETAIL: archiveId: 11-2, wal start: 000000030000000000000000, wal stop: 000000030000000000000001\n" "P00 INFO: stanza: db\n" " status: error\n" " archiveId: 11-2, total WAL checked: 8, total valid WAL: 5\n" " checksum invalid: 1, size invalid: 1, other: 1\n" " backup: 20181119-152800F, status: manifest missing, total files checked: 0, total valid files: 0\n" " backup: 20181119-152810F, status: invalid, total files checked: 0, total valid files: 0\n" " backup: 20181119-152900F, status: invalid, total files checked: 3, total valid files: 2\n" " checksum invalid: 1\n" " backup: 20181119-152900F_20181119-152909D, status: invalid, total files checked: 6," " total valid files: 3\n" " missing: 1, checksum invalid: 1, other: 1"); harnessLogLevelReset(); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("text output, not verbose, with verify failures"); hrnCfgArgRawZ(argList, cfgOptOutput, "text"); HRN_CFG_LOAD(cfgCmdVerify, argList); // Verify text output, not verbose, with failures TEST_RESULT_STR_Z( verifyProcess(cfgOptionBool(cfgOptVerbose)), "stanza: db\n" "status: error\n" " archiveId: 11-2, total WAL checked: 8, total valid WAL: 5\n" " checksum invalid: 1, size invalid: 1, other: 1\n" " backup: 20181119-152800F, status: manifest missing, total files checked: 0, total valid files: 0\n" " backup: 20181119-152810F, status: invalid, total files checked: 0, total valid files: 0\n" " backup: 20181119-152900F, status: invalid, total files checked: 3, total valid files: 2\n" " checksum invalid: 1\n" " backup: 20181119-152900F_20181119-152909D, status: invalid, total files checked: 6, total valid files: 3\n" " missing: 1, checksum invalid: 1, other: 1", "verify text output, not verbose, with verify failures"); TEST_RESULT_LOG( "P01 INFO: invalid checksum" " '11-2/0000000200000007/000000020000000700000FFD-a6e1a64f0813352bc2e97f116a1800377e17d2e4.gz'\n" "P01 INFO: invalid size" " '11-2/0000000200000007/000000020000000700000FFF-ee161f898c9012dd0c28b3fd1e7140b9cf411306'\n" "P01 INFO: invalid result" " 11-2/0000000200000008/000000020000000800000003-656817043007aa2100c44c712bcb456db705dab9: [41] raised from " "local-1 shim protocol: unable to open file '" TEST_PATH "/repo/archive/db" "/11-2/0000000200000008/000000020000000800000003-656817043007aa2100c44c712bcb456db705dab9' for read:" " [13] Permission denied\n" "P00 INFO: backup '20181119-152810F' manifest does not contain any target files to verify\n" "P01 INFO: invalid checksum '20181119-152900F/pg_data/PG_VERSION'\n" "P01 INFO: file missing '20181119-152900F_20181119-152909D/pg_data/testmissing'\n" "P00 INFO: backup '20181119-153000F' appears to be in progress, skipping\n" "P01 INFO: invalid result UNPROCESSEDBACKUP/pg_data/testother: [41] raised from local-1 shim protocol:" " unable to open file '" TEST_PATH "/repo/backup/db/UNPROCESSEDBACKUP/pg_data/testother' for read: [13]" " Permission denied"); } // ***************************************************************************************************************************** if (testBegin("cmdVerify()")) { // Load Parameters StringList *argList = strLstDup(argListBase); HRN_CFG_LOAD(cfgCmdVerify, argList); #define TEST_BACKUP_DB1_CURRENT_FULL3_DIFF1 \ "20181119-152900F_20181119-152909D={" \ "\"backrest-format\":5,\"backrest-version\":\"2.08dev\"," \ "\"backup-archive-start\":\"000000010000000000000006\",\"backup-archive-stop\":\"000000010000000000000007\"," \ "\"backup-info-repo-size\":2369186,\"backup-info-repo-size-delta\":2369186," \ "\"backup-info-size\":20162900,\"backup-info-size-delta\":20162900," \ "\"backup-timestamp-start\":1542640898,\"backup-timestamp-stop\":1542640911,\"backup-type\":\"full\"," \ "\"db-id\":1,\"option-archive-check\":true,\"option-archive-copy\":false,\"option-backup-standby\":false," \ "\"option-checksum-page\":true,\"option-compress\":true,\"option-hardlink\":false,\"option-online\":true}\n" #define TEST_BACKUP_DB2_CURRENT_FULL1 \ "20201119-163000F={" \ "\"backrest-format\":5,\"backrest-version\":\"2.08dev\"," \ "\"backup-archive-start\":\"000000020000000000000001\",\"backup-archive-stop\":\"000000020000000000000001\"," \ "\"backup-info-repo-size\":2369186,\"backup-info-repo-size-delta\":2369186," \ "\"backup-info-size\":20162900,\"backup-info-size-delta\":20162900," \ "\"backup-timestamp-start\":1542640898,\"backup-timestamp-stop\":1542640911,\"backup-type\":\"full\"," \ "\"db-id\":2,\"option-archive-check\":true,\"option-archive-copy\":false,\"option-backup-standby\":false," \ "\"option-checksum-page\":true,\"option-compress\":true,\"option-hardlink\":false,\"option-online\":true}\n" // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("prior backup verification incomplete - referenced file checked"); HRN_INFO_PUT( storageRepoWrite(), INFO_ARCHIVE_PATH_FILE, TEST_ARCHIVE_INFO_MULTI_HISTORY_BASE, .comment = "valid archive.info"); HRN_INFO_PUT( storageRepoWrite(), INFO_ARCHIVE_PATH_FILE INFO_COPY_EXT, TEST_ARCHIVE_INFO_MULTI_HISTORY_BASE, .comment = "valid archive.info.copy"); #define TEST_BACKUP_INFO \ "[backup:current]\n" \ TEST_BACKUP_DB1_CURRENT_FULL3 \ TEST_BACKUP_DB1_CURRENT_FULL3_DIFF1 \ TEST_BACKUP_DB2_CURRENT_FULL1 \ "\n" \ "[db]\n" \ TEST_BACKUP_DB2_11 \ "\n" \ "[db:history]\n" \ TEST_BACKUP_DB1_HISTORY \ "\n" \ TEST_BACKUP_DB2_HISTORY HRN_INFO_PUT(storageRepoWrite(), INFO_BACKUP_PATH_FILE, TEST_BACKUP_INFO); HRN_INFO_PUT(storageRepoWrite(), INFO_BACKUP_PATH_FILE INFO_COPY_EXT, TEST_BACKUP_INFO); // Create valid full backup for DB1 #define TEST_MANIFEST_FULL_DB1 \ TEST_MANIFEST_HEADER \ TEST_MANIFEST_DB_94 \ TEST_MANIFEST_OPTION_ALL \ TEST_MANIFEST_TARGET \ TEST_MANIFEST_DB \ TEST_MANIFEST_FILE \ TEST_MANIFEST_FILE_DEFAULT \ TEST_MANIFEST_LINK \ TEST_MANIFEST_LINK_DEFAULT \ TEST_MANIFEST_PATH \ TEST_MANIFEST_PATH_DEFAULT // Write manifests for full backup HRN_INFO_PUT( storageRepoWrite(), STORAGE_REPO_BACKUP "/20181119-152900F/" BACKUP_MANIFEST_FILE, TEST_MANIFEST_FULL_DB1, .comment = "valid manifest - full"); HRN_INFO_PUT( storageRepoWrite(), STORAGE_REPO_BACKUP "/20181119-152900F/" BACKUP_MANIFEST_FILE INFO_COPY_EXT, TEST_MANIFEST_FULL_DB1, .comment = "valid manifest copy - full"); // Create valid diff backup for DB1 #define TEST_MANIFEST_DIFF_DB1 \ TEST_MANIFEST_HEADER \ TEST_MANIFEST_DB_94 \ TEST_MANIFEST_OPTION_ALL \ TEST_MANIFEST_TARGET \ TEST_MANIFEST_DB \ "\n" \ "[target:file]\n" \ "pg_data/PG_VERSION={\"checksum\":\"184473f470864e067ee3a22e64b47b0a1c356f29\",\"reference\":\"20181119-152900F\"" \ ",\"size\":4,\"timestamp\":1565282114}\n" \ TEST_MANIFEST_FILE_DEFAULT \ TEST_MANIFEST_LINK \ TEST_MANIFEST_LINK_DEFAULT \ TEST_MANIFEST_PATH \ TEST_MANIFEST_PATH_DEFAULT // Write manifests for diff backup HRN_INFO_PUT( storageRepoWrite(), STORAGE_REPO_BACKUP "/20181119-152900F_20181119-152909D/" BACKUP_MANIFEST_FILE, TEST_MANIFEST_DIFF_DB1, .comment = "valid manifest - diff"); HRN_INFO_PUT( storageRepoWrite(), STORAGE_REPO_BACKUP "/20181119-152900F_20181119-152909D/" BACKUP_MANIFEST_FILE INFO_COPY_EXT, TEST_MANIFEST_DIFF_DB1, .comment = "valid manifest copy - diff"); // Put the file referenced by both backups into the full backup HRN_STORAGE_PUT_Z(storageRepoWrite(), STORAGE_REPO_BACKUP "/20181119-152900F/pg_data/PG_VERSION", fileContents); // Redirect stdout to a file int stdoutSave = dup(STDOUT_FILENO); const String *stdoutFile = STRDEF(TEST_PATH "/stdout.info"); THROW_ON_SYS_ERROR(freopen(strZ(stdoutFile), "w", stdout) == NULL, FileWriteError, "unable to reopen stdout"); // Not in a test wrapper to avoid writing to stdout cmdVerify(); // Restore normal stdout dup2(stdoutSave, STDOUT_FILENO); // Check output of verify command stored in file TEST_STORAGE_GET(storageTest, strZ(stdoutFile), "", .remove = true); // The error for the referenced file is logged twice because it is checked again by the second backup since the first backup // verification had not yet completed before the second backup verification began TEST_RESULT_LOG( "P01 INFO: invalid checksum '20181119-152900F/pg_data/PG_VERSION'\n" "P01 INFO: invalid checksum '20181119-152900F/pg_data/PG_VERSION'\n" "P00 INFO: stanza: db\n" " status: error\n" " backup: 20181119-152900F, status: invalid, total files checked: 1, total valid files: 0\n" " checksum invalid: 1\n" " backup: 20181119-152900F_20181119-152909D, status: invalid, total files checked: 1," " total valid files: 0\n" " checksum invalid: 1"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("valid backup, prior backup verification complete - referenced file not checked"); // Set process max to 1 and add more files to check so first backup completes before second is checked hrnCfgArgRawZ(argList, cfgOptProcessMax, "1"); HRN_CFG_LOAD(cfgCmdVerify, argList); String *manifestContent = strNewFmt( TEST_MANIFEST_HEADER TEST_MANIFEST_DB_94 TEST_MANIFEST_OPTION_ALL TEST_MANIFEST_TARGET TEST_MANIFEST_DB TEST_MANIFEST_FILE "pg_data/base/1/555_init={\"checksum\":\"%s\",\"size\":1,\"timestamp\":1565282114}\n" "pg_data/base/1/555_init.1={\"size\":0,\"timestamp\":1565282114}\n" TEST_MANIFEST_FILE_DEFAULT TEST_MANIFEST_LINK TEST_MANIFEST_LINK_DEFAULT TEST_MANIFEST_PATH TEST_MANIFEST_PATH_DEFAULT, strZ(strNewEncode(encodingHex, fileChecksum))); HRN_INFO_PUT( storageRepoWrite(), STORAGE_REPO_BACKUP "/20181119-152900F/" BACKUP_MANIFEST_FILE, strZ(manifestContent), .comment = "valid manifest - full"); HRN_INFO_PUT( storageRepoWrite(), STORAGE_REPO_BACKUP "/20181119-152900F/" BACKUP_MANIFEST_FILE INFO_COPY_EXT, strZ(manifestContent), .comment = "valid manifest copy - full"); HRN_STORAGE_PUT_Z( storageRepoWrite(), STORAGE_REPO_BACKUP "/20181119-152900F/pg_data/base/1/555_init", fileContents, .comment = "invalid size"); // Diff manifest manifestContent = strNewZ( TEST_MANIFEST_HEADER TEST_MANIFEST_DB_94 TEST_MANIFEST_OPTION_ALL TEST_MANIFEST_TARGET TEST_MANIFEST_DB "\n" "[target:file]\n" "pg_data/PG_VERSION={\"checksum\":\"184473f470864e067ee3a22e64b47b0a1c356f29\",\"reference\":\"20181119-152900F\"" ",\"size\":4,\"timestamp\":1565282114}\n" TEST_MANIFEST_FILE_DEFAULT TEST_MANIFEST_LINK TEST_MANIFEST_LINK_DEFAULT TEST_MANIFEST_PATH TEST_MANIFEST_PATH_DEFAULT); HRN_INFO_PUT( storageRepoWrite(), STORAGE_REPO_BACKUP "/20181119-152900F_20181119-152909D/" BACKUP_MANIFEST_FILE, strZ(manifestContent), .comment = "valid manifest - diff"); HRN_INFO_PUT( storageRepoWrite(), STORAGE_REPO_BACKUP "/20181119-152900F_20181119-152909D/" BACKUP_MANIFEST_FILE INFO_COPY_EXT, strZ(manifestContent), .comment = "valid manifest copy - diff"); // Create valid full backup and valid diff backup manifestContent = strNewFmt( TEST_MANIFEST_HEADER "backup-bundle=true\n" "\n" "[backup:db]\n" TEST_BACKUP_DB2_11 TEST_MANIFEST_OPTION_ALL TEST_MANIFEST_TARGET TEST_MANIFEST_DB "\n" "[target:file]\n" "pg_data/validfile={\"bni\":1,\"bno\":3,\"checksum\":\"%s\",\"size\":%u,\"timestamp\":1565282114}\n" "pg_data/zerofile={\"size\":0,\"timestamp\":1565282114}\n" "pg_data/biind={\"bi\":1,\"bim\":3,\"checksum\":\"9865d483bc5a94f2e30056fc256ed3066af54d04\",\"size\":4" ",\"timestamp\":1565282114}\n" TEST_MANIFEST_FILE_DEFAULT TEST_MANIFEST_LINK TEST_MANIFEST_LINK_DEFAULT TEST_MANIFEST_PATH TEST_MANIFEST_PATH_DEFAULT, strZ(strNewEncode(encodingHex, fileChecksum)), (unsigned int)fileSize); HRN_INFO_PUT( storageRepoWrite(), STORAGE_REPO_BACKUP "/20201119-163000F/" BACKUP_MANIFEST_FILE, strZ(manifestContent), .comment = "valid manifest - full"); HRN_INFO_PUT( storageRepoWrite(), STORAGE_REPO_BACKUP "/20201119-163000F/" BACKUP_MANIFEST_FILE INFO_COPY_EXT, strZ(manifestContent), .comment = "valid manifest copy - full"); HRN_STORAGE_PUT_Z( storageRepoWrite(), STORAGE_REPO_BACKUP "/20201119-163000F/bundle/1", zNewFmt("XXX%s", fileContents), .comment = "valid file"); HRN_STORAGE_PUT_Z( storageRepoWrite(), STORAGE_REPO_BACKUP "/20201119-163000F/pg_data/biind.pgbi", "ZZZZ", .comment = "pgbi file"); // Create WAL file with just header info and small WAL size Buffer *walBuffer = bufNew((size_t)(1024 * 1024)); bufUsedSet(walBuffer, bufSize(walBuffer)); memset(bufPtr(walBuffer), 0, bufSize(walBuffer)); HRN_PG_WAL_TO_BUFFER(walBuffer, PG_VERSION_11, .size = 1024 * 1024); const char *walBufferSha1 = strZ(strNewEncode(encodingHex, cryptoHashOne(hashTypeSha1, walBuffer))); HRN_STORAGE_PUT( storageRepoWrite(), zNewFmt(STORAGE_REPO_ARCHIVE "/11-2/0000000200000000/000000020000000000000001-%s", walBufferSha1), walBuffer, .comment = "valid WAL"); // Redirect stdout to a file stdoutSave = dup(STDOUT_FILENO); stdoutFile = STRDEF(TEST_PATH "/stdout.info"); THROW_ON_SYS_ERROR(freopen(strZ(stdoutFile), "w", stdout) == NULL, FileWriteError, "unable to reopen stdout"); // Not in a test wrapper to avoid writing to stdout cmdVerify(); // Restore normal stdout dup2(stdoutSave, STDOUT_FILENO); // Check output of verify command stored in file TEST_STORAGE_GET(storageTest, strZ(stdoutFile), "", .remove = true); TEST_RESULT_LOG( "P01 INFO: invalid checksum '20181119-152900F/pg_data/PG_VERSION'\n" "P01 INFO: invalid size '20181119-152900F/pg_data/base/1/555_init'\n" "P01 INFO: file missing '20181119-152900F/pg_data/base/1/555_init.1'\n" "P00 INFO: stanza: db\n" " status: error\n" " backup: 20181119-152900F, status: invalid, total files checked: 3, total valid files: 0\n" " missing: 1, checksum invalid: 1, size invalid: 1\n" " backup: 20181119-152900F_20181119-152909D, status: invalid, total files checked: 1," " total valid files: 0\n" " checksum invalid: 1"); } // ***************************************************************************************************************************** if (testBegin("cmdVerify() verbose text")) { // Load Parameters StringList *argList = strLstDup(argListBase); hrnCfgArgRawZ(argList, cfgOptOutput, "text"); hrnCfgArgRawZ(argList, cfgOptVerbose, "y"); HRN_CFG_LOAD(cfgCmdVerify, argList); #define TEST_BACKUP_DB1_CURRENT_FULL3_DIFF1 \ "20181119-152900F_20181119-152909D={" \ "\"backrest-format\":5,\"backrest-version\":\"2.08dev\"," \ "\"backup-archive-start\":\"000000010000000000000006\",\"backup-archive-stop\":\"000000010000000000000007\"," \ "\"backup-info-repo-size\":2369186,\"backup-info-repo-size-delta\":2369186," \ "\"backup-info-size\":20162900,\"backup-info-size-delta\":20162900," \ "\"backup-timestamp-start\":1542640898,\"backup-timestamp-stop\":1542640911,\"backup-type\":\"full\"," \ "\"db-id\":1,\"option-archive-check\":true,\"option-archive-copy\":false,\"option-backup-standby\":false," \ "\"option-checksum-page\":true,\"option-compress\":true,\"option-hardlink\":false,\"option-online\":true}\n" #define TEST_BACKUP_DB2_CURRENT_FULL1 \ "20201119-163000F={" \ "\"backrest-format\":5,\"backrest-version\":\"2.08dev\"," \ "\"backup-archive-start\":\"000000020000000000000001\",\"backup-archive-stop\":\"000000020000000000000001\"," \ "\"backup-info-repo-size\":2369186,\"backup-info-repo-size-delta\":2369186," \ "\"backup-info-size\":20162900,\"backup-info-size-delta\":20162900," \ "\"backup-timestamp-start\":1542640898,\"backup-timestamp-stop\":1542640911,\"backup-type\":\"full\"," \ "\"db-id\":2,\"option-archive-check\":true,\"option-archive-copy\":false,\"option-backup-standby\":false," \ "\"option-checksum-page\":true,\"option-compress\":true,\"option-hardlink\":false,\"option-online\":true}\n" // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("prior backup verification incomplete - referenced file checked verbose, text output"); HRN_INFO_PUT( storageRepoWrite(), INFO_ARCHIVE_PATH_FILE, TEST_ARCHIVE_INFO_MULTI_HISTORY_BASE, .comment = "valid archive.info"); HRN_INFO_PUT( storageRepoWrite(), INFO_ARCHIVE_PATH_FILE INFO_COPY_EXT, TEST_ARCHIVE_INFO_MULTI_HISTORY_BASE, .comment = "valid archive.info.copy"); #define TEST_BACKUP_INFO \ "[backup:current]\n" \ TEST_BACKUP_DB1_CURRENT_FULL3 \ TEST_BACKUP_DB1_CURRENT_FULL3_DIFF1 \ TEST_BACKUP_DB2_CURRENT_FULL1 \ "\n" \ "[db]\n" \ TEST_BACKUP_DB2_11 \ "\n" \ "[db:history]\n" \ TEST_BACKUP_DB1_HISTORY \ "\n" \ TEST_BACKUP_DB2_HISTORY HRN_INFO_PUT(storageRepoWrite(), INFO_BACKUP_PATH_FILE, TEST_BACKUP_INFO); HRN_INFO_PUT(storageRepoWrite(), INFO_BACKUP_PATH_FILE INFO_COPY_EXT, TEST_BACKUP_INFO); // Create valid full backup #define TEST_MANIFEST_FULL_DB2 \ TEST_MANIFEST_HEADER \ TEST_MANIFEST_DB_94 \ TEST_MANIFEST_OPTION_ALL \ TEST_MANIFEST_TARGET \ TEST_MANIFEST_DB \ TEST_MANIFEST_FILE \ "pg_data/biind={\"bi\":1,\"bim\":3,\"checksum\":\"ffffffffffffffffffffffffffffffffffffffff\",\"size\":4" \ ",\"timestamp\":1565282114}\n" \ TEST_MANIFEST_FILE_DEFAULT \ TEST_MANIFEST_LINK \ TEST_MANIFEST_LINK_DEFAULT \ TEST_MANIFEST_PATH \ TEST_MANIFEST_PATH_DEFAULT // Write manifests for full backup HRN_INFO_PUT( storageRepoWrite(), STORAGE_REPO_BACKUP "/20181119-152900F/" BACKUP_MANIFEST_FILE, TEST_MANIFEST_FULL_DB2, .comment = "valid manifest - full"); HRN_INFO_PUT( storageRepoWrite(), STORAGE_REPO_BACKUP "/20181119-152900F/" BACKUP_MANIFEST_FILE INFO_COPY_EXT, TEST_MANIFEST_FULL_DB2, .comment = "valid manifest copy - full"); HRN_STORAGE_PUT_Z( storageRepoWrite(), STORAGE_REPO_BACKUP "/20181119-152900F/pg_data/biind.pgbi", "ZVZV", .comment = "pgbi file"); // Create valid diff backup #define TEST_MANIFEST_DIFF_DB2 \ TEST_MANIFEST_HEADER \ TEST_MANIFEST_DB_94 \ TEST_MANIFEST_OPTION_ALL \ TEST_MANIFEST_TARGET \ TEST_MANIFEST_DB \ "\n" \ "[target:file]\n" \ "pg_data/PG_VERSION={\"checksum\":\"184473f470864e067ee3a22e64b47b0a1c356f29\",\"reference\":\"20181119-152900F\"" \ ",\"size\":4,\"timestamp\":1565282114}\n" \ "pg_data/biind={\"bi\":1,\"bim\":3,\"checksum\":\"ffffffffffffffffffffffffffffffffffffffff\"," \ "\"reference\":\"20181119-152900F\",\"size\":4,\"timestamp\":1565282114}\n" \ TEST_MANIFEST_FILE_DEFAULT \ TEST_MANIFEST_LINK \ TEST_MANIFEST_LINK_DEFAULT \ TEST_MANIFEST_PATH \ TEST_MANIFEST_PATH_DEFAULT // Write manifests for diff backup HRN_INFO_PUT( storageRepoWrite(), STORAGE_REPO_BACKUP "/20181119-152900F_20181119-152909D/" BACKUP_MANIFEST_FILE, TEST_MANIFEST_DIFF_DB2, .comment = "valid manifest - diff"); HRN_INFO_PUT( storageRepoWrite(), STORAGE_REPO_BACKUP "/20181119-152900F_20181119-152909D/" BACKUP_MANIFEST_FILE INFO_COPY_EXT, TEST_MANIFEST_DIFF_DB2, .comment = "valid manifest copy - diff"); // Put the file referenced by both backups into the full backup HRN_STORAGE_PUT_Z(storageRepoWrite(), STORAGE_REPO_BACKUP "/20181119-152900F/pg_data/PG_VERSION", fileContents); // Redirect stdout to a file int stdoutSave = dup(STDOUT_FILENO); const String *stdoutFile = STRDEF(TEST_PATH "/stdout.info"); THROW_ON_SYS_ERROR(freopen(strZ(stdoutFile), "w", stdout) == NULL, FileWriteError, "unable to reopen stdout"); // Not in a test wrapper to avoid writing to stdout cmdVerify(); // Restore normal stdout dup2(stdoutSave, STDOUT_FILENO); // Check output of verify command stored in file TEST_STORAGE_GET( storageTest, strZ(stdoutFile), "stanza: db\n" "status: error\n" " archiveId: none found\n" " backup: 20181119-152900F, status: invalid, total files checked: 2, total valid files: 0\n" " missing: 0, checksum invalid: 2, size invalid: 0, other: 0\n" " backup: 20181119-152900F_20181119-152909D, status: invalid, total files checked: 2, total valid files: 1\n" " missing: 0, checksum invalid: 1, size invalid: 0, other: 0\n", .remove = true); TEST_RESULT_LOG( "P01 INFO: invalid checksum '20181119-152900F/pg_data/PG_VERSION'\n" "P01 INFO: invalid checksum '20181119-152900F/pg_data/biind.pgbi'\n" "P00 INFO: stanza: db\n" " status: error\n" " archiveId: none found\n" " backup: 20181119-152900F, status: invalid, total files checked: 2, total valid files: 0\n" " missing: 0, checksum invalid: 2, size invalid: 0, other: 0\n" " backup: 20181119-152900F_20181119-152909D, status: invalid, total files checked: 2," " total valid files: 1\n" " missing: 0, checksum invalid: 1, size invalid: 0, other: 0"); } // ***************************************************************************************************************************** if (testBegin("verifyProcess(), none output, not verbose, no failures")) { // ------------------------------------------------------------------------------------------------------------------------- // Load Parameters with multi-repo StringList *argList = strLstDup(argListBase); hrnCfgArgKeyRawZ(argList, cfgOptRepoPath, 4, TEST_PATH "/repo4"); hrnCfgArgRawZ(argList, cfgOptOutput, "none"); HRN_CFG_LOAD(cfgCmdVerify, argList); // Store valid archive/backup info files HRN_INFO_PUT( storageRepoWrite(), INFO_ARCHIVE_PATH_FILE, TEST_ARCHIVE_INFO_MULTI_HISTORY_BASE, .comment = "valid archive.info"); HRN_INFO_PUT( storageRepoWrite(), INFO_ARCHIVE_PATH_FILE INFO_COPY_EXT, TEST_ARCHIVE_INFO_MULTI_HISTORY_BASE, .comment = "valid archive.info.copy"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("none output, not verbose, with no verify failures"); #define TEST_NO_CURRENT_BACKUP \ "[db]\n" \ TEST_BACKUP_DB2_11 \ "\n" \ "[db:history]\n" \ TEST_BACKUP_DB1_HISTORY \ "\n" \ TEST_BACKUP_DB2_HISTORY HRN_INFO_PUT(storageRepoWrite(), INFO_BACKUP_PATH_FILE, TEST_NO_CURRENT_BACKUP, .comment = "no current backups"); HRN_INFO_PUT( storageRepoWrite(), INFO_BACKUP_PATH_FILE INFO_COPY_EXT, TEST_NO_CURRENT_BACKUP, .comment = "no current backups copy"); // Create WAL file with just header info and small WAL size Buffer *walBuffer = bufNew((size_t)(1024 * 1024)); bufUsedSet(walBuffer, bufSize(walBuffer)); memset(bufPtr(walBuffer), 0, bufSize(walBuffer)); HRN_PG_WAL_TO_BUFFER(walBuffer, PG_VERSION_11, .size = 1024 * 1024); const char *walBufferSha1 = strZ(strNewEncode(encodingHex, cryptoHashOne(hashTypeSha1, walBuffer))); HRN_STORAGE_PUT( storageRepoIdxWrite(0), zNewFmt(STORAGE_REPO_ARCHIVE "/11-2/0000000200000007/000000020000000700000FFE-%s", walBufferSha1), walBuffer, .comment = "valid WAL"); harnessLogLevelSet(logLevelDetail); // Verify text output with no verify errors TEST_RESULT_STR_Z(verifyProcess(cfgOptionBool(cfgOptVerbose)), "", "verify none output, not verbose, with no failures"); TEST_RESULT_LOG( "P00 DETAIL: no backups exist in the repo\n" "P00 DETAIL: archiveId: 11-2, wal start: 000000020000000700000FFE, wal stop: 000000020000000700000FFE"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("invalid WAL magic"); // Create WAL file with just header info and small WAL size walBuffer = bufNew((size_t)(1024 * 1024)); bufUsedSet(walBuffer, bufSize(walBuffer)); memset(bufPtr(walBuffer), 0, bufSize(walBuffer)); HRN_PG_WAL_OVERRIDE_TO_BUFFER(walBuffer, PG_VERSION_11, 999, .size = 1024 * 1024); const char *walBufferSha2 = strZ(strNewEncode(encodingHex, cryptoHashOne(hashTypeSha1, walBuffer))); HRN_STORAGE_PUT( storageRepoIdxWrite(0), zNewFmt(STORAGE_REPO_ARCHIVE "/11-2/0000000200000007/000000020000000700000FFD-%s", walBufferSha2), walBuffer, .comment = "invalid WAL magic"); HRN_CFG_LOAD(cfgCmdVerify, argList); TEST_ERROR( verifyProcess(cfgOptionBool(cfgOptVerbose)), VersionNotSupportedError, "unexpected WAL magic 999\n" "HINT: is this version of PostgreSQL supported?"); TEST_RESULT_LOG( "P00 DETAIL: no backups exist in the repo"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("none output, verbose, override WAL magic, with no verify failures"); hrnCfgArgRawZ(argList, cfgOptVerbose, "y"); hrnCfgArgRawZ(argList, cfgOptPgVersionForce, PG_VERSION_11_Z); HRN_CFG_LOAD(cfgCmdVerify, argList); TEST_RESULT_STR_Z( verifyProcess(cfgOptionBool(cfgOptVerbose)), "stanza: db\n" "status: ok\n" " archiveId: 11-2, total WAL checked: 2, total valid WAL: 2\n" " missing: 0, checksum invalid: 0, size invalid: 0, other: 0\n" " backup: none found", "verify none output, verbose, with no failures"); TEST_RESULT_LOG( "P00 DETAIL: no backups exist in the repo\n" "P00 DETAIL: archiveId: 11-2, wal start: 000000020000000700000FFD, wal stop: 000000020000000700000FFE"); } // ***************************************************************************************************************************** if (testBegin("verifyProcess(), text")) { // ------------------------------------------------------------------------------------------------------------------------- // Load Parameters with multi-repo StringList *argList = strLstDup(argListBase); hrnCfgArgKeyRawZ(argList, cfgOptRepoPath, 4, TEST_PATH "/repo4"); hrnCfgArgRawZ(argList, cfgOptOutput, "text"); HRN_CFG_LOAD(cfgCmdVerify, argList); // Store valid archive/backup info files HRN_INFO_PUT( storageRepoWrite(), INFO_ARCHIVE_PATH_FILE, TEST_ARCHIVE_INFO_MULTI_HISTORY_BASE, .comment = "valid archive.info"); HRN_INFO_PUT( storageRepoWrite(), INFO_ARCHIVE_PATH_FILE INFO_COPY_EXT, TEST_ARCHIVE_INFO_MULTI_HISTORY_BASE, .comment = "valid archive.info.copy"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("text output, not verbose, with no verify failures"); #define TEST_NO_CURRENT_BACKUP \ "[db]\n" \ TEST_BACKUP_DB2_11 \ "\n" \ "[db:history]\n" \ TEST_BACKUP_DB1_HISTORY \ "\n" \ TEST_BACKUP_DB2_HISTORY HRN_INFO_PUT(storageRepoWrite(), INFO_BACKUP_PATH_FILE, TEST_NO_CURRENT_BACKUP, .comment = "no current backups"); HRN_INFO_PUT( storageRepoWrite(), INFO_BACKUP_PATH_FILE INFO_COPY_EXT, TEST_NO_CURRENT_BACKUP, .comment = "no current backups copy"); // Create WAL file with just header info and small WAL size Buffer *walBuffer = bufNew((size_t)(1024 * 1024)); bufUsedSet(walBuffer, bufSize(walBuffer)); memset(bufPtr(walBuffer), 0, bufSize(walBuffer)); HRN_PG_WAL_TO_BUFFER(walBuffer, PG_VERSION_11, .size = 1024 * 1024); const char *walBufferSha1 = strZ(strNewEncode(encodingHex, cryptoHashOne(hashTypeSha1, walBuffer))); HRN_STORAGE_PUT( storageRepoIdxWrite(0), zNewFmt(STORAGE_REPO_ARCHIVE "/11-2/0000000200000007/000000020000000700000FFE-%s", walBufferSha1), walBuffer, .comment = "valid WAL"); harnessLogLevelSet(logLevelDetail); // Verify text output with no verify errors TEST_RESULT_STR_Z(verifyProcess(cfgOptionBool(cfgOptVerbose)), "", "verify text output, not verbose, with no failures"); TEST_RESULT_LOG( "P00 DETAIL: no backups exist in the repo\n" "P00 DETAIL: archiveId: 11-2, wal start: 000000020000000700000FFE, wal stop: 000000020000000700000FFE"); } // ***************************************************************************************************************************** if (testBegin("verifyProcess(), text, verbose")) { // ------------------------------------------------------------------------------------------------------------------------- // Load Parameters with multi-repo StringList *argList = strLstDup(argListBase); hrnCfgArgKeyRawZ(argList, cfgOptRepoPath, 4, TEST_PATH "/repo4"); hrnCfgArgRawZ(argList, cfgOptOutput, "text"); hrnCfgArgRawZ(argList, cfgOptVerbose, "y"); HRN_CFG_LOAD(cfgCmdVerify, argList); // Store valid archive/backup info files HRN_INFO_PUT( storageRepoWrite(), INFO_ARCHIVE_PATH_FILE, TEST_ARCHIVE_INFO_MULTI_HISTORY_BASE, .comment = "valid archive.info"); HRN_INFO_PUT( storageRepoWrite(), INFO_ARCHIVE_PATH_FILE INFO_COPY_EXT, TEST_ARCHIVE_INFO_MULTI_HISTORY_BASE, .comment = "valid archive.info.copy"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("text output, verbose with no verify failures"); #define TEST_NO_CURRENT_BACKUP \ "[db]\n" \ TEST_BACKUP_DB2_11 \ "\n" \ "[db:history]\n" \ TEST_BACKUP_DB1_HISTORY \ "\n" \ TEST_BACKUP_DB2_HISTORY HRN_INFO_PUT(storageRepoWrite(), INFO_BACKUP_PATH_FILE, TEST_NO_CURRENT_BACKUP, .comment = "no current backups"); HRN_INFO_PUT( storageRepoWrite(), INFO_BACKUP_PATH_FILE INFO_COPY_EXT, TEST_NO_CURRENT_BACKUP, .comment = "no current backups copy"); // Create WAL file with just header info and small WAL size Buffer *walBuffer = bufNew((size_t)(1024 * 1024)); bufUsedSet(walBuffer, bufSize(walBuffer)); memset(bufPtr(walBuffer), 0, bufSize(walBuffer)); HRN_PG_WAL_TO_BUFFER(walBuffer, PG_VERSION_11, .size = 1024 * 1024); const char *walBufferSha1 = strZ(strNewEncode(encodingHex, cryptoHashOne(hashTypeSha1, walBuffer))); HRN_STORAGE_PUT( storageRepoIdxWrite(0), zNewFmt(STORAGE_REPO_ARCHIVE "/11-2/0000000200000007/000000020000000700000FFE-%s", walBufferSha1), walBuffer, .comment = "valid WAL"); harnessLogLevelSet(logLevelDetail); // Verify text output with no verify errors TEST_RESULT_STR_Z( verifyProcess(cfgOptionBool(cfgOptVerbose)), "stanza: db\n" "status: ok\n" " archiveId: 11-2, total WAL checked: 1, total valid WAL: 1\n" " missing: 0, checksum invalid: 0, size invalid: 0, other: 0\n" " backup: none found", "verify text output, verbose, with no failures"); TEST_RESULT_LOG( "P00 DETAIL: no backups exist in the repo\n" "P00 DETAIL: archiveId: 11-2, wal start: 000000020000000700000FFE, wal stop: 000000020000000700000FFE"); } FUNCTION_HARNESS_RETURN_VOID(); }