From 20cf74343889d96beae9f280913fb4d540d5f99c Mon Sep 17 00:00:00 2001 From: Denis Garsh Date: Mon, 17 Aug 2026 16:04:21 +0300 Subject: [PATCH 1/4] Fix backup.manifest.copy for custom files --- src/command/repo/push.c | 16 ++++-- test/src/module/command/repoTest.c | 85 +++++++++++++++++++++++------- 2 files changed, 78 insertions(+), 23 deletions(-) diff --git a/src/command/repo/push.c b/src/command/repo/push.c index 720b8e6871..da1ae61be6 100644 --- a/src/command/repo/push.c +++ b/src/command/repo/push.c @@ -76,9 +76,10 @@ storagePushProcess(const String *file, CompressType compressType, int compressLe IoFilterGroup *const writeFilterGroup = ioWriteFilterGroup(destinationIo); const String *manifestFileName = strNewFmt(STORAGE_REPO_BACKUP "/%s/" BACKUP_MANIFEST_FILE, strZ(backupLabel)); - Manifest *manifest = manifestLoadFile( - storage, manifestFileName, - cipherTypeNone, NULL); + const String *manifestFileNameCopy = strNewFmt("%s" INFO_COPY_EXT, strZ(manifestFileName)); + + // Load main manifest only. Don't fallback to copy. So resumable backup cannot be made to appear complete. + Manifest *manifest = manifestNewLoad(storageReadIo(storageNewReadP(storage, manifestFileName))); // Add SHA1 filter ioFilterGroupAdd(writeFilterGroup, cryptoHashNew(hashTypeSha1)); @@ -151,6 +152,7 @@ storagePushProcess(const String *file, CompressType compressType, int compressLe manifestFile.sizeRepo = customFile.sizeRepo; manifestFile.timestamp = customFile.timestamp; manifestFile.checksumSha1 = customFile.checksumSha1; + manifestFile.checksumRepoSha1 = customFile.checksumRepoSha1; manifestCustomFileUpdate(manifest, &manifestFile); found = true; @@ -161,14 +163,18 @@ storagePushProcess(const String *file, CompressType compressType, int compressLe if (!found) manifestCustomFileAdd(manifest, &customFile); - // Save manifest + // Save copy first and then copy it to the main manifest, matching backup completion semantics. IoWrite *const manifestWrite = storageWriteIo( storageNewWriteP( storageRepoWrite(), - manifestFileName + manifestFileNameCopy )); manifestSave(manifest, manifestWrite); + + storageCopy( + storageNewReadP(storage, manifestFileNameCopy), + storageNewWriteP(storageRepoWrite(), manifestFileName)); } MEM_CONTEXT_TEMP_END(); diff --git a/test/src/module/command/repoTest.c b/test/src/module/command/repoTest.c index 97ef3666b6..06c4df4ce5 100644 --- a/test/src/module/command/repoTest.c +++ b/test/src/module/command/repoTest.c @@ -132,6 +132,23 @@ testManifestCustomFilesValidate(Manifest *manifest) FUNCTION_HARNESS_RETURN(STRING, result); } +static bool +testBackupManifestCopyValidate(const Storage *const storage, const String *const backupLabel) +{ + FUNCTION_HARNESS_BEGIN(); + FUNCTION_HARNESS_PARAM(STORAGE, storage); + FUNCTION_HARNESS_PARAM(STRING, backupLabel); + FUNCTION_HARNESS_END(); + + const String *const manifestFile = strNewFmt(STORAGE_REPO_BACKUP "/%s/" BACKUP_MANIFEST_FILE, strZ(backupLabel)); + + const bool result = bufEq( + storageGetP(storageNewReadP(storage, manifestFile)), + storageGetP(storageNewReadP(storage, strNewFmt("%s" INFO_COPY_EXT, strZ(manifestFile))))); + + FUNCTION_HARNESS_RETURN(BOOL, result); +} + /*********************************************************************************************************************************** Test Run ***********************************************************************************************************************************/ @@ -1518,7 +1535,11 @@ testRun(void) TEST_RESULT_VOID(cmdStoragePush(), "push file"); TEST_RESULT_LOG("P00 INFO: push file path/aaa.txt to the archive."); - TEST_STORAGE_LIST(storageRepo(), STORAGE_PATH_BACKUP "/" TEST_STANZA "/" TEST_BACKUP_LABEL_FULL, "aaa.txt\nbackup.manifest\n", .comment = "check path exists and file added"); + TEST_STORAGE_LIST( + storageRepo(), STORAGE_PATH_BACKUP "/" TEST_STANZA "/" TEST_BACKUP_LABEL_FULL, + "aaa.txt\nbackup.manifest\nbackup.manifest.copy\n", .comment = "check path exists and file added"); + TEST_RESULT_BOOL( + testBackupManifestCopyValidate(storageRepo(), STRDEF(TEST_BACKUP_LABEL_FULL)), true, "check manifest copy"); TEST_STORAGE_GET(storageRepo(), STORAGE_PATH_BACKUP "/" TEST_STANZA "/" TEST_BACKUP_LABEL_FULL "/aaa.txt", "TESTDATA"); @@ -1538,7 +1559,11 @@ testRun(void) TEST_RESULT_VOID(cmdStoragePush(), "push file"); TEST_RESULT_LOG("P00 INFO: push file path/aaa.txt to the archive."); - TEST_STORAGE_LIST(storageRepo(), STORAGE_PATH_BACKUP "/" TEST_STANZA "/" TEST_BACKUP_LABEL_FULL, "aaa.txt\nbackup.manifest\n", .comment = "check path exists and file added"); + TEST_STORAGE_LIST( + storageRepo(), STORAGE_PATH_BACKUP "/" TEST_STANZA "/" TEST_BACKUP_LABEL_FULL, + "aaa.txt\nbackup.manifest\nbackup.manifest.copy\n", .comment = "check path exists and file added"); + TEST_RESULT_BOOL( + testBackupManifestCopyValidate(storageRepo(), STRDEF(TEST_BACKUP_LABEL_FULL)), true, "check manifest copy"); TEST_STORAGE_GET(storageRepo(), STORAGE_PATH_BACKUP "/" TEST_STANZA "/" TEST_BACKUP_LABEL_FULL "/aaa.txt", TEST_DATA); @@ -1562,15 +1587,37 @@ testRun(void) hrnCfgArgRawZ(argList, cfgOptCompressLevel, "3"); strLstAddZ(argList, "path/aaa.txt"); + HRN_CFG_LOAD(cfgCmdRepoPush, argList); + + TEST_RESULT_VOID(cmdStoragePush(), "push file"); + TEST_RESULT_LOG("P00 INFO: push file path/aaa.txt to the archive."); + TEST_STORAGE_LIST( + storageRepo(), STORAGE_PATH_BACKUP "/" TEST_STANZA "/" TEST_BACKUP_LABEL_FULL, + "aaa.txt\naaa.txt.gz\nbackup.manifest\nbackup.manifest.copy\n", .comment = "check path exists and file added"); + TEST_RESULT_BOOL( + testBackupManifestCopyValidate(storageRepo(), STRDEF(TEST_BACKUP_LABEL_FULL)), true, "check manifest copy"); + + TEST_STORAGE_GET(storageRepo(), STORAGE_PATH_BACKUP "/" TEST_STANZA "/" TEST_BACKUP_LABEL_FULL "/aaa.txt", TEST_DATA, .compressType = compressTypeGz); + + manifest = manifestLoadFile( + storageRepo(), STR(STORAGE_REPO_BACKUP "/" TEST_BACKUP_LABEL_FULL "/" BACKUP_MANIFEST_FILE), cipherTypeNone, NULL); + + /* Check manifest record */ + TEST_RESULT_STR_Z( + testManifestCustomFilesValidate(manifest), + "aaa.txt 445\naaa.txt.gz 445\n", + "compare file list"); + + TEST_TITLE("do not push to resumable backup manifest copy"); HRN_INFO_PUT( - storageRepoWrite(), STORAGE_REPO_BACKUP "/" TEST_STANZA "/" TEST_BACKUP_LABEL_FULL "/" BACKUP_MANIFEST_FILE, + storageRepoWrite(), STORAGE_REPO_BACKUP "/20260201-173011F/" BACKUP_MANIFEST_FILE INFO_COPY_EXT, TEST_MANIFEST_HEADER "\n" "[backup:db]\n" "db-catalog-version=201608131\n" "db-control-version=960\n" "db-id=1\n" - "db-system-id=" HRN_PG_SYSTEMID_94_Z "\n" // 9.4 system id is used so version will trigger error + "db-system-id=" HRN_PG_SYSTEMID_94_Z "\n" "db-version=\"9.6\"\n" TEST_MANIFEST_OPTION_ALL TEST_MANIFEST_TARGET @@ -1581,24 +1628,26 @@ testRun(void) TEST_MANIFEST_LINK_DEFAULT TEST_MANIFEST_PATH TEST_MANIFEST_PATH_DEFAULT, - .comment = "manifest db section mismatch"); + .comment = "manifest copy only"); + + argList = strLstNew(); + hrnCfgArgKeyRawZ(argList, cfgOptRepoPath, 1, TEST_PATH "/bogus"); + hrnCfgArgKeyRawZ(argList, cfgOptRepoPath, 2, TEST_PATH "/repo"); + hrnCfgArgRawZ(argList, cfgOptCompressType, "none"); + hrnCfgArgRawZ(argList, cfgOptStanza, TEST_STANZA); + hrnCfgArgRawZ(argList, cfgOptSet, "20260201-173011F"); + hrnCfgArgRawZ(argList, cfgOptRepo, "2"); + strLstAddZ(argList, "path/aaa.txt"); HRN_CFG_LOAD(cfgCmdRepoPush, argList); - TEST_RESULT_VOID(cmdStoragePush(), "push file"); + TEST_ERROR( + cmdStoragePush(), FileMissingError, + "unable to open missing file '" TEST_PATH "/repo/backup/" TEST_STANZA "/20260201-173011F/backup.manifest' for read"); TEST_RESULT_LOG("P00 INFO: push file path/aaa.txt to the archive."); - TEST_STORAGE_LIST(storageRepo(), STORAGE_PATH_BACKUP "/" TEST_STANZA "/" TEST_BACKUP_LABEL_FULL, "aaa.txt\naaa.txt.gz\nbackup.manifest\n", .comment = "check path exists and file added"); - - TEST_STORAGE_GET(storageRepo(), STORAGE_PATH_BACKUP "/" TEST_STANZA "/" TEST_BACKUP_LABEL_FULL "/aaa.txt", TEST_DATA, .compressType = compressTypeGz); - - manifest = manifestLoadFile( - storageRepo(), STR(STORAGE_REPO_BACKUP "/" TEST_BACKUP_LABEL_FULL "/" BACKUP_MANIFEST_FILE), cipherTypeNone, NULL); - - /* Check manifest record */ - TEST_RESULT_STR_Z( - testManifestCustomFilesValidate(manifest), - "aaa.txt 445\naaa.txt.gz 445\n", - "compare file list"); + TEST_STORAGE_LIST( + storageRepo(), STORAGE_PATH_BACKUP "/" TEST_STANZA "/20260201-173011F", + "backup.manifest.copy\n", .comment = "main manifest was not created"); TEST_TITLE("push encrypted file not supported"); argList = strLstNew(); From 07986f826b9689a6b713d536547d8bcdbe6a79d6 Mon Sep 17 00:00:00 2001 From: Denis Garsh Date: Mon, 17 Aug 2026 16:25:54 +0300 Subject: [PATCH 2/4] refactor test --- test/src/module/command/repoTest.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/test/src/module/command/repoTest.c b/test/src/module/command/repoTest.c index 06c4df4ce5..d7080344af 100644 --- a/test/src/module/command/repoTest.c +++ b/test/src/module/command/repoTest.c @@ -18,6 +18,7 @@ Test Repo Commands #include "info/infoBackup.h" #define TEST_BACKUP_LABEL_FULL "20260201-173010F" +#define TEST_BACKUP_LABEL_RESUME "20260201-173011F" #define TEST_STANZA "testStanza01" #define TEST_DATA \ @@ -1610,7 +1611,7 @@ testRun(void) TEST_TITLE("do not push to resumable backup manifest copy"); HRN_INFO_PUT( - storageRepoWrite(), STORAGE_REPO_BACKUP "/20260201-173011F/" BACKUP_MANIFEST_FILE INFO_COPY_EXT, + storageRepoWrite(), STORAGE_REPO_BACKUP "/" TEST_BACKUP_LABEL_RESUME "/" BACKUP_MANIFEST_FILE INFO_COPY_EXT, TEST_MANIFEST_HEADER "\n" "[backup:db]\n" @@ -1635,7 +1636,7 @@ testRun(void) hrnCfgArgKeyRawZ(argList, cfgOptRepoPath, 2, TEST_PATH "/repo"); hrnCfgArgRawZ(argList, cfgOptCompressType, "none"); hrnCfgArgRawZ(argList, cfgOptStanza, TEST_STANZA); - hrnCfgArgRawZ(argList, cfgOptSet, "20260201-173011F"); + hrnCfgArgRawZ(argList, cfgOptSet, TEST_BACKUP_LABEL_RESUME); hrnCfgArgRawZ(argList, cfgOptRepo, "2"); strLstAddZ(argList, "path/aaa.txt"); @@ -1643,10 +1644,11 @@ testRun(void) TEST_ERROR( cmdStoragePush(), FileMissingError, - "unable to open missing file '" TEST_PATH "/repo/backup/" TEST_STANZA "/20260201-173011F/backup.manifest' for read"); + "unable to open missing file '" TEST_PATH "/repo/backup/" TEST_STANZA "/" TEST_BACKUP_LABEL_RESUME + "/backup.manifest' for read"); TEST_RESULT_LOG("P00 INFO: push file path/aaa.txt to the archive."); TEST_STORAGE_LIST( - storageRepo(), STORAGE_PATH_BACKUP "/" TEST_STANZA "/20260201-173011F", + storageRepo(), STORAGE_PATH_BACKUP "/" TEST_STANZA "/" TEST_BACKUP_LABEL_RESUME, "backup.manifest.copy\n", .comment = "main manifest was not created"); TEST_TITLE("push encrypted file not supported"); From 8e58402812e2049bc4cddc1aa8ec14bc67e3bf66 Mon Sep 17 00:00:00 2001 From: Denis Garsh Date: Tue, 18 Aug 2026 08:15:03 +0300 Subject: [PATCH 3/4] Test CI fix --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4100918e79..f147623862 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -35,7 +35,7 @@ jobs: - param: doc --vm=u22 # All integration tests - - param: test --vm=u22 --param=build-package --param=module=integration + - param: test --vm=u22 --param=module=integration # All unit tests with coverage, backtrace and alternate timezone - param: test --vm=u22 --param=c-only --param=no-valgrind --param=tz=America/New_York From 4d7e73e9278e2d3f1cf8adfce8ed69a5fe35be0b Mon Sep 17 00:00:00 2001 From: Denis Garsh Date: Tue, 18 Aug 2026 08:41:49 +0300 Subject: [PATCH 4/4] Revert "Test CI fix" This reverts commit 8e58402812e2049bc4cddc1aa8ec14bc67e3bf66. --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f147623862..4100918e79 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -35,7 +35,7 @@ jobs: - param: doc --vm=u22 # All integration tests - - param: test --vm=u22 --param=module=integration + - param: test --vm=u22 --param=build-package --param=module=integration # All unit tests with coverage, backtrace and alternate timezone - param: test --vm=u22 --param=c-only --param=no-valgrind --param=tz=America/New_York