/*********************************************************************************************************************************** Test Info Command NOTE: references to 9.4 are intentionally included in this test to ensure that info will work with no longer supported versions. ***********************************************************************************************************************************/ #include "common/crypto/cipherBlock.h" #include "common/io/bufferRead.h" #include "common/io/bufferWrite.h" #include "storage/posix/storage.h" #include "common/harnessConfig.h" #include "common/harnessFork.h" #include "common/harnessInfo.h" /*********************************************************************************************************************************** Test Run ***********************************************************************************************************************************/ static void testRun(void) { FUNCTION_HARNESS_VOID(); // Create storage object for writing to test locations when a stanza is not set Storage *storageTest = storagePosixNewP(TEST_PATH_STR, .write = true); // The tests expect the timezone to be UTC hrnTzSet("UTC"); // ***************************************************************************************************************************** if (testBegin("infoRender()")) { StringList *argList = strLstNew(); hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH "/repo"); StringList *argListText = strLstDup(argList); hrnCfgArgRawZ(argList, cfgOptOutput, "json"); HRN_CFG_LOAD(cfgCmdInfo, argList); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("no stanzas have been created"); TEST_RESULT_STR_Z(infoRender(), "[]", "json - repo but no stanzas"); HRN_CFG_LOAD(cfgCmdInfo, argListText); TEST_RESULT_STR_Z(infoRender(), "No stanzas exist in the repository.\n", "text - no stanzas"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("repo is still empty but stanza option is specified"); StringList *argListStanzaOpt = strLstDup(argList); hrnCfgArgRawZ(argListStanzaOpt, cfgOptStanza, "stanza1"); HRN_CFG_LOAD(cfgCmdInfo, argListStanzaOpt); TEST_RESULT_STR_Z( infoRender(), // {uncrustify_off - indentation} "[" "{" "\"archive\":[]," "\"backup\":[]," "\"cipher\":\"none\"," "\"db\":[]," "\"name\":\"stanza1\"," "\"repo\":[" "{" "\"cipher\":\"none\"," "\"key\":1," "\"status\":{" "\"code\":1," "\"message\":\"missing stanza path\"" "}" "}" "]," "\"status\":{" "\"code\":1," "\"lock\":{\"backup\":{\"held\":false}}," "\"message\":\"missing stanza path\"" "}" "}" "]", // {uncrustify_on} "json - empty repo, stanza option specified"); StringList *argListTextStanzaOpt = strLstDup(argListText); hrnCfgArgRawZ(argListTextStanzaOpt, cfgOptStanza, "stanza1"); HRN_CFG_LOAD(cfgCmdInfo, argListTextStanzaOpt); TEST_RESULT_STR_Z( infoRender(), "stanza: stanza1\n" " status: error (missing stanza path)\n", "text - empty repo, stanza option specified"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("stanza path exists but is empty"); HRN_STORAGE_PATH_CREATE(storageRepoWrite(), STORAGE_REPO_ARCHIVE, .comment = "create repo stanza archive path"); HRN_STORAGE_PATH_CREATE(storageRepoWrite(), STORAGE_REPO_BACKUP, .comment = "create repo stanza backup path"); TEST_RESULT_STR_Z( infoRender(), "stanza: stanza1\n" " status: error (missing stanza data)\n" " cipher: none\n", "text - missing stanza data"); HRN_CFG_LOAD(cfgCmdInfo, argList); TEST_RESULT_STR_Z( infoRender(), // {uncrustify_off - indentation} "[" "{" "\"archive\":[]," "\"backup\":[]," "\"cipher\":\"none\"," "\"db\":[]," "\"name\":\"stanza1\"," "\"repo\":[" "{" "\"cipher\":\"none\"," "\"key\":1," "\"status\":{" "\"code\":3," "\"message\":\"missing stanza data\"" "}" "}" "]," "\"status\":{" "\"code\":3," "\"lock\":{\"backup\":{\"held\":false}}," "\"message\":\"missing stanza data\"" "}" "}" "]", // {uncrustify_on} "json - missing stanza data"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("backup.info file exists, but archive.info does not"); // Put backup info to file HRN_INFO_PUT( storageTest, TEST_PATH "/repo/" STORAGE_PATH_BACKUP "/stanza1/" INFO_BACKUP_FILE, "[db]\n" "db-catalog-version=201608131\n" "db-control-version=960\n" "db-id=2\n" "db-system-id=6569239123849665679\n" "db-version=\"9.6\"\n" "\n" "[db:history]\n" "1={\"db-catalog-version\":201510051,\"db-control-version\":960,\"db-system-id\":6569239123849665666" ",\"db-version\":\"9.5\"}\n" "2={\"db-catalog-version\":201608131,\"db-control-version\":960,\"db-system-id\":6569239123849665679" ",\"db-version\":\"9.6\"}\n"); TEST_RESULT_STR_Z( infoRender(), // {uncrustify_off - indentation} "[" "{" "\"archive\":[]," "\"backup\":[]," "\"cipher\":\"none\"," "\"db\":[]," "\"name\":\"stanza1\"," "\"repo\":[" "{" "\"cipher\":\"none\"," "\"key\":1," "\"status\":{" "\"code\":99," "\"message\":\"[FileMissingError] unable to load info file '" TEST_PATH "/repo/archive/stanza1/archive.info' or '" TEST_PATH "/repo/archive/stanza1/archive.info.copy':\\n" "FileMissingError: unable to open missing file '" TEST_PATH "/repo/archive/stanza1/archive.info'" " for read\\n" "FileMissingError: unable to open missing file '" TEST_PATH "/repo/archive/stanza1/archive.info.copy' for read\\n" "HINT: archive.info cannot be opened but is required to push/get WAL segments.\\n" "HINT: is archive_command configured correctly in postgresql.conf?\\n" "HINT: has a stanza-create been performed?\\n" "HINT: use --no-archive-check to disable archive checks during backup if you have an alternate" " archiving scheme.\"" "}" "}" "]," "\"status\":{" "\"code\":99," "\"lock\":{\"backup\":{\"held\":false}}," "\"message\":\"other\"" "}" "}" "]", // {uncrustify_on} "json - other error, single repo"); HRN_CFG_LOAD(cfgCmdInfo, argListTextStanzaOpt); TEST_RESULT_STR_Z( infoRender(), "stanza: stanza1\n" " status: error (other)\n" " [FileMissingError] unable to load info file '" TEST_PATH "/repo/archive/stanza1/archive.info' or" " '" TEST_PATH "/repo/archive/stanza1/archive.info.copy':\n" " FileMissingError: unable to open missing file '" TEST_PATH "/repo/archive/stanza1/archive.info' for read\n" " FileMissingError: unable to open missing file '" TEST_PATH "/repo/archive/stanza1/archive.info.copy'" " for read\n" " HINT: archive.info cannot be opened but is required to push/get WAL segments.\n" " HINT: is archive_command configured correctly in postgresql.conf?\n" " HINT: has a stanza-create been performed?\n" " HINT: use --no-archive-check to disable archive checks during backup if you have an alternate archiving" " scheme.\n" " cipher: none\n", "text - other error, single repo"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("info files exist with mismatched db-ids and no current backups - lock detected"); // Only the current db information from the db:history will be processed. HRN_INFO_PUT( storageRepoWrite(), INFO_ARCHIVE_PATH_FILE, "[db]\n" "db-id=3\n" "db-system-id=6569239123849665679\n" "db-version=\"9.6\"\n" "\n" "[db:history]\n" "1={\"db-id\":6569239123849665679,\"db-version\":\"9.6\"}\n" "2={\"db-id\":6569239123849665666,\"db-version\":\"9.5\"}\n" "3={\"db-id\":6569239123849665679,\"db-version\":\"9.6\"}\n"); // Create a WAL directory in 9.5-2 but since there are no WAL files or backups it will not show HRN_STORAGE_PATH_CREATE( storageRepoWrite(), STORAGE_REPO_ARCHIVE "/9.5-2/0000000100000000", .comment = "create empty db2 archive WAL1 directory"); // archive section will cross reference backup db-id 2 to archive db-id 3 but db section will only use the db-ids from // backup.info. Execute while a backup lock is held. HRN_FORK_BEGIN() { HRN_FORK_CHILD_BEGIN() { lockInit(cfgOptionStr(cfgOptLockPath), STRDEF("999-ffffffff")); TEST_RESULT_BOOL( lockAcquireP(cmdLockFileName(STRDEF("stanza1"), lockTypeBackup, 1)), true, "create backup/expire lock"); // Notify parent that lock has been acquired HRN_FORK_CHILD_NOTIFY_PUT(); // Wait for parent to allow release lock HRN_FORK_CHILD_NOTIFY_GET(); lockReleaseP(); } HRN_FORK_CHILD_END(); HRN_FORK_PARENT_BEGIN() { // Wait for child to acquire lock HRN_FORK_PARENT_NOTIFY_GET(0); HRN_CFG_LOAD(cfgCmdInfo, argList); TEST_RESULT_STR_Z( infoRender(), // {uncrustify_off - indentation} "[" "{" "\"archive\":[" "{" "\"database\":{" "\"id\":2," "\"repo-key\":1" "}," "\"id\":\"9.6-3\"," "\"max\":null," "\"min\":null" "}" "]," "\"backup\":[]," "\"cipher\":\"none\"," "\"db\":[" "{" "\"id\":1," "\"repo-key\":1," "\"system-id\":6569239123849665666," "\"version\":\"9.5\"" "}," "{" "\"id\":2," "\"repo-key\":1," "\"system-id\":6569239123849665679," "\"version\":\"9.6\"" "}" "]," "\"name\":\"stanza1\"," "\"repo\":[" "{" "\"cipher\":\"none\"," "\"key\":1," "\"status\":{" "\"code\":2," "\"message\":\"no valid backups\"" "}" "}" "]," "\"status\":{" "\"code\":2," "\"lock\":{\"backup\":{\"held\":true}}," "\"message\":\"no valid backups\"" "}" "}" "]", // {uncrustify_on} "json - single stanza, no valid backups, backup/expire lock detected"); HRN_CFG_LOAD(cfgCmdInfo, argListText); TEST_RESULT_STR_Z( infoRender(), "stanza: stanza1\n" " status: error (no valid backups, backup/expire running)\n" " cipher: none\n" "\n" " db (current)\n" " wal archive min/max (9.6): none present\n", "text - single stanza, no valid backups, backup/expire lock detected"); // Notify child to release lock HRN_FORK_PARENT_NOTIFY_PUT(0); } HRN_FORK_PARENT_END(); } HRN_FORK_END(); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("multi-repo - stanza missing on specified repo"); StringList *argList2 = strLstDup(argListTextStanzaOpt); hrnCfgArgKeyRawZ(argList2, cfgOptRepoPath, 2, TEST_PATH "/repo2"); hrnCfgArgRawZ(argList2, cfgOptRepo, "2"); HRN_CFG_LOAD(cfgCmdInfo, argList2); TEST_RESULT_STR_Z( infoRender(), "stanza: stanza1\n" " status: error (missing stanza path)\n", "text - multi-repo, requested stanza missing on selected repo"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("multi-repo - WAL segment on repo1"); argList2 = strLstDup(argListTextStanzaOpt); hrnCfgArgKeyRawZ(argList2, cfgOptRepoPath, 2, TEST_PATH "/repo2"); hrnCfgArgRawZ(argList2, cfgOptRepo, "1"); HRN_CFG_LOAD(cfgCmdInfo, argList2); // Add WAL segment HRN_STORAGE_PUT_EMPTY( storageRepoIdxWrite(0), STORAGE_REPO_ARCHIVE "/9.6-3/0000000300000000/000000030000000000000001-47dff2b7552a9d66e4bae1a762488a6885e7082c.gz", .comment = "write WAL db3 timeline 3 repo1"); TEST_RESULT_STR_Z( infoRender(), "stanza: stanza1\n" " status: error (no valid backups)\n" " cipher: none\n" "\n" " db (current)\n" " wal archive min/max (9.6): 000000030000000000000001/000000030000000000000001\n", "text - multi-repo, single stanza, one wal segment"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("coverage for stanzaStatus branches && percent complete null"); // Db1 and Db3 (from above) have same system-id and db-version so consider them the same for WAL reporting HRN_STORAGE_PUT_EMPTY( storageRepoIdxWrite(0), STORAGE_REPO_ARCHIVE "/9.6-1/0000000100000000/000000010000000000000002-ac61b8f1ec7b1e6c3eaee9345214595eb7daa9a1.gz", .comment = "write WAL db1 timeline 1 repo1"); HRN_STORAGE_PUT_EMPTY( storageRepoIdxWrite(0), STORAGE_REPO_ARCHIVE "/9.6-1/0000000100000000/000000010000000000000003-37dff2b7552a9d66e4bae1a762488a6885e7082c.gz", .comment = "write WAL db1 timeline 1 repo1"); HRN_STORAGE_PUT_EMPTY( storageRepoIdxWrite(0), STORAGE_REPO_ARCHIVE "/9.6-1/0000000200000000/000000020000000000000003-37dff2b7552a9d66e4bae1a762488a6885e7082c.gz", .comment = "write WAL db1 timeline 2 repo1"); HRN_STORAGE_PATH_CREATE( storageRepoWrite(), STORAGE_REPO_ARCHIVE "/9.6-1/0000000300000000", .comment = "create empty db1 timeline 3 directory"); // Create a WAL file in 9.5-2 so that a prior will show HRN_STORAGE_PUT_EMPTY( storageRepoIdxWrite(0), STORAGE_REPO_ARCHIVE "/9.5-2/0000000100000000/000000010000000000000001-ac61b8f1ec7b1e6c3eaee9345214595eb7daa9a1.gz", .comment = "write WAL db2 timeline 1 repo1"); HRN_INFO_PUT( storageRepoIdxWrite(0), INFO_BACKUP_PATH_FILE, "[db]\n" "db-catalog-version=201608131\n" "db-control-version=960\n" "db-id=3\n" "db-system-id=6569239123849665679\n" "db-version=\"9.6\"\n" "\n" "[backup:current]\n" "20181116-154756F={\"backrest-format\":5,\"backrest-version\":\"2.04\"," "\"backup-archive-start\":null,\"backup-archive-stop\":null," "\"backup-info-repo-size\":3159776,\"backup-info-repo-size-delta\":3159,\"backup-info-size\":26897030," "\"backup-info-size-delta\":26897030,\"backup-timestamp-start\":1542383276,\"backup-timestamp-stop\":1542383289," "\"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" "20201116-154900F={\"backrest-format\":5,\"backrest-version\":\"2.30\"," "\"backup-archive-start\":\"000000030000000000000001\",\"backup-archive-stop\":\"000000030000000000000001\"," "\"backup-info-repo-size\":3159776,\"backup-info-repo-size-delta\":3159,\"backup-info-size\":26897033," "\"backup-info-size-delta\":26897033,\"backup-timestamp-start\":1605541676,\"backup-timestamp-stop\":1605541680," "\"backup-type\":\"full\",\"db-id\":3,\"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" "\n" "[db:history]\n" "1={\"db-catalog-version\":201608131,\"db-control-version\":960,\"db-system-id\":6569239123849665679" ",\"db-version\":\"9.6\"}\n" "2={\"db-catalog-version\":201510051,\"db-control-version\":960,\"db-system-id\":6569239123849665666" ",\"db-version\":\"9.5\"}\n" "3={\"db-catalog-version\":201608131,\"db-control-version\":960,\"db-system-id\":6569239123849665679" ",\"db-version\":\"9.6\"}\n"); // Execute while a backup lock is held HRN_FORK_BEGIN() { HRN_FORK_CHILD_BEGIN() { String *lockFileName = cmdLockFileName(STRDEF("stanza1"), lockTypeBackup, 1); lockInit(cfgOptionStr(cfgOptLockPath), STRDEF("777-afafafaf")); TEST_RESULT_BOOL(lockAcquireP(lockFileName), true, "create backup/expire lock"); TEST_RESULT_VOID(lockWriteP(lockFileName), "write lock data"); // Notify parent that lock has been acquired HRN_FORK_CHILD_NOTIFY_PUT(); // Wait for parent to allow release lock HRN_FORK_CHILD_NOTIFY_GET(); lockReleaseP(); } HRN_FORK_CHILD_END(); HRN_FORK_PARENT_BEGIN() { // Wait for child to acquire lock HRN_FORK_PARENT_NOTIFY_GET(0); HRN_CFG_LOAD(cfgCmdInfo, argList); TEST_RESULT_STR_Z( infoRender(), // {uncrustify_off - indentation} "[" "{" "\"archive\":[" "{" "\"database\":{" "\"id\":1," "\"repo-key\":1" "}," "\"id\":\"9.6-1\"," "\"max\":\"000000020000000000000003\"," "\"min\":\"000000010000000000000002\"" "}," "{" "\"database\":{" "\"id\":2," "\"repo-key\":1" "}," "\"id\":\"9.5-2\"," "\"max\":\"000000010000000000000001\"," "\"min\":\"000000010000000000000001\"" "}," "{" "\"database\":{" "\"id\":3," "\"repo-key\":1" "}," "\"id\":\"9.6-3\"," "\"max\":\"000000030000000000000001\"," "\"min\":\"000000030000000000000001\"" "}" "]," "\"backup\":[" "{" "\"archive\":{" "\"start\":null," "\"stop\":null" "}," "\"backrest\":{" "\"format\":5," "\"version\":\"2.04\"" "}," "\"database\":{" "\"id\":1," "\"repo-key\":1" "}," "\"info\":{" "\"delta\":26897030," "\"repository\":{" "\"delta\":3159," "\"size\":3159776" "}," "\"size\":26897030" "}," "\"label\":\"20181116-154756F\"," "\"prior\":null," "\"reference\":null," "\"timestamp\":{" "\"start\":1542383276," "\"stop\":1542383289" "}," "\"type\":\"full\"" "}," "{" "\"archive\":{" "\"start\":\"000000030000000000000001\"," "\"stop\":\"000000030000000000000001\"" "}," "\"backrest\":{" "\"format\":5," "\"version\":\"2.30\"" "}," "\"database\":{" "\"id\":3," "\"repo-key\":1" "}," "\"info\":{" "\"delta\":26897033," "\"repository\":{" "\"delta\":3159," "\"size\":3159776" "}," "\"size\":26897033" "}," "\"label\":\"20201116-154900F\"," "\"prior\":null," "\"reference\":null," "\"timestamp\":{" "\"start\":1605541676," "\"stop\":1605541680" "}," "\"type\":\"full\"" "}" "]," "\"cipher\":\"none\"," "\"db\":[" "{" "\"id\":1," "\"repo-key\":1," "\"system-id\":6569239123849665679," "\"version\":\"9.6\"" "}," "{" "\"id\":2," "\"repo-key\":1," "\"system-id\":6569239123849665666," "\"version\":\"9.5\"" "}," "{" "\"id\":3," "\"repo-key\":1," "\"system-id\":6569239123849665679," "\"version\":\"9.6\"" "}" "]," "\"name\":\"stanza1\"," "\"repo\":[" "{" "\"cipher\":\"none\"," "\"key\":1," "\"status\":{" "\"code\":0," "\"message\":\"ok\"" "}" "}" "]," "\"status\":{" "\"code\":0," "\"lock\":{\"backup\":{\"held\":true}}," "\"message\":\"ok\"" "}" "}" "]", // {uncrustify_on} "json - single stanza, valid backup, no priors, no archives in latest DB, backup/expire lock detected"); HRN_CFG_LOAD(cfgCmdInfo, argListText); TEST_RESULT_STR_Z( infoRender(), "stanza: stanza1\n" " status: ok (backup/expire running)\n" " cipher: none\n" "\n" " db (prior)\n" " wal archive min/max (9.5): 000000010000000000000001/000000010000000000000001\n" "\n" " db (current)\n" " wal archive min/max (9.6): 000000010000000000000002/000000030000000000000001\n" "\n" " full backup: 20181116-154756F\n" " timestamp start/stop: 2018-11-16 15:47:56+00 / 2018-11-16 15:48:09+00\n" " wal start/stop: n/a\n" " database size: 25.7MB, database backup size: 25.7MB\n" " repo1: backup set size: 3MB, backup size: 3.1KB\n" "\n" " full backup: 20201116-154900F\n" " timestamp start/stop: 2020-11-16 15:47:56+00 / 2020-11-16 15:48:00+00\n" " wal start/stop: 000000030000000000000001 / 000000030000000000000001\n" " database size: 25.7MB, database backup size: 25.7MB\n" " repo1: backup set size: 3MB, backup size: 3.1KB\n", "text - single stanza, valid backup, no priors, no archives in latest DB, backup/expire lock detected"); // Notify child to release lock HRN_FORK_PARENT_NOTIFY_PUT(0); } HRN_FORK_PARENT_END(); } HRN_FORK_END(); // Cleanup HRN_STORAGE_PATH_REMOVE(storageTest, TEST_PATH "/repo/" STORAGE_PATH_ARCHIVE "/stanza1/9.6-1", .recurse = true); HRN_STORAGE_PATH_REMOVE(storageTest, TEST_PATH "/repo/" STORAGE_PATH_ARCHIVE "/stanza1/9.5-2", .recurse = true); HRN_STORAGE_PATH_REMOVE(storageTest, TEST_PATH "/repo/" STORAGE_PATH_ARCHIVE "/stanza1/9.6-3", .recurse = true); // backup.info/archive.info files exist, backups exist, archives exist, multi-repo (mixed) with one stanza existing on both // repos and the db history is different between the repos // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("mixed multi-repo, percent complete non-null"); HRN_STORAGE_PUT_EMPTY( storageTest, TEST_PATH "/repo/" STORAGE_PATH_ARCHIVE "/stanza1/9.4-1/0000000100000000/000000010000000000000002-ac61b8f1ec7b1e6c3eaee9345214595eb7daa9a1.gz", .comment = "write WAL db1 timeline 1 repo1"); HRN_STORAGE_PUT_EMPTY( storageTest, TEST_PATH "/repo/" STORAGE_PATH_ARCHIVE "/stanza1/9.4-1/0000000100000000/000000010000000000000003-37dff2b7552a9d66e4bae1a762488a6885e7082c.gz", .comment = "write WAL db1 timeline 1 repo1"); HRN_STORAGE_PUT_EMPTY( storageTest, TEST_PATH "/repo/" STORAGE_PATH_ARCHIVE "/stanza1/9.4-1/0000000200000000/000000020000000000000003-37dff2b7552a9d66e4bae1a762488a6885e7082c.gz", .comment = "write WAL db1 timeline 2 repo1"); HRN_INFO_PUT( storageTest, TEST_PATH "/repo/" STORAGE_PATH_ARCHIVE "/stanza1/" INFO_ARCHIVE_FILE, "[db]\n" "db-id=2\n" "db-system-id=6626363367545678089\n" "db-version=\"9.5\"\n" "\n" "[db:history]\n" "1={\"db-id\":6625592122879095702,\"db-version\":\"9.4\"}\n" "2={\"db-id\":6626363367545678089,\"db-version\":\"9.5\"}\n", .comment = "put archive info to file - stanza1, repo1"); HRN_INFO_PUT( storageTest, TEST_PATH "/repo/" STORAGE_PATH_BACKUP "/stanza1/" INFO_BACKUP_FILE, "[backup:current]\n" "20181119-152138F={" "\"backrest-format\":5,\"backrest-version\":\"2.08dev\"," "\"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\":1542640898,\"backup-timestamp-stop\":1542640899,\"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" "20181119-152138F_20181119-152152D={" "\"backrest-format\":5,\"backrest-version\":\"2.08dev\",\"backup-archive-start\":\"000000010000000000000003\"," "\"backup-archive-stop\":\"000000020000000000000003\",\"backup-info-repo-size\":2369186," "\"backup-info-repo-size-delta\":346,\"backup-info-size\":20162900,\"backup-info-size-delta\":8428," "\"backup-prior\":\"20181119-152138F\",\"backup-reference\":[\"20181119-152138F\"]," "\"backup-timestamp-start\":1542640912,\"backup-timestamp-stop\":1542640915,\"backup-type\":\"diff\"," "\"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" "20181119-152138F_20181119-152155I={" "\"backrest-format\":5,\"backrest-version\":\"2.08dev\"," "\"backup-archive-start\":\"000000010000000000000003\"," "\"backup-info-repo-size\":2369186," "\"backup-info-repo-size-delta\":346,\"backup-info-size\":20162900,\"backup-info-size-delta\":8428," "\"backup-lsn-start\":\"285/89000028\",\"backup-lsn-stop\":\"285/89001F88\"," "\"backup-prior\":\"20181119-152138F_20181119-152152D\"," "\"backup-reference\":[\"20181119-152138F\",\"20181119-152138F_20181119-152152D\"]," "\"backup-timestamp-start\":1542640915,\"backup-timestamp-stop\":1542640917,\"backup-type\":\"incr\"," "\"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" "20201116-155000F={" "\"backrest-format\":5,\"backrest-version\":\"2.30\"," "\"backup-archive-start\":\"000000010000000000000002\",\"backup-archive-stop\":\"000000010000000000000003\"," "\"backup-info-repo-size\":3159000,\"backup-info-repo-size-delta\":3100,\"backup-info-size\":26897000," "\"backup-info-size-delta\":26897020,\"backup-timestamp-start\":1605541800,\"backup-timestamp-stop\":1605541802," "\"backup-type\":\"full\",\"db-id\":2,\"option-archive-check\":true,\"option-archive-copy\":true," "\"option-backup-standby\":false,\"option-checksum-page\":false,\"option-compress\":false,\"option-hardlink\":false," "\"option-online\":true}\n" "20201116-155000F_20201119-152100I={" "\"backrest-format\":5,\"backrest-version\":\"2.30\"," "\"backup-annotation\":{\"extra key\":\"this is an annotation\",\"source\":\"this is another annotation\"}," "\"backup-archive-start\":\"000000010000000000000005\",\"backup-archive-stop\":\"000000010000000000000005\"," "\"backup-error\":false,\"backup-info-repo-size\":2369186," "\"backup-info-repo-size-delta\":346,\"backup-info-repo-size-map\":100,\"backup-info-repo-size-map-delta\":12" ",\"backup-info-size\":20162900,\"backup-info-size-delta\":8428,\"backup-lsn-start\":\"285/89000028\"," "\"backup-prior\":\"20201116-155000F\",\"backup-reference\":[\"20201116-155000F\"]," "\"backup-timestamp-start\":1605799260,\"backup-timestamp-stop\":1605799263,\"backup-type\":\"incr\"," "\"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" "\n" "[db]\n" "db-catalog-version=201510051\n" "db-control-version=942\n" "db-id=2\n" "db-system-id=6626363367545678089\n" "db-version=\"9.5\"\n" "\n" "[db:history]\n" "1={\"db-catalog-version\":201409291,\"db-control-version\":942,\"db-system-id\":6625592122879095702" ",\"db-version\":\"9.4\"}\n" "2={\"db-catalog-version\":201510051,\"db-control-version\":942,\"db-system-id\":6626363367545678089" ",\"db-version\":\"9.5\"}\n", .comment = "put backup info to file - stanza1, repo1"); // Manifest with all features #define TEST_MANIFEST_HEADER \ "[backup]\n" \ "backup-archive-start=\"000000030000028500000089\"\n" \ "backup-archive-stop=\"000000030000028500000089\"\n" \ "backup-label=\"20190818-084502F_20190820-084502D\"\n" \ "backup-lsn-start=\"285/89000028\"\n" \ "backup-lsn-stop=\"285/89001F88\"\n" \ "backup-prior=\"20190818-084502F\"\n" \ "backup-timestamp-copy-start=1565282141\n" \ "backup-timestamp-start=1565282140\n" \ "backup-timestamp-stop=1565282142\n" \ "backup-type=\"full\"\n" \ "\n" \ "[backup:db]\n" \ "db-catalog-version=201409291\n" \ "db-control-version=942\n" \ "db-id=1\n" \ "db-system-id=1000000000000000094\n" \ "db-version=\"9.4\"\n" \ "\n" \ "[backup:option]\n" \ "option-archive-check=true\n" \ "option-archive-copy=true\n" \ "option-backup-standby=false\n" \ "option-buffer-size=16384\n" \ "option-checksum-page=true\n" \ "option-compress=false\n" \ "option-compress-level=3\n" \ "option-compress-level-network=3\n" \ "option-delta=false\n" \ "option-hardlink=false\n" \ "option-online=false\n" \ "option-process-max=32\n" #define TEST_MANIFEST_TARGET \ "\n" \ "[backup:target]\n" \ "pg_data={\"path\":\"/pg/base\",\"type\":\"path\"}\n" \ "pg_data/pg_hba.conf={\"file\":\"pg_hba.conf\",\"path\":\"../pg_config\",\"type\":\"link\"}\n" \ "pg_data/pg_stat={\"path\":\"../pg_stat\",\"type\":\"link\"}\n" \ "pg_tblspc/1={\"path\":\"/tblspc/ts1\",\"tablespace-id\":\"1\",\"tablespace-name\":\"ts1\",\"type\":\"link\"}\n" \ "pg_tblspc/12={\"path\":\"/tblspc/ts12\",\"tablespace-id\":\"12\",\"tablespace-name\":\"ts12\",\"type\":\"link\"}\n" #define TEST_MANIFEST_DB \ "\n" \ "[db]\n" \ "mail={\"db-id\":16456,\"db-last-system-id\":99999}\n" \ "postgres={\"db-id\":12173,\"db-last-system-id\":99999}\n" \ "template0={\"db-id\":12168,\"db-last-system-id\":99999}\n" \ "template1={\"db-id\":1,\"db-last-system-id\":99999}\n" \ #define TEST_MANIFEST_FILE \ "\n" \ "[target:file]\n" \ "pg_data/PG_VERSION={\"checksum\":\"184473f470864e067ee3a22e64b47b0a1c356f29\"" \ ",\"reference\":\"20190818-084502F_20190819-084506D\",\"size\":4,\"timestamp\":1565282114}\n" \ "pg_data/base/16384/17000={\"checksum\":\"e0101dd8ffb910c9c202ca35b5f828bcb9697bed\",\"checksum-page\":false" \ ",\"checksum-page-error\":[1],\"repo-size\":4096,\"size\":8192,\"timestamp\":1565282114}\n" \ "pg_data/base/16384/PG_VERSION={\"checksum\":\"184473f470864e067ee3a22e64b47b0a1c356f29\",\"group\":false,\"size\":4" \ ",\"timestamp\":1565282115}\n" \ "pg_data/base/32768/33000={\"checksum\":\"7a16d165e4775f7c92e8cdf60c0af57313f0bf90\",\"checksum-page\":true" \ ",\"reference\":\"20190818-084502F\",\"size\":1073741824,\"timestamp\":1565282116}\n" \ "pg_data/base/32768/33000.32767={\"checksum\":\"6e99b589e550e68e934fd235ccba59fe5b592a9e\",\"checksum-page\":true" \ ",\"reference\":\"20190818-084502F\",\"size\":32768,\"timestamp\":1565282114}\n" \ "pg_data/postgresql.conf={\"checksum\":\"6721d92c9fcdf4248acff1f9a1377127d9064807\",\"size\":4457" \ ",\"timestamp\":1565282114}\n" \ "pg_data/special={\"mode\":\"0640\",\"size\":0,\"timestamp\":1565282120,\"user\":false}\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" \ "pg_data/postgresql.conf={\"destination\":\"../pg_config/postgresql.conf\",\"group\":false,\"user\":\"user1\"}\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\":\"user2\"}\n" \ "pg_data/base={\"group\":\"group2\"}\n" \ "pg_data/base/16384={\"mode\":\"0750\"}\n" \ "pg_data/base/32768={}\n" \ "pg_data/base/65536={\"user\":false}\n" #define TEST_MANIFEST_PATH_DEFAULT \ "\n" \ "[target:path:default]\n" \ "group=false\n" \ "mode=\"0700\"\n" \ "user=\"user1\"\n" HRN_INFO_PUT( storageTest, TEST_PATH "/repo/" STORAGE_PATH_BACKUP "/stanza1/20181119-152138F_20181119-152155I/" BACKUP_MANIFEST_FILE, TEST_MANIFEST_HEADER 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 = "write manifest - stanza1, repo1"); HRN_INFO_PUT( storageTest, TEST_PATH "/repo/" STORAGE_PATH_ARCHIVE "/stanza2/" INFO_ARCHIVE_FILE, "[db]\n" "db-id=1\n" "db-system-id=6625633699176220261\n" "db-version=\"9.4\"\n" "\n" "[db:history]\n" "1={\"db-id\":6625633699176220261,\"db-version\":\"9.4\"}\n", .comment = "put archive info to file - stanza2, repo1"); HRN_INFO_PUT( storageTest, TEST_PATH "/repo/" STORAGE_PATH_BACKUP "/stanza2/" INFO_BACKUP_FILE, "[db]\n" "db-catalog-version=201409291\n" "db-control-version=942\n" "db-id=1\n" "db-system-id=6625633699176220261\n" "db-version=\"9.4\"\n" "\n" "[db:history]\n" "1={\"db-catalog-version\":201409291,\"db-control-version\":942,\"db-system-id\":6625633699176220261" ",\"db-version\":\"9.4\"}\n", .comment = "put backup info to file - stanza2, repo1"); // Write encrypted info files to encrypted repo2 HRN_INFO_PUT( storageTest, TEST_PATH "/repo2/" STORAGE_PATH_ARCHIVE "/stanza1/" INFO_ARCHIVE_FILE, "[db]\n" "db-id=1\n" "db-system-id=6626363367545678089\n" "db-version=\"9.5\"\n" "\n" "[cipher]\n" "cipher-pass=\"" TEST_CIPHER_PASS_ARCHIVE "\"\n" "\n" "[db:history]\n" "1={\"db-id\":6626363367545678089,\"db-version\":\"9.5\"}\n", .cipherType = cipherTypeAes256Cbc, .cipherPass = TEST_CIPHER_PASS, .comment = "write encrypted archive.info, stanza1, repo2"); HRN_INFO_PUT( storageTest, TEST_PATH "/repo2/" STORAGE_PATH_BACKUP "/stanza1/" INFO_BACKUP_FILE, "[db]\n" "db-catalog-version=201510051\n" "db-control-version=942\n" "db-id=1\n" "db-system-id=6626363367545678089\n" "db-version=\"9.5\"\n" "\n" "[backup:current]\n" "20201116-200000F={\"backrest-format\":5,\"backrest-version\":\"2.30\"," "\"backup-archive-start\":\"000000010000000000000004\",\"backup-archive-stop\":\"000000010000000000000004\"," "\"backup-error\":true," "\"backup-info-repo-size\":3159000,\"backup-info-repo-size-delta\":3100,\"backup-info-size\":26897000," "\"backup-info-size-delta\":26897020,\"backup-timestamp-start\":1605556800,\"backup-timestamp-stop\":1605556805," "\"backup-type\":\"full\",\"db-id\":1,\"option-archive-check\":true,\"option-archive-copy\":true," "\"option-backup-standby\":true,\"option-checksum-page\":false,\"option-compress\":false,\"option-hardlink\":true," "\"option-online\":true}\n" "\n" "[cipher]\n" "cipher-pass=\"somepass\"\n" "\n" "[db:history]\n" "1={\"db-catalog-version\":201510051,\"db-control-version\":942,\"db-system-id\":6626363367545678089" ",\"db-version\":\"9.5\"}\n", .cipherType = cipherTypeAes256Cbc, .cipherPass = TEST_CIPHER_PASS, .comment = "write encrypted backup.info, stanza1, repo2"); // Add WAL on repo1 and encrypted repo2 for stanza1 HRN_STORAGE_PUT_EMPTY( storageTest, TEST_PATH "/repo/" STORAGE_PATH_ARCHIVE "/stanza1/9.5-2/0000000100000000/000000010000000000000002-ac61b8f1ec7b1e6c3eaee9345214595eb7daa9a1.gz"); HRN_STORAGE_PUT_EMPTY( storageTest, TEST_PATH "/repo/" STORAGE_PATH_ARCHIVE "/stanza1/9.5-2/0000000100000000/000000010000000000000003-37dff2b7552a9d66e4bae1a762488a6885e7082c.gz"); HRN_STORAGE_PUT_EMPTY( storageTest, TEST_PATH "/repo/" STORAGE_PATH_ARCHIVE "/stanza1/9.5-2/0000000100000000/000000010000000000000004-ee61b8f1ec7b1e6c3eaee9345214595eb7daa9a1.gz"); HRN_STORAGE_PUT_EMPTY( storageTest, TEST_PATH "/repo/" STORAGE_PATH_ARCHIVE "/stanza1/9.5-2/0000000100000000/000000010000000000000005-abc123f1ec7b1e6c3eaee9345214595eb7daa9a1.gz"); HRN_STORAGE_PUT_EMPTY( storageTest, TEST_PATH "/repo2/" STORAGE_PATH_ARCHIVE "/stanza1/9.5-1/0000000100000000/000000010000000000000003-37dff2b7552a9d66e4bae1a762488a6885e7082c.gz"); HRN_STORAGE_PUT_EMPTY( storageTest, TEST_PATH "/repo2/" STORAGE_PATH_ARCHIVE "/stanza1/9.5-1/0000000100000000/000000010000000000000004-ff61b8f1ec7b1e6c3eaee9345214595eb7daa9a1.gz"); // Add a manifest on the encrypted repo2 #define TEST_MANIFEST_HEADER2 \ "[backup]\n" \ "backup-archive-start=\"000000010000000000000004\"\n" \ "backup-archive-stop=\"000000010000000000000004\"\n" \ "backup-label=\"20201116-200000F\"\n" \ "backup-timestamp-copy-start=1605556800\n" \ "backup-timestamp-start=1605556800\n" \ "backup-timestamp-stop=1605556802\n" \ "backup-type=\"full\"\n" \ "\n" \ "[backup:db]\n" \ "db-catalog-version=201510051\n" \ "db-control-version=942\n" \ "db-id=1\n" \ "db-system-id=6626363367545678089\n" \ "db-version=\"9.5\"\n" \ "\n" \ "[backup:option]\n" \ "option-archive-check=true\n" \ "option-archive-copy=true\n" \ "option-backup-standby=true\n" \ "option-buffer-size=16384\n" \ "option-checksum-page=false\n" \ "option-compress=false\n" \ "option-compress-level=3\n" \ "option-compress-level-network=3\n" \ "option-delta=false\n" \ "option-hardlink=true\n" \ "option-online=true\n" \ "option-process-max=32\n" \ // Create encrypted manifest file HRN_INFO_PUT( storageTest, TEST_PATH "/repo2/" STORAGE_PATH_BACKUP "/stanza1/20201116-200000F/" BACKUP_MANIFEST_FILE, TEST_MANIFEST_HEADER2 TEST_MANIFEST_TARGET "\n" "[cipher]\n" "cipher-pass=\"someotherpass\"\n" TEST_MANIFEST_DB TEST_MANIFEST_FILE TEST_MANIFEST_FILE_DEFAULT TEST_MANIFEST_LINK TEST_MANIFEST_LINK_DEFAULT TEST_MANIFEST_PATH TEST_MANIFEST_PATH_DEFAULT, .cipherType = cipherTypeAes256Cbc, .cipherPass = "somepass", .comment = "write encrypted manifest, stanza1, repo2"); // Create a stanza on repo2 that is not on repo1 HRN_INFO_PUT( storageTest, TEST_PATH "/repo2/" STORAGE_PATH_ARCHIVE "/stanza3/" INFO_ARCHIVE_FILE, "[db]\n" "db-id=1\n" "db-system-id=6626363367545678089\n" "db-version=\"9.4\"\n" "\n" "[cipher]\n" "cipher-pass=\"" TEST_CIPHER_PASS_ARCHIVE "\"\n" "\n" "[db:history]\n" "1={\"db-id\":6626363367545678089,\"db-version\":\"9.4\"}\n", .cipherType = cipherTypeAes256Cbc, .cipherPass = TEST_CIPHER_PASS, .comment = "write encrypted archive.info, repo2, stanza3"); HRN_INFO_PUT( storageTest, TEST_PATH "/repo2/" STORAGE_PATH_BACKUP "/stanza3/" INFO_BACKUP_FILE, "[db]\n" "db-catalog-version=201409291\n" "db-control-version=942\n" "db-id=1\n" "db-system-id=6626363367545678089\n" "db-version=\"9.4\"\n" "\n" "[backup:current]\n" "20201110-100000F={\"backrest-format\":5,\"backrest-version\":\"2.25\"," "\"backup-archive-start\":\"000000010000000000000001\",\"backup-archive-stop\":\"000000010000000000000002\"," "\"backup-info-repo-size\":3159000,\"backup-info-repo-size-delta\":3100,\"backup-info-size\":26897000," "\"backup-info-size-delta\":26897020,\"backup-timestamp-start\":1605002400,\"backup-timestamp-stop\":1605002402," "\"backup-type\":\"full\",\"db-id\":1,\"option-archive-check\":true,\"option-archive-copy\":true," "\"option-backup-standby\":true,\"option-checksum-page\":false,\"option-compress\":false,\"option-hardlink\":true," "\"option-online\":true}\n" "\n" "[cipher]\n" "cipher-pass=\"somepass\"\n" "\n" "[db:history]\n" "1={\"db-catalog-version\":201409291,\"db-control-version\":942,\"db-system-id\":6626363367545678089" ",\"db-version\":\"9.4\"}\n", .cipherType = cipherTypeAes256Cbc, .cipherPass = TEST_CIPHER_PASS, .comment = "write encrypted backup.info, repo2, stanza3"); // Store some WAL in stanza on repo2 that is not on repo1 HRN_STORAGE_PUT_EMPTY( storageTest, TEST_PATH "/repo2/" STORAGE_PATH_ARCHIVE "/stanza3/9.4-1/0000000100000000/000000010000000000000001-11dff2b7552a9d66e4bae1a762488a6885e7082c.gz"); HRN_STORAGE_PUT_EMPTY( storageTest, TEST_PATH "/repo2/" STORAGE_PATH_ARCHIVE "/stanza3/9.4-1/0000000100000000/000000010000000000000002-2261b8f1ec7b1e6c3eaee9345214595eb7daa9a1.gz"); // Set up the configuration StringList *argListMultiRepo = strLstNew(); hrnCfgArgRawZ(argListMultiRepo, cfgOptRepoPath, TEST_PATH "/repo"); hrnCfgArgKeyRawZ(argListMultiRepo, cfgOptRepoPath, 2, TEST_PATH "/repo2"); hrnCfgArgKeyRawStrId(argListMultiRepo, cfgOptRepoCipherType, 2, cipherTypeAes256Cbc); hrnCfgEnvKeyRawZ(cfgOptRepoCipherPass, 2, TEST_CIPHER_PASS); StringList *argListMultiRepoJson = strLstDup(argListMultiRepo); hrnCfgArgRawZ(argListMultiRepoJson, cfgOptOutput, "json"); HRN_FORK_BEGIN() { HRN_FORK_CHILD_BEGIN() { String *lockFileName = cmdLockFileName(STRDEF("stanza2"), lockTypeBackup, 1); lockInit(cfgOptionStr(cfgOptLockPath), STRDEF("999-ffffffff")); TEST_RESULT_BOOL(lockAcquireP(lockFileName), true, "create backup/expire lock"); TEST_RESULT_VOID( lockWriteP( lockFileName, .percentComplete = VARUINT(4545), .sizeComplete = VARUINT64(1435765), .size = VARUINT64(3159000)), "write lock data"); // Notify parent that lock has been acquired HRN_FORK_CHILD_NOTIFY_PUT(); // Wait for parent to allow release lock HRN_FORK_CHILD_NOTIFY_GET(); lockReleaseP(); } HRN_FORK_CHILD_END(); HRN_FORK_PARENT_BEGIN() { // Wait for child to acquire lock HRN_FORK_PARENT_NOTIFY_GET(0); HRN_CFG_LOAD(cfgCmdInfo, argListMultiRepoJson); TEST_RESULT_STR_Z( infoRender(), // {uncrustify_off - indentation} "[" "{" "\"archive\":[" "{" "\"database\":{" "\"id\":1," "\"repo-key\":1" "}," "\"id\":\"9.4-1\"," "\"max\":\"000000020000000000000003\"," "\"min\":\"000000010000000000000002\"" "}," "{" "\"database\":{" "\"id\":2," "\"repo-key\":1" "}," "\"id\":\"9.5-2\"," "\"max\":\"000000010000000000000005\"," "\"min\":\"000000010000000000000002\"" "}," "{" "\"database\":{" "\"id\":1," "\"repo-key\":2" "}," "\"id\":\"9.5-1\"," "\"max\":\"000000010000000000000004\"," "\"min\":\"000000010000000000000003\"" "}" "]," "\"backup\":[" "{" "\"archive\":{" "\"start\":\"000000010000000000000002\"," "\"stop\":\"000000010000000000000002\"" "}," "\"backrest\":{" "\"format\":5," "\"version\":\"2.08dev\"" "}," "\"database\":{" "\"id\":1," "\"repo-key\":1" "}," "\"info\":{" "\"delta\":20162900," "\"repository\":{" "\"delta\":2369186," "\"size\":2369186" "}," "\"size\":20162900" "}," "\"label\":\"20181119-152138F\"," "\"prior\":null," "\"reference\":null," "\"timestamp\":{" "\"start\":1542640898," "\"stop\":1542640899" "}," "\"type\":\"full\"" "}," "{" "\"archive\":{" "\"start\":\"000000010000000000000003\"," "\"stop\":\"000000020000000000000003\"" "}," "\"backrest\":{" "\"format\":5," "\"version\":\"2.08dev\"" "}," "\"database\":{" "\"id\":1," "\"repo-key\":1" "}," "\"info\":{" "\"delta\":8428," "\"repository\":{" "\"delta\":346," "\"size\":2369186" "}," "\"size\":20162900" "}," "\"label\":\"20181119-152138F_20181119-152152D\"," "\"prior\":\"20181119-152138F\"," "\"reference\":[" "\"20181119-152138F\"" "]," "\"timestamp\":{" "\"start\":1542640912," "\"stop\":1542640915" "}," "\"type\":\"diff\"" "}," "{" "\"archive\":{" "\"start\":\"000000010000000000000003\"," "\"stop\":null" "}," "\"backrest\":{" "\"format\":5," "\"version\":\"2.08dev\"" "}," "\"database\":{" "\"id\":1," "\"repo-key\":1" "}," "\"info\":{" "\"delta\":8428," "\"repository\":{" "\"delta\":346," "\"size\":2369186" "}," "\"size\":20162900" "}," "\"label\":\"20181119-152138F_20181119-152155I\"," "\"lsn\":{" "\"start\":\"285/89000028\"," "\"stop\":\"285/89001F88\"}," "\"prior\":\"20181119-152138F_20181119-152152D\"," "\"reference\":[" "\"20181119-152138F\"," "\"20181119-152138F_20181119-152152D\"" "]," "\"timestamp\":{" "\"start\":1542640915," "\"stop\":1542640917" "}," "\"type\":\"incr\"" "}," "{" "\"archive\":{" "\"start\":\"000000010000000000000002\"," "\"stop\":\"000000010000000000000003\"" "}," "\"backrest\":{" "\"format\":5," "\"version\":\"2.30\"" "}," "\"database\":{" "\"id\":2," "\"repo-key\":1" "}," "\"info\":{" "\"delta\":26897020," "\"repository\":{" "\"delta\":3100," "\"size\":3159000" "}," "\"size\":26897000" "}," "\"label\":\"20201116-155000F\"," "\"prior\":null," "\"reference\":null," "\"timestamp\":{" "\"start\":1605541800," "\"stop\":1605541802" "}," "\"type\":\"full\"" "}," "{" "\"archive\":{" "\"start\":\"000000010000000000000004\"," "\"stop\":\"000000010000000000000004\"" "}," "\"backrest\":{" "\"format\":5," "\"version\":\"2.30\"" "}," "\"database\":{" "\"id\":1," "\"repo-key\":2" "}," "\"error\":true," "\"info\":{" "\"delta\":26897020," "\"repository\":{" "\"delta\":3100," "\"size\":3159000" "}," "\"size\":26897000" "}," "\"label\":\"20201116-200000F\"," "\"prior\":null," "\"reference\":null," "\"timestamp\":{" "\"start\":1605556800," "\"stop\":1605556805" "}," "\"type\":\"full\"" "}," "{" "\"annotation\":{" "\"extra key\":\"this is an annotation\"," "\"source\":\"this is another annotation\"" "}," "\"archive\":{" "\"start\":\"000000010000000000000005\"," "\"stop\":\"000000010000000000000005\"" "}," "\"backrest\":{" "\"format\":5," "\"version\":\"2.30\"" "}," "\"database\":{" "\"id\":2," "\"repo-key\":1" "}," "\"error\":false," "\"info\":{" "\"delta\":8428," "\"repository\":{" "\"delta\":346," "\"delta-map\":12," "\"size-map\":100" "}," "\"size\":20162900" "}," "\"label\":\"20201116-155000F_20201119-152100I\"," "\"prior\":\"20201116-155000F\"," "\"reference\":[" "\"20201116-155000F\"" "]," "\"timestamp\":{" "\"start\":1605799260," "\"stop\":1605799263" "}," "\"type\":\"incr\"" "}" "]," "\"cipher\":\"mixed\"," "\"db\":[" "{" "\"id\":1," "\"repo-key\":1," "\"system-id\":6625592122879095702," "\"version\":\"9.4\"" "}," "{" "\"id\":2," "\"repo-key\":1," "\"system-id\":6626363367545678089," "\"version\":\"9.5\"" "}," "{" "\"id\":1," "\"repo-key\":2," "\"system-id\":6626363367545678089," "\"version\":\"9.5\"" "}" "]," "\"name\":\"stanza1\"," "\"repo\":[" "{" "\"cipher\":\"none\"," "\"key\":1," "\"status\":{" "\"code\":0," "\"message\":\"ok\"" "}" "}," "{" "\"cipher\":\"aes-256-cbc\"," "\"key\":2," "\"status\":{" "\"code\":0," "\"message\":\"ok\"" "}" "}" "]," "\"status\":{" "\"code\":0," "\"lock\":{\"backup\":{\"held\":false}}," "\"message\":\"ok\"" "}" "}," "{" "\"archive\":[" "{" "\"database\":{" "\"id\":1," "\"repo-key\":1" "}," "\"id\":\"9.4-1\"," "\"max\":null," "\"min\":null" "}" "]," "\"backup\":[]," "\"cipher\":\"mixed\"," "\"db\":[" "{" "\"id\":1," "\"repo-key\":1," "\"system-id\":6625633699176220261," "\"version\":\"9.4\"" "}" "]," "\"name\":\"stanza2\"," "\"repo\":[" "{" "\"cipher\":\"none\"," "\"key\":1," "\"status\":{" "\"code\":2," "\"message\":\"no valid backups\"" "}" "}," "{" "\"cipher\":\"aes-256-cbc\"," "\"key\":2," "\"status\":{" "\"code\":1," "\"message\":\"missing stanza path\"" "}" "}" "]," "\"status\":{" "\"code\":4," "\"lock\":{\"backup\":{\"held\":true,\"size\":3159000,\"size-cplt\":1435765}}," "\"message\":\"different across repos\"" "}" "}," "{" "\"archive\":[" "{" "\"database\":{" "\"id\":1," "\"repo-key\":2" "}," "\"id\":\"9.4-1\"," "\"max\":\"000000010000000000000002\"," "\"min\":\"000000010000000000000001\"" "}" "]," "\"backup\":[" "{" "\"archive\":{" "\"start\":\"000000010000000000000001\"," "\"stop\":\"000000010000000000000002\"" "}," "\"backrest\":{" "\"format\":5," "\"version\":\"2.25\"" "}," "\"database\":{" "\"id\":1," "\"repo-key\":2" "}," "\"info\":{" "\"delta\":26897020," "\"repository\":{" "\"delta\":3100," "\"size\":3159000" "}," "\"size\":26897000" "}," "\"label\":\"20201110-100000F\"," "\"prior\":null," "\"reference\":null," "\"timestamp\":{" "\"start\":1605002400," "\"stop\":1605002402" "}," "\"type\":\"full\"" "}" "]," "\"cipher\":\"mixed\"," "\"db\":[" "{" "\"id\":1," "\"repo-key\":2," "\"system-id\":6626363367545678089," "\"version\":\"9.4\"" "}" "]," "\"name\":\"stanza3\"," "\"repo\":[" "{" "\"cipher\":\"none\"," "\"key\":1," "\"status\":{" "\"code\":1," "\"message\":\"missing stanza path\"" "}" "}," "{" "\"cipher\":\"aes-256-cbc\"," "\"key\":2," "\"status\":{" "\"code\":0," "\"message\":\"ok\"" "}" "}" "]," "\"status\":{" "\"code\":4," "\"lock\":{\"backup\":{\"held\":false}}," "\"message\":\"different across repos\"" "}" "}" "]", // {uncrustify_on} "json - multiple stanzas, some with valid backups, archives in latest DB, backup lock held on one stanza"); // Notify child to release lock HRN_FORK_PARENT_NOTIFY_PUT(0); } HRN_FORK_PARENT_END(); } HRN_FORK_END(); HRN_FORK_BEGIN() { HRN_FORK_CHILD_BEGIN() { lockInit(cfgOptionStr(cfgOptLockPath), STRDEF("999-ffffffff")); String *lockFileStanza1Repo1 = cmdLockFileName(STRDEF("stanza1"), lockTypeBackup, 1); TEST_RESULT_BOOL(lockAcquireP(lockFileStanza1Repo1), true, "create backup/expire lock"); TEST_RESULT_VOID( lockWriteP( lockFileStanza1Repo1, .size = VARUINT64(3159000), .sizeComplete = VARUINT64(1754830), .percentComplete = VARUINT(5555)), "write lock data"); String *lockFileStanza1Repo2 = cmdLockFileName(STRDEF("stanza1"), lockTypeBackup, 2); TEST_RESULT_BOOL(lockAcquireP(lockFileStanza1Repo2), true, "create backup/expire lock"); TEST_RESULT_VOID( lockWriteP( lockFileStanza1Repo2, .size = VARUINT64(3159000), .sizeComplete = VARUINT64(2369250), .percentComplete = VARUINT(7500)), "write lock data"); String *lockFileStanza2Repo1 = cmdLockFileName(STRDEF("stanza2"), lockTypeBackup, 1); TEST_RESULT_BOOL(lockAcquireP(lockFileStanza2Repo1), true, "create backup/expire lock"); TEST_RESULT_VOID( lockWriteP( lockFileStanza2Repo1, .size = VARUINT64(3159000), .sizeComplete = VARUINT64(1754830), .percentComplete = VARUINT(5555)), "write lock data"); // Notify parent that lock has been acquired HRN_FORK_CHILD_NOTIFY_PUT(); // Wait for parent to allow release lock HRN_FORK_CHILD_NOTIFY_GET(); lockReleaseP(); } HRN_FORK_CHILD_END(); HRN_FORK_PARENT_BEGIN() { // Wait for child to acquire lock HRN_FORK_PARENT_NOTIFY_GET(0); HRN_CFG_LOAD(cfgCmdInfo, argListMultiRepo); TEST_RESULT_STR_Z( infoRender(), "stanza: stanza1\n" " status: ok (backup/expire running - 65.28% complete)\n" " cipher: mixed\n" " repo1: none\n" " repo2: aes-256-cbc\n" "\n" " db (prior)\n" " wal archive min/max (9.4): 000000010000000000000002/000000020000000000000003\n" "\n" " full backup: 20181119-152138F\n" " timestamp start/stop: 2018-11-19 15:21:38+00 / 2018-11-19 15:21:39+00\n" " wal start/stop: 000000010000000000000002 / 000000010000000000000002\n" " database size: 19.2MB, database backup size: 19.2MB\n" " repo1: backup set size: 2.3MB, backup size: 2.3MB\n" "\n" " diff backup: 20181119-152138F_20181119-152152D\n" " timestamp start/stop: 2018-11-19 15:21:52+00 / 2018-11-19 15:21:55+00\n" " wal start/stop: 000000010000000000000003 / 000000020000000000000003\n" " database size: 19.2MB, database backup size: 8.2KB\n" " repo1: backup set size: 2.3MB, backup size: 346B\n" " backup reference total: 1 full\n" "\n" " incr backup: 20181119-152138F_20181119-152155I\n" " timestamp start/stop: 2018-11-19 15:21:55+00 / 2018-11-19 15:21:57+00\n" " wal start/stop: n/a\n" " database size: 19.2MB, database backup size: 8.2KB\n" " repo1: backup set size: 2.3MB, backup size: 346B\n" " backup reference total: 1 full, 1 diff\n" "\n" " db (current)\n" " wal archive min/max (9.5): 000000010000000000000002/000000010000000000000005\n" "\n" " full backup: 20201116-155000F\n" " timestamp start/stop: 2020-11-16 15:50:00+00 / 2020-11-16 15:50:02+00\n" " wal start/stop: 000000010000000000000002 / 000000010000000000000003\n" " database size: 25.7MB, database backup size: 25.7MB\n" " repo1: backup set size: 3MB, backup size: 3KB\n" "\n" " full backup: 20201116-200000F\n" " timestamp start/stop: 2020-11-16 20:00:00+00 / 2020-11-16 20:00:05+00\n" " wal start/stop: 000000010000000000000004 / 000000010000000000000004\n" " database size: 25.7MB, database backup size: 25.7MB\n" " repo2: backup set size: 3MB, backup size: 3KB\n" " error(s) detected during backup\n" "\n" " incr backup: 20201116-155000F_20201119-152100I\n" " timestamp start/stop: 2020-11-19 15:21:00+00 / 2020-11-19 15:21:03+00\n" " wal start/stop: 000000010000000000000005 / 000000010000000000000005\n" " database size: 19.2MB, database backup size: 8.2KB\n" " repo1: backup size: 346B\n" " backup reference total: 1 full\n" "\n" "stanza: stanza2\n" " status: mixed (backup/expire running - 55.55% complete)\n" " repo1: error (no valid backups)\n" " repo2: error (missing stanza path)\n" " cipher: mixed\n" " repo1: none\n" " repo2: aes-256-cbc\n" "\n" " db (current)\n" " wal archive min/max (9.4): none present\n" "\n" "stanza: stanza3\n" " status: mixed\n" " repo1: error (missing stanza path)\n" " repo2: ok\n" " cipher: mixed\n" " repo1: none\n" " repo2: aes-256-cbc\n" "\n" " db (current)\n" " wal archive min/max (9.4): 000000010000000000000001/000000010000000000000002\n" "\n" " full backup: 20201110-100000F\n" " timestamp start/stop: 2020-11-10 10:00:00+00 / 2020-11-10 10:00:02+00\n" " wal start/stop: 000000010000000000000001 / 000000010000000000000002\n" " database size: 25.7MB, database backup size: 25.7MB\n" " repo2: backup set size: 3MB, backup size: 3KB\n", "text - multiple stanzas, multi-repo with valid backups, backup lock held on one stanza"); // Notify child to release lock HRN_FORK_PARENT_NOTIFY_PUT(0); } HRN_FORK_PARENT_END(); } HRN_FORK_END(); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("multi-repo: stanza exists but requested backup does not"); argList2 = strLstDup(argListMultiRepo); hrnCfgArgRawZ(argList2, cfgOptStanza, "stanza1"); hrnCfgArgRawZ(argList2, cfgOptSet, "bogus"); HRN_CFG_LOAD(cfgCmdInfo, argList2); TEST_RESULT_STR_Z( infoRender(), "stanza: stanza1\n" " status: error (requested backup not found)\n" " cipher: mixed\n" " repo1: none\n" " repo2: aes-256-cbc\n", "text, multi-repo, backup not found"); hrnCfgArgRawZ(argList2, cfgOptOutput, "json"); HRN_CFG_LOAD(cfgCmdInfo, argList2); TEST_RESULT_STR_Z( infoRender(), // {uncrustify_off - indentation} "[" "{" "\"archive\":[]," "\"backup\":[]," "\"cipher\":\"mixed\"," "\"db\":[]," "\"name\":\"stanza1\"," "\"repo\":[" "{" "\"cipher\":\"none\"," "\"key\":1," "\"status\":{" "\"code\":6," "\"message\":\"requested backup not found\"" "}" "}," "{" "\"cipher\":\"aes-256-cbc\"," "\"key\":2," "\"status\":{" "\"code\":6," "\"message\":\"requested backup not found\"" "}" "}" "]," "\"status\":{" "\"code\":6," "\"lock\":{\"backup\":{\"held\":false}}," "\"message\":\"requested backup not found\"" "}" "}" "]", // {uncrustify_on} "json, multi-repo, backup not found"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("multi-repo: backup set requested on single repo, with 1 checksum error"); argList2 = strLstDup(argListMultiRepo); hrnCfgArgRawZ(argList2, cfgOptStanza, "stanza1"); hrnCfgArgRawZ(argList2, cfgOptSet, "20181119-152138F_20181119-152155I"); hrnCfgArgRawZ(argList2, cfgOptRepo, "1"); HRN_CFG_LOAD(cfgCmdInfo, argList2); // Switch to America/New_York to test + timezone offset without minutes hrnTzSet("America/New_York"); TEST_RESULT_STR_Z( infoRender(), "stanza: stanza1\n" " status: ok\n" " cipher: none\n" "\n" " db (prior)\n" " wal archive min/max (9.4): 000000010000000000000002/000000020000000000000003\n" "\n" " incr backup: 20181119-152138F_20181119-152155I\n" " timestamp start/stop: 2018-11-19 10:21:55-05 / 2018-11-19 10:21:57-05\n" " wal start/stop: n/a\n" " lsn start/stop: 285/89000028 / 285/89001F88\n" " database size: 19.2MB, database backup size: 8.2KB\n" " repo1: backup set size: 2.3MB, backup size: 346B\n" " backup reference list: 20181119-152138F, 20181119-152138F_20181119-152152D\n" " database list: mail (16456), postgres (12173)\n" " symlinks:\n" " pg_hba.conf => ../pg_config/pg_hba.conf\n" " pg_stat => ../pg_stat\n" " tablespaces:\n" " ts1 (1) => /tblspc/ts1\n" " ts12 (12) => /tblspc/ts12\n" " error list: base/16384/17000\n", "text - backup set requested"); // Reset timezone hrnTzSet("UTC"); hrnCfgArgRawZ(argList2, cfgOptOutput, "json"); HRN_CFG_LOAD(cfgCmdInfo, argList2); TEST_RESULT_STR_Z( infoRender(), // {uncrustify_off - indentation} "[" "{" "\"archive\":[" "{" "\"database\":{" "\"id\":1," "\"repo-key\":1" "}," "\"id\":\"9.4-1\"," "\"max\":\"000000020000000000000003\"," "\"min\":\"000000010000000000000002\"" "}," "{" "\"database\":{" "\"id\":2," "\"repo-key\":1" "}," "\"id\":\"9.5-2\"," "\"max\":\"000000010000000000000005\"," "\"min\":\"000000010000000000000002\"" "}" "]," "\"backup\":[" "{" "\"archive\":{" "\"start\":\"000000010000000000000003\"," "\"stop\":null" "}," "\"backrest\":{" "\"format\":5," "\"version\":\"2.08dev\"" "}," "\"database\":{" "\"id\":1," "\"repo-key\":1" "}," "\"database-ref\":[" "{\"name\":\"mail\",\"oid\":16456}," "{\"name\":\"postgres\",\"oid\":12173}" "]," "\"error\":true," "\"error-list\":[\"base/16384/17000\"]," "\"info\":{" "\"delta\":8428," "\"repository\":{" "\"delta\":346," "\"size\":2369186" "}," "\"size\":20162900" "}," "\"label\":\"20181119-152138F_20181119-152155I\"," "\"link\":[" "{\"destination\":\"../pg_config/pg_hba.conf\",\"name\":\"pg_hba.conf\"}," "{\"destination\":\"../pg_stat\",\"name\":\"pg_stat\"}" "]," "\"lsn\":{\"start\":\"285/89000028\",\"stop\":\"285/89001F88\"}," "\"prior\":\"20181119-152138F_20181119-152152D\"," "\"reference\":[\"20181119-152138F\",\"20181119-152138F_20181119-152152D\"]," "\"tablespace\":[" "{\"destination\":\"/tblspc/ts1\",\"name\":\"ts1\",\"oid\":1}," "{\"destination\":\"/tblspc/ts12\",\"name\":\"ts12\",\"oid\":12}" "]," "\"timestamp\":{" "\"start\":1542640915," "\"stop\":1542640917" "}," "\"type\":\"incr\"" "}" "]," "\"cipher\":\"none\"," "\"db\":[" "{" "\"id\":1," "\"repo-key\":1," "\"system-id\":6625592122879095702," "\"version\":\"9.4\"" "}," "{" "\"id\":2," "\"repo-key\":1," "\"system-id\":6626363367545678089," "\"version\":\"9.5\"" "}" "]," "\"name\":\"stanza1\"," "\"repo\":[" "{" "\"cipher\":\"none\"," "\"key\":1," "\"status\":{" "\"code\":0," "\"message\":\"ok\"" "}" "}" "]," "\"status\":{" "\"code\":0," "\"lock\":{\"backup\":{\"held\":false}}," "\"message\":\"ok\"" "}" "}" "]", // {uncrustify_on} "json - backup set requested"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("multi-repo: filter by backup type"); argList2 = strLstDup(argListMultiRepo); hrnCfgArgRawZ(argList2, cfgOptStanza, "stanza1"); hrnCfgArgRawZ(argList2, cfgOptType, "full"); HRN_CFG_LOAD(cfgCmdInfo, argList2); TEST_RESULT_STR_Z( infoRender(), "stanza: stanza1\n" " status: ok\n" " cipher: mixed\n" " repo1: none\n" " repo2: aes-256-cbc\n" "\n" " db (prior)\n" " wal archive min/max (9.4): 000000010000000000000002/000000020000000000000003\n" "\n" " full backup: 20181119-152138F\n" " timestamp start/stop: 2018-11-19 15:21:38+00 / 2018-11-19 15:21:39+00\n" " wal start/stop: 000000010000000000000002 / 000000010000000000000002\n" " database size: 19.2MB, database backup size: 19.2MB\n" " repo1: backup set size: 2.3MB, backup size: 2.3MB\n" "\n" " db (current)\n" " wal archive min/max (9.5): 000000010000000000000002/000000010000000000000005\n" "\n" " full backup: 20201116-155000F\n" " timestamp start/stop: 2020-11-16 15:50:00+00 / 2020-11-16 15:50:02+00\n" " wal start/stop: 000000010000000000000002 / 000000010000000000000003\n" " database size: 25.7MB, database backup size: 25.7MB\n" " repo1: backup set size: 3MB, backup size: 3KB\n" "\n" " full backup: 20201116-200000F\n" " timestamp start/stop: 2020-11-16 20:00:00+00 / 2020-11-16 20:00:05+00\n" " wal start/stop: 000000010000000000000004 / 000000010000000000000004\n" " database size: 25.7MB, database backup size: 25.7MB\n" " repo2: backup set size: 3MB, backup size: 3KB\n" " error(s) detected during backup\n", "text - multi-repo, filter by backup type"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("multi-repo: read encrypted manifest and confirm requested database found without setting --repo"); argList2 = strLstDup(argListMultiRepo); hrnCfgArgRawZ(argList2, cfgOptStanza, "stanza1"); hrnCfgArgRawZ(argList2, cfgOptSet, "20201116-200000F"); HRN_CFG_LOAD(cfgCmdInfo, argList2); // Switch to Asia/Kolkata to test - timezone offset with 30 minutes hrnTzSet("Asia/Kolkata"); TEST_RESULT_STR_Z( infoRender(), "stanza: stanza1\n" " status: ok\n" " cipher: mixed\n" " repo1: none\n" " repo2: aes-256-cbc\n" "\n" " db (current)\n" " wal archive min/max (9.5): 000000010000000000000002/000000010000000000000005\n" "\n" " full backup: 20201116-200000F\n" " timestamp start/stop: 2020-11-17 01:30:00+05:30 / 2020-11-17 01:30:05+05:30\n" " wal start/stop: 000000010000000000000004 / 000000010000000000000004\n" " database size: 25.7MB, database backup size: 25.7MB\n" " repo2: backup set size: 3MB, backup size: 3KB\n" " database list: mail (16456), postgres (12173)\n" " symlinks:\n" " pg_hba.conf => ../pg_config/pg_hba.conf\n" " pg_stat => ../pg_stat\n" " tablespaces:\n" " ts1 (1) => /tblspc/ts1\n" " ts12 (12) => /tblspc/ts12\n" " error list: base/16384/17000\n", "text - multi-repo, backup set requested, found on repo2, report stanza and db over all repos"); // Reset timezone hrnTzSet("UTC"); hrnCfgArgRawZ(argList2, cfgOptOutput, "json"); HRN_CFG_LOAD(cfgCmdInfo, argList2); TEST_RESULT_STR_Z( infoRender(), // {uncrustify_off - indentation} "[" "{" "\"archive\":[" "{" "\"database\":{" "\"id\":1," "\"repo-key\":1" "}," "\"id\":\"9.4-1\"," "\"max\":\"000000020000000000000003\"," "\"min\":\"000000010000000000000002\"" "}," "{" "\"database\":{" "\"id\":2," "\"repo-key\":1" "}," "\"id\":\"9.5-2\"," "\"max\":\"000000010000000000000005\"," "\"min\":\"000000010000000000000002\"" "}," "{" "\"database\":{" "\"id\":1," "\"repo-key\":2" "}," "\"id\":\"9.5-1\"," "\"max\":\"000000010000000000000004\"," "\"min\":\"000000010000000000000003\"" "}" "]," "\"backup\":[" "{" "\"archive\":{" "\"start\":\"000000010000000000000004\"," "\"stop\":\"000000010000000000000004\"" "}," "\"backrest\":{" "\"format\":5," "\"version\":\"2.30\"" "}," "\"database\":{" "\"id\":1," "\"repo-key\":2" "}," "\"database-ref\":[" "{\"name\":\"mail\",\"oid\":16456}," "{\"name\":\"postgres\",\"oid\":12173}" "]," "\"error\":true," "\"error-list\":[\"base/16384/17000\"]," "\"info\":{" "\"delta\":26897020," "\"repository\":{" "\"delta\":3100," "\"size\":3159000" "}," "\"size\":26897000" "}," "\"label\":\"20201116-200000F\"," "\"link\":[" "{\"destination\":\"../pg_config/pg_hba.conf\",\"name\":\"pg_hba.conf\"}," "{\"destination\":\"../pg_stat\",\"name\":\"pg_stat\"}" "]," "\"prior\":null," "\"reference\":null," "\"tablespace\":[" "{\"destination\":\"/tblspc/ts1\",\"name\":\"ts1\",\"oid\":1}," "{\"destination\":\"/tblspc/ts12\",\"name\":\"ts12\",\"oid\":12}" "]," "\"timestamp\":{" "\"start\":1605556800," "\"stop\":1605556805" "}," "\"type\":\"full\"" "}" "]," "\"cipher\":\"mixed\"," "\"db\":[" "{" "\"id\":1," "\"repo-key\":1," "\"system-id\":6625592122879095702," "\"version\":\"9.4\"" "}," "{" "\"id\":2," "\"repo-key\":1," "\"system-id\":6626363367545678089," "\"version\":\"9.5\"" "}," "{" "\"id\":1," "\"repo-key\":2," "\"system-id\":6626363367545678089," "\"version\":\"9.5\"" "}" "]," "\"name\":\"stanza1\"," "\"repo\":[" "{" "\"cipher\":\"none\"," "\"key\":1," "\"status\":{" "\"code\":0," "\"message\":\"ok\"" "}" "}," "{" "\"cipher\":\"aes-256-cbc\"," "\"key\":2," "\"status\":{" "\"code\":0," "\"message\":\"ok\"" "}" "}" "]," "\"status\":{" "\"code\":0," "\"lock\":{\"backup\":{\"held\":false}}," "\"message\":\"ok\"" "}" "}" "]", // {uncrustify_on} "json - multi-repo, backup set requested, found on repo2, report stanza and db over all repos"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("backup set requested but no links, multiple checksum errors"); // Remove the environment variable so config system will only count one repo hrnCfgEnvKeyRemoveRaw(cfgOptRepoCipherPass, 2); argList2 = strLstDup(argListTextStanzaOpt); hrnCfgArgRawZ(argList2, cfgOptSet, "20181119-152138F_20181119-152155I"); hrnCfgArgRawZ(argList2, cfgOptRepo, "1"); HRN_CFG_LOAD(cfgCmdInfo, argList2); #define TEST_MANIFEST_TARGET_NO_LINK \ "\n" \ "[backup:target]\n" \ "pg_data={\"path\":\"/pg/base\",\"type\":\"path\"}\n" \ #define TEST_MANIFEST_FILE_MULTIPLE_CHECKSUM_ERRORS \ "\n" \ "[target:file]\n" \ "pg_data/PG_VERSION={\"checksum\":\"184473f470864e067ee3a22e64b47b0a1c356f29\"" \ ",\"reference\":\"20190818-084502F_20190819-084506D\",\"size\":4,\"timestamp\":1565282114}\n" \ "pg_data/base/16384/17000={\"checksum\":\"e0101dd8ffb910c9c202ca35b5f828bcb9697bed\",\"checksum-page\":false" \ ",\"checksum-page-error\":[1],\"repo-size\":4096,\"size\":8192,\"timestamp\":1565282114}\n" \ "pg_data/base/16384/PG_VERSION={\"checksum\":\"184473f470864e067ee3a22e64b47b0a1c356f29\",\"group\":false,\"size\":4" \ ",\"timestamp\":1565282115}\n" \ "pg_data/base/32768/33000={\"checksum\":\"7a16d165e4775f7c92e8cdf60c0af57313f0bf90\",\"checksum-page\":false" \ ",\"reference\":\"20190818-084502F\",\"size\":1073741824,\"timestamp\":1565282116}\n" \ "pg_data/base/32768/33000.32767={\"checksum\":\"6e99b589e550e68e934fd235ccba59fe5b592a9e\",\"checksum-page\":true" \ ",\"reference\":\"20190818-084502F\",\"size\":32768,\"timestamp\":1565282114}\n" \ "pg_data/postgresql.conf={\"checksum\":\"6721d92c9fcdf4248acff1f9a1377127d9064807\",\"size\":4457" \ ",\"timestamp\":1565282114}\n" \ "pg_data/special={\"mode\":\"0640\",\"size\":0,\"timestamp\":1565282120,\"user\":false}\n" HRN_INFO_PUT( storageRepoWrite(), STORAGE_REPO_BACKUP "/20181119-152138F_20181119-152155I/" BACKUP_MANIFEST_FILE, TEST_MANIFEST_HEADER TEST_MANIFEST_TARGET_NO_LINK TEST_MANIFEST_DB TEST_MANIFEST_FILE_MULTIPLE_CHECKSUM_ERRORS TEST_MANIFEST_FILE_DEFAULT TEST_MANIFEST_LINK TEST_MANIFEST_LINK_DEFAULT TEST_MANIFEST_PATH TEST_MANIFEST_PATH_DEFAULT, .comment = "write manifest with checksum errors and no links"); // Switch to Pacific/Chatham to test + timezone offset with 45 minutes hrnTzSet("Pacific/Chatham"); TEST_RESULT_STR_Z( infoRender(), "stanza: stanza1\n" " status: ok\n" " cipher: none\n" "\n" " db (prior)\n" " wal archive min/max (9.4): 000000010000000000000002/000000020000000000000003\n" "\n" " incr backup: 20181119-152138F_20181119-152155I\n" " timestamp start/stop: 2018-11-20 05:06:55+13:45 / 2018-11-20 05:06:57+13:45\n" " wal start/stop: n/a\n" " lsn start/stop: 285/89000028 / 285/89001F88\n" " database size: 19.2MB, database backup size: 8.2KB\n" " repo1: backup set size: 2.3MB, backup size: 346B\n" " backup reference list: 20181119-152138F, 20181119-152138F_20181119-152152D\n" " database list: mail (16456), postgres (12173)\n" " error list: base/16384/17000, base/32768/33000\n", "text - backup set requested, no links"); // Reset timezone hrnTzSet("UTC"); hrnCfgArgRawZ(argList2, cfgOptOutput, "json"); HRN_CFG_LOAD(cfgCmdInfo, argList2); TEST_RESULT_STR_Z( infoRender(), // {uncrustify_off - indentation} "[" "{" "\"archive\":[" "{" "\"database\":{" "\"id\":1," "\"repo-key\":1" "}," "\"id\":\"9.4-1\"," "\"max\":\"000000020000000000000003\"," "\"min\":\"000000010000000000000002\"" "}," "{" "\"database\":{" "\"id\":2," "\"repo-key\":1" "}," "\"id\":\"9.5-2\"," "\"max\":\"000000010000000000000005\"," "\"min\":\"000000010000000000000002\"" "}" "]," "\"backup\":[" "{" "\"archive\":{" "\"start\":\"000000010000000000000003\"," "\"stop\":null" "}," "\"backrest\":{" "\"format\":5," "\"version\":\"2.08dev\"" "}," "\"database\":{" "\"id\":1,\"repo-key\":1" "}," "\"database-ref\":[" "{\"name\":\"mail\",\"oid\":16456}," "{\"name\":\"postgres\",\"oid\":12173}" "]," "\"error\":true," "\"error-list\":[\"base/16384/17000\",\"base/32768/33000\"]," "\"info\":{" "\"delta\":8428," "\"repository\":{" "\"delta\":346," "\"size\":2369186" "}," "\"size\":20162900" "}," "\"label\":\"20181119-152138F_20181119-152155I\"," "\"link\":null," "\"lsn\":{" "\"start\":\"285/89000028\"," "\"stop\":\"285/89001F88\"" "}," "\"prior\":\"20181119-152138F_20181119-152152D\"," "\"reference\":[\"20181119-152138F\",\"20181119-152138F_20181119-152152D\"]," "\"tablespace\":null," "\"timestamp\":{" "\"start\":1542640915," "\"stop\":1542640917" "}," "\"type\":\"incr\"" "}" "]," "\"cipher\":\"none\"," "\"db\":[" "{" "\"id\":1," "\"repo-key\":1," "\"system-id\":6625592122879095702," "\"version\":\"9.4\"" "}," "{" "\"id\":2," "\"repo-key\":1," "\"system-id\":6626363367545678089," "\"version\":\"9.5\"" "}" "]," "\"name\":\"stanza1\"," "\"repo\":[" "{" "\"cipher\":\"none\"," "\"key\":1," "\"status\":{" "\"code\":0," "\"message\":\"ok\"" "}" "}" "]," "\"status\":{" "\"code\":0," "\"lock\":{\"backup\":{\"held\":false}}," "\"message\":\"ok\"" "}" "}" "]", // {uncrustify_on} "json - backup set requested, no links"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("backup set requested but no databases, no checksum error"); // Using the same configuration from previous test argList2 = strLstDup(argListTextStanzaOpt); hrnCfgArgRawZ(argList2, cfgOptSet, "20181119-152138F_20181119-152155I"); hrnCfgArgRawZ(argList2, cfgOptRepo, "1"); HRN_CFG_LOAD(cfgCmdInfo, argList2); #define TEST_MANIFEST_NO_DB \ "\n" \ "[db]\n" \ "template0={\"db-id\":12168,\"db-last-system-id\":99999}\n" \ "template1={\"db-id\":1,\"db-last-system-id\":99999}\n" \ #define TEST_MANIFEST_FILE_NO_CHECKSUM_ERROR \ "\n" \ "[target:file]\n" \ "pg_data/PG_VERSION={\"checksum\":\"184473f470864e067ee3a22e64b47b0a1c356f29\"" \ ",\"reference\":\"20190818-084502F_20190819-084506D\",\"size\":4,\"timestamp\":1565282114}\n" \ "pg_data/base/16384/17000={\"checksum\":\"e0101dd8ffb910c9c202ca35b5f828bcb9697bed\",\"checksum-page\":true" \ ",\"checksum-page-error\":[1],\"repo-size\":4096,\"size\":8192,\"timestamp\":1565282114}\n" \ "pg_data/base/16384/PG_VERSION={\"checksum\":\"184473f470864e067ee3a22e64b47b0a1c356f29\",\"group\":false,\"size\":4" \ ",\"timestamp\":1565282115}\n" \ "pg_data/base/32768/33000={\"checksum\":\"7a16d165e4775f7c92e8cdf60c0af57313f0bf90\",\"checksum-page\":true" \ ",\"reference\":\"20190818-084502F\",\"size\":1073741824,\"timestamp\":1565282116}\n" \ "pg_data/base/32768/33000.32767={\"checksum\":\"6e99b589e550e68e934fd235ccba59fe5b592a9e\",\"checksum-page\":true" \ ",\"reference\":\"20190818-084502F\",\"size\":32768,\"timestamp\":1565282114}\n" \ "pg_data/postgresql.conf={\"checksum\":\"6721d92c9fcdf4248acff1f9a1377127d9064807\",\"size\":4457" \ ",\"timestamp\":1565282114}\n" \ "pg_data/special={\"mode\":\"0640\",\"size\":0,\"timestamp\":1565282120,\"user\":false}\n" HRN_INFO_PUT( storageRepoWrite(), STORAGE_REPO_BACKUP "/20181119-152138F_20181119-152155I/" BACKUP_MANIFEST_FILE, TEST_MANIFEST_HEADER TEST_MANIFEST_TARGET_NO_LINK TEST_MANIFEST_NO_DB TEST_MANIFEST_FILE_NO_CHECKSUM_ERROR TEST_MANIFEST_FILE_DEFAULT TEST_MANIFEST_LINK TEST_MANIFEST_LINK_DEFAULT TEST_MANIFEST_PATH TEST_MANIFEST_PATH_DEFAULT, .comment = " rewrite same manifest without checksum errors"); // Switch to America/St_Johns to test - timezone offset with 30 minutes hrnTzSet("America/St_Johns"); TEST_RESULT_STR_Z( infoRender(), "stanza: stanza1\n" " status: ok\n" " cipher: none\n" "\n" " db (prior)\n" " wal archive min/max (9.4): 000000010000000000000002/000000020000000000000003\n" "\n" " incr backup: 20181119-152138F_20181119-152155I\n" " timestamp start/stop: 2018-11-19 11:51:55-03:30 / 2018-11-19 11:51:57-03:30\n" " wal start/stop: n/a\n" " lsn start/stop: 285/89000028 / 285/89001F88\n" " database size: 19.2MB, database backup size: 8.2KB\n" " repo1: backup set size: 2.3MB, backup size: 346B\n" " backup reference list: 20181119-152138F, 20181119-152138F_20181119-152152D\n" " database list: none\n", "text - backup set requested, no db and no checksum error"); // Reset timezone hrnTzSet("UTC"); hrnCfgArgRawZ(argList2, cfgOptOutput, "json"); HRN_CFG_LOAD(cfgCmdInfo, argList2); TEST_RESULT_STR_Z( infoRender(), // {uncrustify_off - indentation} "[" "{" "\"archive\":[" "{" "\"database\":{" "\"id\":1," "\"repo-key\":1" "}," "\"id\":\"9.4-1\"," "\"max\":\"000000020000000000000003\"," "\"min\":\"000000010000000000000002\"" "}," "{" "\"database\":{" "\"id\":2," "\"repo-key\":1" "}," "\"id\":\"9.5-2\"," "\"max\":\"000000010000000000000005\"," "\"min\":\"000000010000000000000002\"" "}" "]," "\"backup\":[" "{" "\"archive\":{" "\"start\":\"000000010000000000000003\"," "\"stop\":null" "}," "\"backrest\":{" "\"format\":5," "\"version\":\"2.08dev\"" "}," "\"database\":{" "\"id\":1," "\"repo-key\":1" "}," "\"database-ref\":[]," "\"info\":{" "\"delta\":8428," "\"repository\":{" "\"delta\":346," "\"size\":2369186" "}," "\"size\":20162900" "}," "\"label\":\"20181119-152138F_20181119-152155I\"," "\"link\":null," "\"lsn\":{" "\"start\":\"285/89000028\"," "\"stop\":\"285/89001F88\"" "}," "\"prior\":\"20181119-152138F_20181119-152152D\"," "\"reference\":[\"20181119-152138F\",\"20181119-152138F_20181119-152152D\"]," "\"tablespace\":null," "\"timestamp\":{" "\"start\":1542640915," "\"stop\":1542640917" "}," "\"type\":\"incr\"" "}" "]," "\"cipher\":\"none\"," "\"db\":[" "{" "\"id\":1," "\"repo-key\":1," "\"system-id\":6625592122879095702," "\"version\":\"9.4\"" "}," "{" "\"id\":2," "\"repo-key\":1," "\"system-id\":6626363367545678089," "\"version\":\"9.5\"" "}" "]," "\"name\":\"stanza1\"," "\"repo\":[" "{" "\"cipher\":\"none\"," "\"key\":1," "\"status\":{" "\"code\":0," "\"message\":\"ok\"" "}" "}" "]," "\"status\":{" "\"code\":0," "\"lock\":{\"backup\":{\"held\":false}}," "\"message\":\"ok\"" "}" "}" "]", // {uncrustify_on} "json - backup set requested, no db and no checksum error"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("backup set requested with missing backup lsn stop location"); argList2 = strLstDup(argListTextStanzaOpt); hrnCfgArgRawZ(argList2, cfgOptSet, "20201116-155000F_20201119-152100I"); hrnCfgArgRawZ(argList2, cfgOptRepo, "1"); HRN_CFG_LOAD(cfgCmdInfo, argList2); HRN_INFO_PUT( storageRepoWrite(), STORAGE_REPO_BACKUP "/20201116-155000F_20201119-152100I/" BACKUP_MANIFEST_FILE, TEST_MANIFEST_HEADER2 TEST_MANIFEST_TARGET_NO_LINK TEST_MANIFEST_NO_DB TEST_MANIFEST_FILE_NO_CHECKSUM_ERROR TEST_MANIFEST_FILE_DEFAULT TEST_MANIFEST_LINK TEST_MANIFEST_LINK_DEFAULT TEST_MANIFEST_PATH TEST_MANIFEST_PATH_DEFAULT, .comment = "write manifest - without lsn info in header"); TEST_RESULT_STR_Z( infoRender(), "stanza: stanza1\n" " status: ok\n" " cipher: none\n" "\n" " db (current)\n" " wal archive min/max (9.5): 000000010000000000000002/000000010000000000000005\n" "\n" " incr backup: 20201116-155000F_20201119-152100I\n" " timestamp start/stop: 2020-11-19 15:21:00+00 / 2020-11-19 15:21:03+00\n" " wal start/stop: 000000010000000000000005 / 000000010000000000000005\n" " database size: 19.2MB, database backup size: 8.2KB\n" " repo1: backup size: 346B\n" " backup reference list: 20201116-155000F\n" " database list: none\n" " annotation(s)\n" " extra key: this is an annotation\n" " source: this is another annotation\n", "text - backup set requested, no lsn start/stop location"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("multi-repo: stanza found"); // Reconfigure environment variable for repo2 hrnCfgEnvKeyRawZ(cfgOptRepoCipherPass, 2, TEST_CIPHER_PASS); argList2 = strLstDup(argListMultiRepoJson); hrnCfgArgRawZ(argList2, cfgOptStanza, "stanza2"); HRN_CFG_LOAD(cfgCmdInfo, argList2); TEST_RESULT_STR_Z( infoRender(), // {uncrustify_off - indentation} "[" "{" "\"archive\":[" "{" "\"database\":{" "\"id\":1," "\"repo-key\":1" "}," "\"id\":\"9.4-1\"," "\"max\":null," "\"min\":null" "}" "]," "\"backup\":[]," "\"cipher\":\"mixed\"," "\"db\":[" "{" "\"id\":1," "\"repo-key\":1," "\"system-id\":6625633699176220261," "\"version\":\"9.4\"" "}" "]," "\"name\":\"stanza2\"," "\"repo\":[" "{" "\"cipher\":\"none\"," "\"key\":1," "\"status\":{" "\"code\":2," "\"message\":\"no valid backups\"" "}" "}," "{" "\"cipher\":\"aes-256-cbc\"," "\"key\":2," "\"status\":{" "\"code\":1," "\"message\":\"missing stanza path\"" "}" "}" "]," "\"status\":{" "\"code\":4," "\"lock\":{\"backup\":{\"held\":false}}," "\"message\":\"different across repos\"" "}" "}" "]", // {uncrustify_on} "json - multiple stanzas - selected found, repo1"); argList2 = strLstDup(argListMultiRepo); hrnCfgArgRawZ(argList2, cfgOptStanza, "stanza2"); HRN_CFG_LOAD(cfgCmdInfo, argList2); TEST_RESULT_STR_Z( infoRender(), "stanza: stanza2\n" " status: mixed\n" " repo1: error (no valid backups)\n" " repo2: error (missing stanza path)\n" " cipher: mixed\n" " repo1: none\n" " repo2: aes-256-cbc\n" "\n" " db (current)\n" " wal archive min/max (9.4): none present\n", "text - multiple stanzas - selected found, repo1"); // Remove backups from repo2 for stanza1 so multi-repos are scanned but backups are on only 1 repo // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("multi-repo, backups only on one"); argList2 = strLstDup(argListMultiRepo); hrnCfgArgRawZ(argList2, cfgOptStanza, "stanza1"); HRN_CFG_LOAD(cfgCmdInfo, argList2); HRN_INFO_PUT( storageRepoIdxWrite(1), INFO_BACKUP_PATH_FILE, "[db]\n" "db-catalog-version=201510051\n" "db-control-version=942\n" "db-id=1\n" "db-system-id=6626363367545678089\n" "db-version=\"9.5\"\n" "\n" "[cipher]\n" "cipher-pass=\"somepass\"\n" "\n" "[db:history]\n" "1={\"db-catalog-version\":201510051,\"db-control-version\":942,\"db-system-id\":6626363367545678089" ",\"db-version\":\"9.5\"}\n", .cipherType = cipherTypeAes256Cbc, .cipherPass = TEST_CIPHER_PASS, .comment = "backup.info without current, repo2, stanza1"); TEST_RESULT_STR_Z( infoRender(), "stanza: stanza1\n" " status: mixed\n" " repo1: ok\n" " repo2: error (no valid backups)\n" " cipher: mixed\n" " repo1: none\n" " repo2: aes-256-cbc\n" "\n" " db (prior)\n" " wal archive min/max (9.4): 000000010000000000000002/000000020000000000000003\n" "\n" " full backup: 20181119-152138F\n" " timestamp start/stop: 2018-11-19 15:21:38+00 / 2018-11-19 15:21:39+00\n" " wal start/stop: 000000010000000000000002 / 000000010000000000000002\n" " database size: 19.2MB, database backup size: 19.2MB\n" " repo1: backup set size: 2.3MB, backup size: 2.3MB\n" "\n" " diff backup: 20181119-152138F_20181119-152152D\n" " timestamp start/stop: 2018-11-19 15:21:52+00 / 2018-11-19 15:21:55+00\n" " wal start/stop: 000000010000000000000003 / 000000020000000000000003\n" " database size: 19.2MB, database backup size: 8.2KB\n" " repo1: backup set size: 2.3MB, backup size: 346B\n" " backup reference total: 1 full\n" "\n" " incr backup: 20181119-152138F_20181119-152155I\n" " timestamp start/stop: 2018-11-19 15:21:55+00 / 2018-11-19 15:21:57+00\n" " wal start/stop: n/a\n" " database size: 19.2MB, database backup size: 8.2KB\n" " repo1: backup set size: 2.3MB, backup size: 346B\n" " backup reference total: 1 full, 1 diff\n" "\n" " db (current)\n" " wal archive min/max (9.5): 000000010000000000000002/000000010000000000000005\n" "\n" " full backup: 20201116-155000F\n" " timestamp start/stop: 2020-11-16 15:50:00+00 / 2020-11-16 15:50:02+00\n" " wal start/stop: 000000010000000000000002 / 000000010000000000000003\n" " database size: 25.7MB, database backup size: 25.7MB\n" " repo1: backup set size: 3MB, backup size: 3KB\n" "\n" " incr backup: 20201116-155000F_20201119-152100I\n" " timestamp start/stop: 2020-11-19 15:21:00+00 / 2020-11-19 15:21:03+00\n" " wal start/stop: 000000010000000000000005 / 000000010000000000000005\n" " database size: 19.2MB, database backup size: 8.2KB\n" " repo1: backup size: 346B\n" " backup reference total: 1 full\n", "text - multi-repo, valid backups only on repo1"); // Remove archives for prior backup so archiveMin prior DB == NULL but backupList > 0 (edge case) // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("multi-repo, prior backup: no archives but backups (code coverage)"); HRN_STORAGE_PATH_REMOVE( storageRepoIdxWrite(0), STORAGE_REPO_ARCHIVE "/9.4-1", .recurse = true, .comment = "remove archives on db prior"); HRN_INFO_PUT( storageTest, TEST_PATH "/repo/" STORAGE_PATH_BACKUP "/stanza1/" INFO_BACKUP_FILE, "[backup:current]\n" "20201116-155000F={" "\"backrest-format\":5,\"backrest-version\":\"2.30\"," "\"backup-archive-start\":\"000000010000000000000002\",\"backup-archive-stop\":\"000000010000000000000003\"," "\"backup-info-repo-size\":3159000,\"backup-info-repo-size-delta\":3100,\"backup-info-size\":26897000," "\"backup-info-size-delta\":26897020,\"backup-timestamp-start\":1605541800,\"backup-timestamp-stop\":1605541802," "\"backup-type\":\"full\",\"db-id\":1,\"option-archive-check\":true,\"option-archive-copy\":true," "\"option-backup-standby\":false,\"option-checksum-page\":false,\"option-compress\":false,\"option-hardlink\":false," "\"option-online\":true}\n" "20201116-155000F_20201119-152100I={" "\"backrest-format\":5,\"backrest-version\":\"2.30\"," "\"backup-annotation\":{\"extra key\":\"this is an annotation\",\"source\":\"this is another annotation\"}," "\"backup-archive-start\":\"000000010000000000000005\",\"backup-archive-stop\":\"000000010000000000000005\"," "\"backup-error\":false,\"backup-info-repo-size\":2369186," "\"backup-info-repo-size-delta\":346,\"backup-info-repo-size-map\":100,\"backup-info-repo-size-map-delta\":12" ",\"backup-info-size\":20162900,\"backup-info-size-delta\":8428,\"backup-lsn-start\":\"285/89000028\"," "\"backup-prior\":\"20201116-155000F\",\"backup-reference\":[\"20201116-155000F\"]," "\"backup-timestamp-start\":1605799260,\"backup-timestamp-stop\":1605799263,\"backup-type\":\"incr\"," "\"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" "20201116-155000F_20201120-152100I={" "\"backrest-format\":5,\"backrest-version\":\"2.30\"," "\"backup-annotation\":{\"extra key\":\"this is an annotation\",\"source\":\"this is another annotation\"}," "\"backup-archive-start\":\"000000010000000000000006\",\"backup-archive-stop\":\"000000010000000000000006\"," "\"backup-error\":false,\"backup-info-repo-size\":2369186," "\"backup-info-repo-size-delta\":346,\"backup-info-repo-size-map\":100,\"backup-info-repo-size-map-delta\":12" ",\"backup-info-size\":20162900,\"backup-info-size-delta\":8428,\"backup-lsn-start\":\"285/89000028\"," "\"backup-prior\":\"20201116-155000F_20201119-152100I\"," "\"backup-reference\":[\"20201116-155000F\",\"20201116-155000F_20201119-152100I\"]," "\"backup-timestamp-start\":1605799260,\"backup-timestamp-stop\":1605799263,\"backup-type\":\"incr\"," "\"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" "\n" "[db]\n" "db-catalog-version=201510051\n" "db-control-version=942\n" "db-id=1\n" "db-system-id=6626363367545678089\n" "db-version=\"9.5\"\n" "\n" "[db:history]\n" "1={\"db-catalog-version\":201510051,\"db-control-version\":942,\"db-system-id\":6626363367545678089" ",\"db-version\":\"9.5\"}\n", .comment = "put backup info to file - stanza1, repo1"); TEST_RESULT_STR_Z( infoRender(), "stanza: stanza1\n" " status: mixed\n" " repo1: ok\n" " repo2: error (no valid backups)\n" " cipher: mixed\n" " repo1: none\n" " repo2: aes-256-cbc\n" "\n" " db (current)\n" " wal archive min/max (9.5): 000000010000000000000002/000000010000000000000005\n" "\n" " full backup: 20201116-155000F\n" " timestamp start/stop: 2020-11-16 15:50:00+00 / 2020-11-16 15:50:02+00\n" " wal start/stop: 000000010000000000000002 / 000000010000000000000003\n" " database size: 25.7MB, database backup size: 25.7MB\n" " repo1: backup set size: 3MB, backup size: 3KB\n" "\n" " incr backup: 20201116-155000F_20201119-152100I\n" " timestamp start/stop: 2020-11-19 15:21:00+00 / 2020-11-19 15:21:03+00\n" " wal start/stop: 000000010000000000000005 / 000000010000000000000005\n" " database size: 19.2MB, database backup size: 8.2KB\n" " repo1: backup size: 346B\n" " backup reference total: 1 full\n" "\n" " incr backup: 20201116-155000F_20201120-152100I\n" " timestamp start/stop: 2020-11-19 15:21:00+00 / 2020-11-19 15:21:03+00\n" " wal start/stop: 000000010000000000000006 / 000000010000000000000006\n" " database size: 19.2MB, database backup size: 8.2KB\n" " repo1: backup size: 346B\n" " backup reference total: 1 full, 1 incr\n", "text - multi-repo, prior backup: no archives but backups (code coverage)"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("Annotation assert not null value"); argList2 = strLstDup(argListMultiRepo); hrnCfgArgRawZ(argList2, cfgOptStanza, "stanza1"); hrnCfgArgRawZ(argList2, cfgOptSet, "20181119-152138F_20181119-152155I"); hrnCfgArgRawZ(argList2, cfgOptRepo, "1"); HRN_CFG_LOAD(cfgCmdInfo, argList2); HRN_INFO_PUT( storageTest, TEST_PATH "/repo/" STORAGE_PATH_BACKUP "/stanza1/" INFO_BACKUP_FILE, "[backup:current]\n" "20181119-152138F={" "\"backrest-format\":5,\"backrest-version\":\"2.08dev\"," "\"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\":1542640898,\"backup-timestamp-stop\":1542640899,\"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" "20181119-152138F_20181119-152152D={" "\"backrest-format\":5,\"backrest-version\":\"2.08dev\",\"backup-archive-start\":\"000000010000000000000003\"," "\"backup-archive-stop\":\"000000020000000000000003\",\"backup-info-repo-size\":2369186," "\"backup-info-repo-size-delta\":346,\"backup-info-size\":20162900,\"backup-info-size-delta\":8428," "\"backup-prior\":\"20181119-152138F\",\"backup-reference\":[\"20181119-152138F\"]," "\"backup-timestamp-start\":1542640912,\"backup-timestamp-stop\":1542640915,\"backup-type\":\"diff\"," "\"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" "20181119-152138F_20181119-152155I={" "\"backrest-format\":5,\"backrest-version\":\"2.08dev\"," "\"backup-annotation\":{\"key1\":null}," "\"backup-archive-start\":\"000000010000000000000003\"," "\"backup-info-repo-size\":2369186," "\"backup-info-repo-size-delta\":346,\"backup-info-size\":20162900,\"backup-info-size-delta\":8428," "\"backup-lsn-start\":\"285/89000028\",\"backup-lsn-stop\":\"285/89001F88\"," "\"backup-prior\":\"20181119-152138F_20181119-152152D\"," "\"backup-reference\":[\"20181119-152138F\",\"20181119-152138F_20181119-152152D\"]," "\"backup-timestamp-start\":1542640915,\"backup-timestamp-stop\":1542640917,\"backup-type\":\"incr\"," "\"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" "\n" "[db]\n" "db-catalog-version=201510051\n" "db-control-version=942\n" "db-id=2\n" "db-system-id=6626363367545678089\n" "db-version=\"9.5\"\n" "\n" "[db:history]\n" "1={\"db-catalog-version\":201409291,\"db-control-version\":942,\"db-system-id\":6625592122879095702" ",\"db-version\":\"9.4\"}\n" "2={\"db-catalog-version\":201510051,\"db-control-version\":942,\"db-system-id\":6626363367545678089" ",\"db-version\":\"9.5\"}\n", .comment = "put backup info to file - stanza1, repo1"); TEST_ERROR(infoRender(), AssertError, "assertion 'value != NULL' failed"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("multi-repo, stanza requested does not exist, but other stanzas do"); argList2 = strLstDup(argListMultiRepo); hrnCfgArgRawZ(argList2, cfgOptStanza, "stanza4"); HRN_CFG_LOAD(cfgCmdInfo, argList2); TEST_RESULT_STR_Z( infoRender(), "stanza: stanza4\n" " status: error (missing stanza path)\n", "multi-repo, stanza requested does not exist, but other stanzas do"); // Add stanza3 to repo1 but with a current PG that is different than repo2 // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("multi-repo, current database different across repos"); argList2 = strLstDup(argListMultiRepo); hrnCfgArgRawZ(argList2, cfgOptStanza, "stanza3"); HRN_CFG_LOAD(cfgCmdInfo, argList2); HRN_INFO_PUT( storageRepoIdxWrite(0), INFO_ARCHIVE_PATH_FILE, "[db]\n" "db-id=2\n" "db-system-id=6626363367545678888\n" "db-version=\"9.5\"\n" "\n" "[db:history]\n" "1={\"db-id\":6626363367545678089,\"db-version\":\"9.4\"}\n" "2={\"db-id\":6626363367545678888,\"db-version\":\"9.5\"}\n", .comment = "put archive info to file - stanza3, repo1 stanza upgraded"); HRN_INFO_PUT( storageRepoIdxWrite(0), INFO_BACKUP_PATH_FILE, "[db]\n" "db-catalog-version=201409291\n" "db-control-version=942\n" "db-id=2\n" "db-system-id=6626363367545678888\n" "db-version=\"9.5\"\n" "\n" "[backup:current]\n" "20201212-192538F={\"backrest-format\":5,\"backrest-version\":\"2.25\"," "\"backup-archive-start\":\"000000010000000000000002\",\"backup-archive-stop\":\"000000010000000000000003\"," "\"backup-info-repo-size\":3159000,\"backup-info-repo-size-delta\":3100,\"backup-info-size\":26897000," "\"backup-info-size-delta\":26897020,\"backup-timestamp-start\":1607801138,\"backup-timestamp-stop\":1607801140," "\"backup-type\":\"full\",\"db-id\":1,\"option-archive-check\":true,\"option-archive-copy\":true," "\"option-backup-standby\":true,\"option-checksum-page\":false,\"option-compress\":false,\"option-hardlink\":true," "\"option-online\":true}\n" "20210112-192538F={\"backrest-format\":5,\"backrest-version\":\"2.25\"," "\"backup-archive-start\":\"000000010000000000000006\",\"backup-archive-stop\":\"000000010000000000000006\"," "\"backup-info-repo-size\":3159000,\"backup-info-repo-size-delta\":3100,\"backup-info-size\":26897000," "\"backup-info-size-delta\":26897020,\"backup-timestamp-start\":1687010984,\"backup-timestamp-stop\":1687011000," "\"backup-type\":\"full\",\"db-id\":2,\"option-archive-check\":true,\"option-archive-copy\":true," "\"option-backup-standby\":true,\"option-checksum-page\":false,\"option-compress\":false,\"option-hardlink\":true," "\"option-online\":true}\n" "\n" "[db:history]\n" "1={\"db-catalog-version\":201409291,\"db-control-version\":942,\"db-system-id\":6626363367545678089" ",\"db-version\":\"9.4\"}\n" "2={\"db-catalog-version\":201409291,\"db-control-version\":942,\"db-system-id\":6626363367545678888" ",\"db-version\":\"9.5\"}\n", .comment = "put backup info to file - stanza3, repo1 stanza upgraded"); // Create stanza3 db1 WAL, repo1 HRN_STORAGE_PUT_EMPTY( storageRepoIdxWrite(0), STORAGE_REPO_ARCHIVE "/9.4-1/0000000100000000/000000010000000000000002-47dff2b7552a9d66e4bae1a762488a6885e7082c.gz"); HRN_STORAGE_PUT_EMPTY( storageRepoIdxWrite(0), STORAGE_REPO_ARCHIVE "/9.4-1/0000000100000000/000000010000000000000003-47dff2b7552a9d66e4bae1a762488a6885e7082c.gz"); HRN_STORAGE_PUT_EMPTY( storageRepoIdxWrite(0), STORAGE_REPO_ARCHIVE "/9.5-2/0000000100000000/000000010000000000000006-47dff2b7552a9d66e4bae1a762488a6885e7082c.gz"); // Switch to America/New_York to test + timezone offset without minutes hrnTzSet("America/New_York"); TEST_RESULT_STR_Z( infoRender(), "stanza: stanza3\n" " status: error (database mismatch across repos)\n" " repo1: ok\n" " repo2: ok\n" " cipher: mixed\n" " repo1: none\n" " repo2: aes-256-cbc\n" "\n" " db (prior)\n" " wal archive min/max (9.4): 000000010000000000000001/000000010000000000000003\n" "\n" " full backup: 20201110-100000F\n" " timestamp start/stop: 2020-11-10 05:00:00-05 / 2020-11-10 05:00:02-05\n" " wal start/stop: 000000010000000000000001 / 000000010000000000000002\n" " database size: 25.7MB, database backup size: 25.7MB\n" " repo2: backup set size: 3MB, backup size: 3KB\n" "\n" " full backup: 20201212-192538F\n" " timestamp start/stop: 2020-12-12 14:25:38-05 / 2020-12-12 14:25:40-05\n" " wal start/stop: 000000010000000000000002 / 000000010000000000000003\n" " database size: 25.7MB, database backup size: 25.7MB\n" " repo1: backup set size: 3MB, backup size: 3KB\n" "\n" " db (current)\n" " wal archive min/max (9.5): 000000010000000000000006/000000010000000000000006\n" "\n" " full backup: 20210112-192538F\n" " timestamp start/stop: 2023-06-17 10:09:44-04 / 2023-06-17 10:10:00-04\n" " wal start/stop: 000000010000000000000006 / 000000010000000000000006\n" " database size: 25.7MB, database backup size: 25.7MB\n" " repo1: backup set size: 3MB, backup size: 3KB\n", "text - multi-repo, database mismatch, repo2 stanza-upgrade needed"); // Reset timezone hrnTzSet("UTC"); hrnCfgArgRawZ(argList2, cfgOptOutput, "json"); HRN_CFG_LOAD(cfgCmdInfo, argList2); TEST_RESULT_STR_Z( infoRender(), // {uncrustify_off - indentation} "[" "{" "\"archive\":[" "{" "\"database\":{" "\"id\":1," "\"repo-key\":1" "}," "\"id\":\"9.4-1\"," "\"max\":\"000000010000000000000003\"," "\"min\":\"000000010000000000000002\"" "}," "{" "\"database\":{" "\"id\":2," "\"repo-key\":1" "}," "\"id\":\"9.5-2\"," "\"max\":\"000000010000000000000006\"," "\"min\":\"000000010000000000000006\"" "}," "{" "\"database\":{" "\"id\":1," "\"repo-key\":2" "}," "\"id\":\"9.4-1\"," "\"max\":\"000000010000000000000002\"," "\"min\":\"000000010000000000000001\"" "}" "]," "\"backup\":[" "{" "\"archive\":{" "\"start\":\"000000010000000000000001\"," "\"stop\":\"000000010000000000000002\"" "}," "\"backrest\":{" "\"format\":5," "\"version\":\"2.25\"" "}," "\"database\":{" "\"id\":1," "\"repo-key\":2" "}," "\"info\":{" "\"delta\":26897020," "\"repository\":{" "\"delta\":3100," "\"size\":3159000" "}," "\"size\":26897000" "}," "\"label\":\"20201110-100000F\"," "\"prior\":null," "\"reference\":null," "\"timestamp\":{" "\"start\":1605002400," "\"stop\":1605002402" "}," "\"type\":\"full\"" "}," "{" "\"archive\":{" "\"start\":\"000000010000000000000002\"," "\"stop\":\"000000010000000000000003\"" "}," "\"backrest\":{" "\"format\":5," "\"version\":\"2.25\"" "}," "\"database\":{" "\"id\":1," "\"repo-key\":1" "}," "\"info\":{" "\"delta\":26897020," "\"repository\":{" "\"delta\":3100," "\"size\":3159000" "}," "\"size\":26897000" "}," "\"label\":\"20201212-192538F\"," "\"prior\":null," "\"reference\":null," "\"timestamp\":{" "\"start\":1607801138," "\"stop\":1607801140" "}," "\"type\":\"full\"" "}," "{" "\"archive\":{" "\"start\":\"000000010000000000000006\"," "\"stop\":\"000000010000000000000006\"" "}," "\"backrest\":{" "\"format\":5," "\"version\":\"2.25\"" "}," "\"database\":{" "\"id\":2," "\"repo-key\":1" "}," "\"info\":{" "\"delta\":26897020," "\"repository\":{" "\"delta\":3100," "\"size\":3159000" "}," "\"size\":26897000" "}," "\"label\":\"20210112-192538F\"," "\"prior\":null," "\"reference\":null," "\"timestamp\":{" "\"start\":1687010984," "\"stop\":1687011000" "}," "\"type\":\"full\"" "}" "]," "\"cipher\":\"mixed\"," "\"db\":[" "{" "\"id\":1," "\"repo-key\":1," "\"system-id\":6626363367545678089," "\"version\":\"9.4\"" "}," "{" "\"id\":2," "\"repo-key\":1," "\"system-id\":6626363367545678888," "\"version\":\"9.5\"" "}," "{" "\"id\":1," "\"repo-key\":2," "\"system-id\":6626363367545678089," "\"version\":\"9.4\"" "}" "]," "\"name\":\"stanza3\"," "\"repo\":[" "{" "\"cipher\":\"none\"," "\"key\":1," "\"status\":{" "\"code\":0," "\"message\":\"ok\"" "}" "}," "{" "\"cipher\":\"aes-256-cbc\"," "\"key\":2," "\"status\":{" "\"code\":0," "\"message\":\"ok\"" "}" "}" "]," "\"status\":{" "\"code\":5," "\"lock\":{\"backup\":{\"held\":false}}," "\"message\":\"database mismatch across repos\"" "}" "}" "]", // {uncrustify_on} "json - multi-repo, database mismatch, repo2 stanza-upgrade needed"); // Crypto error // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("encryption error"); // Change repo1 to have the same cipher type as repo2 even though on disk it does not HRN_STORAGE_PUT_Z(storageTest, TEST_PATH "/pgbackrest.conf", "[global]\nrepo-cipher-pass=123abc\n"); argList2 = strLstDup(argListMultiRepo); hrnCfgArgKeyRawStrId(argList2, cfgOptRepoCipherType, 1, cipherTypeAes256Cbc); hrnCfgArgRawZ(argList2, cfgOptConfig, TEST_PATH "/pgbackrest.conf"); HRN_CFG_LOAD(cfgCmdInfo, argList2); TEST_RESULT_STR_Z( infoRender(), "stanza: stanza1\n" " status: mixed\n" " repo1: error (other)\n" " [CryptoError] unable to load info file '" TEST_PATH "/repo/backup/stanza1/backup.info' or" " '" TEST_PATH "/repo/backup/stanza1/backup.info.copy':\n" " CryptoError: cipher header invalid\n" " HINT: is or was the repo encrypted?\n" " FileMissingError: unable to open missing file '" TEST_PATH "/repo/backup/stanza1/backup.info.copy'" " for read\n" " HINT: backup.info cannot be opened and is required to perform a backup.\n" " HINT: has a stanza-create been performed?\n" " HINT: use option --stanza if encryption settings are different for the stanza than the global" " settings.\n" " repo2: error (no valid backups)\n" " cipher: aes-256-cbc\n" "\n" " db (current)\n" " wal archive min/max (9.5): 000000010000000000000003/000000010000000000000004\n" "\n" "stanza: stanza2\n" " status: mixed\n" " repo1: error (other)\n" " [CryptoError] unable to load info file '" TEST_PATH "/repo/backup/stanza2/backup.info' or" " '" TEST_PATH "/repo/backup/stanza2/backup.info.copy':\n" " CryptoError: cipher header invalid\n" " HINT: is or was the repo encrypted?\n" " FileMissingError: unable to open missing file '" TEST_PATH "/repo/backup/stanza2/backup.info.copy'" " for read\n" " HINT: backup.info cannot be opened and is required to perform a backup.\n" " HINT: has a stanza-create been performed?\n" " HINT: use option --stanza if encryption settings are different for the stanza than the global" " settings.\n" " repo2: error (missing stanza path)\n" " cipher: aes-256-cbc\n" "\n" "stanza: stanza3\n" " status: mixed\n" " repo1: error (other)\n" " [CryptoError] unable to load info file '" TEST_PATH "/repo/backup/stanza3/backup.info' or" " '" TEST_PATH "/repo/backup/stanza3/backup.info.copy':\n" " CryptoError: cipher header invalid\n" " HINT: is or was the repo encrypted?\n" " FileMissingError: unable to open missing file '" TEST_PATH "/repo/backup/stanza3/backup.info.copy'" " for read\n" " HINT: backup.info cannot be opened and is required to perform a backup.\n" " HINT: has a stanza-create been performed?\n" " HINT: use option --stanza if encryption settings are different for the stanza than the global" " settings.\n" " repo2: ok\n" " cipher: aes-256-cbc\n" "\n" " db (current)\n" " wal archive min/max (9.4): 000000010000000000000001/000000010000000000000002\n" "\n" " full backup: 20201110-100000F\n" " timestamp start/stop: 2020-11-10 10:00:00+00 / 2020-11-10 10:00:02+00\n" " wal start/stop: 000000010000000000000001 / 000000010000000000000002\n" " database size: 25.7MB, database backup size: 25.7MB\n" " repo2: backup set size: 3MB, backup size: 3KB\n", "text - multi-repo, multi-stanza cipher error"); // Backup label not found, one repo in error // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("backup label exists on one repo, other repo in error"); hrnCfgArgRawZ(argList2, cfgOptStanza, "stanza3"); hrnCfgArgRawZ(argList2, cfgOptSet, "20201110-100000F"); HRN_CFG_LOAD(cfgCmdInfo, argList2); TEST_RESULT_STR_Z( infoRender(), "stanza: stanza3\n" " status: mixed\n" " repo1: error (other)\n" " [CryptoError] unable to load info file '" TEST_PATH "/repo/backup/stanza3/backup.info' or" " '" TEST_PATH "/repo/backup/stanza3/backup.info.copy':\n" " CryptoError: cipher header invalid\n" " HINT: is or was the repo encrypted?\n" " FileMissingError: unable to open missing file '" TEST_PATH "/repo/backup/stanza3/backup.info.copy'" " for read\n" " HINT: backup.info cannot be opened and is required to perform a backup.\n" " HINT: has a stanza-create been performed?\n" " HINT: use option --stanza if encryption settings are different for the stanza than the global" " settings.\n" " repo2: error (requested backup not found)\n" " cipher: aes-256-cbc\n", "backup label not found, one repo in error"); // Crypto error // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("WAL read error"); argList2 = strLstDup(argListMultiRepo); hrnCfgArgRawZ(argList2, cfgOptStanza, "stanza1"); HRN_CFG_LOAD(cfgCmdInfo, argList2); HRN_STORAGE_PATH_CREATE( storageRepoWrite(), STORAGE_REPO_ARCHIVE "/9.4-1", .mode = 0200, .comment = "WAL directory with bad permissions"); TEST_RESULT_STR_Z( infoRender(), "stanza: stanza1\n" " status: mixed\n" " repo1: error (other)\n" " [PathOpenError] unable to list file info for path '" TEST_PATH "/repo/archive/stanza1/9.4-1': [13]" " Permission denied\n" " repo2: error (no valid backups)\n" " cipher: mixed\n" " repo1: none\n" " repo2: aes-256-cbc\n" "\n" " db (current)\n" " wal archive min/max (9.5): 000000010000000000000003/000000010000000000000004\n", "WAL directory read error"); // Unset environment key hrnCfgEnvKeyRemoveRaw(cfgOptRepoCipherPass, 2); } // ***************************************************************************************************************************** if (testBegin("database mismatch - special cases")) { // These tests cover branches not covered in other tests TEST_TITLE("multi-repo, database mismatch, pg system-id only"); StringList *argList2 = strLstNew(); hrnCfgArgRawZ(argList2, cfgOptRepoPath, TEST_PATH "/repo"); hrnCfgArgRawZ(argList2, cfgOptStanza, "stanza1"); hrnCfgArgKeyRawZ(argList2, cfgOptRepoPath, 2, TEST_PATH "/repo2"); HRN_CFG_LOAD(cfgCmdInfo, argList2); HRN_INFO_PUT( storageRepoIdxWrite(0), INFO_BACKUP_PATH_FILE, "[db]\n" "db-catalog-version=201409291\n" "db-control-version=942\n" "db-id=1\n" "db-system-id=6569239123849665679\n" "db-version=\"9.4\"\n" "\n" "[backup:current]\n" "20201116-155000F={" "\"backrest-format\":5,\"backrest-version\":\"2.30\"," "\"backup-archive-start\":\"000000010000000000000002\",\"backup-archive-stop\":\"000000010000000000000003\"," "\"backup-info-repo-size\":3159000,\"backup-info-repo-size-delta\":3100,\"backup-info-size\":26897000," "\"backup-info-size-delta\":26897020,\"backup-timestamp-start\":1605541800,\"backup-timestamp-stop\":1605541802," "\"backup-type\":\"full\",\"db-id\":1,\"option-archive-check\":true,\"option-archive-copy\":true," "\"option-backup-standby\":false,\"option-checksum-page\":false,\"option-compress\":false,\"option-hardlink\":false," "\"option-online\":true}\n" "\n" "[db:history]\n" "1={\"db-catalog-version\":201409291,\"db-control-version\":942,\"db-system-id\":6569239123849665679" ",\"db-version\":\"9.4\"}\n", .comment = "put backup info to file, repo1"); HRN_INFO_PUT( storageRepoIdxWrite(0), INFO_ARCHIVE_PATH_FILE, "[db]\n" "db-id=1\n" "db-system-id=6569239123849665679\n" "db-version=\"9.4\"\n" "\n" "[db:history]\n" "1={\"db-id\":6569239123849665679,\"db-version\":\"9.4\"}\n", .comment = "put archive info to file, repo1"); // Create stanza1, repo1, archives HRN_STORAGE_PUT_EMPTY( storageRepoIdxWrite(0), STORAGE_REPO_ARCHIVE "/9.4-1/0000000100000000/000000010000000000000002-22dff2b7552a9d66e4bae1a762488a6885e7082c.gz"); HRN_STORAGE_PUT_EMPTY( storageRepoIdxWrite(0), STORAGE_REPO_ARCHIVE "/9.4-1/0000000100000000/000000010000000000000003-37dff2b7552a9d66e4bae1a762488a6885e7082c.gz"); HRN_INFO_PUT( storageRepoIdxWrite(1), INFO_BACKUP_PATH_FILE, "[db]\n" "db-catalog-version=201409291\n" "db-control-version=942\n" "db-id=1\n" "db-system-id=6569239123849665679\n" "db-version=\"9.5\"\n" "\n" "[backup:current]\n" "20201116-155010F={" "\"backrest-format\":5,\"backrest-version\":\"2.30\"," "\"backup-archive-start\":\"000000010000000000000001\",\"backup-archive-stop\":\"000000010000000000000002\"," "\"backup-info-repo-size\":3159000,\"backup-info-repo-size-delta\":3100,\"backup-info-size\":26897000," "\"backup-info-size-delta\":26897020,\"backup-timestamp-start\":1605541810,\"backup-timestamp-stop\":1605541812," "\"backup-type\":\"full\",\"db-id\":1,\"option-archive-check\":true,\"option-archive-copy\":true," "\"option-backup-standby\":false,\"option-checksum-page\":false,\"option-compress\":false,\"option-hardlink\":false," "\"option-online\":true}\n" "\n" "[db:history]\n" "1={\"db-catalog-version\":201409291,\"db-control-version\":942,\"db-system-id\":6569239123849665679" ",\"db-version\":\"9.5\"}\n", .comment = "put backup info to file, repo2, same system-id, different version"); HRN_INFO_PUT( storageRepoIdxWrite(1), INFO_ARCHIVE_PATH_FILE, "[db]\n" "db-id=1\n" "db-system-id=6569239123849665679\n" "db-version=\"9.5\"\n" "\n" "[db:history]\n" "1={\"db-id\":6569239123849665679,\"db-version\":\"9.5\"}\n", .comment = "put archive info to file, repo2, same system-id, different version"); HRN_STORAGE_PUT_EMPTY( storageRepoIdxWrite(1), STORAGE_REPO_ARCHIVE "/9.5-1/0000000100000000/000000010000000000000001-11dff2b7552a9d66e4bae1a762488a6885e7082c.gz"); HRN_STORAGE_PUT_EMPTY( storageRepoIdxWrite(1), STORAGE_REPO_ARCHIVE "/9.5-1/0000000100000000/000000010000000000000002-222ff2b7552a9d66e4bae1a762488a6885e7082c.gz"); // Note that although the time on the backup in repo2 > repo1, repo1 current db is not the same because of the version so // the repo1, since read first, will be considered the current PG TEST_RESULT_STR_Z( infoRender(), "stanza: stanza1\n" " status: error (database mismatch across repos)\n" " repo1: ok\n" " repo2: ok\n" " cipher: none\n" "\n" " db (prior)\n" " wal archive min/max (9.5): 000000010000000000000001/000000010000000000000002\n" "\n" " full backup: 20201116-155010F\n" " timestamp start/stop: 2020-11-16 15:50:10+00 / 2020-11-16 15:50:12+00\n" " wal start/stop: 000000010000000000000001 / 000000010000000000000002\n" " database size: 25.7MB, database backup size: 25.7MB\n" " repo2: backup set size: 3MB, backup size: 3KB\n" "\n" " db (current)\n" " wal archive min/max (9.4): 000000010000000000000002/000000010000000000000003\n" "\n" " full backup: 20201116-155000F\n" " timestamp start/stop: 2020-11-16 15:50:00+00 / 2020-11-16 15:50:02+00\n" " wal start/stop: 000000010000000000000002 / 000000010000000000000003\n" " database size: 25.7MB, database backup size: 25.7MB\n" " repo1: backup set size: 3MB, backup size: 3KB\n", "text - db mismatch, diff system-id across repos, repo1 considered current db since read first"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("multi-repo, database mismatch, pg version only"); HRN_INFO_PUT( storageRepoIdxWrite(1), INFO_BACKUP_PATH_FILE, "[db]\n" "db-catalog-version=201409291\n" "db-control-version=942\n" "db-id=1\n" "db-system-id=6569239123849665888\n" "db-version=\"9.4\"\n" "\n" "[backup:current]\n" "20201116-155010F={" "\"backrest-format\":5,\"backrest-version\":\"2.30\"," "\"backup-archive-start\":\"000000010000000000000001\",\"backup-archive-stop\":\"000000010000000000000002\"," "\"backup-info-repo-size\":3159000,\"backup-info-repo-size-delta\":3100,\"backup-info-size\":26897000," "\"backup-info-size-delta\":26897020,\"backup-timestamp-start\":1605541810,\"backup-timestamp-stop\":1605541812," "\"backup-type\":\"full\",\"db-id\":1,\"option-archive-check\":true,\"option-archive-copy\":true," "\"option-backup-standby\":false,\"option-checksum-page\":false,\"option-compress\":false,\"option-hardlink\":false," "\"option-online\":true}\n" "\n" "[db:history]\n" "1={\"db-catalog-version\":201409291,\"db-control-version\":942,\"db-system-id\":6569239123849665888" ",\"db-version\":\"9.4\"}\n", .comment = "put backup info to file, repo2, different system-id, same version"); HRN_INFO_PUT( storageRepoIdxWrite(1), INFO_ARCHIVE_PATH_FILE, "[db]\n" "db-id=1\n" "db-system-id=6569239123849665888\n" "db-version=\"9.4\"\n" "\n" "[db:history]\n" "1={\"db-id\":6569239123849665888,\"db-version\":\"9.4\"}\n", .comment = "put archive info to file, repo2, different system-id, same version"); TEST_RESULT_STR_Z( infoRender(), "stanza: stanza1\n" " status: error (database mismatch across repos)\n" " repo1: ok\n" " repo2: ok\n" " cipher: none\n" "\n" " db (prior)\n" " wal archive min/max (9.4): none present\n" "\n" " full backup: 20201116-155010F\n" " timestamp start/stop: 2020-11-16 15:50:10+00 / 2020-11-16 15:50:12+00\n" " wal start/stop: 000000010000000000000001 / 000000010000000000000002\n" " database size: 25.7MB, database backup size: 25.7MB\n" " repo2: backup set size: 3MB, backup size: 3KB\n" "\n" " db (current)\n" " wal archive min/max (9.4): 000000010000000000000002/000000010000000000000003\n" "\n" " full backup: 20201116-155000F\n" " timestamp start/stop: 2020-11-16 15:50:00+00 / 2020-11-16 15:50:02+00\n" " wal start/stop: 000000010000000000000002 / 000000010000000000000003\n" " database size: 25.7MB, database backup size: 25.7MB\n" " repo1: backup set size: 3MB, backup size: 3KB\n", "text - db mismatch, diff version across repos, repo1 considered current db since read first"); } // ***************************************************************************************************************************** if (testBegin("cmdInfo()")) { StringList *argList = strLstNew(); hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH "/repo"); HRN_CFG_LOAD(cfgCmdInfo, argList); HRN_STORAGE_PATH_CREATE(storageRepoWrite(), STORAGE_REPO_ARCHIVE, .comment = "create repo archive path"); HRN_STORAGE_PATH_CREATE(storageRepoWrite(), STORAGE_REPO_BACKUP, .comment = "create repo backup path"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("no stanza exist"); // 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 cmdInfo(); // Restore normal stdout dup2(stdoutSave, STDOUT_FILENO); // Check output of info command stored in file TEST_STORAGE_GET(storageTest, strZ(stdoutFile), "No stanzas exist in the repository.\n", .remove = true); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("set option invalid without stanza option"); hrnCfgArgRawZ(argList, cfgOptSet, "bogus"); TEST_ERROR(hrnCfgLoadP(cfgCmdInfo, argList), OptionInvalidError, "option 'set' not valid without option 'stanza'"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("repo-level error"); HRN_STORAGE_PATH_CREATE(storageTest, TEST_PATH "/repo2", .mode = 0200, .comment = "repo directory with bad permissions"); argList = strLstNew(); hrnCfgArgKeyRawZ(argList, cfgOptRepoPath, 1, TEST_PATH "/repo2"); HRN_CFG_LOAD(cfgCmdInfo, argList); TEST_RESULT_STR_Z( infoRender(), "stanza: [invalid]\n" " status: error (other)\n" " [PathOpenError] unable to list file info for path '" TEST_PATH "/repo2/backup': [13] Permission denied\n" " cipher: none\n", "text - invalid stanza"); hrnCfgArgRawZ(argList, cfgOptOutput, "json"); HRN_CFG_LOAD(cfgCmdInfo, argList); TEST_RESULT_STR_Z( infoRender(), // {uncrustify_off - indentation} "[" "{" "\"archive\":[]," "\"backup\":[]," "\"cipher\":\"none\"," "\"db\":[]," "\"name\":\"[invalid]\"," "\"repo\":[" "{" "\"cipher\":\"none\"," "\"key\":1," "\"status\":{" "\"code\":99," "\"message\":\"[PathOpenError] unable to list file info for path '" TEST_PATH "/repo2/backup':" " [13] Permission denied\"" "}" "}" "]," "\"status\":{" "\"code\":99," "\"lock\":{\"backup\":{\"held\":false}}," "\"message\":\"other\"" "}" "}" "]", // {uncrustify_on} "json - invalid stanza"); argList = strLstNew(); hrnCfgArgKeyRawZ(argList, cfgOptRepoPath, 1, TEST_PATH "/repo2"); hrnCfgArgRawZ(argList, cfgOptStanza, "stanza1"); HRN_CFG_LOAD(cfgCmdInfo, argList); TEST_RESULT_STR_Z( infoRender(), "stanza: stanza1\n" " status: error (other)\n" " [PathOpenError] unable to list file info for path '" TEST_PATH "/repo2/backup': [13] Permission denied\n" " cipher: none\n", "text - stanza requested"); hrnCfgArgKeyRawZ(argList, cfgOptRepoPath, 2, TEST_PATH "/repo"); HRN_CFG_LOAD(cfgCmdInfo, argList); TEST_RESULT_STR_Z( infoRender(), "stanza: stanza1\n" " status: mixed\n" " repo1: error (other)\n" " [PathOpenError] unable to list file info for path '" TEST_PATH "/repo2/backup':" " [13] Permission denied\n" " repo2: error (missing stanza path)\n" " cipher: none\n", "text - stanza repo structure exists"); } FUNCTION_HARNESS_RETURN_VOID(); }