1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2025-07-07 00:35:37 +02:00
Files
pgbackrest/test/src/module/command/infoTest.c
David Steele ad7ba46bc6 Improve the predictability of floating point numbers formatted as strings.
Some C libraries (e.g.musl) render floating point numbers differently when using printf(). This does not cause any problems for the core code but the unit tests require more predictability to function smoothly without a lot of exceptions.

To accomplish this, wrap the various floating point operations in functions that mostly continue doing math using double but format the output string using integers. This leads to more predictable output at the cost of some complexity.

Rounding could also be accomplished using nearbyint() but this would require linking the math library, which does not seem worth it for a fairly simple operation.
2025-06-05 13:27:45 -04:00

3478 lines
184 KiB
C

/***********************************************************************************************************************************
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();
}