1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2025-04-15 11:36:40 +02:00
Cynthia Shang f32eb9b94e
Partial multi-repository implementation.
Multi-repository implementations for the archive-push, check, info, stanza-create, stanza-upgrade, and stanza-delete commands.

Multi-repo configuration is disabled so there should be no behavioral changes between these commands and their current single-repo implementations.

Multi-repo documentation and integration tests are still in the multi-repo development branch. All unit tests work as multi-repo since they are able to bypass the configuration restrictions.
2021-01-21 15:21:50 -05:00

2198 lines
132 KiB
C

/***********************************************************************************************************************************
Test Expire Command
***********************************************************************************************************************************/
#include <unistd.h>
#include "common/io/bufferRead.h"
#include "storage/posix/storage.h"
#include "common/harnessConfig.h"
#include "common/harnessInfo.h"
/***********************************************************************************************************************************
Helper functions
***********************************************************************************************************************************/
void
archiveGenerate(
Storage *storageTest, String *archiveStanzaPath, const unsigned int start, unsigned int end, const char *archiveId,
const char *majorWal)
{
// For simplicity, only allow 2 digits
if (end > 99)
end = 99;
String *wal = NULL;
for (unsigned int i = start; i <= end; i++)
{
if (i < 10)
wal = strNewFmt("%s0000000%u-9baedd24b61aa15305732ac678c4e2c102435a09", majorWal, i);
else
wal = strNewFmt("%s000000%u-9baedd24b61aa15305732ac678c4e2c102435a09", majorWal, i);
storagePutP(
storageNewWriteP(storageTest, strNewFmt("%s/%s/%s/%s", strZ(archiveStanzaPath), archiveId, majorWal, strZ(wal))),
BUFSTRDEF(BOGUS_STR));
}
}
String *
archiveExpectList(const unsigned int start, unsigned int end, const char *majorWal)
{
String *result = strNew("");
// For simplicity, only allow 2 digits
if (end > 99)
end = 99;
String *wal = NULL;
for (unsigned int i = start; i <= end; i++)
{
if (i < 10)
wal = strNewFmt("%s0000000%u-9baedd24b61aa15305732ac678c4e2c102435a09", majorWal, i);
else
wal = strNewFmt("%s000000%u-9baedd24b61aa15305732ac678c4e2c102435a09", majorWal, i);
strCatFmt(result, "%s\n", strZ(wal));
}
return result;
}
/***********************************************************************************************************************************
Test Run
***********************************************************************************************************************************/
void
testRun(void)
{
FUNCTION_HARNESS_VOID();
Storage *storageTest = storagePosixNewP(strNew(testPath()), .write = true);
String *backupStanzaPath = strNew("repo/backup/db");
String *backupInfoFileName = strNewFmt("%s/backup.info", strZ(backupStanzaPath));
String *archiveStanzaPath = strNew("repo/archive/db");
String *archiveInfoFileName = strNewFmt("%s/archive.info", strZ(archiveStanzaPath));
StringList *argListBase = strLstNew();
strLstAddZ(argListBase, "--stanza=db");
strLstAdd(argListBase, strNewFmt("--repo1-path=%s/repo", testPath()));
StringList *argListAvoidWarn = strLstDup(argListBase);
strLstAddZ(argListAvoidWarn, "--repo1-retention-full=1"); // avoid warning
uint64_t timeNow = (uint64_t)time(NULL); // time in seconds since Epoch
String *backupInfoContent = strNewFmt(
"[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\":%" PRIu64 ",\"backup-timestamp-stop\":%" PRIu64 ",\"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-152800F={"
"\"backrest-format\":5,\"backrest-version\":\"2.08dev\","
"\"backup-archive-start\":\"000000010000000000000004\",\"backup-archive-stop\":\"000000010000000000000004\","
"\"backup-info-repo-size\":2369186,\"backup-info-repo-size-delta\":2369186,"
"\"backup-info-size\":20162900,\"backup-info-size-delta\":20162900,"
"\"backup-timestamp-start\":%" PRIu64 ",\"backup-timestamp-stop\":%" PRIu64 ",\"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-152800F_20181119-152152D={"
"\"backrest-format\":5,\"backrest-version\":\"2.08dev\",\"backup-archive-start\":\"000000010000000000000006\","
"\"backup-archive-stop\":\"000000010000000000000006\",\"backup-info-repo-size\":2369186,"
"\"backup-info-repo-size-delta\":346,\"backup-info-size\":20162900,\"backup-info-size-delta\":8428,"
"\"backup-prior\":\"20181119-152800F\",\"backup-reference\":[\"20181119-152800F\"],"
"\"backup-timestamp-start\":%" PRIu64 ",\"backup-timestamp-stop\":%" PRIu64 ",\"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-152800F_20181119-152155I={"
"\"backrest-format\":5,\"backrest-version\":\"2.08dev\",\"backup-archive-start\":\"000000010000000000000007\","
"\"backup-archive-stop\":\"000000010000000000000007\",\"backup-info-repo-size\":2369186,"
"\"backup-info-repo-size-delta\":346,\"backup-info-size\":20162900,\"backup-info-size-delta\":8428,"
"\"backup-prior\":\"20181119-152800F_20181119-152152D\","
"\"backup-reference\":[\"20181119-152800F\",\"20181119-152800F_20181119-152152D\"],"
"\"backup-timestamp-start\":%" PRIu64 ",\"backup-timestamp-stop\":%" PRIu64 ",\"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"
"20181119-152900F={"
"\"backrest-format\":5,\"backrest-version\":\"2.08dev\","
"\"backup-archive-start\":\"000000010000000000000009\",\"backup-archive-stop\":\"000000010000000000000009\","
"\"backup-info-repo-size\":2369186,\"backup-info-repo-size-delta\":2369186,"
"\"backup-info-size\":20162900,\"backup-info-size-delta\":20162900,"
"\"backup-timestamp-start\":%" PRIu64 ",\"backup-timestamp-stop\":%" PRIu64 ",\"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-152900F_20181119-152600D={"
"\"backrest-format\":5,\"backrest-version\":\"2.08dev\",\"backup-archive-start\":\"000000010000000000000011\","
"\"backup-archive-stop\":\"000000010000000000000011\",\"backup-info-repo-size\":2369186,"
"\"backup-info-repo-size-delta\":346,\"backup-info-size\":20162900,\"backup-info-size-delta\":8428,"
"\"backup-prior\":\"20181119-152900F\",\"backup-reference\":[\"20181119-152900F\"],"
"\"backup-timestamp-start\":%" PRIu64 ",\"backup-timestamp-stop\":%" PRIu64 ",\"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"
"\n"
"[db]\n"
"db-catalog-version=201409291\n"
"db-control-version=942\n"
"db-id=1\n"
"db-system-id=6625592122879095702\n"
"db-version=\"9.4\"\n"
"\n"
"[db:history]\n"
"1={\"db-catalog-version\":201409291,\"db-control-version\":942,\"db-system-id\":6625592122879095702,"
"\"db-version\":\"9.4\"}", timeNow - (41 * SEC_PER_DAY), timeNow - (40 * SEC_PER_DAY), timeNow - (30 * SEC_PER_DAY),
timeNow - (30 * SEC_PER_DAY), timeNow - (25 * SEC_PER_DAY), timeNow - (25 * SEC_PER_DAY), timeNow - (20 * SEC_PER_DAY),
timeNow - (20 * SEC_PER_DAY), timeNow - (10 * SEC_PER_DAY), timeNow - (10 * SEC_PER_DAY), timeNow - (5 * SEC_PER_DAY),
timeNow - (5 * SEC_PER_DAY));
const Buffer *backupInfoBase = harnessInfoChecksumZ(strZ(backupInfoContent));
// Sleep the remainder of the current second. If cmdExpire() gets the same time as timeNow then expiration won't work as
// expected in the tests.
sleepMSec(MSEC_PER_SEC - (timeMSec() % MSEC_PER_SEC));
// *****************************************************************************************************************************
if (testBegin("expireBackup()"))
{
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("manifest file removal");
// Create backup.info
InfoBackup *infoBackup = NULL;
TEST_ASSIGN(infoBackup, infoBackupNewLoad(ioBufferReadNew(backupInfoBase)), "get backup.info");
// Create backup directories and manifest files
String *full1 = strNew("20181119-152138F");
String *full2 = strNew("20181119-152800F");
String *full1Path = strNewFmt("%s/%s", strZ(backupStanzaPath), strZ(full1));
String *full2Path = strNewFmt("%s/%s", strZ(backupStanzaPath), strZ(full2));
// Load Parameters
StringList *argList = strLstDup(argListAvoidWarn);
harnessCfgLoad(cfgCmdExpire, argList);
TEST_RESULT_VOID(
storagePutP(
storageNewWriteP(storageTest, strNewFmt("%s/%s", strZ(full1Path), BACKUP_MANIFEST_FILE)), BUFSTRDEF(BOGUS_STR)),
"full1 put manifest");
TEST_RESULT_VOID(
storagePutP(
storageNewWriteP(
storageTest, strNewFmt("%s/%s", strZ(full1Path), BACKUP_MANIFEST_FILE ".copy")), BUFSTRDEF(BOGUS_STR)),
"full1 put manifest copy");
TEST_RESULT_VOID(
storagePutP(storageNewWriteP(storageTest, strNewFmt("%s/%s", strZ(full1Path), "bogus")),
BUFSTRDEF(BOGUS_STR)), "full1 put extra file");
TEST_RESULT_VOID(storagePathCreateP(storageTest, full2Path), "full2 empty");
TEST_RESULT_VOID(expireBackup(infoBackup, full1), "expire backup with both manifest files");
TEST_RESULT_BOOL(
(strLstSize(storageListP(storageTest, full1Path)) && strLstExistsZ(storageListP(storageTest, full1Path), "bogus")),
true, "full1 - only manifest files removed");
TEST_RESULT_VOID(expireBackup(infoBackup, full2), "expire backup with no manifest - does not error");
TEST_RESULT_STRLST_Z(
infoBackupDataLabelList(infoBackup, NULL),
"20181119-152900F\n20181119-152900F_20181119-152600D\n",
"only backups in set passed to expireBackup are removed from backup:current (result is sorted)");
}
// *****************************************************************************************************************************
if (testBegin("expireFullBackup()"))
{
// Create backup.info
InfoBackup *infoBackup = NULL;
TEST_ASSIGN(infoBackup, infoBackupNewLoad(ioBufferReadNew(backupInfoBase)), "get backup.info");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("retention-full not set - nothing expired");
// Load Parameters
StringList *argList = strLstDup(argListBase);
harnessCfgLoad(cfgCmdExpire, argList);
TEST_RESULT_UINT(expireFullBackup(infoBackup), 0, "retention-full not set");
harnessLogResult(
"P00 WARN: option 'repo1-retention-full' is not set for 'repo1-retention-full-type=count', the repository may run out"
" of space\n"
" HINT: to retain full backups indefinitely (without warning), set option 'repo1-retention-full' to the"
" maximum.");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("retention-full set - full backup no dependencies expired");
strLstAddZ(argList, "--repo1-retention-full=2");
harnessCfgLoad(cfgCmdExpire, argList);
TEST_RESULT_UINT(expireFullBackup(infoBackup), 1, "retention-full=2 - one full backup expired");
TEST_RESULT_UINT(infoBackupDataTotal(infoBackup), 5, "current backups reduced by 1 full - no dependencies");
TEST_RESULT_STRLST_Z(
infoBackupDataLabelList(infoBackup, NULL),
"20181119-152800F\n20181119-152800F_20181119-152152D\n20181119-152800F_20181119-152155I\n20181119-152900F\n"
"20181119-152900F_20181119-152600D\n",
"remaining backups correct");
harnessLogResult("P00 INFO: expire full backup 20181119-152138F");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("retention-full set - full backup with dependencies expired");
argList = strLstDup(argListBase);
strLstAddZ(argList, "--repo1-retention-full=1");
harnessCfgLoad(cfgCmdExpire, argList);
TEST_RESULT_UINT(expireFullBackup(infoBackup), 3, "retention-full=1 - one full backup and dependencies expired");
TEST_RESULT_UINT(infoBackupDataTotal(infoBackup), 2, "current backups reduced by 1 full and dependencies");
TEST_RESULT_STRLST_Z(
infoBackupDataLabelList(infoBackup, NULL), "20181119-152900F\n20181119-152900F_20181119-152600D\n",
"remaining backups correct");
harnessLogResult(
"P00 INFO: expire full backup set: 20181119-152800F, 20181119-152800F_20181119-152152D, "
"20181119-152800F_20181119-152155I");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("retention-full set - no backups expired");
TEST_RESULT_UINT(expireFullBackup(infoBackup), 0, "retention-full=1 - not enough backups to expire any");
TEST_RESULT_STRLST_Z(
infoBackupDataLabelList(infoBackup, NULL), "20181119-152900F\n20181119-152900F_20181119-152600D\n",
" remaining backups correct");
}
// *****************************************************************************************************************************
if (testBegin("expireDiffBackup()"))
{
// Create backup.info
InfoBackup *infoBackup = NULL;
TEST_ASSIGN(infoBackup, infoBackupNewLoad(ioBufferReadNew(backupInfoBase)), "get backup.info");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("retention-diff not set");
// Load Parameters
StringList *argList = strLstDup(argListAvoidWarn);
harnessCfgLoad(cfgCmdExpire, argList);
TEST_RESULT_UINT(expireDiffBackup(infoBackup), 0, "retention-diff not set - nothing expired");
TEST_RESULT_UINT(infoBackupDataTotal(infoBackup), 6, "current backups not expired");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("retention-diff set - nothing yet to expire");
// Add retention-diff
StringList *argListTemp = strLstDup(argList);
strLstAddZ(argListTemp, "--repo1-retention-diff=6");
harnessCfgLoad(cfgCmdExpire, argListTemp);
TEST_RESULT_UINT(expireDiffBackup(infoBackup), 0, "retention-diff set - too soon to expire");
TEST_RESULT_UINT(infoBackupDataTotal(infoBackup), 6, "current backups not expired");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("retention-diff set - diff and dependent incr expired");
strLstAddZ(argList, "--repo1-retention-diff=2");
harnessCfgLoad(cfgCmdExpire, argList);
TEST_RESULT_UINT(expireDiffBackup(infoBackup), 2, "retention-diff=2 - full considered in diff");
TEST_RESULT_UINT(infoBackupDataTotal(infoBackup), 4, "current backups reduced by 1 diff and dependent increment");
TEST_RESULT_STRLST_Z(
infoBackupDataLabelList(infoBackup, NULL),
"20181119-152138F\n20181119-152800F\n20181119-152900F\n20181119-152900F_20181119-152600D\n",
"remaining backups correct");
harnessLogResult(
"P00 INFO: expire diff backup set: 20181119-152800F_20181119-152152D, 20181119-152800F_20181119-152155I");
TEST_RESULT_UINT(expireDiffBackup(infoBackup), 0, "retention-diff=2 but no more to expire");
TEST_RESULT_UINT(infoBackupDataTotal(infoBackup), 4, "current backups not reduced");
//--------------------------------------------------------------------------------------------------------------------------
argList = strLstDup(argListAvoidWarn);
strLstAddZ(argList, "--repo1-retention-diff=1");
harnessCfgLoad(cfgCmdExpire, argList);
TEST_ASSIGN(infoBackup, infoBackupNewLoad(ioBufferReadNew(backupInfoBase)), "get backup.info");
TEST_RESULT_UINT(expireDiffBackup(infoBackup), 2, "retention-diff set to 1 - full considered in diff");
TEST_RESULT_STRLST_Z(
infoBackupDataLabelList(infoBackup, NULL),
"20181119-152138F\n20181119-152800F\n20181119-152900F\n20181119-152900F_20181119-152600D\n",
" remaining backups correct");
harnessLogResult(
"P00 INFO: expire diff backup set: 20181119-152800F_20181119-152152D, 20181119-152800F_20181119-152155I");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("retention-diff set - diff with no dependents expired");
// Create backup.info with two diff - oldest to be expired - no "set:"
const Buffer *backupInfoContent = harnessInfoChecksumZ
(
"[backup:current]\n"
"20181119-152800F={"
"\"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\":1542640911,\"backup-type\":\"full\","
"\"db-id\":1,\"option-archive-check\":true,\"option-archive-copy\":false,\"option-backup-standby\":false,"
"\"option-checksum-page\":true,\"option-compress\":true,\"option-hardlink\":false,\"option-online\":true}\n"
"20181119-152800F_20181119-152152D={"
"\"backrest-format\":5,\"backrest-version\":\"2.08dev\",\"backup-archive-start\":\"000000010000000000000003\","
"\"backup-archive-stop\":\"000000010000000000000003\",\"backup-info-repo-size\":2369186,"
"\"backup-info-repo-size-delta\":346,\"backup-info-size\":20162900,\"backup-info-size-delta\":8428,"
"\"backup-prior\":\"20181119-152800F\",\"backup-reference\":[\"20181119-152800F\"],"
"\"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-152800F_20181119-152155D={"
"\"backrest-format\":5,\"backrest-version\":\"2.08dev\",\"backup-archive-start\":\"000000010000000000000004\","
"\"backup-archive-stop\":\"000000010000000000000004\",\"backup-info-repo-size\":2369186,"
"\"backup-info-repo-size-delta\":346,\"backup-info-size\":20162900,\"backup-info-size-delta\":8428,"
"\"backup-prior\":\"20181119-152800F\",\"backup-reference\":[\"20181119-152800F\"],"
"\"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"
"\n"
"[db]\n"
"db-catalog-version=201409291\n"
"db-control-version=942\n"
"db-id=1\n"
"db-system-id=6625592122879095702\n"
"db-version=\"9.4\"\n"
"\n"
"[db:history]\n"
"1={\"db-catalog-version\":201409291,\"db-control-version\":942,\"db-system-id\":6625592122879095702,"
"\"db-version\":\"9.4\"}"
);
TEST_ASSIGN(infoBackup, infoBackupNewLoad(ioBufferReadNew(backupInfoContent)), "get backup.info");
// Load parameters
argList = strLstDup(argListAvoidWarn);
strLstAddZ(argList, "--repo1-retention-diff=1");
harnessCfgLoad(cfgCmdExpire, argList);
TEST_RESULT_UINT(expireDiffBackup(infoBackup), 1, "retention-diff set - only oldest diff expired");
TEST_RESULT_UINT(infoBackupDataTotal(infoBackup), 2, "current backups reduced by one");
TEST_RESULT_STRLST_Z(
infoBackupDataLabelList(infoBackup, NULL), "20181119-152800F\n20181119-152800F_20181119-152155D\n",
"remaining backups correct");
harnessLogResult(
"P00 INFO: expire diff backup 20181119-152800F_20181119-152152D");
}
// *****************************************************************************************************************************
if (testBegin("removeExpiredBackup()"))
{
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("remove expired backup from disk - backup not in current backup");
// Create backup.info
storagePutP(
storageNewWriteP(storageTest, backupInfoFileName),
harnessInfoChecksumZ(
"[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\":1542640911,\"backup-type\":\"full\","
"\"db-id\":1,\"option-archive-check\":true,\"option-archive-copy\":false,\"option-backup-standby\":false,"
"\"option-checksum-page\":true,\"option-compress\":true,\"option-hardlink\":false,\"option-online\":true}\n"
"\n"
"[db]\n"
"db-catalog-version=201409291\n"
"db-control-version=942\n"
"db-id=1\n"
"db-system-id=6625592122879095702\n"
"db-version=\"9.4\"\n"
"\n"
"[db:history]\n"
"1={\"db-catalog-version\":201409291,\"db-control-version\":942,\"db-system-id\":6625592122879095702,"
"\"db-version\":\"9.4\"}"));
InfoBackup *infoBackup = NULL;
TEST_ASSIGN(infoBackup, infoBackupLoadFile(storageTest, backupInfoFileName, cipherTypeNone, NULL), "get backup.info");
// Create backup directories, manifest files and other path/file
String *full = strNewFmt("%s/%s", strZ(backupStanzaPath), "20181119-152100F");
String *diff = strNewFmt("%s/%s", strZ(backupStanzaPath), "20181119-152100F_20181119-152152D");
String *otherPath = strNewFmt("%s/%s", strZ(backupStanzaPath), "bogus");
String *otherFile = strNewFmt("%s/%s", strZ(backupStanzaPath), "20181118-152100F_20181119-152152D.save");
String *full1 = strNewFmt("%s/%s", strZ(backupStanzaPath), "20181119-152138F");
TEST_RESULT_VOID(
storagePutP(storageNewWriteP(storageTest, strNewFmt("%s/%s", strZ(full), "bogus")),
BUFSTRDEF(BOGUS_STR)), "put file");
TEST_RESULT_VOID(
storagePutP(storageNewWriteP(storageTest, strNewFmt("%s/%s", strZ(full1), "somefile")),
BUFSTRDEF(BOGUS_STR)), "put file");
TEST_RESULT_VOID(storagePathCreateP(storageTest, diff), "empty backup directory must not error on delete");
TEST_RESULT_VOID(storagePathCreateP(storageTest, otherPath), "other path must not be removed");
TEST_RESULT_VOID(
storagePutP(storageNewWriteP(storageTest, otherFile),
BUFSTRDEF(BOGUS_STR)), "directory look-alike file must not be removed");
// Load Parameters
StringList *argList = strLstDup(argListBase);
strLstAddZ(argList, "--repo1-retention-full=1");
harnessCfgLoad(cfgCmdExpire, argList);
TEST_RESULT_VOID(removeExpiredBackup(infoBackup, NULL), "remove backups not in backup.info current");
harnessLogResult(
"P00 INFO: remove expired backup 20181119-152100F_20181119-152152D\n"
"P00 INFO: remove expired backup 20181119-152100F");
TEST_RESULT_STRLST_Z(
strLstSort(storageListP(storageTest, backupStanzaPath), sortOrderAsc),
"20181118-152100F_20181119-152152D.save\n20181119-152138F\nbackup.info\nbogus\n",
"remaining file/directories correct");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("remove expired backup from disk - no current backups");
// Create backup.info without current backups
const Buffer *backupInfoContent = harnessInfoChecksumZ
(
"[db]\n"
"db-catalog-version=201409291\n"
"db-control-version=942\n"
"db-id=1\n"
"db-system-id=6625592122879095702\n"
"db-version=\"9.4\"\n"
"\n"
"[db:history]\n"
"1={\"db-catalog-version\":201409291,\"db-control-version\":942,\"db-system-id\":6625592122879095702,"
"\"db-version\":\"9.4\"}"
);
TEST_ASSIGN(infoBackup, infoBackupNewLoad(ioBufferReadNew(backupInfoContent)), "get backup.info");
TEST_RESULT_VOID(removeExpiredBackup(infoBackup, NULL), "remove backups - backup.info current empty");
harnessLogResult("P00 INFO: remove expired backup 20181119-152138F");
TEST_RESULT_STRLST_Z(
strLstSort(storageListP(storageTest, backupStanzaPath), sortOrderAsc),
"20181118-152100F_20181119-152152D.save\nbackup.info\nbogus\n", "remaining file/directories correct");
}
// *****************************************************************************************************************************
if (testBegin("removeExpiredArchive() & cmdExpire()"))
{
TEST_TITLE("check repo local");
// Load Parameters
StringList *argList = strLstNew();
strLstAddZ(argList, "--stanza=db");
strLstAddZ(argList, "--repo1-retention-full=1"); // avoid warning
strLstAddZ(argList, "--repo1-host=/repo/not/local");
harnessCfgLoad(cfgCmdExpire, argList);
TEST_ERROR_FMT(
cmdExpire(), HostInvalidError, "expire command must be run on the repository host");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("check stop file");
argList = strLstDup(argListAvoidWarn);
harnessCfgLoad(cfgCmdExpire, argList);
// Create the stop file
TEST_RESULT_VOID(
storagePutP(
storageNewWriteP(storageLocalWrite(), lockStopFileName(cfgOptionStr(cfgOptStanza))), BUFSTRDEF("")),
"create stop file");
TEST_ERROR_FMT(cmdExpire(), StopError, "stop file exists for stanza db");
TEST_RESULT_VOID(
storageRemoveP(storageLocalWrite(), lockStopFileName(cfgOptionStr(cfgOptStanza))), "remove the stop file");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("retention-archive not set");
// Load Parameters
argList = strLstDup(argListBase);
harnessCfgLoad(cfgCmdExpire, argList);
// Create backup.info without current backups
const Buffer *backupInfoContent = harnessInfoChecksumZ
(
"[db]\n"
"db-catalog-version=201409291\n"
"db-control-version=942\n"
"db-id=1\n"
"db-system-id=6625592122879095702\n"
"db-version=\"9.4\"\n"
"\n"
"[db:history]\n"
"1={\"db-catalog-version\":201409291,\"db-control-version\":942,\"db-system-id\":6625592122879095702,"
"\"db-version\":\"9.4\"}"
);
InfoBackup *infoBackup = NULL;
TEST_ASSIGN(infoBackup, infoBackupNewLoad(ioBufferReadNew(backupInfoContent)), "get backup.info");
TEST_RESULT_VOID(removeExpiredArchive(infoBackup, false), "archive retention not set");
harnessLogResult(
"P00 WARN: option 'repo1-retention-full' is not set for 'repo1-retention-full-type=count', the repository may run out"
" of space\n"
" HINT: to retain full backups indefinitely (without warning), set option 'repo1-retention-full' to the"
" maximum.\n"
"P00 INFO: option 'repo1-retention-archive' is not set - archive logs will not be expired");
TEST_RESULT_VOID(removeExpiredArchive(infoBackup, true), "archive retention not set - retention-full-type=time");
harnessLogResult("P00 INFO: time-based archive retention not met - archive logs will not be expired");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("retention-archive set - no current backups");
// Set archive retention, archive retention type default but no current backups - code path test
strLstAddZ(argList, "--repo1-retention-archive=4");
harnessCfgLoad(cfgCmdExpire, argList);
TEST_RESULT_VOID(removeExpiredArchive(infoBackup, false), "archive retention set, retention type default, no current backups");
harnessLogResult(
"P00 WARN: option 'repo1-retention-full' is not set for 'repo1-retention-full-type=count', the repository may run out"
" of space\n"
" HINT: to retain full backups indefinitely (without warning), set option 'repo1-retention-full' to the"
" maximum.");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("retention-archive set - no archive on disk");
// Create backup.info with current backups spread over different timelines
storagePutP(storageNewWriteP(storageTest, backupInfoFileName),
harnessInfoChecksumZ(
"[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\":1542640911,\"backup-type\":\"full\","
"\"db-id\":1,\"option-archive-check\":true,\"option-archive-copy\":false,\"option-backup-standby\":false,"
"\"option-checksum-page\":true,\"option-compress\":true,\"option-hardlink\":false,\"option-online\":true}\n"
"20181119-152800F={"
"\"backrest-format\":5,\"backrest-version\":\"2.08dev\","
"\"backup-archive-start\":\"000000020000000000000002\",\"backup-archive-stop\":\"000000020000000000000002\","
"\"backup-info-repo-size\":2369186,\"backup-info-repo-size-delta\":2369186,"
"\"backup-info-size\":20162900,\"backup-info-size-delta\":20162900,"
"\"backup-timestamp-start\":1542640898,\"backup-timestamp-stop\":1542640911,\"backup-type\":\"full\","
"\"db-id\":1,\"option-archive-check\":true,\"option-archive-copy\":false,\"option-backup-standby\":false,"
"\"option-checksum-page\":true,\"option-compress\":true,\"option-hardlink\":false,\"option-online\":true}\n"
"20181119-152800F_20181119-152152D={"
"\"backrest-format\":5,\"backrest-version\":\"2.08dev\",\"backup-archive-start\":\"000000020000000000000004\","
"\"backup-archive-stop\":\"000000020000000000000005\",\"backup-info-repo-size\":2369186,"
"\"backup-info-repo-size-delta\":346,\"backup-info-size\":20162900,\"backup-info-size-delta\":8428,"
"\"backup-prior\":\"20181119-152800F\",\"backup-reference\":[\"20181119-152800F\"],"
"\"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-152800F_20181119-152155I={"
"\"backrest-format\":5,\"backrest-version\":\"2.08dev\",\"backup-archive-start\":\"000000020000000000000007\","
"\"backup-archive-stop\":\"000000020000000000000007\",\"backup-info-repo-size\":2369186,"
"\"backup-info-repo-size-delta\":346,\"backup-info-size\":20162900,\"backup-info-size-delta\":8428,"
"\"backup-prior\":\"20181119-152800F_20181119-152152D\","
"\"backup-reference\":[\"20181119-152800F\",\"20181119-152800F_20181119-152152D\"],"
"\"backup-timestamp-start\":1542640912,\"backup-timestamp-stop\":1542640915,\"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"
"20181119-152800F_20181119-152252D={"
"\"backrest-format\":5,\"backrest-version\":\"2.08dev\",\"backup-archive-start\":\"000000020000000000000009\","
"\"backup-archive-stop\":\"000000020000000000000009\",\"backup-info-repo-size\":2369186,"
"\"backup-info-repo-size-delta\":346,\"backup-info-size\":20162900,\"backup-info-size-delta\":8428,"
"\"backup-prior\":\"20181119-152800F\",\"backup-reference\":[\"20181119-152800F\"],"
"\"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-152900F={"
"\"backrest-format\":5,\"backrest-version\":\"2.08dev\","
"\"backup-archive-start\":\"000000010000000000000003\",\"backup-archive-stop\":\"000000010000000000000004\","
"\"backup-info-repo-size\":2369186,\"backup-info-repo-size-delta\":2369186,"
"\"backup-info-size\":20162900,\"backup-info-size-delta\":20162900,"
"\"backup-timestamp-start\":1542640898,\"backup-timestamp-stop\":1542640911,\"backup-type\":\"full\","
"\"db-id\":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"
"20181119-152900F_20181119-152500I={"
"\"backrest-format\":5,\"backrest-version\":\"2.08dev\",\"backup-archive-start\":\"000000010000000000000006\","
"\"backup-archive-stop\":\"000000010000000000000006\",\"backup-info-repo-size\":2369186,"
"\"backup-info-repo-size-delta\":346,\"backup-info-size\":20162900,\"backup-info-size-delta\":8428,"
"\"backup-prior\":\"20181119-152900F\",\"backup-reference\":[\"20181119-152900F\"],"
"\"backup-timestamp-start\":1542640912,\"backup-timestamp-stop\":1542640915,\"backup-type\":\"diff\","
"\"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=201707211\n"
"db-control-version=1002\n"
"db-id=2\n"
"db-system-id=6626363367545678089\n"
"db-version=\"10\"\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\":201707211,\"db-control-version\":1002,\"db-system-id\":6626363367545678089,"
"\"db-version\":\"10\"}\n"));
TEST_ASSIGN(infoBackup, infoBackupLoadFile(storageTest, backupInfoFileName, cipherTypeNone, NULL), "get backup.info");
storagePutP(
storageNewWriteP(storageTest, archiveInfoFileName),
harnessInfoChecksumZ(
"[db]\n"
"db-id=2\n"
"db-system-id=6626363367545678089\n"
"db-version=\"10\"\n"
"\n"
"[db:history]\n"
"1={\"db-id\":6625592122879095702,\"db-version\":\"9.4\"}\n"
"2={\"db-id\":6626363367545678089,\"db-version\":\"10\"}"));
TEST_RESULT_VOID(removeExpiredArchive(infoBackup, true), "no archive on disk");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("retention-archive set - remove archives across timelines");
archiveGenerate(storageTest, archiveStanzaPath, 1, 10, "9.4-1", "0000000100000000");
archiveGenerate(storageTest, archiveStanzaPath, 1, 10, "9.4-1", "0000000200000000");
archiveGenerate(storageTest, archiveStanzaPath, 1, 10, "10-2", "0000000100000000");
argList = strLstDup(argListAvoidWarn);
strLstAddZ(argList, "--repo1-retention-archive=3");
harnessCfgLoad(cfgCmdExpire, argList);
TEST_RESULT_VOID(removeExpiredArchive(infoBackup, false), "archive retention type = full (default), repo1-retention-archive=3");
TEST_RESULT_STRLST_STR(
strLstSort(storageListP(
storageTest, strNewFmt("%s/%s/%s", strZ(archiveStanzaPath), "9.4-1", "0000000100000000")), sortOrderAsc),
archiveExpectList(2, 10, "0000000100000000"), "only 9.4-1/0000000100000000/000000010000000000000001 removed");
TEST_RESULT_STRLST_STR(
strLstSort(storageListP(
storageTest, strNewFmt("%s/%s/%s", strZ(archiveStanzaPath), "9.4-1", "0000000200000000")), sortOrderAsc),
archiveExpectList(1, 10, "0000000200000000"),
"none removed from 9.4-1/0000000200000000 - crossing timelines to play through PITR");
TEST_RESULT_STRLST_STR(
strLstSort(storageListP(
storageTest, strNewFmt("%s/%s/%s", strZ(archiveStanzaPath), "10-2", "0000000100000000")), sortOrderAsc),
archiveExpectList(3, 10, "0000000100000000"),
"000000010000000000000001 and 000000010000000000000002 removed from 10-2/0000000100000000");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("retention-archive set - latest archive not expired");
argList = strLstDup(argListAvoidWarn);
strLstAddZ(argList, "--repo1-retention-archive=2");
harnessCfgLoad(cfgCmdExpire, argList);
TEST_RESULT_VOID(removeExpiredArchive(infoBackup, false), "archive retention type = full (default), repo1-retention-archive=2");
TEST_RESULT_STRLST_STR(
strLstSort(storageListP(
storageTest, strNewFmt("%s/%s/%s", strZ(archiveStanzaPath), "9.4-1", "0000000100000000")), sortOrderAsc),
archiveExpectList(2, 2, "0000000100000000"),
"only 9.4-1/0000000100000000/000000010000000000000002 remains in major wal 1");
TEST_RESULT_STRLST_STR(
strLstSort(storageListP(
storageTest, strNewFmt("%s/%s/%s", strZ(archiveStanzaPath), "9.4-1", "0000000200000000")), sortOrderAsc),
archiveExpectList(2, 10, "0000000200000000"),
"only 9.4-1/0000000200000000/000000010000000000000001 removed from major wal 2");
TEST_RESULT_STRLST_STR(
strLstSort(storageListP(
storageTest, strNewFmt("%s/%s/%s", strZ(archiveStanzaPath), "10-2", "0000000100000000")), sortOrderAsc),
archiveExpectList(3, 10, "0000000100000000"),
"none removed from 10-2/0000000100000000");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("retention-archive set to lowest - keep PITR for each archiveId");
argList = strLstDup(argListAvoidWarn);
strLstAddZ(argList, "--repo1-retention-archive=1");
harnessCfgLoad(cfgCmdExpire, argList);
TEST_RESULT_VOID(removeExpiredArchive(infoBackup, false), "archive retention type = full (default), repo1-retention-archive=1");
TEST_RESULT_STRLST_STR(
strLstSort(storageListP(
storageTest, strNewFmt("%s/%s/%s", strZ(archiveStanzaPath), "9.4-1", "0000000100000000")), sortOrderAsc),
archiveExpectList(2, 2, "0000000100000000"),
"only 9.4-1/0000000100000000/000000010000000000000002 remains in major wal 1");
TEST_RESULT_STRLST_STR(
strLstSort(storageListP(
storageTest, strNewFmt("%s/%s/%s", strZ(archiveStanzaPath), "9.4-1", "0000000200000000")), sortOrderAsc),
archiveExpectList(2, 10, "0000000200000000"),
"nothing removed from 9.4-1/0000000200000000 major wal 2 - each archiveId must have one backup to play through PITR");
TEST_RESULT_STRLST_STR(
strLstSort(storageListP(
storageTest, strNewFmt("%s/%s/%s", strZ(archiveStanzaPath), "10-2", "0000000100000000")), sortOrderAsc),
archiveExpectList(3, 10, "0000000100000000"), "none removed from 10-2/0000000100000000");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("retention-archive, retention-archive-type=diff, retention-diff set");
argList = strLstDup(argListAvoidWarn);
strLstAddZ(argList, "--repo1-retention-archive=2");
strLstAddZ(argList, "--repo1-retention-archive-type=diff");
strLstAddZ(argList, "--repo1-retention-diff=2");
harnessCfgLoad(cfgCmdExpire, argList);
TEST_RESULT_VOID(
removeExpiredArchive(infoBackup, false),
"full counts as differential and incremental associated with differential expires");
String *result = strNew("");
strCatFmt(
result,
"%s%s%s%s",
strZ(archiveExpectList(2, 2, "0000000200000000")), strZ(archiveExpectList(4, 5, "0000000200000000")),
strZ(archiveExpectList(7, 7, "0000000200000000")), strZ(archiveExpectList(9, 10, "0000000200000000")));
TEST_RESULT_STRLST_STR(
strLstSort(storageListP(
storageTest, strNewFmt("%s/%s/%s", strZ(archiveStanzaPath), "9.4-1", "0000000100000000")), sortOrderAsc),
archiveExpectList(2, 2, "0000000100000000"),
"only 9.4-1/0000000100000000/000000010000000000000002 remains in major wal 1");
TEST_RESULT_STRLST_STR(
strLstSort(storageListP(
storageTest, strNewFmt("%s/%s/%s", strZ(archiveStanzaPath), "9.4-1", "0000000200000000")), sortOrderAsc),
result, "all in-between removed from 9.4-1/0000000200000000 major wal 2 - last backup able to play through PITR");
TEST_RESULT_STRLST_STR(
strLstSort(storageListP(
storageTest, strNewFmt("%s/%s/%s", strZ(archiveStanzaPath), "10-2", "0000000100000000")), sortOrderAsc),
archiveExpectList(3, 10, "0000000100000000"), "none removed from 10-2/0000000100000000");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("retention-archive, retention-archive-type=incr");
argList = strLstDup(argListAvoidWarn);
strLstAddZ(argList, "--repo1-retention-archive=4");
strLstAddZ(argList, "--repo1-retention-archive-type=incr");
harnessCfgLoad(cfgCmdExpire, argList);
// Regenerate archive
archiveGenerate(storageTest, archiveStanzaPath, 1, 10, "9.4-1", "0000000200000000");
TEST_RESULT_VOID(removeExpiredArchive(infoBackup, false), "differential and full count as an incremental");
result = strNew("");
strCatFmt(
result,
"%s%s%s",
strZ(archiveExpectList(2, 2, "0000000200000000")), strZ(archiveExpectList(4, 5, "0000000200000000")),
strZ(archiveExpectList(7, 10, "0000000200000000")));
TEST_RESULT_STRLST_STR(
strLstSort(storageListP(
storageTest, strNewFmt("%s/%s/%s", strZ(archiveStanzaPath), "9.4-1", "0000000100000000")), sortOrderAsc),
archiveExpectList(2, 2, "0000000100000000"),
"only 9.4-1/0000000100000000/000000010000000000000002 remains in major wal 1");
TEST_RESULT_STRLST_STR(
strLstSort(storageListP(
storageTest, strNewFmt("%s/%s/%s", strZ(archiveStanzaPath), "9.4-1", "0000000200000000")), sortOrderAsc),
result, "incremental and after remain in 9.4-1/0000000200000000 major wal 2");
TEST_RESULT_STRLST_STR(
strLstSort(storageListP(
storageTest, strNewFmt("%s/%s/%s", strZ(archiveStanzaPath), "10-2", "0000000100000000")), sortOrderAsc),
archiveExpectList(3, 10, "0000000100000000"), "none removed from 10-2/0000000100000000");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("expire command - dry run");
argList = strLstDup(argListBase);
strLstAddZ(argList, "--repo1-retention-full=2");
strLstAddZ(argList, "--repo1-retention-diff=3");
strLstAddZ(argList, "--repo1-retention-archive=2");
strLstAddZ(argList, "--repo1-retention-archive-type=diff");
strLstAddZ(argList, "--dry-run");
harnessCfgLoad(cfgCmdExpire, argList);
// Write backup.manifest so infoBackup reconstruct produces same results as backup.info on disk
storagePutP(
storageNewWriteP(storageTest, strNewFmt("%s/20181119-152138F/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath))),
BUFSTRDEF("tmp"));
storagePutP(
storageNewWriteP(storageTest, strNewFmt("%s/20181119-152800F/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath))),
BUFSTRDEF("tmp"));
storagePutP(
storageNewWriteP(storageTest, strNewFmt("%s/20181119-152800F_20181119-152152D/" BACKUP_MANIFEST_FILE,
strZ(backupStanzaPath))), BUFSTRDEF("tmp"));
storagePutP(
storageNewWriteP(storageTest, strNewFmt("%s/20181119-152800F_20181119-152155I/" BACKUP_MANIFEST_FILE,
strZ(backupStanzaPath))), BUFSTRDEF("tmp"));
storagePutP(
storageNewWriteP(storageTest, strNewFmt("%s/20181119-152800F_20181119-152252D/" BACKUP_MANIFEST_FILE,
strZ(backupStanzaPath))), BUFSTRDEF("tmp"));
storagePutP(
storageNewWriteP(storageTest, strNewFmt("%s/20181119-152900F/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath))),
BUFSTRDEF("tmp"));
storagePutP(
storageNewWriteP(storageTest, strNewFmt("%s/20181119-152900F_20181119-152500I/" BACKUP_MANIFEST_FILE,
strZ(backupStanzaPath))), BUFSTRDEF("tmp"));
TEST_RESULT_VOID(cmdExpire(), "expire (dry-run) do not remove last backup in archive sub path or sub path");
TEST_RESULT_BOOL(
storagePathExistsP(storageTest, strNewFmt("%s/%s", strZ(archiveStanzaPath), "9.4-1/0000000100000000")), true,
"archive sub path not removed");
TEST_RESULT_BOOL(
storageExistsP(storageTest, strNewFmt("%s/20181119-152138F/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath))), true,
"backup not removed");
harnessLogResult(
"P00 INFO: [DRY-RUN] expire full backup 20181119-152138F\n"
"P00 INFO: [DRY-RUN] remove expired backup 20181119-152138F");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("expire via backup command");
// Copy the repo to another repo
TEST_SYSTEM_FMT("mkdir %s/repo2", testPath());
TEST_SYSTEM_FMT("cp -r %s/repo/* %s/repo2/", testPath(), testPath());
// Configure multi-repo and set the repo option to expire the second repo (non-default) files
argList = strLstDup(argListBase);
strLstAddZ(argList, "--repo1-retention-full=2");
strLstAddZ(argList, "--repo1-retention-diff=3");
strLstAddZ(argList, "--repo1-retention-archive=2");
strLstAddZ(argList, "--repo1-retention-archive-type=diff");
hrnCfgArgKeyRawFmt(argList, cfgOptRepoPath, 2, "%s/repo2", testPath());
hrnCfgArgKeyRawZ(argList, cfgOptRepoRetentionFull, 2, "2");
hrnCfgArgKeyRawZ(argList, cfgOptRepoRetentionDiff, 2, "3");
hrnCfgArgKeyRawZ(argList, cfgOptRepoRetentionArchive, 2, "2");
hrnCfgArgKeyRawZ(argList, cfgOptRepoRetentionArchiveType, 2, "diff");
hrnCfgArgRawZ(argList, cfgOptRepo, "2");
strLstAdd(argList, strNewFmt("--pg1-path=%s/pg", testPath()));
harnessCfgLoad(cfgCmdBackup, argList);
TEST_RESULT_VOID(cmdExpire(), "via backup command: expire last backup in archive sub path and remove sub path");
TEST_RESULT_BOOL(
storagePathExistsP(storageTest, STRDEF("repo2/archive/db/9.4-1/0000000100000000")), false,
"archive sub path removed repo2");
TEST_RESULT_BOOL(
storagePathExistsP(storageTest, strNewFmt("%s/9.4-1/0000000100000000", strZ(archiveStanzaPath))), true,
"archive sub path repo1 not removed");
String *backupLabel = strNew("20181119-152138F");
TEST_ASSIGN(
infoBackup, infoBackupLoadFile(storageTest, STRDEF("repo2/backup/db/backup.info"), cipherTypeNone, NULL),
"get backup.info repo2");
TEST_RESULT_BOOL(strLstExists(infoBackupDataLabelList(infoBackup, NULL), backupLabel), false, "backup removed from repo2");
TEST_ASSIGN(infoBackup, infoBackupLoadFile(storageTest, backupInfoFileName, cipherTypeNone, NULL), "get backup.info repo1");
TEST_RESULT_BOOL(strLstExists(infoBackupDataLabelList(infoBackup, NULL), backupLabel), true, "backup exists repo1");
harnessLogResult(
"P00 INFO: expire full backup 20181119-152138F\n"
"P00 INFO: remove expired backup 20181119-152138F");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("expire command requires repo option");
argList = strLstDup(argListBase);
hrnCfgArgKeyRawFmt(argList, cfgOptRepoPath, 2, "%s/repo2", testPath());
hrnCfgArgKeyRawZ(argList, cfgOptRepoRetentionFull, 2, "3");
TEST_ERROR_FMT(
harnessCfgLoad(cfgCmdExpire, argList), OptionRequiredError, "expire command requires option: repo\n"
"HINT: this command requires a specific repository to operate on");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("expire command - no dry run");
// Add to previous list and specify repo
strLstAddZ(argList, "--repo1-retention-full=2");
strLstAddZ(argList, "--repo1-retention-diff=3");
strLstAddZ(argList, "--repo1-retention-archive=2");
strLstAddZ(argList, "--repo1-retention-archive-type=diff");
hrnCfgArgRawZ(argList, cfgOptRepo, "1");
harnessCfgLoad(cfgCmdExpire, argList);
TEST_RESULT_VOID(cmdExpire(), "expire last backup in archive sub path and remove sub path");
TEST_RESULT_BOOL(
storagePathExistsP(storageTest, strNewFmt("%s/%s", strZ(archiveStanzaPath), "9.4-1/0000000100000000")), false,
"archive sub path removed");
harnessLogResult(
"P00 INFO: expire full backup 20181119-152138F\n"
"P00 INFO: remove expired backup 20181119-152138F");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("expire command - dry run: archive and backups not removed");
argList = strLstDup(argListAvoidWarn);
strLstAddZ(argList, "--repo1-retention-archive=1");
strLstAddZ(argList, "--dry-run");
harnessCfgLoad(cfgCmdExpire, argList);
TEST_RESULT_VOID(cmdExpire(), "expire (dry-run) - log expired backups and archive path to remove");
TEST_RESULT_BOOL(
storagePathExistsP(storageTest, strNewFmt("%s/%s", strZ(archiveStanzaPath), "9.4-1")), true,
"archive path not removed");
TEST_RESULT_BOOL(
(storageExistsP(storageTest, strNewFmt("%s/20181119-152800F/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath))) &&
storageExistsP(
storageTest, strNewFmt("%s/20181119-152800F_20181119-152152D/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath))) &&
storageExistsP(
storageTest, strNewFmt("%s/20181119-152800F_20181119-152155I/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath))) &&
storageExistsP(
storageTest, strNewFmt("%s/20181119-152800F_20181119-152252D/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath)))),
true, "backup not removed");
harnessLogResult(strZ(strNewFmt(
"P00 INFO: [DRY-RUN] expire full backup set: 20181119-152800F, 20181119-152800F_20181119-152152D, "
"20181119-152800F_20181119-152155I, 20181119-152800F_20181119-152252D\n"
"P00 INFO: [DRY-RUN] remove expired backup 20181119-152800F_20181119-152252D\n"
"P00 INFO: [DRY-RUN] remove expired backup 20181119-152800F_20181119-152155I\n"
"P00 INFO: [DRY-RUN] remove expired backup 20181119-152800F_20181119-152152D\n"
"P00 INFO: [DRY-RUN] remove expired backup 20181119-152800F\n"
"P00 INFO: [DRY-RUN] remove archive path: %s/%s/9.4-1", testPath(), strZ(archiveStanzaPath))));
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("expire via backup command - archive and backups removed");
argList = strLstDup(argListAvoidWarn);
strLstAddZ(argList, "--repo1-retention-archive=1");
strLstAdd(argList, strNewFmt("--pg1-path=%s/pg", testPath()));
harnessCfgLoad(cfgCmdBackup, argList);
TEST_RESULT_VOID(cmdExpire(), "via backup command: expire backups and remove archive path");
TEST_RESULT_BOOL(
storagePathExistsP(storageTest, strNewFmt("%s/%s", strZ(archiveStanzaPath), "9.4-1")),
false, "archive path removed");
harnessLogResult(strZ(strNewFmt(
"P00 INFO: expire full backup set: 20181119-152800F, 20181119-152800F_20181119-152152D, "
"20181119-152800F_20181119-152155I, 20181119-152800F_20181119-152252D\n"
"P00 INFO: remove expired backup 20181119-152800F_20181119-152252D\n"
"P00 INFO: remove expired backup 20181119-152800F_20181119-152155I\n"
"P00 INFO: remove expired backup 20181119-152800F_20181119-152152D\n"
"P00 INFO: remove expired backup 20181119-152800F\n"
"P00 INFO: remove archive path: %s/%s/9.4-1", testPath(), strZ(archiveStanzaPath))));
TEST_ASSIGN(infoBackup, infoBackupLoadFile(storageTest, backupInfoFileName, cipherTypeNone, NULL), "get backup.info");
TEST_RESULT_UINT(infoBackupDataTotal(infoBackup), 2, "backup.info updated on disk");
TEST_RESULT_STRLST_Z(
strLstSort(infoBackupDataLabelList(infoBackup, NULL), sortOrderAsc),
"20181119-152900F\n20181119-152900F_20181119-152500I\n", "remaining current backups correct");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("expire command - archive removed");
archiveGenerate(storageTest, archiveStanzaPath, 1, 1, "9.4-1", "0000000100000000");
argList = strLstDup(argListAvoidWarn);
strLstAddZ(argList, "--repo1-retention-archive=1");
harnessCfgLoad(cfgCmdExpire, argList);
TEST_RESULT_VOID(cmdExpire(), "expire remove archive path");
harnessLogResult(strZ(strNewFmt("P00 INFO: remove archive path: %s/%s/9.4-1", testPath(), strZ(archiveStanzaPath))));
//--------------------------------------------------------------------------------------------------------------------------
storagePutP(storageNewWriteP(storageTest, backupInfoFileName),
harnessInfoChecksumZ(
"[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\":1542640911,\"backup-type\":\"full\","
"\"db-id\":1,\"option-archive-check\":true,\"option-archive-copy\":false,\"option-backup-standby\":false,"
"\"option-checksum-page\":true,\"option-compress\":true,\"option-hardlink\":false,\"option-online\":true}\n"
"20181119-152800F={"
"\"backrest-format\":5,\"backrest-version\":\"2.08dev\","
"\"backup-info-repo-size\":2369186,\"backup-info-repo-size-delta\":2369186,"
"\"backup-info-size\":20162900,\"backup-info-size-delta\":20162900,"
"\"backup-timestamp-start\":1542640898,\"backup-timestamp-stop\":1542640911,\"backup-type\":\"full\","
"\"db-id\":1,\"option-archive-check\":true,\"option-archive-copy\":false,\"option-backup-standby\":false,"
"\"option-checksum-page\":true,\"option-compress\":true,\"option-hardlink\":false,\"option-online\":true}\n"
"20181119-152900F={"
"\"backrest-format\":5,\"backrest-version\":\"2.08dev\","
"\"backup-archive-start\":\"000000010000000000000004\",\"backup-archive-stop\":\"000000010000000000000004\","
"\"backup-info-repo-size\":2369186,\"backup-info-repo-size-delta\":2369186,"
"\"backup-info-size\":20162900,\"backup-info-size-delta\":20162900,"
"\"backup-timestamp-start\":1542640898,\"backup-timestamp-stop\":1542640911,\"backup-type\":\"full\","
"\"db-id\":1,\"option-archive-check\":true,\"option-archive-copy\":false,\"option-backup-standby\":false,"
"\"option-checksum-page\":true,\"option-compress\":true,\"option-hardlink\":false,\"option-online\":true}\n"
"\n"
"[db]\n"
"db-catalog-version=201707211\n"
"db-control-version=1002\n"
"db-id=2\n"
"db-system-id=6626363367545678089\n"
"db-version=\"10\"\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\":201707211,\"db-control-version\":1002,\"db-system-id\":6626363367545678089,"
"\"db-version\":\"10\"}\n"));
TEST_ASSIGN(infoBackup, infoBackupLoadFile(storageTest, backupInfoFileName, cipherTypeNone, NULL), "get backup.info");
archiveGenerate(storageTest, archiveStanzaPath, 1, 5, "9.4-1", "0000000100000000");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("retention backup no archive-start");
argList = strLstDup(argListAvoidWarn);
strLstAddZ(argList, "--repo1-retention-archive=2");
strLstAddZ(argList, "--repo1-retention-archive-type=full");
harnessCfgLoad(cfgCmdExpire, argList);
TEST_RESULT_VOID(
removeExpiredArchive(infoBackup, false), "backup selected for retention does not have archive-start so do nothing");
TEST_RESULT_STRLST_STR(
strLstSort(storageListP(
storageTest, strNewFmt("%s/%s/%s", strZ(archiveStanzaPath), "9.4-1", "0000000100000000")), sortOrderAsc),
archiveExpectList(1, 5, "0000000100000000"), "nothing removed from 9.4-1/0000000100000000");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("prior backup has no archive-start");
argList = strLstDup(argListAvoidWarn);
strLstAddZ(argList, "--repo1-retention-archive=1");
strLstAddZ(argList, "--repo1-retention-archive-type=full");
harnessCfgLoad(cfgCmdExpire, argList);
harnessLogLevelSet(logLevelDetail);
TEST_RESULT_VOID(
removeExpiredArchive(infoBackup, false), "backup earlier than selected for retention does not have archive-start");
harnessLogResult(
"P00 DETAIL: archive retention on backup 20181119-152138F, archiveId = 9.4-1, start = 000000010000000000000002,"
" stop = 000000010000000000000002\n"
"P00 DETAIL: archive retention on backup 20181119-152900F, archiveId = 9.4-1, start = 000000010000000000000004\n"
"P00 DETAIL: remove archive: archiveId = 9.4-1, start = 000000010000000000000001, stop = 000000010000000000000001\n"
"P00 DETAIL: remove archive: archiveId = 9.4-1, start = 000000010000000000000003, stop = 000000010000000000000003");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("expire history files - dry run");
// Load Parameters
argList = strLstDup(argListBase);
strLstAddZ(argList, "--repo1-retention-full=2");
strLstAddZ(argList, "--dry-run");
harnessCfgLoad(cfgCmdExpire, argList);
// Create backup.info and archives spread over different timelines
storagePutP(storageNewWriteP(storageTest, backupInfoFileName),
harnessInfoChecksumZ(
"[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\":1542640911,\"backup-type\":\"full\","
"\"db-id\":1,\"option-archive-check\":true,\"option-archive-copy\":false,\"option-backup-standby\":false,"
"\"option-checksum-page\":true,\"option-compress\":true,\"option-hardlink\":false,\"option-online\":true}\n"
"20181119-152900F={"
"\"backrest-format\":5,\"backrest-version\":\"2.08dev\","
"\"backup-archive-start\":\"000000030000000000000006\",\"backup-archive-stop\":\"000000030000000000000006\","
"\"backup-info-repo-size\":2369186,\"backup-info-repo-size-delta\":2369186,"
"\"backup-info-size\":20162900,\"backup-info-size-delta\":20162900,"
"\"backup-timestamp-start\":1542640898,\"backup-timestamp-stop\":1542640911,\"backup-type\":\"full\","
"\"db-id\":2,\"option-archive-check\":true,\"option-archive-copy\":false,\"option-backup-standby\":false,"
"\"option-checksum-page\":true,\"option-compress\":true,\"option-hardlink\":false,\"option-online\":true}\n"
"20181119-152900F_20181119-152500I={"
"\"backrest-format\":5,\"backrest-version\":\"2.08dev\",\"backup-archive-start\":\"000000030000000000000008\","
"\"backup-archive-stop\":\"000000030000000000000008\",\"backup-info-repo-size\":2369186,"
"\"backup-info-repo-size-delta\":346,\"backup-info-size\":20162900,\"backup-info-size-delta\":8428,"
"\"backup-prior\":\"20181119-152900F\",\"backup-reference\":[\"20181119-152900F\"],"
"\"backup-timestamp-start\":1542640912,\"backup-timestamp-stop\":1542640915,\"backup-type\":\"diff\","
"\"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=201707211\n"
"db-control-version=1002\n"
"db-id=2\n"
"db-system-id=6626363367545678089\n"
"db-version=\"10\"\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\":201707211,\"db-control-version\":1002,\"db-system-id\":6626363367545678089,"
"\"db-version\":\"10\"}\n"));
TEST_ASSIGN(infoBackup, infoBackupLoadFile(storageTest, backupInfoFileName, cipherTypeNone, NULL), "get backup.info");
storagePutP(
storageNewWriteP(storageTest, strNewFmt("%s/20181119-152138F/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath))),
BUFSTRDEF("tmp"));
storagePutP(
storageNewWriteP(storageTest, archiveInfoFileName),
harnessInfoChecksumZ(
"[db]\n"
"db-id=2\n"
"db-system-id=6626363367545678089\n"
"db-version=\"10\"\n"
"\n"
"[db:history]\n"
"1={\"db-id\":6625592122879095702,\"db-version\":\"9.4\"}\n"
"2={\"db-id\":6626363367545678089,\"db-version\":\"10\"}"));
storagePathRemoveP(storageTest, strNewFmt("%s/10-2/0000000100000000", strZ(archiveStanzaPath)), .recurse=true);
archiveGenerate(storageTest, archiveStanzaPath, 2, 2, "9.4-1", "0000000100000000");
archiveGenerate(storageTest, archiveStanzaPath, 6, 10, "10-2", "0000000300000000");
storagePutP(
storageNewWriteP(storageTest, strNewFmt("%s/10-2/00000002.history", strZ(archiveStanzaPath))), BUFSTRDEF("tmp"));
storagePutP(
storageNewWriteP(storageTest, strNewFmt("%s/10-2/00000003.history", strZ(archiveStanzaPath))), BUFSTRDEF("tmp"));
TEST_RESULT_VOID(cmdExpire(), "expire (dry-run) do not remove 00000002.history file");
TEST_RESULT_BOOL(
storageExistsP(storageTest, strNewFmt("%s/10-2/00000002.history", strZ(archiveStanzaPath))), true,
"history file not removed");
harnessLogResult(
"P00 DETAIL: [DRY-RUN] archive retention on backup 20181119-152138F, archiveId = 9.4-1, "
"start = 000000010000000000000002\n"
"P00 DETAIL: [DRY-RUN] no archive to remove, archiveId = 9.4-1\n"
"P00 DETAIL: [DRY-RUN] archive retention on backup 20181119-152900F, archiveId = 10-2, "
"start = 000000030000000000000006\n"
"P00 DETAIL: [DRY-RUN] no archive to remove, archiveId = 10-2\n"
"P00 DETAIL: [DRY-RUN] remove history file: archiveId = 10-2, file = 00000002.history");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("expire history files - no dry run");
// Load Parameters
argList = strLstDup(argListBase);
strLstAddZ(argList, "--repo1-retention-full=2");
harnessCfgLoad(cfgCmdExpire, argList);
TEST_RESULT_VOID(cmdExpire(), "expire remove 00000002.history file");
TEST_RESULT_BOOL(
storageExistsP(storageTest, strNewFmt("%s/10-2/00000002.history", strZ(archiveStanzaPath))), false,
"00000002.history file removed");
TEST_RESULT_BOOL(
storageExistsP(storageTest, strNewFmt("%s/10-2/00000003.history", strZ(archiveStanzaPath))), true,
"00000003.history file not removed");
harnessLogResult(
"P00 DETAIL: archive retention on backup 20181119-152138F, archiveId = 9.4-1, start = 000000010000000000000002\n"
"P00 DETAIL: no archive to remove, archiveId = 9.4-1\n"
"P00 DETAIL: archive retention on backup 20181119-152900F, archiveId = 10-2, start = 000000030000000000000006\n"
"P00 DETAIL: no archive to remove, archiveId = 10-2\n"
"P00 DETAIL: remove history file: archiveId = 10-2, file = 00000002.history");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("expire history files via backup command");
// Load Parameters
argList = strLstDup(argListBase);
strLstAddZ(argList, "--repo1-retention-full=2");
strLstAdd(argList, strNewFmt("--pg1-path=%s/pg", testPath()));
harnessCfgLoad(cfgCmdBackup, argList);
storagePutP(
storageNewWriteP(storageTest, strNewFmt("%s/10-2/00000002.history", strZ(archiveStanzaPath))), BUFSTRDEF("tmp"));
TEST_RESULT_VOID(cmdExpire(), "expire history files via backup command");
TEST_RESULT_BOOL(
storageExistsP(storageTest, strNewFmt("%s/10-2/00000002.history", strZ(archiveStanzaPath))), false,
"00000002.history file removed again");
TEST_RESULT_BOOL(
storageExistsP(storageTest, strNewFmt("%s/10-2/00000003.history", strZ(archiveStanzaPath))), true,
"00000003.history file not removed");
harnessLogResult(
"P00 DETAIL: archive retention on backup 20181119-152138F, archiveId = 9.4-1, start = 000000010000000000000002\n"
"P00 DETAIL: no archive to remove, archiveId = 9.4-1\n"
"P00 DETAIL: archive retention on backup 20181119-152900F, archiveId = 10-2, start = 000000030000000000000006\n"
"P00 DETAIL: no archive to remove, archiveId = 10-2\n"
"P00 DETAIL: remove history file: archiveId = 10-2, file = 00000002.history");
harnessLogLevelReset();
}
// *****************************************************************************************************************************
if (testBegin("info files mismatch"))
{
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("archive.info has only current db with different db history id as backup.info");
// Load Parameters
StringList *argList = strLstDup(argListBase);
strLstAddZ(argList, "--repo1-retention-full=2");
harnessCfgLoad(cfgCmdExpire, argList);
storagePutP(storageNewWriteP(storageTest, backupInfoFileName),
harnessInfoChecksumZ(
"[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\":1542640911,\"backup-type\":\"full\","
"\"db-id\":1,\"option-archive-check\":true,\"option-archive-copy\":false,\"option-backup-standby\":false,"
"\"option-checksum-page\":true,\"option-compress\":true,\"option-hardlink\":false,\"option-online\":true}\n"
"20181119-152800F={"
"\"backrest-format\":5,\"backrest-version\":\"2.08dev\","
"\"backup-archive-start\":\"000000010000000000000004\",\"backup-archive-stop\":\"000000010000000000000004\","
"\"backup-info-repo-size\":2369186,\"backup-info-repo-size-delta\":2369186,"
"\"backup-info-size\":20162900,\"backup-info-size-delta\":20162900,"
"\"backup-timestamp-start\":1542640898,\"backup-timestamp-stop\":1542640911,\"backup-type\":\"full\","
"\"db-id\":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"
"20181119-152900F={"
"\"backrest-format\":5,\"backrest-version\":\"2.08dev\","
"\"backup-archive-start\":\"000000010000000000000006\",\"backup-archive-stop\":\"000000010000000000000006\","
"\"backup-info-repo-size\":2369186,\"backup-info-repo-size-delta\":2369186,"
"\"backup-info-size\":20162900,\"backup-info-size-delta\":20162900,"
"\"backup-timestamp-start\":1542640898,\"backup-timestamp-stop\":1542640911,\"backup-type\":\"full\","
"\"db-id\":2,\"option-archive-check\":true,\"option-archive-copy\":false,\"option-backup-standby\":false,"
"\"option-checksum-page\":true,\"option-compress\":true,\"option-hardlink\":false,\"option-online\":true}\n"
"\n"
"[db]\n"
"db-catalog-version=201707211\n"
"db-control-version=1002\n"
"db-id=2\n"
"db-system-id=6626363367545678089\n"
"db-version=\"10\"\n"
"\n"
"[db:history]\n"
"1={\"db-catalog-version\":201409291,\"db-control-version\":1002,\"db-system-id\":6625592122879095702,"
"\"db-version\":\"10\"}\n"
"2={\"db-catalog-version\":201707211,\"db-control-version\":1002,\"db-system-id\":6626363367545678089,"
"\"db-version\":\"10\"}\n"));
// Write backup.manifest so infoBackup reconstruct produces same results as backup.info on disk and removeExpiredBackup
// will find backup directories to remove
storagePutP(
storageNewWriteP(storageTest, strNewFmt("%s/20181119-152138F/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath))),
BUFSTRDEF("tmp"));
storagePutP(
storageNewWriteP(storageTest, strNewFmt("%s/20181119-152800F/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath))),
BUFSTRDEF("tmp"));
storagePutP(
storageNewWriteP(storageTest, strNewFmt("%s/20181119-152900F/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath))),
BUFSTRDEF("tmp"));
storagePutP(
storageNewWriteP(storageTest, archiveInfoFileName),
harnessInfoChecksumZ(
"[db]\n"
"db-id=1\n"
"db-system-id=6626363367545678089\n"
"db-version=\"10\"\n"
"\n"
"[db:history]\n"
"1={\"db-id\":6626363367545678089,\"db-version\":\"10\"}"));
// Create 10-1 and 10-2 although 10-2 is not realistic since the archive.info knows nothing about it - it is just to
// confirm that nothing from disk is removed and it will also be used for the next test.
archiveGenerate(storageTest, archiveStanzaPath, 1, 7, "10-1", "0000000100000000");
archiveGenerate(storageTest, archiveStanzaPath, 1, 7, "10-2", "0000000100000000");
TEST_ERROR(cmdExpire(), FormatError, "archive expiration cannot continue - archive and backup history lists do not match");
harnessLogResult(
"P00 INFO: expire full backup 20181119-152138F\n"
"P00 INFO: remove expired backup 20181119-152138F");
TEST_RESULT_STRLST_STR(
strLstSort(storageListP(
storageTest, strNewFmt("%s/%s/%s", strZ(archiveStanzaPath), "10-1", "0000000100000000")), sortOrderAsc),
archiveExpectList(1, 7, "0000000100000000"), "none removed from 10-1/0000000100000000");
TEST_RESULT_STRLST_STR(
strLstSort(storageListP(
storageTest, strNewFmt("%s/%s/%s", strZ(archiveStanzaPath), "10-2", "0000000100000000")), sortOrderAsc),
archiveExpectList(1, 7, "0000000100000000"), "none removed from 10-2/0000000100000000");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("archive.info old history db system id not the same as backup.info");
storagePutP(
storageNewWriteP(storageTest, archiveInfoFileName),
harnessInfoChecksumZ(
"[db]\n"
"db-id=2\n"
"db-system-id=6626363367545678089\n"
"db-version=\"10\"\n"
"\n"
"[db:history]\n"
"1={\"db-id\":6626363367545671234,\"db-version\":\"10\"}\n"
"2={\"db-id\":6626363367545678089,\"db-version\":\"10\"}"));
TEST_ERROR(cmdExpire(), FormatError, "archive expiration cannot continue - archive and backup history lists do not match");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("archive.info old history db version not the same as backup.info");
storagePutP(
storageNewWriteP(storageTest, archiveInfoFileName),
harnessInfoChecksumZ(
"[db]\n"
"db-id=2\n"
"db-system-id=6626363367545678089\n"
"db-version=\"10\"\n"
"\n"
"[db:history]\n"
"1={\"db-id\":6625592122879095702,\"db-version\":\"9.4\"}\n"
"2={\"db-id\":6626363367545678089,\"db-version\":\"10\"}"));
TEST_ERROR(cmdExpire(), FormatError, "archive expiration cannot continue - archive and backup history lists do not match");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("archive.info has only current db with same db history id as backup.info");
storagePutP(storageNewWriteP(storageTest, backupInfoFileName),
harnessInfoChecksumZ(
"[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\":1542640911,\"backup-type\":\"full\","
"\"db-id\":1,\"option-archive-check\":true,\"option-archive-copy\":false,\"option-backup-standby\":false,"
"\"option-checksum-page\":true,\"option-compress\":true,\"option-hardlink\":false,\"option-online\":true}\n"
"20181119-152800F={"
"\"backrest-format\":5,\"backrest-version\":\"2.08dev\","
"\"backup-archive-start\":\"000000010000000000000004\",\"backup-archive-stop\":\"000000010000000000000004\","
"\"backup-info-repo-size\":2369186,\"backup-info-repo-size-delta\":2369186,"
"\"backup-info-size\":20162900,\"backup-info-size-delta\":20162900,"
"\"backup-timestamp-start\":1542640898,\"backup-timestamp-stop\":1542640911,\"backup-type\":\"full\","
"\"db-id\":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"
"20181119-152900F={"
"\"backrest-format\":5,\"backrest-version\":\"2.08dev\","
"\"backup-archive-start\":\"000000010000000000000006\",\"backup-archive-stop\":\"000000010000000000000006\","
"\"backup-info-repo-size\":2369186,\"backup-info-repo-size-delta\":2369186,"
"\"backup-info-size\":20162900,\"backup-info-size-delta\":20162900,"
"\"backup-timestamp-start\":1542640898,\"backup-timestamp-stop\":1542640911,\"backup-type\":\"full\","
"\"db-id\":2,\"option-archive-check\":true,\"option-archive-copy\":false,\"option-backup-standby\":false,"
"\"option-checksum-page\":true,\"option-compress\":true,\"option-hardlink\":false,\"option-online\":true}\n"
"\n"
"[db]\n"
"db-catalog-version=201707211\n"
"db-control-version=1002\n"
"db-id=2\n"
"db-system-id=6626363367545678089\n"
"db-version=\"10\"\n"
"\n"
"[db:history]\n"
"1={\"db-catalog-version\":201409291,\"db-control-version\":1002,\"db-system-id\":6625592122879095702,"
"\"db-version\":\"10\"}\n"
"2={\"db-catalog-version\":201707211,\"db-control-version\":1002,\"db-system-id\":6626363367545678089,"
"\"db-version\":\"10\"}\n"));
// Write backup.manifest so infoBackup reconstruct produces same results as backup.info on disk and removeExpiredBackup
// will find backup directories to remove
storagePutP(
storageNewWriteP(storageTest, strNewFmt("%s/20181119-152138F/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath))),
BUFSTRDEF("tmp"));
storagePutP(
storageNewWriteP(storageTest, strNewFmt("%s/20181119-152800F/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath))),
BUFSTRDEF("tmp"));
storagePutP(
storageNewWriteP(storageTest, strNewFmt("%s/20181119-152900F/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath))),
BUFSTRDEF("tmp"));
storagePutP(
storageNewWriteP(storageTest, archiveInfoFileName),
harnessInfoChecksumZ(
"[db]\n"
"db-id=2\n"
"db-system-id=6626363367545678089\n"
"db-version=\"10\"\n"
"\n"
"[db:history]\n"
"2={\"db-id\":6626363367545678089,\"db-version\":\"10\"}"));
argList = strLstDup(argListBase);
strLstAddZ(argList, "--repo1-retention-full=1");
harnessCfgLoad(cfgCmdExpire, argList);
// Here, although backup 20181119-152138F of 10-1 will be expired, the WAL in 10-1 will not since the archive.info
// does not know about that dir. Again, not really realistic since if it is on disk and reconstructed it would have. So
// here we are testing that things on disk that we are not aware of are not touched.
TEST_RESULT_VOID(cmdExpire(), "Expire archive that archive.info is aware of");
harnessLogResult(
"P00 INFO: expire full backup 20181119-152138F\n"
"P00 INFO: expire full backup 20181119-152800F\n"
"P00 INFO: remove expired backup 20181119-152800F\n"
"P00 INFO: remove expired backup 20181119-152138F");
TEST_RESULT_STRLST_STR(
strLstSort(storageListP(
storageTest, strNewFmt("%s/%s/%s", strZ(archiveStanzaPath), "10-1", "0000000100000000")), sortOrderAsc),
archiveExpectList(1, 7, "0000000100000000"), "none removed from 10-1/0000000100000000");
TEST_RESULT_STRLST_STR(
strLstSort(storageListP(
storageTest, strNewFmt("%s/%s/%s", strZ(archiveStanzaPath), "10-2", "0000000100000000")), sortOrderAsc),
archiveExpectList(6, 7, "0000000100000000"),
"all prior to 000000010000000000000006 removed from 10-2/0000000100000000");
}
// *****************************************************************************************************************************
if (testBegin("expireAdhocBackup()"))
{
// Create backup.info
storagePutP(storageNewWriteP(storageTest, backupInfoFileName),
harnessInfoChecksumZ(
"[backup:current]\n"
"20181119-152138F={"
"\"backrest-format\":5,\"backrest-version\":\"2.08dev\","
"\"backup-archive-start\":\"000000020000000000000001\",\"backup-archive-stop\":\"000000020000000000000001\","
"\"backup-info-repo-size\":2369186,\"backup-info-repo-size-delta\":2369186,"
"\"backup-info-size\":20162900,\"backup-info-size-delta\":20162900,"
"\"backup-timestamp-start\":1542640898,\"backup-timestamp-stop\":1542640911,\"backup-type\":\"full\","
"\"db-id\":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-152800F={"
"\"backrest-format\":5,\"backrest-version\":\"2.08dev\","
"\"backup-archive-start\":\"000000020000000000000002\",\"backup-archive-stop\":\"000000020000000000000002\","
"\"backup-info-repo-size\":2369186,\"backup-info-repo-size-delta\":2369186,"
"\"backup-info-size\":20162900,\"backup-info-size-delta\":20162900,"
"\"backup-timestamp-start\":1542640898,\"backup-timestamp-stop\":1542640911,\"backup-type\":\"full\","
"\"db-id\":1,\"option-archive-check\":true,\"option-archive-copy\":false,\"option-backup-standby\":false,"
"\"option-checksum-page\":true,\"option-compress\":true,\"option-hardlink\":false,\"option-online\":true}\n"
"20181119-152800F_20181119-152152D={"
"\"backrest-format\":5,\"backrest-version\":\"2.08dev\",\"backup-archive-start\":\"000000020000000000000004\","
"\"backup-archive-stop\":\"000000020000000000000005\",\"backup-info-repo-size\":2369186,"
"\"backup-info-repo-size-delta\":346,\"backup-info-size\":20162900,\"backup-info-size-delta\":8428,"
"\"backup-prior\":\"20181119-152800F\",\"backup-reference\":[\"20181119-152800F\"],"
"\"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-152800F_20181119-152155I={"
"\"backrest-format\":5,\"backrest-version\":\"2.08dev\",\"backup-archive-start\":\"000000020000000000000007\","
"\"backup-archive-stop\":\"000000020000000000000007\",\"backup-info-repo-size\":2369186,"
"\"backup-info-repo-size-delta\":346,\"backup-info-size\":20162900,\"backup-info-size-delta\":8428,"
"\"backup-prior\":\"20181119-152800F_20181119-152152D\","
"\"backup-reference\":[\"20181119-152800F\",\"20181119-152800F_20181119-152152D\"],"
"\"backup-timestamp-start\":1542640912,\"backup-timestamp-stop\":1542640915,\"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"
"20181119-152800F_20181119-152252D={"
"\"backrest-format\":5,\"backrest-version\":\"2.08dev\",\"backup-archive-start\":\"000000020000000000000009\","
"\"backup-archive-stop\":\"000000020000000000000009\",\"backup-info-repo-size\":2369186,"
"\"backup-info-repo-size-delta\":346,\"backup-info-size\":20162900,\"backup-info-size-delta\":8428,"
"\"backup-prior\":\"20181119-152800F\",\"backup-reference\":[\"20181119-152800F\"],"
"\"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-152850F={"
"\"backrest-format\":5,\"backrest-version\":\"2.08dev\","
"\"backup-archive-start\":\"000000010000000000000002\",\"backup-archive-stop\":\"000000010000000000000004\","
"\"backup-info-repo-size\":2369186,\"backup-info-repo-size-delta\":2369186,"
"\"backup-info-size\":20162900,\"backup-info-size-delta\":20162900,"
"\"backup-timestamp-start\":1542640898,\"backup-timestamp-stop\":1542640911,\"backup-type\":\"full\","
"\"db-id\":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"
"20181119-152900F={"
"\"backrest-format\":5,\"backrest-version\":\"2.08dev\","
"\"backup-archive-start\":\"000000010000000000000006\",\"backup-archive-stop\":\"000000010000000000000007\","
"\"backup-info-repo-size\":2369186,\"backup-info-repo-size-delta\":2369186,"
"\"backup-info-size\":20162900,\"backup-info-size-delta\":20162900,"
"\"backup-timestamp-start\":1542640898,\"backup-timestamp-stop\":1542640911,\"backup-type\":\"full\","
"\"db-id\":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=201909212\n"
"db-control-version=1201\n"
"db-id=2\n"
"db-system-id=6626363367545678089\n"
"db-version=\"12\"\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\":201909212,\"db-control-version\":1201,\"db-system-id\":6626363367545678089,"
"\"db-version\":\"12\"}\n"));
// Add backup directories with manifest file including a resumable backup dependent on last backup
storagePutP(
storageNewWriteP(storageTest, strNewFmt("%s/20181119-152138F/" BACKUP_MANIFEST_FILE,
strZ(backupStanzaPath))), BUFSTRDEF("tmp"));
storagePutP(
storageNewWriteP(storageTest, strNewFmt("%s/20181119-152800F/" BACKUP_MANIFEST_FILE,
strZ(backupStanzaPath))), BUFSTRDEF("tmp"));
storagePutP(
storageNewWriteP(storageTest, strNewFmt("%s/20181119-152800F_20181119-152152D/" BACKUP_MANIFEST_FILE,
strZ(backupStanzaPath))), BUFSTRDEF("tmp"));
storagePutP(
storageNewWriteP(storageTest, strNewFmt("%s/20181119-152800F_20181119-152155I/" BACKUP_MANIFEST_FILE,
strZ(backupStanzaPath))), BUFSTRDEF("tmp"));
storagePutP(
storageNewWriteP(storageTest, strNewFmt("%s/20181119-152800F_20181119-152252D/" BACKUP_MANIFEST_FILE,
strZ(backupStanzaPath))), BUFSTRDEF("tmp"));
storagePutP(
storageNewWriteP(storageTest, strNewFmt("%s/20181119-152850F/" BACKUP_MANIFEST_FILE,
strZ(backupStanzaPath))), BUFSTRDEF("tmp"));
storagePutP(
storageNewWriteP(storageTest, strNewFmt("%s/20181119-152900F/" BACKUP_MANIFEST_FILE,
strZ(backupStanzaPath))), BUFSTRDEF("tmp"));
// Resumable backup
storagePutP(
storageNewWriteP(storageTest, strNewFmt("%s/20181119-152900F_20181119-153000I/" BACKUP_MANIFEST_FILE INFO_COPY_EXT,
strZ(backupStanzaPath))),
harnessInfoChecksumZ(
"[backup]\n"
"backup-archive-start=\"000000010000000000000008\"\n"
"backup-label=null\n"
"backup-prior=\"20181119-152900F\"\n"
"backup-timestamp-copy-start=0\n"
"backup-timestamp-start=0\n"
"backup-timestamp-stop=0\n"
"backup-type=\"incr\"\n"
"\n"
"[backup:db]\n"
"db-catalog-version=201909212\n"
"db-control-version=1201\n"
"db-id=2\n"
"db-system-id=6626363367545678089\n"
"db-version=\"12\"\n"
"\n"
"[backup:option]\n"
"option-archive-check=false\n"
"option-archive-copy=false\n"
"option-checksum-page=false\n"
"option-compress=false\n"
"option-compress-type=\"none\"\n"
"option-hardlink=false\n"
"option-online=false\n"
"\n"
"[backup:target]\n"
"pg_data={\"path\":\"{[path]}/pg\",\"type\":\"path\"}\n"
"\n"
"[db]\n"
"postgres={\"db-id\":12980,\"db-last-system-id\":12979}\n"
"\n"
"[target:file]\n"
"pg_data/PG_VERSION={\"size\":3,\"timestamp\":1565282100}\n"
"\n"
"[target:file:default]\n"
"group=\"postgres\"\n"
"master=false\n"
"mode=\"0600\"\n"
"user=\"postgres\"\n"
"\n"
"[target:path]\n"
"pg_data={}\n"
"\n"
"[target:path:default]\n"
"group=\"postgres\"\n"
"mode=\"0700\"\n"
"user=\"postgres\"\n"));
InfoBackup *infoBackup = NULL;
TEST_ASSIGN(infoBackup, infoBackupLoadFile(storageTest, backupInfoFileName, cipherTypeNone, NULL), "get backup.info");
// Create "latest" symlink
const String *latestLink = storagePathP(storageTest, strNewFmt("%s/latest", strZ(backupStanzaPath)));
THROW_ON_SYS_ERROR_FMT(
symlink(strZ(infoBackupData(infoBackup, infoBackupDataTotal(infoBackup) - 1).backupLabel), strZ(latestLink)) == -1,
FileOpenError, "unable to create symlink '%s' to '%s'", strZ(latestLink),
strZ(infoBackupData(infoBackup, infoBackupDataTotal(infoBackup) - 1).backupLabel));
// Create archive info
storagePutP(
storageNewWriteP(storageTest, archiveInfoFileName),
harnessInfoChecksumZ(
"[db]\n"
"db-id=2\n"
"db-system-id=6626363367545678089\n"
"db-version=\"12\"\n"
"\n"
"[db:history]\n"
"1={\"db-id\":6625592122879095702,\"db-version\":\"9.4\"}\n"
"2={\"db-id\":6626363367545678089,\"db-version\":\"12\"}"));
// Create archive directories and generate archive
archiveGenerate(storageTest, archiveStanzaPath, 1, 10, "9.4-1", "0000000200000000");
archiveGenerate(storageTest, archiveStanzaPath, 1, 10, "12-2", "0000000100000000");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("invalid backup label");
TEST_RESULT_UINT(
expireAdhocBackup(infoBackup, STRDEF("20201119-123456F_20201119-234567I")), 0,
"label format OK but backup does not exist");
harnessLogResult(
"P00 WARN: backup 20201119-123456F_20201119-234567I does not exist\n"
" HINT: run the info command and confirm the backup is listed");
TEST_ERROR(
expireAdhocBackup(infoBackup, STRDEF(BOGUS_STR)), OptionInvalidValueError,
"'" BOGUS_STR "' is not a valid backup label format");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("expire backup and dependent");
StringList *argList = strLstDup(argListBase);
strLstAddZ(argList, "--repo1-retention-full=1");
strLstAddZ(argList, "--set=20181119-152800F_20181119-152152D");
harnessCfgLoad(cfgCmdExpire, argList);
// Set the log level to detail so archive expiration messages are seen
harnessLogLevelSet(logLevelDetail);
TEST_RESULT_VOID(cmdExpire(), "adhoc expire only backup and dependent");
TEST_RESULT_BOOL(
(storageExistsP(storageTest, strNewFmt("%s/20181119-152138F/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath))) &&
storageExistsP(storageTest, strNewFmt("%s/20181119-152800F/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath))) &&
storageExistsP(
storageTest, strNewFmt("%s/20181119-152800F_20181119-152252D/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath))) &&
storageExistsP(
storageTest, strNewFmt("%s/20181119-152850F/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath))) &&
storageExistsP(
storageTest, strNewFmt("%s/20181119-152900F/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath))) &&
storageExistsP(
storageTest, strNewFmt("%s/20181119-152900F_20181119-153000I/" BACKUP_MANIFEST_FILE INFO_COPY_EXT,
strZ(backupStanzaPath))) &&
!storageExistsP(
storageTest, strNewFmt("%s/20181119-152800F_20181119-152152D/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath))) &&
!storageExistsP(
storageTest, strNewFmt("%s/20181119-152800F_20181119-152155I/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath)))),
true, "only adhoc and dependents removed - resumable and all other backups remain");
TEST_RESULT_STR(storageInfoP(storageRepo(), STRDEF(STORAGE_REPO_BACKUP "/latest")).linkDestination,
STRDEF("20181119-152900F"), "latest link not updated");
harnessLogResult(
"P00 INFO: expire adhoc backup set: 20181119-152800F_20181119-152152D, 20181119-152800F_20181119-152155I\n"
"P00 INFO: remove expired backup 20181119-152800F_20181119-152155I\n"
"P00 INFO: remove expired backup 20181119-152800F_20181119-152152D\n"
"P00 DETAIL: archive retention on backup 20181119-152138F, archiveId = 9.4-1, start = 000000020000000000000001,"
" stop = 000000020000000000000001\n"
"P00 DETAIL: archive retention on backup 20181119-152800F, archiveId = 9.4-1, start = 000000020000000000000002\n"
"P00 DETAIL: no archive to remove, archiveId = 9.4-1\n"
"P00 DETAIL: archive retention on backup 20181119-152850F, archiveId = 12-2, start = 000000010000000000000002,"
" stop = 000000010000000000000004\n"
"P00 DETAIL: archive retention on backup 20181119-152900F, archiveId = 12-2, start = 000000010000000000000006\n"
"P00 DETAIL: remove archive: archiveId = 12-2, start = 000000010000000000000001, stop = 000000010000000000000001\n"
"P00 DETAIL: remove archive: archiveId = 12-2, start = 000000010000000000000005, stop = 000000010000000000000005");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("expire full and archive (no dependents)");
argList = strLstDup(argListBase);
strLstAddZ(argList, "--repo1-retention-full=1");
strLstAddZ(argList, "--set=20181119-152138F");
harnessCfgLoad(cfgCmdExpire, argList);
TEST_RESULT_VOID(cmdExpire(), "adhoc expire full backup");
TEST_RESULT_BOOL(
(storageExistsP(storageTest, strNewFmt("%s/20181119-152800F/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath))) &&
storageExistsP(
storageTest, strNewFmt("%s/20181119-152800F_20181119-152252D/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath))) &&
storageExistsP(
storageTest, strNewFmt("%s/20181119-152850F/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath))) &&
storageExistsP(
storageTest, strNewFmt("%s/20181119-152900F/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath))) &&
storageExistsP(
storageTest, strNewFmt("%s/20181119-152900F_20181119-153000I/" BACKUP_MANIFEST_FILE INFO_COPY_EXT,
strZ(backupStanzaPath))) &&
!storageExistsP(storageTest, strNewFmt("%s/20181119-152138F/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath)))),
true, "only adhoc full removed");
harnessLogResult(
"P00 INFO: expire adhoc backup 20181119-152138F\n"
"P00 INFO: remove expired backup 20181119-152138F\n"
"P00 DETAIL: archive retention on backup 20181119-152800F, archiveId = 9.4-1, start = 000000020000000000000002\n"
"P00 DETAIL: remove archive: archiveId = 9.4-1, start = 000000020000000000000001, stop = 000000020000000000000001\n"
"P00 DETAIL: archive retention on backup 20181119-152850F, archiveId = 12-2, start = 000000010000000000000002,"
" stop = 000000010000000000000004\n"
"P00 DETAIL: archive retention on backup 20181119-152900F, archiveId = 12-2, start = 000000010000000000000006\n"
"P00 DETAIL: no archive to remove, archiveId = 12-2");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("expire latest and resumable");
argList = strLstDup(argListBase);
strLstAddZ(argList, "--repo1-retention-full=1");
strLstAddZ(argList, "--set=20181119-152900F");
harnessCfgLoad(cfgCmdExpire, argList);
String *archiveRemaining = strNew("");
strCatFmt(
archiveRemaining, "%s%s", strZ(archiveExpectList(2, 4, "0000000100000000")),
strZ(archiveExpectList(6, 10, "0000000100000000")));
TEST_RESULT_VOID(cmdExpire(), "adhoc expire latest backup");
TEST_RESULT_BOOL(
(storageExistsP(storageTest, strNewFmt("%s/20181119-152800F/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath))) &&
storageExistsP(
storageTest, strNewFmt("%s/20181119-152800F_20181119-152252D/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath))) &&
!storageExistsP(
storageTest, strNewFmt("%s/20181119-152900F/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath))) &&
!storageExistsP(
storageTest, strNewFmt("%s/20181119-152900F_20181119-153000I/" BACKUP_MANIFEST_FILE INFO_COPY_EXT,
strZ(backupStanzaPath)))),
true, "latest and resumable removed");
harnessLogResult(
"P00 WARN: expiring latest backup 20181119-152900F - the ability to perform point-in-time-recovery (PITR) may be"
" affected\n"
" HINT: non-default settings for 'repo1-retention-archive'/'repo1-retention-archive-type'"
" (even in prior expires) can cause gaps in the WAL.\n"
"P00 INFO: expire adhoc backup 20181119-152900F\n"
"P00 INFO: remove expired backup 20181119-152900F_20181119-153000I\n"
"P00 INFO: remove expired backup 20181119-152900F\n"
"P00 DETAIL: archive retention on backup 20181119-152800F, archiveId = 9.4-1, start = 000000020000000000000002\n"
"P00 DETAIL: no archive to remove, archiveId = 9.4-1\n"
"P00 DETAIL: archive retention on backup 20181119-152850F, archiveId = 12-2, start = 000000010000000000000002\n"
"P00 DETAIL: no archive to remove, archiveId = 12-2");
TEST_RESULT_STR(storageInfoP(storageRepo(), STRDEF(STORAGE_REPO_BACKUP "/latest")).linkDestination,
STRDEF("20181119-152850F"), "latest link updated");
TEST_RESULT_STRLST_STR(
strLstSort(storageListP(
storageTest, strNewFmt("%s/%s/%s", strZ(archiveStanzaPath), "12-2", "0000000100000000")), sortOrderAsc),
archiveRemaining,
"no archives removed from latest except what was already removed");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("error on expire last full backup in current db-id");
argList = strLstDup(argListAvoidWarn);
strLstAddZ(argList, "--set=20181119-152850F");
harnessCfgLoad(cfgCmdExpire, argList);
TEST_ERROR(
cmdExpire(), BackupSetInvalidError,
"full backup 20181119-152850F cannot be expired until another full backup has been created");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("allow adhoc expire on last full backup in prior db-id");
argList = strLstDup(argListAvoidWarn);
strLstAddZ(argList, "--set=20181119-152800F");
harnessCfgLoad(cfgCmdExpire, argList);
TEST_RESULT_VOID(cmdExpire(), "adhoc expire last prior db-id backup");
TEST_RESULT_BOOL(
(storageExistsP(storageTest, strNewFmt("%s/20181119-152850F/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath))) &&
!storageExistsP(
storageTest, strNewFmt("%s/20181119-152800F/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath))) &&
!storageExistsP(
storageTest, strNewFmt("%s/20181119-152800F_20181119-152252D/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath)))),
true, "only last prior backup removed");
harnessLogResult(
strZ(strNewFmt(
"P00 INFO: expire adhoc backup set: 20181119-152800F, 20181119-152800F_20181119-152252D\n"
"P00 INFO: remove expired backup 20181119-152800F_20181119-152252D\n"
"P00 INFO: remove expired backup 20181119-152800F\n"
"P00 INFO: remove archive path: %s/repo/archive/db/9.4-1\n"
"P00 DETAIL: archive retention on backup 20181119-152850F, archiveId = 12-2, start = 000000010000000000000002\n"
"P00 DETAIL: no archive to remove, archiveId = 12-2", testPath())));
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("error on expire last full backup on disk");
argList = strLstDup(argListAvoidWarn);
strLstAddZ(argList, "--set=20181119-152850F");
harnessCfgLoad(cfgCmdExpire, argList);
TEST_ERROR(
cmdExpire(), BackupSetInvalidError,
"full backup 20181119-152850F cannot be expired until another full backup has been created");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("adhoc dry-run");
// Create backup.info
storagePutP(storageNewWriteP(storageTest, backupInfoFileName),
harnessInfoChecksumZ(
"[backup:current]\n"
"20181119-152850F={"
"\"backrest-format\":5,\"backrest-version\":\"2.08dev\","
"\"backup-archive-start\":\"000000010000000000000002\",\"backup-archive-stop\":\"000000010000000000000004\","
"\"backup-info-repo-size\":2369186,\"backup-info-repo-size-delta\":2369186,"
"\"backup-info-size\":20162900,\"backup-info-size-delta\":20162900,"
"\"backup-timestamp-start\":1542640898,\"backup-timestamp-stop\":1542640911,\"backup-type\":\"full\","
"\"db-id\":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"
"20181119-152850F_20181119-152252D={"
"\"backrest-format\":5,\"backrest-version\":\"2.08dev\",\"backup-archive-start\":\"000000010000000000000006\","
"\"backup-archive-stop\":\"000000010000000000000007\",\"backup-info-repo-size\":2369186,"
"\"backup-info-repo-size-delta\":346,\"backup-info-size\":20162900,\"backup-info-size-delta\":8428,"
"\"backup-prior\":\"20181119-152850F\",\"backup-reference\":[\"20181119-152850F\"],"
"\"backup-timestamp-start\":1542640912,\"backup-timestamp-stop\":1542640915,\"backup-type\":\"diff\","
"\"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=201909212\n"
"db-control-version=1201\n"
"db-id=2\n"
"db-system-id=6626363367545678089\n"
"db-version=\"12\"\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\":201909212,\"db-control-version\":1201,\"db-system-id\":6626363367545678089,"
"\"db-version\":\"12\"}\n"));
argList = strLstDup(argListAvoidWarn);
strLstAddZ(argList, "--set=20181119-152850F_20181119-152252D");
strLstAddZ(argList, "--dry-run");
harnessCfgLoad(cfgCmdExpire, argList);
// Load the backup info. Do not store a manifest file for the adhoc backup for code coverage
TEST_ASSIGN(infoBackup, infoBackupLoadFile(storageTest, backupInfoFileName, cipherTypeNone, NULL), "get backup.info");
// Create the manifest file to create the directory then remove the file for code coverage
storagePutP(
storageNewWriteP(storageTest, strNewFmt("%s/20181119-152850F_20181119-152252D/" BACKUP_MANIFEST_FILE,
strZ(backupStanzaPath))), BUFSTRDEF("tmp"));
storageRemoveP(
storageTest, strNewFmt("%s/20181119-152850F_20181119-152252D/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath)));
String *adhocBackupLabel = strNew("20181119-152850F_20181119-152252D");
TEST_RESULT_UINT(expireAdhocBackup(infoBackup, adhocBackupLabel), 1, "adhoc expire last dependent backup");
TEST_RESULT_VOID(removeExpiredBackup(infoBackup, adhocBackupLabel), "code coverage: removeExpireBackup with no manifests");
harnessLogResult(
"P00 WARN: [DRY-RUN] expiring latest backup 20181119-152850F_20181119-152252D - the ability to perform"
" point-in-time-recovery (PITR) may be affected\n"
" HINT: non-default settings for 'repo1-retention-archive'/'repo1-retention-archive-type'"
" (even in prior expires) can cause gaps in the WAL.\n"
"P00 INFO: [DRY-RUN] expire adhoc backup 20181119-152850F_20181119-152252D\n"
"P00 INFO: [DRY-RUN] remove expired backup 20181119-152850F_20181119-152252D");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("resumable possibly based on adhoc expire backup");
argList = strLstDup(argListAvoidWarn);
strLstAddZ(argList, "--set=20181119-152850F_20181119-152252D");
harnessCfgLoad(cfgCmdExpire, argList);
// Create backup.info
storagePutP(storageNewWriteP(storageTest, backupInfoFileName),
harnessInfoChecksumZ(
"[backup:current]\n"
"20181119-152850F={"
"\"backrest-format\":5,\"backrest-version\":\"2.08dev\","
"\"backup-archive-start\":\"000000010000000000000002\",\"backup-archive-stop\":\"000000010000000000000004\","
"\"backup-info-repo-size\":2369186,\"backup-info-repo-size-delta\":2369186,"
"\"backup-info-size\":20162900,\"backup-info-size-delta\":20162900,"
"\"backup-timestamp-start\":1542640898,\"backup-timestamp-stop\":1542640911,\"backup-type\":\"full\","
"\"db-id\":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"
"20181119-152850F_20181119-152252D={"
"\"backrest-format\":5,\"backrest-version\":\"2.08dev\",\"backup-archive-start\":\"000000010000000000000006\","
"\"backup-archive-stop\":\"000000010000000000000007\",\"backup-info-repo-size\":2369186,"
"\"backup-info-repo-size-delta\":346,\"backup-info-size\":20162900,\"backup-info-size-delta\":8428,"
"\"backup-prior\":\"20181119-152850F\",\"backup-reference\":[\"20181119-152850F\"],"
"\"backup-timestamp-start\":1542640912,\"backup-timestamp-stop\":1542640915,\"backup-type\":\"diff\","
"\"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=201909212\n"
"db-control-version=1201\n"
"db-id=2\n"
"db-system-id=6626363367545678089\n"
"db-version=\"12\"\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\":201909212,\"db-control-version\":1201,\"db-system-id\":6626363367545678089,"
"\"db-version\":\"12\"}\n"));
// Adhoc backup and resumable backup manifests
storagePutP(
storageNewWriteP(storageTest, strNewFmt("%s/20181119-152850F_20181119-152252D/" BACKUP_MANIFEST_FILE,
strZ(backupStanzaPath))), BUFSTRDEF("tmp"));
storagePutP(
storageNewWriteP(storageTest, strNewFmt("%s/20181119-152850F_20181200-152252D/" BACKUP_MANIFEST_FILE INFO_COPY_EXT,
strZ(backupStanzaPath))),
harnessInfoChecksumZ(
"[backup]\n"
"backup-archive-start=\"000000010000000000000009\"\n"
"backup-label=null\n"
"backup-prior=\"20181119-152850F\"\n"
"backup-timestamp-copy-start=0\n"
"backup-timestamp-start=0\n"
"backup-timestamp-stop=0\n"
"backup-type=\"incr\"\n"
"\n"
"[backup:db]\n"
"db-catalog-version=201909212\n"
"db-control-version=1201\n"
"db-id=2\n"
"db-system-id=6626363367545678089\n"
"db-version=\"12\"\n"
"\n"
"[backup:option]\n"
"option-archive-check=false\n"
"option-archive-copy=false\n"
"option-checksum-page=false\n"
"option-compress=false\n"
"option-compress-type=\"none\"\n"
"option-hardlink=false\n"
"option-online=false\n"
"\n"
"[backup:target]\n"
"pg_data={\"path\":\"{[path]}/pg\",\"type\":\"path\"}\n"
"\n"
"[db]\n"
"postgres={\"db-id\":12980,\"db-last-system-id\":12979}\n"
"\n"
"[target:file]\n"
"pg_data/PG_VERSION={\"size\":3,\"timestamp\":1565282100}\n"
"\n"
"[target:file:default]\n"
"group=\"postgres\"\n"
"master=false\n"
"mode=\"0600\"\n"
"user=\"postgres\"\n"
"\n"
"[target:path]\n"
"pg_data={}\n"
"\n"
"[target:path:default]\n"
"group=\"postgres\"\n"
"mode=\"0700\"\n"
"user=\"postgres\"\n"));
archiveGenerate(storageTest, archiveStanzaPath, 2, 10, "12-2", "0000000100000000");
TEST_RESULT_VOID(cmdExpire(), "adhoc expire latest with resumable possibly based on it");
harnessLogResult(
"P00 WARN: expiring latest backup 20181119-152850F_20181119-152252D - the ability to perform point-in-time-recovery"
" (PITR) may be affected\n"
" HINT: non-default settings for 'repo1-retention-archive'/'repo1-retention-archive-type'"
" (even in prior expires) can cause gaps in the WAL.\n"
"P00 INFO: expire adhoc backup 20181119-152850F_20181119-152252D\n"
"P00 INFO: remove expired backup 20181119-152850F_20181119-152252D\n"
"P00 DETAIL: archive retention on backup 20181119-152850F, archiveId = 12-2, start = 000000010000000000000002\n"
"P00 DETAIL: no archive to remove, archiveId = 12-2");
harnessLogLevelReset();
}
// *****************************************************************************************************************************
if (testBegin("expireTimeBasedBackup()"))
{
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("no current backups");
InfoBackup *infoBackup = NULL;
TEST_ASSIGN(infoBackup, infoBackupNewLoad(ioBufferReadNew(harnessInfoChecksumZ(
"[db]\n"
"db-catalog-version=201409291\n"
"db-control-version=942\n"
"db-id=1\n"
"db-system-id=6625592122879095702\n"
"db-version=\"9.4\"\n"
"\n"
"[db:history]\n"
"1={\"db-catalog-version\":201409291,\"db-control-version\":942,\"db-system-id\":6625592122879095702,"
"\"db-version\":\"9.4\"}"))), "empty backup.info");
TEST_RESULT_UINT(expireTimeBasedBackup(infoBackup, (time_t)(timeNow - (40 * SEC_PER_DAY))), 0, "no backups to expire");
//--------------------------------------------------------------------------------------------------------------------------
// Set up
StringList *argListTime = strLstDup(argListBase);
strLstAddZ(argListTime, "--repo1-retention-full-type=time");
// Create backup.info and archive.info
storagePutP(storageNewWriteP(storageTest, backupInfoFileName), backupInfoBase);
storagePutP(
storageNewWriteP(storageTest, archiveInfoFileName),
harnessInfoChecksumZ(
"[db]\n"
"db-id=1\n"
"db-system-id=6625592122879095702\n"
"db-version=\"9.4\"\n"
"\n"
"[db:history]\n"
"1={\"db-id\":6625592122879095702,\"db-version\":\"9.4\"}"));
// Write backup.manifest so infoBackup reconstruct produces same results as backup.info on disk
storagePutP(
storageNewWriteP(storageTest, strNewFmt("%s/20181119-152138F/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath))),
BUFSTRDEF("tmp"));
storagePutP(
storageNewWriteP(storageTest, strNewFmt("%s/20181119-152800F/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath))),
BUFSTRDEF("tmp"));
storagePutP(
storageNewWriteP(storageTest, strNewFmt("%s/20181119-152800F_20181119-152152D/" BACKUP_MANIFEST_FILE,
strZ(backupStanzaPath))), BUFSTRDEF("tmp"));
storagePutP(
storageNewWriteP(storageTest, strNewFmt("%s/20181119-152800F_20181119-152155I/" BACKUP_MANIFEST_FILE,
strZ(backupStanzaPath))), BUFSTRDEF("tmp"));
storagePutP(
storageNewWriteP(storageTest, strNewFmt("%s/20181119-152900F/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath))),
BUFSTRDEF("tmp"));
storagePutP(
storageNewWriteP(storageTest, strNewFmt("%s/20181119-152900F_20181119-152600D/" BACKUP_MANIFEST_FILE,
strZ(backupStanzaPath))), BUFSTRDEF("tmp"));
// Genreate archive for backups in backup.info
archiveGenerate(storageTest, archiveStanzaPath, 1, 11, "9.4-1", "0000000100000000");
// Set the log level to detail so archive expiration messages are seen
harnessLogLevelSet(logLevelDetail);
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("oldest backup not expired");
StringList *argList = strLstDup(argListTime);
harnessCfgLoad(cfgCmdExpire, argList);
TEST_ASSIGN(infoBackup, infoBackupNewLoad(ioBufferReadNew(backupInfoBase)), "get backup.info");
TEST_RESULT_VOID(cmdExpire(), "repo-retention-full not set for time-based");
harnessLogResult(
"P00 WARN: option 'repo1-retention-full' is not set for 'repo1-retention-full-type=time', the repository may run out"
" of space\n"
" HINT: to retain full backups indefinitely (without warning), set option 'repo1-retention-full' to the"
" maximum.\n"
"P00 INFO: time-based archive retention not met - archive logs will not be expired");
// Stop time equals retention time
TEST_RESULT_UINT(
expireTimeBasedBackup(infoBackup, (time_t)(timeNow - (40 * SEC_PER_DAY))), 0,
"oldest backup stop time equals retention time");
TEST_RESULT_STRLST_Z(
infoBackupDataLabelList(infoBackup, NULL),
"20181119-152138F\n20181119-152800F\n20181119-152800F_20181119-152152D\n20181119-152800F_20181119-152155I\n"
"20181119-152900F\n20181119-152900F_20181119-152600D\n", "no backups expired");
// Add a time period
strLstAddZ(argList, "--repo1-retention-full=35");
harnessCfgLoad(cfgCmdExpire, argList);
TEST_RESULT_VOID(cmdExpire(), "oldest backup older but other backups too young");
TEST_RESULT_STRLST_STR(
strLstSort(storageListP(
storageTest, strNewFmt("%s/%s/%s", strZ(archiveStanzaPath), "9.4-1", "0000000100000000")), sortOrderAsc),
archiveExpectList(1, 11, "0000000100000000"),
"no archives expired");
TEST_RESULT_STRLST_Z(
infoBackupDataLabelList(infoBackup, NULL),
"20181119-152138F\n20181119-152800F\n20181119-152800F_20181119-152152D\n20181119-152800F_20181119-152155I\n"
"20181119-152900F\n20181119-152900F_20181119-152600D\n", "no backups expired");
harnessLogResult("P00 INFO: time-based archive retention not met - archive logs will not be expired");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("oldest backup expired");
argList = strLstDup(argListTime);
strLstAddZ(argList, "--repo1-retention-full=30");
strLstAddZ(argList, "--dry-run");
harnessCfgLoad(cfgCmdExpire, argList);
TEST_RESULT_VOID(cmdExpire(), "only oldest backup expired - dry-run");
harnessLogResult(
"P00 INFO: [DRY-RUN] expire time-based backup 20181119-152138F\n"
"P00 INFO: [DRY-RUN] remove expired backup 20181119-152138F\n"
"P00 DETAIL: [DRY-RUN] archive retention on backup 20181119-152800F, archiveId = 9.4-1,"
" start = 000000010000000000000004\n"
"P00 DETAIL: [DRY-RUN] remove archive: archiveId = 9.4-1, start = 000000010000000000000001,"
" stop = 000000010000000000000003");
strLstAddZ(argList, "--repo1-retention-archive=9999999");
harnessCfgLoad(cfgCmdExpire, argList);
TEST_RESULT_VOID(cmdExpire(), "only oldest backup expired - dry-run, retention-archive set to max, no archives expired");
harnessLogResult(
"P00 INFO: [DRY-RUN] expire time-based backup 20181119-152138F\n"
"P00 INFO: [DRY-RUN] remove expired backup 20181119-152138F");
argList = strLstDup(argListTime);
strLstAddZ(argList, "--repo1-retention-full=30");
strLstAddZ(argList, "--repo1-retention-archive=1"); // 1-day: expire all non-essential archive prior to newest full backup
strLstAddZ(argList, "--dry-run");
harnessCfgLoad(cfgCmdExpire, argList);
TEST_RESULT_VOID(cmdExpire(), "only oldest backup expired but retention archive set lower - dry-run");
harnessLogResult(
"P00 INFO: [DRY-RUN] expire time-based backup 20181119-152138F\n"
"P00 INFO: [DRY-RUN] remove expired backup 20181119-152138F\n"
"P00 DETAIL: [DRY-RUN] archive retention on backup 20181119-152800F, archiveId = 9.4-1,"
" start = 000000010000000000000004, stop = 000000010000000000000004\n"
"P00 DETAIL: [DRY-RUN] archive retention on backup 20181119-152800F_20181119-152152D, archiveId = 9.4-1,"
" start = 000000010000000000000006, stop = 000000010000000000000006\n"
"P00 DETAIL: [DRY-RUN] archive retention on backup 20181119-152800F_20181119-152155I, archiveId = 9.4-1,"
" start = 000000010000000000000007, stop = 000000010000000000000007\n"
"P00 DETAIL: [DRY-RUN] archive retention on backup 20181119-152900F, archiveId = 9.4-1,"
" start = 000000010000000000000009\n"
"P00 DETAIL: [DRY-RUN] remove archive: archiveId = 9.4-1, start = 000000010000000000000001,"
" stop = 000000010000000000000003\n"
"P00 DETAIL: [DRY-RUN] remove archive: archiveId = 9.4-1, start = 000000010000000000000005,"
" stop = 000000010000000000000005\n"
"P00 DETAIL: [DRY-RUN] remove archive: archiveId = 9.4-1, start = 000000010000000000000008,"
" stop = 000000010000000000000008");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("repo1-retention-archive-type=diff");
argList = strLstDup(argListTime);
strLstAddZ(argList, "--repo1-retention-full=30");
strLstAddZ(argList, "--repo1-retention-archive-type=diff");
strLstAddZ(argList, "--repo1-retention-archive=1"); // 1-diff: expire all non-essential archive prior to newest diff backup
strLstAddZ(argList, "--dry-run");
harnessCfgLoad(cfgCmdExpire, argList);
TEST_RESULT_VOID(cmdExpire(), "only oldest backup expired, retention archive is DIFF - dry-run");
harnessLogResult(
"P00 WARN: [DRY-RUN] option 'repo1-retention-diff' is not set for 'repo1-retention-archive-type=diff'\n"
" HINT: to retain differential backups indefinitely (without warning), set option 'repo1-retention-diff'"
" to the maximum.\n"
"P00 INFO: [DRY-RUN] expire time-based backup 20181119-152138F\n"
"P00 INFO: [DRY-RUN] remove expired backup 20181119-152138F\n"
"P00 DETAIL: [DRY-RUN] archive retention on backup 20181119-152800F, archiveId = 9.4-1,"
" start = 000000010000000000000004, stop = 000000010000000000000004\n"
"P00 DETAIL: [DRY-RUN] archive retention on backup 20181119-152800F_20181119-152152D, archiveId = 9.4-1,"
" start = 000000010000000000000006, stop = 000000010000000000000006\n"
"P00 DETAIL: [DRY-RUN] archive retention on backup 20181119-152800F_20181119-152155I, archiveId = 9.4-1,"
" start = 000000010000000000000007, stop = 000000010000000000000007\n"
"P00 DETAIL: [DRY-RUN] archive retention on backup 20181119-152900F, archiveId = 9.4-1,"
" start = 000000010000000000000009, stop = 000000010000000000000009\n"
"P00 DETAIL: [DRY-RUN] archive retention on backup 20181119-152900F_20181119-152600D, archiveId = 9.4-1,"
" start = 000000010000000000000011\n"
"P00 DETAIL: [DRY-RUN] remove archive: archiveId = 9.4-1, start = 000000010000000000000001,"
" stop = 000000010000000000000003\n"
"P00 DETAIL: [DRY-RUN] remove archive: archiveId = 9.4-1, start = 000000010000000000000005,"
" stop = 000000010000000000000005\n"
"P00 DETAIL: [DRY-RUN] remove archive: archiveId = 9.4-1, start = 000000010000000000000008,"
" stop = 000000010000000000000008\n"
"P00 DETAIL: [DRY-RUN] remove archive: archiveId = 9.4-1, start = 000000010000000000000010,"
" stop = 000000010000000000000010");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("expire oldest full");
argList = strLstDup(argListTime);
strLstAddZ(argList, "--repo1-retention-full=25");
harnessCfgLoad(cfgCmdExpire, argList);
// Expire oldest from backup.info only, leaving the backup and archives on disk then save backup.info without oldest backup
TEST_RESULT_UINT(expireTimeBasedBackup(infoBackup, (time_t)(timeNow - (25 * SEC_PER_DAY))), 1, "expire oldest backup");
TEST_RESULT_VOID(
infoBackupSaveFile(infoBackup, storageTest, backupInfoFileName, cipherTypeNone, NULL),
"save backup.info without oldest");
harnessLogResult("P00 INFO: expire time-based backup 20181119-152138F");
TEST_RESULT_VOID(cmdExpire(), "only oldest backup expired");
harnessLogResult(
"P00 INFO: remove expired backup 20181119-152138F\n"
"P00 DETAIL: archive retention on backup 20181119-152800F, archiveId = 9.4-1, start = 000000010000000000000004\n"
"P00 DETAIL: remove archive: archiveId = 9.4-1, start = 000000010000000000000001, stop = 000000010000000000000003");
//--------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("newest backup - retention met but must keep one");
argList = strLstDup(argListTime);
strLstAddZ(argList, "--repo1-retention-full=1");
harnessCfgLoad(cfgCmdExpire, argList);
TEST_RESULT_VOID(cmdExpire(), "expire all but newest");
harnessLogResult(
"P00 INFO: expire time-based backup set: 20181119-152800F, 20181119-152800F_20181119-152152D,"
" 20181119-152800F_20181119-152155I\n"
"P00 INFO: remove expired backup 20181119-152800F_20181119-152155I\n"
"P00 INFO: remove expired backup 20181119-152800F_20181119-152152D\n"
"P00 INFO: remove expired backup 20181119-152800F\n"
"P00 DETAIL: archive retention on backup 20181119-152900F, archiveId = 9.4-1, start = 000000010000000000000009\n"
"P00 DETAIL: remove archive: archiveId = 9.4-1, start = 000000010000000000000004, stop = 000000010000000000000008");
harnessLogLevelReset();
}
FUNCTION_HARNESS_RESULT_VOID();
}