From e5f516aa6d90c3b7fd2930e8bff49b8f98553d98 Mon Sep 17 00:00:00 2001 From: Denis Kovalev Date: Fri, 11 Jul 2025 18:45:07 +0300 Subject: [PATCH 01/12] Reimplement JSON output in verify command --- src/build/config/config.yaml | 1 + src/build/help/help.xml | 1 + src/command/verify/verify.c | 374 +++++++++--- src/config/parse.auto.c.inc | 1 + test/define.yaml | 2 +- test/src/module/command/verifyTest.c | 817 ++++++++++++++++++++++++++- 6 files changed, 1104 insertions(+), 92 deletions(-) diff --git a/src/build/config/config.yaml b/src/build/config/config.yaml index 5161ed81c1..a6e54b2b1a 100644 --- a/src/build/config/config.yaml +++ b/src/build/config/config.yaml @@ -351,6 +351,7 @@ option: allow-list: - none - text + - json version: default: text allow-list: diff --git a/src/build/help/help.xml b/src/build/help/help.xml index 1e25b65f5f..905f31da19 100644 --- a/src/build/help/help.xml +++ b/src/build/help/help.xml @@ -2734,6 +2734,7 @@ none - No verify output. text - Output verify information to stdout. + json - Output verify information to stdout in json format. diff --git a/src/command/verify/verify.c b/src/command/verify/verify.c index 6f5ebd8e0e..177f64de35 100644 --- a/src/command/verify/verify.c +++ b/src/command/verify/verify.c @@ -30,6 +30,7 @@ Verify contents of the repository. #include "protocol/helper.h" #include "protocol/parallel.h" #include "storage/helper.h" +#include "common/type/json.h" /*********************************************************************************************************************************** Constants @@ -37,6 +38,27 @@ Constants #define VERIFY_STATUS_OK "ok" #define VERIFY_STATUS_ERROR "error" +// Naming convention: _KEY__VAR. If the key exists in multiple sections, then _ is omitted. +VARIANT_STRDEF_STATIC(KEY_ARCHIVES_VAR, "archives"); +VARIANT_STRDEF_STATIC(ARCHIVE_KEY_ARCHIVEID_VAR, "archiveId"); +VARIANT_STRDEF_STATIC(ARCHIVE_KEY_CHECKED_VAR, "checked"); +VARIANT_STRDEF_STATIC(KEY_VALID_VAR, "valid"); +VARIANT_STRDEF_STATIC(KEY_MISSING_VAR, "missing"); +VARIANT_STRDEF_STATIC(KEY_CHECKSUMINVALID_VAR, "checksumInvalid"); +VARIANT_STRDEF_STATIC(KEY_SIZEINVALID_VAR, "sizeInvalid"); +VARIANT_STRDEF_STATIC(KEY_OTHER_VAR, "other"); +VARIANT_STRDEF_STATIC(KEY_BACKUPS_VAR, "backups"); +VARIANT_STRDEF_STATIC(BACKUP_KEY_LABEL_VAR, "label"); +VARIANT_STRDEF_STATIC(KEY_STATUS_VAR, "status"); +VARIANT_STRDEF_STATIC(BACKUP_KEY_CHECKED_VAR, "checked"); +VARIANT_STRDEF_STATIC(KEY_ERRORS_VAR, "errors"); +VARIANT_STRDEF_STATIC(VERIFY_KEY_STANZA_VAR, "stanza"); +VARIANT_STRDEF_STATIC(VERIFY_KEY_STATUS_ERROR, "error"); +VARIANT_STRDEF_STATIC(VERIFY_KEY_STATUS_OK, "ok"); +VARIANT_STRDEF_STATIC(VERIFY_MSG_KEY_LEVEL, "level"); +VARIANT_STRDEF_STATIC(VERIFY_MSG_KEY_MESSAGE, "message"); +VARIANT_STRDEF_STATIC(VERIFY_MSG_KEY_PID, "pid"); + /*********************************************************************************************************************************** Data Types and Structures ***********************************************************************************************************************************/ @@ -132,8 +154,80 @@ typedef struct VerifyJobData bool enableArchiveFilter; // Only check archives in the specified range const String *archiveStart; // Start of the WAL range to be verified const String *archiveStop; // End of the WAL range to be verified + VariantList *errorList; // List of errors that occurred during the job } VerifyJobData; +/*********************************************************************************************************************************** +Helper function to add a string with log level to an error list +***********************************************************************************************************************************/ + +static void +verifyErrorNew(VariantList *errorList, const LogLevel logLevel, const String *const message) +{ + FUNCTION_TEST_BEGIN(); + FUNCTION_TEST_PARAM(VARIANT_LIST, errorList); + FUNCTION_LOG_PARAM(ENUM, logLevel); // Log level + FUNCTION_TEST_PARAM(STRING, message); // Error message + FUNCTION_TEST_END(); + + FUNCTION_AUDIT_HELPER(); + + ASSERT(message != NULL); + + MEM_CONTEXT_BEGIN(lstMemContext((List *)errorList)) + { + KeyValue *const errorMsg = kvNew(); + + kvPut(errorMsg, VERIFY_MSG_KEY_LEVEL, VARUINT(logLevel)); + kvPut(errorMsg, VERIFY_MSG_KEY_MESSAGE, VARSTR(strDup(message))); + + varLstAdd(errorList, varNewKv(errorMsg)); + } + + if (logLevel != logLevelOff) + { + LOG(logLevel, 0, strZ(message)); + } + + MEM_CONTEXT_END(); + + FUNCTION_TEST_RETURN_VOID(); +} + +/********************************************************************************************************************************** +Helper function to add a string with log level and process id to an error list +***********************************************************************************************************************************/ + +static void +verifyErrorPidNew(VariantList *errorList, const LogLevel logLevel, const unsigned int pid, const String *const message) +{ + FUNCTION_TEST_BEGIN(); + FUNCTION_TEST_PARAM(VARIANT_LIST, errorList); + FUNCTION_LOG_PARAM(ENUM, logLevel); // Log level + FUNCTION_TEST_PARAM(UINT, pid); // Process id + FUNCTION_TEST_PARAM(STRING, message); // Error message + FUNCTION_TEST_END(); + + FUNCTION_AUDIT_HELPER(); + + ASSERT(message != NULL); + + MEM_CONTEXT_BEGIN(lstMemContext((List *)errorList)) + { + KeyValue *const errorMsg = kvNew(); + + kvPut(errorMsg, VERIFY_MSG_KEY_LEVEL, VARUINT(logLevel)); + kvPut(errorMsg, VERIFY_MSG_KEY_MESSAGE, VARSTR(strDup(message))); + kvPut(errorMsg, VERIFY_MSG_KEY_PID, VARUINT(pid)); + + varLstAdd(errorList, varNewKv(errorMsg)); + } + LOG_PID(logLevel, pid, 0, strZ(message)); + MEM_CONTEXT_END(); + + FUNCTION_TEST_RETURN_VOID(); +} + /*********************************************************************************************************************************** Helper function to add a file to an invalid file list ***********************************************************************************************************************************/ @@ -198,12 +292,13 @@ verifyFileLoad(const String *const pathFileName, const String *const cipherPass) Get status of info files in the repository ***********************************************************************************************************************************/ static VerifyInfoFile -verifyInfoFile(const String *const pathFileName, const bool keepFile, const String *const cipherPass) +verifyInfoFile(const String *const pathFileName, const bool keepFile, const String *const cipherPass, VariantList *const errorList) { FUNCTION_LOG_BEGIN(logLevelDebug); FUNCTION_LOG_PARAM(STRING, pathFileName); // Fully qualified path/file name FUNCTION_LOG_PARAM(BOOL, keepFile); // Should the file be kept in memory? FUNCTION_TEST_PARAM(STRING, cipherPass); // Password to open file if encrypted + FUNCTION_TEST_PARAM(LIST, errorList); // List of errors FUNCTION_LOG_END(); FUNCTION_AUDIT_STRUCT(); @@ -248,7 +343,7 @@ verifyInfoFile(const String *const pathFileName, const bool keepFile, const Stri if (result.errorCode == errorTypeCode(&ChecksumError)) strCat(errorMsg, strNewFmt(" %s", strZ(pathFileName))); - LOG_DETAIL(strZ(errorMsg)); + verifyErrorNew(errorList, logLevelDetail, errorMsg); } TRY_END(); } @@ -261,9 +356,11 @@ verifyInfoFile(const String *const pathFileName, const bool keepFile, const Stri Get the archive.info file ***********************************************************************************************************************************/ static InfoArchive * -verifyArchiveInfoFile(void) +verifyArchiveInfoFile(VariantList *const errorList) { - FUNCTION_LOG_VOID(logLevelDebug); + FUNCTION_LOG_BEGIN(logLevelDebug); + FUNCTION_TEST_PARAM(LIST, errorList); // List of errors + FUNCTION_LOG_END(); InfoArchive *result = NULL; @@ -271,7 +368,8 @@ verifyArchiveInfoFile(void) { // Get the main info file const VerifyInfoFile verifyArchiveInfo = verifyInfoFile( - INFO_ARCHIVE_PATH_FILE_STR, true, cfgOptionStrNull(cfgOptRepoCipherPass)); + INFO_ARCHIVE_PATH_FILE_STR, true, cfgOptionStrNull(cfgOptRepoCipherPass), + errorList); // If the main file did not error, then report on the copy's status and check checksums if (verifyArchiveInfo.errorCode == 0) @@ -281,7 +379,7 @@ verifyArchiveInfoFile(void) // Attempt to load the copy and report on it's status but don't keep it in memory const VerifyInfoFile verifyArchiveInfoCopy = verifyInfoFile( - INFO_ARCHIVE_PATH_FILE_COPY_STR, false, cfgOptionStrNull(cfgOptRepoCipherPass)); + INFO_ARCHIVE_PATH_FILE_COPY_STR, false, cfgOptionStrNull(cfgOptRepoCipherPass), errorList); // If the copy loaded successfully, then check the checksums if (verifyArchiveInfoCopy.errorCode == 0) @@ -289,14 +387,16 @@ verifyArchiveInfoFile(void) // If the info and info.copy checksums don't match each other than one (or both) of the files could be corrupt so // log a warning but must trust main if (!strEq(verifyArchiveInfo.checksum, verifyArchiveInfoCopy.checksum)) - LOG_DETAIL("archive.info.copy does not match archive.info"); + { + verifyErrorNew(errorList, logLevelDetail, strNewZ("archive.info.copy does not match archive.info")); + } } } else { // Attempt to load the copy const VerifyInfoFile verifyArchiveInfoCopy = verifyInfoFile( - INFO_ARCHIVE_PATH_FILE_COPY_STR, true, cfgOptionStrNull(cfgOptRepoCipherPass)); + INFO_ARCHIVE_PATH_FILE_COPY_STR, true, cfgOptionStrNull(cfgOptRepoCipherPass), errorList); // If loaded successfully, then return the copy as usable if (verifyArchiveInfoCopy.errorCode == 0) @@ -315,9 +415,11 @@ verifyArchiveInfoFile(void) Get the backup.info file ***********************************************************************************************************************************/ static InfoBackup * -verifyBackupInfoFile(void) +verifyBackupInfoFile(VariantList *const errorList) { - FUNCTION_LOG_VOID(logLevelDebug); + FUNCTION_LOG_BEGIN(logLevelDebug); + FUNCTION_TEST_PARAM(LIST, errorList); // List of errors + FUNCTION_LOG_END(); InfoBackup *result = NULL; @@ -325,7 +427,7 @@ verifyBackupInfoFile(void) { // Get the main info file const VerifyInfoFile verifyBackupInfo = verifyInfoFile( - INFO_BACKUP_PATH_FILE_STR, true, cfgOptionStrNull(cfgOptRepoCipherPass)); + INFO_BACKUP_PATH_FILE_STR, true, cfgOptionStrNull(cfgOptRepoCipherPass), errorList); // If the main file did not error, then report on the copy's status and check checksums if (verifyBackupInfo.errorCode == 0) @@ -335,7 +437,7 @@ verifyBackupInfoFile(void) // Attempt to load the copy and report on it's status but don't keep it in memory const VerifyInfoFile verifyBackupInfoCopy = verifyInfoFile( - INFO_BACKUP_PATH_FILE_COPY_STR, false, cfgOptionStrNull(cfgOptRepoCipherPass)); + INFO_BACKUP_PATH_FILE_COPY_STR, false, cfgOptionStrNull(cfgOptRepoCipherPass), errorList); // If the copy loaded successfully, then check the checksums if (verifyBackupInfoCopy.errorCode == 0) @@ -343,14 +445,16 @@ verifyBackupInfoFile(void) // If the info and info.copy checksums don't match each other than one (or both) of the files could be corrupt so // log a warning but must trust main if (!strEq(verifyBackupInfo.checksum, verifyBackupInfoCopy.checksum)) - LOG_DETAIL("backup.info.copy does not match backup.info"); + { + verifyErrorNew(errorList, logLevelDetail, strNewZ("backup.info.copy does not match backup.info")); + } } } else { // Attempt to load the copy const VerifyInfoFile verifyBackupInfoCopy = verifyInfoFile( - INFO_BACKUP_PATH_FILE_COPY_STR, true, cfgOptionStrNull(cfgOptRepoCipherPass)); + INFO_BACKUP_PATH_FILE_COPY_STR, true, cfgOptionStrNull(cfgOptRepoCipherPass), errorList); // If loaded successfully, then return the copy as usable if (verifyBackupInfoCopy.errorCode == 0) @@ -371,7 +475,7 @@ Get the manifest file static Manifest * verifyManifestFile( VerifyBackupResult *const backupResult, const String *const cipherPass, bool currentBackup, const InfoPg *const pgHistory, - unsigned int *const jobErrorTotal) + unsigned int *const jobErrorTotal, VariantList *const errorList) { FUNCTION_LOG_BEGIN(logLevelDebug); FUNCTION_LOG_PARAM_P(VERIFY_BACKUP_RESULT, backupResult); // The result set for the backup being processed @@ -379,6 +483,7 @@ verifyManifestFile( FUNCTION_LOG_PARAM(BOOL, currentBackup); // Is this possibly a backup currently in progress? FUNCTION_LOG_PARAM(INFO_PG, pgHistory); // Database history FUNCTION_LOG_PARAM_P(UINT, jobErrorTotal); // Pointer to the overall job error total + FUNCTION_TEST_PARAM(LIST, errorList); // List of errors FUNCTION_LOG_END(); Manifest *result = NULL; @@ -388,7 +493,7 @@ verifyManifestFile( const String *const fileName = strNewFmt(STORAGE_REPO_BACKUP "/%s/" BACKUP_MANIFEST_FILE, strZ(backupResult->backupLabel)); // Get the main manifest file - const VerifyInfoFile verifyManifestInfo = verifyInfoFile(fileName, true, cipherPass); + const VerifyInfoFile verifyManifestInfo = verifyInfoFile(fileName, true, cipherPass, errorList); // If the main file did not error, then report on the copy's status and check checksums if (verifyManifestInfo.errorCode == 0) @@ -402,7 +507,7 @@ verifyManifestFile( // Attempt to load the copy and report on it's status but don't keep it in memory const VerifyInfoFile verifyManifestInfoCopy = verifyInfoFile( - strNewFmt("%s%s", strZ(fileName), INFO_COPY_EXT), false, cipherPass); + strNewFmt("%s%s", strZ(fileName), INFO_COPY_EXT), false, cipherPass, errorList); // If the copy loaded successfully, then check the checksums if (verifyManifestInfoCopy.errorCode == 0) @@ -410,7 +515,10 @@ verifyManifestFile( // If the manifest and manifest.copy checksums don't match each other than one (or both) of the files could be // corrupt so log a warning but trust main if (!strEq(verifyManifestInfo.checksum, verifyManifestInfoCopy.checksum)) - LOG_DETAIL_FMT("backup '%s' manifest.copy does not match manifest", strZ(backupResult->backupLabel)); + { + String *errorMsg = strNewFmt("backup '%s' manifest.copy does not match manifest", strZ(backupResult->backupLabel)); + verifyErrorNew(errorList, logLevelDetail, errorMsg); + } } } else @@ -423,12 +531,13 @@ verifyManifestFile( currentBackup = false; const VerifyInfoFile verifyManifestInfoCopy = verifyInfoFile( - strNewFmt("%s%s", strZ(fileName), INFO_COPY_EXT), true, cipherPass); + strNewFmt("%s%s", strZ(fileName), INFO_COPY_EXT), true, cipherPass, errorList); // If loaded successfully, then return the copy as usable if (verifyManifestInfoCopy.errorCode == 0) { - LOG_DETAIL_FMT("%s/backup.manifest is missing or unusable, using copy", strZ(backupResult->backupLabel)); + String *errorMsg = strNewFmt("%s/backup.manifest is missing or unusable, using copy", strZ(backupResult->backupLabel)); + verifyErrorNew(errorList, logLevelDetail, errorMsg); result = verifyManifestInfoCopy.manifest; } @@ -437,14 +546,16 @@ verifyManifestFile( { backupResult->status = backupMissingManifest; - LOG_DETAIL_FMT("manifest missing for '%s' - backup may have expired", strZ(backupResult->backupLabel)); + String *errorMsg = strNewFmt("manifest missing for '%s' - backup may have expired", strZ(backupResult->backupLabel)); + verifyErrorNew(errorList, logLevelDetail, errorMsg); } } else { backupResult->status = backupInProgress; - LOG_INFO_FMT("backup '%s' appears to be in progress, skipping", strZ(backupResult->backupLabel)); + String *errorMsg = strNewFmt("backup '%s' appears to be in progress, skipping", strZ(backupResult->backupLabel)); + verifyErrorNew(errorList, logLevelInfo, errorMsg); } } @@ -470,11 +581,13 @@ verifyManifestFile( // If the PG data is not found in the backup.info history, then error and reset the result if (!found) { - LOG_INFO_FMT( + String *errorMsg = strNewFmt( "'%s' may not be recoverable - PG data (id %u, version %s, system-id %" PRIu64 ") is not in the backup.info" " history, skipping", strZ(backupResult->backupLabel), manData->pgId, strZ(pgVersionToStr(manData->pgVersion)), manData->pgSystemId); + verifyErrorNew(errorList, logLevelInfo, errorMsg); + manifestFree(result); result = NULL; } @@ -545,7 +658,7 @@ Populate the WAL ranges from the provided, sorted, WAL files list for a given ar ***********************************************************************************************************************************/ static void verifyCreateArchiveIdRange( - const VerifyArchiveResult *const archiveIdResult, StringList *const walFileList, unsigned int *const jobErrorTotal) + const VerifyArchiveResult *const archiveIdResult, StringList *const walFileList, unsigned int *const jobErrorTotal, VariantList *const errorList) { FUNCTION_TEST_BEGIN(); FUNCTION_TEST_PARAM_P(VERIFY_ARCHIVE_RESULT, archiveIdResult); // The result set for the archive Id being processed @@ -582,7 +695,8 @@ verifyCreateArchiveIdRange( { if (strEq(walSegment, strSubN(strLstGet(walFileList, walFileIdx + 1), 0, WAL_SEGMENT_NAME_SIZE))) { - LOG_INFO_FMT("duplicate WAL '%s' for '%s' exists, skipping", strZ(walSegment), strZ(archiveIdResult->archiveId)); + String *errorMsg = strNewFmt("duplicate WAL '%s' for '%s' exists, skipping", strZ(walSegment), strZ(archiveIdResult->archiveId)); + verifyErrorNew(errorList, logLevelInfo, errorMsg); (*jobErrorTotal)++; @@ -850,7 +964,7 @@ verifyArchive(VerifyJobData *const jobData) // log archiveResult->totalWalFile += strLstSize(jobData->walFileList); - verifyCreateArchiveIdRange(archiveResult, jobData->walFileList, &jobData->jobErrorTotal); + verifyCreateArchiveIdRange(archiveResult, jobData->walFileList, &jobData->jobErrorTotal, jobData->errorList); } } @@ -893,9 +1007,10 @@ verifyArchive(VerifyJobData *const jobData) else { // No valid WAL to process (may be only duplicates or nothing in WAL path) - remove WAL path from the list - LOG_DETAIL_FMT( + String *errorMsg = strNewFmt( "path '%s/%s' does not contain any valid WAL to be processed", strZ(archiveResult->archiveId), strZ(walPath)); + verifyErrorNew(jobData->errorList, logLevelDetail, errorMsg); strLstRemoveIdx(jobData->walPathList, 0); } @@ -916,7 +1031,8 @@ verifyArchive(VerifyJobData *const jobData) else { // Log that no WAL paths exist in the archive Id dir - remove the archive Id from the list (nothing to process) - LOG_DETAIL_FMT("archive path '%s' is empty", strZ(strLstGet(jobData->archiveIdList, 0))); + String *errorMsg = strNewFmt("archive path '%s' is empty", strZ(strLstGet(jobData->archiveIdList, 0))); + verifyErrorNew(jobData->errorList, logLevelDetail, errorMsg); strLstRemoveIdx(jobData->archiveIdList, 0); } } @@ -973,7 +1089,7 @@ verifyBackup(VerifyJobData *const jobData) // Get a usable backup manifest file Manifest *const manifest = verifyManifestFile( - backupResult, jobData->manifestCipherPass, inProgressBackup, jobData->pgHistory, &jobData->jobErrorTotal); + backupResult, jobData->manifestCipherPass, inProgressBackup, jobData->pgHistory, &jobData->jobErrorTotal, jobData->errorList); // If a usable backup.manifest file is not found if (manifest == NULL) @@ -1162,7 +1278,8 @@ verifyBackup(VerifyJobData *const jobData) { // Nothing to process so report an error, free the manifest, set the status, and remove the backup from processing // list - LOG_INFO_FMT("backup '%s' manifest does not contain any target files to verify", strZ(backupResult->backupLabel)); + String *errorMsg = strNewFmt("backup '%s' manifest does not contain any target files to verify", strZ(backupResult->backupLabel)); + verifyErrorNew(jobData->errorList, logLevelInfo, errorMsg); jobData->jobErrorTotal++; @@ -1253,13 +1370,14 @@ Helper function to output a log message based on job result that is not verifyOk ***********************************************************************************************************************************/ static unsigned int verifyLogInvalidResult( - const String *const fileType, const VerifyResult verifyResult, const unsigned int processId, const String *const filePathName) + const String *const fileType, const VerifyResult verifyResult, const unsigned int processId, const String *const filePathName, VariantList *const errorList) { FUNCTION_TEST_BEGIN(); FUNCTION_TEST_PARAM(STRING, fileType); // Indicates archive or backup file FUNCTION_TEST_PARAM(ENUM, verifyResult); // Result code from the verifyFile() function FUNCTION_TEST_PARAM(UINT, processId); // Process Id reporting the result FUNCTION_TEST_PARAM(STRING, filePathName); // File for which results are being reported + FUNCTION_TEST_PARAM(LIST, errorList); // List of error messages FUNCTION_TEST_END(); ASSERT(fileType != NULL); @@ -1269,11 +1387,23 @@ verifyLogInvalidResult( // legitimately so it is not necessarily an error so the jobErrorTotal should not be incremented if (strEq(fileType, STORAGE_REPO_ARCHIVE_STR) && verifyResult == verifyFileMissing) { - LOG_WARN_PID_FMT(processId, "%s '%s'", verifyErrorMsg(verifyResult), strZ(filePathName)); + MEM_CONTEXT_TEMP_BEGIN(); + { + String *errorMsg = strNewFmt("%s '%s'", verifyErrorMsg(verifyResult), strZ(filePathName)); + verifyErrorPidNew(errorList, logLevelWarn, processId, errorMsg); + } + MEM_CONTEXT_TEMP_END(); FUNCTION_TEST_RETURN(UINT, 0); } - LOG_INFO_PID_FMT(processId, "%s '%s'", verifyErrorMsg(verifyResult), strZ(filePathName)); + + MEM_CONTEXT_TEMP_BEGIN(); + { + String *errorMsg = strNewFmt("%s '%s'", verifyErrorMsg(verifyResult), strZ(filePathName)); + verifyErrorPidNew(errorList, logLevelInfo, processId, errorMsg); + } + MEM_CONTEXT_TEMP_END(); + FUNCTION_TEST_RETURN(UINT, 1); } @@ -1283,7 +1413,7 @@ Helper function to set the currently processing backup label, if any, and check static String * verifySetBackupCheckArchive( const StringList *const backupList, const InfoBackup *const backupInfo, const StringList *const archiveIdList, - const InfoPg *const pgHistory, unsigned int *const jobErrorTotal) + const InfoPg *const pgHistory, unsigned int *const jobErrorTotal, VariantList *const errorList) { FUNCTION_TEST_BEGIN(); FUNCTION_TEST_PARAM(STRING_LIST, backupList); // List of backup labels in the backup directory @@ -1339,7 +1469,8 @@ verifySetBackupCheckArchive( if (!strEmpty(missingFromHistory)) { - LOG_INFO_FMT("archiveIds '%s' are not in the archive.info history list", strZ(missingFromHistory)); + String *errorMsg = strNewFmt("archiveIds '%s' are not in the archive.info history list", strZ(missingFromHistory)); + verifyErrorNew(errorList, logLevelInfo, errorMsg); (*jobErrorTotal)++; } @@ -1430,12 +1561,13 @@ verifyCreateFileErrorsStr( Render the results of the verify command ***********************************************************************************************************************************/ static String * -verifyRender(const List *const archiveIdResultList, const List *const backupResultList, const bool verboseText) +verifyRender(const List *const archiveIdResultList, const List *const backupResultList, const bool verboseText, KeyValue *const jsonKv, VariantList *const errorList) { FUNCTION_TEST_BEGIN(); FUNCTION_TEST_PARAM(LIST, archiveIdResultList); // Result list for all archive Ids in the repo FUNCTION_TEST_PARAM(LIST, backupResultList); // Result list for all backups in the repo FUNCTION_TEST_PARAM(BOOL, verboseText); // Is verbose output requested? + FUNCTION_TEST_PARAM(KEY_VALUE, jsonKv); // Is JSON output requested? FUNCTION_TEST_END(); FUNCTION_AUDIT_HELPER(); @@ -1446,35 +1578,56 @@ verifyRender(const List *const archiveIdResultList, const List *const backupResu String *const result = strNew(); // Render archive results - if (verboseText && lstEmpty(archiveIdResultList)) + VariantList *archivesList = NULL; + VariantList *backupsList = NULL; + if (jsonKv != NULL) + { + archivesList = varLstNew(); + backupsList = varLstNew(); + } + + if (jsonKv == NULL && verboseText && lstEmpty(archiveIdResultList)) + { strCatZ(result, "\n archiveId: none found"); + } else { for (unsigned int archiveIdx = 0; archiveIdx < lstSize(archiveIdResultList); archiveIdx++) { const VerifyArchiveResult *const archiveIdResult = lstGet(archiveIdResultList, archiveIdx); + KeyValue *const archiveKv = ((archivesList == NULL) ? NULL : kvNew()); - if (verboseText || archiveIdResult->totalWalFile - archiveIdResult->totalValidWal != 0) + if (verboseText || jsonKv != NULL || archiveIdResult->totalWalFile - archiveIdResult->totalValidWal != 0) { - strCatFmt( - result, "\n archiveId: %s, total WAL checked: %u, total valid WAL: %u", strZ(archiveIdResult->archiveId), - archiveIdResult->totalWalFile, archiveIdResult->totalValidWal); + if (archiveKv != NULL) + { + kvPut(archiveKv, ARCHIVE_KEY_ARCHIVEID_VAR, VARSTR(archiveIdResult->archiveId)); + kvPut(archiveKv, ARCHIVE_KEY_CHECKED_VAR, VARUINT(archiveIdResult->totalWalFile)); + kvPut(archiveKv, KEY_VALID_VAR, VARUINT(archiveIdResult->totalValidWal)); + } + else + { + strCatFmt( + result, "\n archiveId: %s, total WAL checked: %u, total valid WAL: %u", strZ(archiveIdResult->archiveId), + archiveIdResult->totalWalFile, archiveIdResult->totalValidWal); + } } + unsigned int errMissing = 0; + unsigned int errChecksum = 0; + unsigned int errSize = 0; + unsigned int errOther = 0; + if (archiveIdResult->totalWalFile > 0) { - unsigned int errMissing = 0; - unsigned int errChecksum = 0; - unsigned int errSize = 0; - unsigned int errOther = 0; - for (unsigned int walIdx = 0; walIdx < lstSize(archiveIdResult->walRangeList); walIdx++) { const VerifyWalRange *const walRange = lstGet(archiveIdResult->walRangeList, walIdx); - LOG_DETAIL_FMT( + String *errorMsg = strNewFmt( "archiveId: %s, wal start: %s, wal stop: %s", strZ(archiveIdResult->archiveId), strZ(walRange->start), strZ(walRange->stop)); + verifyErrorNew(errorList, logLevelDetail, errorMsg); unsigned int invalidIdx = 0; @@ -1496,21 +1649,33 @@ verifyRender(const List *const archiveIdResultList, const List *const backupResu } // Create/append file errors string - if (verboseText || errMissing + errChecksum + errSize + errOther > 0) + if (jsonKv == NULL && (verboseText || errMissing + errChecksum + errSize + errOther > 0)) strCat(result, verifyCreateFileErrorsStr(errMissing, errChecksum, errSize, errOther, verboseText)); } + + if (archiveKv != NULL) + { + kvPut(archiveKv, KEY_MISSING_VAR, VARUINT(errMissing)); + kvPut(archiveKv, KEY_CHECKSUMINVALID_VAR, VARUINT(errChecksum)); + kvPut(archiveKv, KEY_SIZEINVALID_VAR, VARUINT(errSize)); + kvPut(archiveKv, KEY_OTHER_VAR, VARUINT(errOther)); + + varLstAdd(archivesList, varNewKv(archiveKv)); + } } } - // Render backup results - if (verboseText && lstEmpty(backupResultList)) + if (jsonKv == NULL && verboseText && lstEmpty(backupResultList)) + { strCatZ(result, "\n backup: none found"); + } else { for (unsigned int backupIdx = 0; backupIdx < lstSize(backupResultList); backupIdx++) { const VerifyBackupResult *const backupResult = lstGet(backupResultList, backupIdx); const char *status; + KeyValue *const backupKv = backupsList == NULL ? NULL : kvNew(); switch (backupResult->status) { @@ -1535,19 +1700,27 @@ verifyRender(const List *const archiveIdResultList, const List *const backupResu } } - if (verboseText || (strcmp(status, "valid") != 0 && strcmp(status, "in-progress") != 0)) + if (backupKv != NULL) + { + kvPut(backupKv, BACKUP_KEY_LABEL_VAR, VARSTR(backupResult->backupLabel)); + kvPut(backupKv, KEY_STATUS_VAR, VARSTRZ(status)); + kvPut(backupKv, BACKUP_KEY_CHECKED_VAR, VARUINT(backupResult->totalFileVerify)); + kvPut(backupKv, KEY_VALID_VAR, VARUINT(backupResult->totalFileValid)); + } + else if (verboseText || (strcmp(status, "valid") != 0 && strcmp(status, "in-progress") != 0)) { strCatFmt( result, "\n backup: %s, status: %s, total files checked: %u, total valid files: %u", strZ(backupResult->backupLabel), status, backupResult->totalFileVerify, backupResult->totalFileValid); } + unsigned int errMissing = 0; + unsigned int errChecksum = 0; + unsigned int errSize = 0; + unsigned int errOther = 0; + if (backupResult->totalFileVerify > 0) { - unsigned int errMissing = 0; - unsigned int errChecksum = 0; - unsigned int errSize = 0; - unsigned int errOther = 0; for (unsigned int invalidIdx = 0; invalidIdx < lstSize(backupResult->invalidFileList); invalidIdx++) { @@ -1564,12 +1737,32 @@ verifyRender(const List *const archiveIdResultList, const List *const backupResu } // Create/append file errors string - if (verboseText || errMissing + errChecksum + errSize + errOther > 0) + if (backupKv == NULL && (verboseText || errMissing + errChecksum + errSize + errOther > 0)) + { strCat(result, verifyCreateFileErrorsStr(errMissing, errChecksum, errSize, errOther, verboseText)); + } + } + + if (backupKv != NULL) + { + kvPut(backupKv, KEY_MISSING_VAR, VARUINT(errMissing)); + kvPut(backupKv, KEY_CHECKSUMINVALID_VAR, VARUINT(errChecksum)); + kvPut(backupKv, KEY_SIZEINVALID_VAR, VARUINT(errSize)); + kvPut(backupKv, KEY_OTHER_VAR, VARUINT(errOther)); + varLstAdd(backupsList, varNewKv(backupKv)); } } } + if (jsonKv != NULL) + { + kvPut(jsonKv, KEY_ARCHIVES_VAR, varNewVarLst(archivesList)); + kvPut(jsonKv, KEY_BACKUPS_VAR, varNewVarLst(backupsList)); + + // Provide JSON based output as well to make testing easier + strCat(result, jsonFromVar(varNewKv(jsonKv))); + } + FUNCTION_TEST_RETURN(STRING, result); } @@ -1584,32 +1777,39 @@ verifyProcess(const bool verboseText) FUNCTION_LOG_END(); String *const result = strNew(); + KeyValue * resultKv = NULL; + bool json = cfgOptionStrId(cfgOptOutput) == CFGOPTVAL_OUTPUT_JSON; MEM_CONTEXT_TEMP_BEGIN() { unsigned int errorTotal = 0; String *resultStr = strNew(); + VariantList *errorList = varLstNew(); // Get the repo storage in case it is remote and encryption settings need to be pulled down const Storage *const storage = storageRepo(); // Get a usable backup info file - const InfoBackup *const backupInfo = verifyBackupInfoFile(); + const InfoBackup *const backupInfo = verifyBackupInfoFile(errorList); + + if (json) { + resultKv = kvNew(); + } // If a usable backup.info file is not found, then report an error in the log if (backupInfo == NULL) { - strCatZ(resultStr, "\n No usable backup.info file"); + verifyErrorNew(errorList, logLevelOff, strNewZ("No usable backup.info file")); errorTotal++; } // Get a usable archive info file - const InfoArchive *const archiveInfo = verifyArchiveInfoFile(); + const InfoArchive *const archiveInfo = verifyArchiveInfoFile(errorList); // If a usable archive.info file is not found, then report an error in the log if (archiveInfo == NULL) { - strCatZ(resultStr, "\n No usable archive.info file"); + verifyErrorNew(errorList, logLevelOff, strNewZ("No usable archive.info file")); errorTotal++; } @@ -1623,7 +1823,7 @@ verifyProcess(const bool verboseText) } CATCH_ANY() { - strCatFmt(resultStr, "\n%s", errorMessage()); + verifyErrorNew(errorList, logLevelOff, strNewZ(errorMessage())); errorTotal++; } TRY_END(); @@ -1643,6 +1843,7 @@ verifyProcess(const bool verboseText) .walCipherPass = infoPgCipherPass(infoArchivePg(archiveInfo)), .archiveIdResultList = lstNewP(sizeof(VerifyArchiveResult), .comparator = archiveIdComparator), .backupResultList = lstNewP(sizeof(VerifyBackupResult), .comparator = lstComparatorStr), + .errorList = errorList, }; // Use backup label if specified via --set @@ -1654,7 +1855,7 @@ verifyProcess(const bool verboseText) { if (!regExpMatchOne(backupRegExpStr, backupLabel)) { - strCatFmt(resultStr, "\n '%s' is not a valid backup label format", strZ(backupLabel)); + verifyErrorNew(errorList, logLevelOff, strNewFmt("'%s' is not a valid backup label format", strZ(backupLabel))); backupLabelInvalid = true; errorTotal++; @@ -1672,7 +1873,7 @@ verifyProcess(const bool verboseText) if (!backupLabelInvalid && backupLabel != NULL && strLstEmpty(jobData.backupList)) { - strCatFmt(resultStr, "\n backup set %s is not valid", strZ(backupLabel)); + verifyErrorNew(errorList, logLevelOff, strNewFmt("backup set %s is not valid", strZ(backupLabel))); backupLabelInvalid = true; errorTotal++; @@ -1697,8 +1898,10 @@ verifyProcess(const bool verboseText) { // Warn if there are no archives or there are no backups in the repo so that the callback need not try to // distinguish between having processed all of the list or if the list was missing in the first place - if (strLstEmpty(jobData.archiveIdList) || strLstEmpty(jobData.backupList)) - LOG_DETAIL_FMT("no %s exist in the repo", strLstEmpty(jobData.archiveIdList) ? "archives" : "backups"); + if (strLstEmpty(jobData.archiveIdList) || strLstEmpty(jobData.backupList)) { + String *errorMsg = strNewFmt("no %s exist in the repo", strLstEmpty(jobData.archiveIdList) ? "archives" : "backups"); + verifyErrorNew(errorList, logLevelDetail, errorMsg); + } // If there are no archives to process, then set the processing flag to skip to processing the backups if (strLstEmpty(jobData.archiveIdList)) @@ -1706,7 +1909,7 @@ verifyProcess(const bool verboseText) // Set current backup if there is one and verify the archive history on disk is in the database history jobData.currentBackup = verifySetBackupCheckArchive( - jobData.backupList, backupInfo, jobData.archiveIdList, jobData.pgHistory, &jobData.jobErrorTotal); + jobData.backupList, backupInfo, jobData.archiveIdList, jobData.pgHistory, &jobData.jobErrorTotal, errorList); // Create the parallel executor ProtocolParallel *const parallelExec = protocolParallelNew( @@ -1772,7 +1975,7 @@ verifyProcess(const bool verboseText) else { jobData.jobErrorTotal += verifyLogInvalidResult( - fileType, verifyResult, processId, filePathName); + fileType, verifyResult, processId, filePathName, errorList); // Add invalid file to the WAL range verifyAddInvalidWalFile( @@ -1788,7 +1991,7 @@ verifyProcess(const bool verboseText) else { jobData.jobErrorTotal += verifyLogInvalidResult( - fileType, verifyResult, processId, filePathName); + fileType, verifyResult, processId, filePathName, errorList); backupResult->status = backupInvalid; verifyInvalidFileAdd(backupResult->invalidFileList, verifyResult, filePathName); } @@ -1798,10 +2001,10 @@ verifyProcess(const bool verboseText) else { // Log a protocol error and increment the jobErrorTotal - LOG_INFO_PID_FMT( - processId, + String *errorMsg = strNewFmt( "%s %s: [%d] %s", verifyErrorMsg(verifyOtherError), strZ(filePathName), protocolParallelJobErrorCode(job), strZ(protocolParallelJobErrorMessage(job))); + verifyErrorPidNew(errorList, logLevelInfo, processId, errorMsg); jobData.jobErrorTotal++; @@ -1841,16 +2044,38 @@ verifyProcess(const bool verboseText) // ??? Need to do the final reconciliation - checking backup required WAL against, valid WAL // Report results - resultStr = verifyRender(jobData.archiveIdResultList, jobData.backupResultList, verboseText); + resultStr = verifyRender(jobData.archiveIdResultList, jobData.backupResultList, verboseText, resultKv, errorList); } - else if (!backupLabelInvalid) + else if (!json && !backupLabelInvalid) strCatZ(resultStr, "\n no archives or backups exist in the repo"); errorTotal += jobData.jobErrorTotal; } + if (json) + { + kvPut(resultKv, VERIFY_KEY_STANZA_VAR, VARSTR(cfgOptionStr(cfgOptStanza))); + kvPut(resultKv, KEY_STATUS_VAR, errorTotal > 0 ? VERIFY_KEY_STATUS_ERROR : VERIFY_KEY_STATUS_OK); + + kvPut(resultKv, KEY_ERRORS_VAR, varNewVarLst(errorList)); + + strCat(result, jsonFromVar(varNewKv(resultKv))); + } else { + for (unsigned int errIdx = 0; errIdx < varLstSize(errorList); errIdx++) + { + const KeyValue *const msg = varKv(varLstGet(errorList, errIdx)); + const LogLevel logLevel = (LogLevel)varUInt(kvGet(msg, VERIFY_MSG_KEY_LEVEL)); + + // Print messages which did not got logged yet + if (logLevel == logLevelOff) { + const String *const message = varStr(kvGet(msg, VERIFY_MSG_KEY_MESSAGE)); + strCatFmt(resultStr, "\n %s", strZ(message)); + } + } + } + // If verbose output or errors then output results - if (verboseText || errorTotal > 0) + if (!json && (verboseText || errorTotal > 0)) { strCatFmt( result, "stanza: %s\nstatus: %s%s", strZ(cfgOptionStr(cfgOptStanza)), @@ -1879,7 +2104,8 @@ cmdVerify(void) LOG_INFO_FMT("%s", strZ(result)); // Output to console when requested - if (cfgOptionStrId(cfgOptOutput) == CFGOPTVAL_OUTPUT_TEXT) + if (cfgOptionStrId(cfgOptOutput) == CFGOPTVAL_OUTPUT_TEXT + || cfgOptionStrId(cfgOptOutput) == CFGOPTVAL_OUTPUT_JSON) { ioFdWriteOneStr(STDOUT_FILENO, result); ioFdWriteOneStr(STDOUT_FILENO, LF_STR); diff --git a/src/config/parse.auto.c.inc b/src/config/parse.auto.c.inc index 1f86333296..229fc513e5 100644 --- a/src/config/parse.auto.c.inc +++ b/src/config/parse.auto.c.inc @@ -3665,6 +3665,7 @@ static const ParseRuleOption parseRuleOption[CFG_OPTION_TOTAL] = ( // opt/output PARSE_RULE_VAL_STRID(None), // opt/output PARSE_RULE_VAL_STRID(Text), // opt/output + PARSE_RULE_VAL_STRID(Json), // opt/output ), // opt/output // opt/output PARSE_RULE_OPTIONAL_DEFAULT // opt/output diff --git a/test/define.yaml b/test/define.yaml index 805e49fb44..2855d3a553 100644 --- a/test/define.yaml +++ b/test/define.yaml @@ -984,7 +984,7 @@ unit: # ---------------------------------------------------------------------------------------------------------------------------- - name: verify - total: 14 + total: 17 coverage: - command/verify/file diff --git a/test/src/module/command/verifyTest.c b/test/src/module/command/verifyTest.c index bf7979b673..f765f31698 100644 --- a/test/src/module/command/verifyTest.c +++ b/test/src/module/command/verifyTest.c @@ -222,6 +222,7 @@ testRun(void) Manifest *manifest = NULL; unsigned int jobErrorTotal = 0; + VariantList *errorList = varLstNew(); VerifyBackupResult backupResult = {.backupLabel = strNewZ(TEST_BACKUP_LABEL_FULL)}; InfoPg *infoPg = NULL; @@ -256,9 +257,24 @@ testRun(void) harnessLogLevelSet(logLevelDetail); backupResult.status = backupValid; - TEST_ASSIGN(manifest, verifyManifestFile(&backupResult, NULL, false, infoPg, &jobErrorTotal), "verify manifest"); + TEST_ASSIGN(manifest, verifyManifestFile(&backupResult, NULL, false, infoPg, &jobErrorTotal, errorList), "verify manifest"); TEST_RESULT_PTR(manifest, NULL, "manifest not set - pg version mismatch"); TEST_RESULT_UINT(backupResult.status, backupInvalid, "manifest unusable - backup invalid"); + TEST_RESULT_UINT(varLstSize(errorList), 2, "error list size"); + + TEST_RESULT_STR(jsonFromVar(varNewVarLst(errorList)), STR("[" + "{" + "\"level\":5," + "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/20181119-152138F/backup.manifest.copy' for read\"" + "}," + "{" + "\"level\":4," + "\"message\":\"'20181119-152138F' may not be recoverable - PG data (id 1, version 9.6, system-id " HRN_PG_SYSTEMID_95_Z ") is not in the backup.info history, skipping\"" + "}" + "]"), + "errorList does not match" + ); + TEST_RESULT_LOG( "P00 DETAIL: unable to open missing file '" TEST_PATH "/repo/backup/db/20181119-152138F/backup.manifest.copy'" " for read\n" @@ -291,7 +307,9 @@ testRun(void) .comment = "manifest copy - invalid system-id"); backupResult.status = backupValid; - TEST_ASSIGN(manifest, verifyManifestFile(&backupResult, NULL, false, infoPg, &jobErrorTotal), "verify manifest"); + + lstClear((List *)errorList); + TEST_ASSIGN(manifest, verifyManifestFile(&backupResult, NULL, false, infoPg, &jobErrorTotal, errorList), "verify manifest"); TEST_RESULT_PTR(manifest, NULL, "manifest not set - pg system-id mismatch"); TEST_RESULT_UINT(backupResult.status, backupInvalid, "manifest unusable - backup invalid"); TEST_RESULT_LOG( @@ -325,7 +343,8 @@ testRun(void) .comment = "manifest copy - invalid db-id"); backupResult.status = backupValid; - TEST_ASSIGN(manifest, verifyManifestFile(&backupResult, NULL, false, infoPg, &jobErrorTotal), "verify manifest"); + lstClear((List *)errorList); + TEST_ASSIGN(manifest, verifyManifestFile(&backupResult, NULL, false, infoPg, &jobErrorTotal, errorList), "verify manifest"); TEST_RESULT_PTR(manifest, NULL, "manifest not set - pg db-id mismatch"); TEST_RESULT_UINT(backupResult.status, backupInvalid, "manifest unusable - backup invalid"); TEST_RESULT_LOG( @@ -338,12 +357,12 @@ testRun(void) TEST_TITLE("missing main manifest, errored copy"); backupResult.status = backupValid; - + lstClear((List *)errorList); HRN_STORAGE_PUT_Z( storageRepoWrite(), TEST_PATH "/repo/" STORAGE_PATH_BACKUP "/db/" TEST_BACKUP_LABEL_FULL "/" BACKUP_MANIFEST_FILE INFO_COPY_EXT, TEST_INVALID_BACKREST_INFO, .comment = "invalid manifest copy"); - TEST_ASSIGN(manifest, verifyManifestFile(&backupResult, NULL, false, infoPg, &jobErrorTotal), "verify manifest"); + TEST_ASSIGN(manifest, verifyManifestFile(&backupResult, NULL, false, infoPg, &jobErrorTotal, errorList), "verify manifest"); TEST_RESULT_UINT(backupResult.status, backupInvalid, "manifest unusable - backup invalid"); TEST_RESULT_LOG( "P00 DETAIL: unable to open missing file '" TEST_PATH "/repo/backup/db/20181119-152138F/backup.manifest' for read\n" @@ -353,11 +372,12 @@ testRun(void) // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("current backup true"); + lstClear((List *)errorList); HRN_STORAGE_PUT_Z( storageRepoWrite(), TEST_PATH "/repo/" STORAGE_PATH_BACKUP "/db/" TEST_BACKUP_LABEL_FULL "/" BACKUP_MANIFEST_FILE, TEST_INVALID_BACKREST_INFO, .comment = "invalid manifest"); - TEST_ASSIGN(manifest, verifyManifestFile(&backupResult, NULL, true, infoPg, &jobErrorTotal), "verify manifest"); + TEST_ASSIGN(manifest, verifyManifestFile(&backupResult, NULL, true, infoPg, &jobErrorTotal, errorList), "verify manifest"); TEST_RESULT_PTR(manifest, NULL, "manifest not set"); TEST_RESULT_UINT(backupResult.status, backupInvalid, "manifest unusable - backup invalid"); TEST_RESULT_LOG( @@ -383,7 +403,8 @@ testRun(void) .comment = "valid manifest"); backupResult.status = backupValid; - TEST_ASSIGN(manifest, verifyManifestFile(&backupResult, NULL, true, infoPg, &jobErrorTotal), "verify manifest"); + lstClear((List *)errorList); + TEST_ASSIGN(manifest, verifyManifestFile(&backupResult, NULL, true, infoPg, &jobErrorTotal, errorList), "verify manifest"); TEST_RESULT_PTR_NE(manifest, NULL, "manifest set"); TEST_RESULT_UINT(backupResult.status, backupValid, "manifest usable"); TEST_RESULT_LOG("P00 DETAIL: backup '20181119-152138F' manifest.copy does not match manifest"); @@ -412,10 +433,11 @@ testRun(void) archiveIdResult->pgWalInfo.size = HRN_PG_WAL_SEGMENT_SIZE_DEFAULT; archiveIdResult->pgWalInfo.version = PG_VERSION_95; + VariantList *errorList = varLstNew(); strLstAddZ(walFileList, "000000020000000200000000-daa497dba64008db824607940609ba1cd7c6c501.gz"); - TEST_RESULT_VOID(verifyCreateArchiveIdRange(archiveIdResult, walFileList, &errTotal), "create archiveId WAL range"); + TEST_RESULT_VOID(verifyCreateArchiveIdRange(archiveIdResult, walFileList, &errTotal, errorList), "create archiveId WAL range"); TEST_RESULT_UINT(errTotal, 0, "no errors"); TEST_RESULT_UINT(lstSize(((VerifyArchiveResult *)lstGet(archiveIdResultList, 0))->walRangeList), 1, "single range"); TEST_ASSIGN( @@ -428,14 +450,15 @@ testRun(void) TEST_TITLE("Duplicate WAL only - no range, all removed from list"); lstClear(archiveIdResult->walRangeList); - + lstClear((List *)errorList); // Add a duplicate strLstAddZ(walFileList, "000000020000000200000000"); - TEST_RESULT_VOID(verifyCreateArchiveIdRange(archiveIdResult, walFileList, &errTotal), "create archiveId WAL range"); + TEST_RESULT_VOID(verifyCreateArchiveIdRange(archiveIdResult, walFileList, &errTotal, errorList), "create archiveId WAL range"); TEST_RESULT_UINT(errTotal, 1, "duplicate WAL error"); TEST_RESULT_UINT(strLstSize(walFileList), 0, "all WAL removed from WAL file list"); TEST_RESULT_UINT(lstSize(archiveIdResult->walRangeList), 0, "no range"); + TEST_RESULT_UINT(varLstSize(errorList), 1, "one error"); TEST_RESULT_LOG("P00 INFO: duplicate WAL '000000020000000200000000' for '9.5-1' exists, skipping"); // ------------------------------------------------------------------------------------------------------------------------- @@ -452,7 +475,8 @@ testRun(void) strLstAddZ(walFileList, "000000020000000200000001"); strLstAddZ(walFileList, "000000020000000200000001"); - TEST_RESULT_VOID(verifyCreateArchiveIdRange(archiveIdResult, walFileList, &errTotal), "create archiveId WAL range"); + lstClear((List *)errorList); + TEST_RESULT_VOID(verifyCreateArchiveIdRange(archiveIdResult, walFileList, &errTotal, errorList), "create archiveId WAL range"); TEST_RESULT_UINT(errTotal, 2, "triplicate WAL error at beginning, duplicate WAL at end"); TEST_RESULT_UINT(strLstSize(walFileList), 4, "only duplicate WAL removed from WAL list"); TEST_RESULT_UINT(lstSize(archiveIdResultList), 1, "single archiveId result"); @@ -590,21 +614,23 @@ testRun(void) strLstAddZ(archiveIdList, "11-2"); unsigned int errTotal = 0; + VariantList *errorList = varLstNew(); // Add backup to end of list strLstAddZ(backupList, "20181119-153000F"); strLstAddZ(archiveIdList, "12-3"); TEST_RESULT_STR_Z( - verifySetBackupCheckArchive(backupList, backupInfo, archiveIdList, pgHistory, &errTotal), + verifySetBackupCheckArchive(backupList, backupInfo, archiveIdList, pgHistory, &errTotal, errorList), "20181119-153000F", "current backup, missing archive"); TEST_RESULT_UINT(errTotal, 1, "error logged"); TEST_RESULT_LOG("P00 INFO: archiveIds '12-3' are not in the archive.info history list"); errTotal = 0; + lstClear((List *)errorList); strLstAddZ(archiveIdList, "13-4"); TEST_RESULT_STR_Z( - verifySetBackupCheckArchive(backupList, backupInfo, archiveIdList, pgHistory, &errTotal), + verifySetBackupCheckArchive(backupList, backupInfo, archiveIdList, pgHistory, &errTotal, errorList), "20181119-153000F", "test multiple archiveIds on disk not in archive.info"); TEST_RESULT_UINT(errTotal, 1, "error logged"); TEST_RESULT_LOG("P00 INFO: archiveIds '12-3, 13-4' are not in the archive.info history list"); @@ -613,7 +639,7 @@ testRun(void) TEST_TITLE("verifyLogInvalidResult() - missing file"); TEST_RESULT_UINT( - verifyLogInvalidResult(STORAGE_REPO_ARCHIVE_STR, verifyFileMissing, 0, STRDEF("missingfilename")), + verifyLogInvalidResult(STORAGE_REPO_ARCHIVE_STR, verifyFileMissing, 0, STRDEF("missingfilename"), errorList), 0, "file missing message"); TEST_RESULT_LOG("P00 WARN: file missing 'missingfilename'"); @@ -639,11 +665,33 @@ testRun(void) lstAdd(archiveIdResult.walRangeList, &walRange); lstAdd(archiveIdResultList, &archiveIdResult); + KeyValue *testKv = kvNew(); + lstClear((List *)errorList); + TEST_RESULT_STR_Z( - verifyRender(archiveIdResultList, backupResultList, cfgOptionBool(cfgOptVerbose)), + verifyRender(archiveIdResultList, backupResultList, cfgOptionBool(cfgOptVerbose), NULL, errorList), "\n" " archiveId: 9.6-1, total WAL checked: 1, total valid WAL: 0", "archive: no invalid file list"); + lstClear((List *)errorList); + + TEST_RESULT_STR_Z( + verifyRender(archiveIdResultList, backupResultList, cfgOptionBool(cfgOptVerbose), testKv, errorList), + "{\"archives\":[" + "{" + "\"archiveId\":\"9.6-1\"," + "\"checked\":1," + "\"checksumInvalid\":0," + "\"missing\":0," + "\"other\":0," + "\"sizeInvalid\":0," + "\"valid\":0" + "}" + "]," + "\"backups\":[" + "]}", + "archive: no invalid file list"); + VerifyInvalidFile invalidFile = { .fileName = strNewZ("file"), @@ -661,14 +709,43 @@ testRun(void) lstAdd(backupResult.invalidFileList, &invalidFile); lstAdd(backupResultList, &backupResult); + lstClear((List *)errorList); TEST_RESULT_STR_Z( - verifyRender(archiveIdResultList, backupResultList, cfgOptionBool(cfgOptVerbose)), + verifyRender(archiveIdResultList, backupResultList, cfgOptionBool(cfgOptVerbose), NULL, errorList), "\n" " archiveId: 9.6-1, total WAL checked: 1, total valid WAL: 0\n" " missing: 1\n" " backup: test-backup-label, status: invalid, total files checked: 1, total valid files: 0\n" " missing: 1", "archive file missing, backup file missing, no text, no verbose"); + lstClear((List *)errorList); + TEST_RESULT_STR_Z( + verifyRender(archiveIdResultList, backupResultList, cfgOptionBool(cfgOptVerbose), testKv, errorList), + "{\"archives\":[" + "{" + "\"archiveId\":\"9.6-1\"," + "\"checked\":1," + "\"checksumInvalid\":0," + "\"missing\":1," + "\"other\":0," + "\"sizeInvalid\":0," + "\"valid\":0" + "}" + "]," + "\"backups\":[" + "{" + "\"checked\":1," + "\"checksumInvalid\":0," + "\"label\":\"test-backup-label\"," + "\"missing\":1," + "\"other\":0," + "\"sizeInvalid\":0," + "\"status\":\"invalid\"," + "\"valid\":0" + "}" + "]}", + "archive file missing, backup file missing, no text, no verbose, json output"); + // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("verifyAddInvalidWalFile() - file missing (coverage test)"); @@ -787,7 +864,7 @@ testRun(void) " /archive.info\n" "P00 INFO: stanza: db\n" " status: error\n" - " backup info file and archive info file do not match\n" + " backup info file and archive info file do not match\n" " archive: id = 1, version = 9.5, system-id = 10000000000000090500\n" " backup : id = 2, version = 11, system-id = 10000000000000110000\n" " HINT: this may be a symptom of repository corruption!"); @@ -849,6 +926,324 @@ testRun(void) harnessLogLevelReset(); } + // ***************************************************************************************************************************** + if (testBegin("cmdVerify() - info files JSON output")){ + // Load Parameters + StringList *argList = strLstDup(argListBase); + hrnCfgArgRawZ(argList, cfgOptOutput, "json"); + HRN_CFG_LOAD(cfgCmdVerify, argList); + + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("backup.info invalid checksum, neither backup copy nor archive infos exist"); + + HRN_STORAGE_PUT_Z(storageRepoWrite(), INFO_BACKUP_PATH_FILE, TEST_INVALID_BACKREST_INFO, .comment = "invalid backup.info"); + + harnessLogLevelSet(logLevelDetail); + + // Redirect stdout to a file + int stdoutSave = dup(STDOUT_FILENO); + const String *stdoutFile = STRDEF(TEST_PATH "/stdout.info"); + + THROW_ON_SYS_ERROR(freopen(strZ(stdoutFile), "w", stdout) == NULL, FileWriteError, "unable to reopen stdout"); + + // Not in a test wrapper to compare stdout + cmdVerify(); + + // Restore normal stdout + dup2(stdoutSave, STDOUT_FILENO); + +#define EXPECTED_OUTPUT_JSON "{" \ + "\"errors\":[" \ + "{"\ + "\"level\":5,"\ + "\"message\":\"invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS' /backup.info\""\ + "},{"\ + "\"level\":5,"\ + "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/backup.info.copy' for read\""\ + "},{"\ + "\"level\":0,"\ + "\"message\":\"No usable backup.info file\""\ + "},{"\ + "\"level\":5,"\ + "\"message\":\"unable to open missing file '" TEST_PATH "/repo/archive/db/archive.info' for read\""\ + "},{"\ + "\"level\":5,"\ + "\"message\":\"unable to open missing file '" TEST_PATH "/repo/archive/db/archive.info.copy' for read\""\ + "},{"\ + "\"level\":0,"\ + "\"message\":\"No usable archive.info file\""\ + "}"\ + "],"\ + "\"stanza\":\"db\","\ + "\"status\":\"error\""\ + "}" + + // Check output of verify command stored in file + TEST_STORAGE_GET(storageTest, strZ(stdoutFile), + EXPECTED_OUTPUT_JSON "\n", + .remove = true); + + TEST_RESULT_LOG( + "P00 DETAIL: invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS'" + " /backup.info\n" + "P00 DETAIL: unable to open missing file '" TEST_PATH "/repo/backup/db/backup.info.copy' for read\n" + "P00 DETAIL: unable to open missing file '" TEST_PATH "/repo/archive/db/archive.info' for read\n" + "P00 DETAIL: unable to open missing file '" TEST_PATH "/repo/archive/db/archive.info.copy' for read\n" + "P00 INFO: " EXPECTED_OUTPUT_JSON + ); +#undef EXPECTED_OUTPUT_JSON + + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("backup.info invalid checksum, backup.info.copy valid, archive.info not exist, archive copy checksum invalid"); + + HRN_STORAGE_PUT_Z( + storageRepoWrite(), INFO_ARCHIVE_PATH_FILE INFO_COPY_EXT, TEST_INVALID_BACKREST_INFO, + .comment = "invalid archive.info.copy"); + HRN_INFO_PUT( + storageRepoWrite(), INFO_BACKUP_PATH_FILE INFO_COPY_EXT, + "[backup:current]\n" + TEST_BACKUP_DB1_CURRENT_FULL1 + "\n" + "[db]\n" + TEST_BACKUP_DB1_95 + "\n" + "[db:history]\n" + TEST_BACKUP_DB1_HISTORY, + .comment = "valid backup.info.copy"); + + // Redirect stdout to a file + stdoutSave = dup(STDOUT_FILENO); + THROW_ON_SYS_ERROR(freopen(strZ(stdoutFile), "w", stdout) == NULL, FileWriteError, "unable to reopen stdout"); + + // Not in a test wrapper to compare stdout + cmdVerify(); + + // Restore normal stdout + dup2(stdoutSave, STDOUT_FILENO); + +#define EXPECTED_OUTPUT_JSON "{"\ + "\"errors\":["\ + "{"\ + "\"level\":5,"\ + "\"message\":\"invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS' /backup.info\""\ + "},{"\ + "\"level\":5,"\ + "\"message\":\"unable to open missing file '" TEST_PATH "/repo/archive/db/archive.info' for read\""\ + "},{"\ + "\"level\":5,\"message\":\"invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS' /archive.info.copy\""\ + "},{"\ + "\"level\":0,\"message\":\"No usable archive.info file\""\ + "}"\ + "],"\ + "\"stanza\":\"db\","\ + "\"status\":\"error\""\ + "}" + + // Check output of verify command stored in file + TEST_STORAGE_GET(storageTest, strZ(stdoutFile), + EXPECTED_OUTPUT_JSON "\n", + .remove = true); + + /* Consume log */ + TEST_RESULT_LOG( + "P00 DETAIL: invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS'" + " /backup.info\n" + "P00 DETAIL: unable to open missing file '" TEST_PATH "/repo/archive/db/archive.info' for read\n" + "P00 DETAIL: invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS'" + " /archive.info.copy\n" + "P00 INFO: " EXPECTED_OUTPUT_JSON + ); +#undef EXPECTED_OUTPUT_JSON + + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("backup.info and copy valid but checksum mismatch, archive.info checksum invalid, archive.info copy valid"); + + HRN_INFO_PUT( + storageRepoWrite(), INFO_BACKUP_PATH_FILE, TEST_BACKUP_INFO_MULTI_HISTORY_BASE, .comment = "valid backup.info"); + HRN_STORAGE_PUT_Z( + storageRepoWrite(), INFO_ARCHIVE_PATH_FILE, TEST_INVALID_BACKREST_INFO, .comment = "invalid archive.info"); + HRN_INFO_PUT( + storageRepoWrite(), INFO_ARCHIVE_PATH_FILE INFO_COPY_EXT, TEST_ARCHIVE_INFO_BASE, .comment = "valid archive.info.copy"); + + // Redirect stdout to a file + stdoutSave = dup(STDOUT_FILENO); + THROW_ON_SYS_ERROR(freopen(strZ(stdoutFile), "w", stdout) == NULL, FileWriteError, "unable to reopen stdout"); + + // Not in a test wrapper to compare stdout + cmdVerify(); + + // Restore normal stdout + dup2(stdoutSave, STDOUT_FILENO); + +#define EXPECTED_OUTPUT_JSON "{"\ + "\"errors\":["\ + "{"\ + "\"level\":5,"\ + "\"message\":\"backup.info.copy does not match backup.info\""\ + "},{"\ + "\"level\":5,"\ + "\"message\":\"invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS' /archive.info\""\ + "},{"\ + "\"level\":0,\"message\":\"backup info file and archive info file do not match\\narchive: id = 1, version = 9.5, system-id = 10000000000000090500\\nbackup : id = 2, version = 11, system-id = 10000000000000110000\\nHINT: this may be a symptom of repository corruption!\""\ + "}"\ + "],"\ + "\"stanza\":\"db\","\ + "\"status\":\"error\""\ +"}" + + // Check output of verify command stored in file + TEST_STORAGE_GET(storageTest, strZ(stdoutFile), + EXPECTED_OUTPUT_JSON "\n", + .remove = true); + + /* Consume log */ + TEST_RESULT_LOG( + "P00 DETAIL: backup.info.copy does not match backup.info\n" + "P00 DETAIL: invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS' /archive.info\n" + "P00 INFO: " EXPECTED_OUTPUT_JSON + ); +#undef EXPECTED_OUTPUT_JSON + + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("backup.info and copy valid and checksums match, archive.info and copy valid, but checksum mismatch"); + + HRN_INFO_PUT( + storageRepoWrite(), INFO_BACKUP_PATH_FILE INFO_COPY_EXT, TEST_BACKUP_INFO_MULTI_HISTORY_BASE, + .comment = "valid backup.info.copy"); + HRN_INFO_PUT( + storageRepoWrite(), INFO_ARCHIVE_PATH_FILE, TEST_ARCHIVE_INFO_MULTI_HISTORY_BASE, .comment = "valid archive.info"); + + // Redirect stdout to a file + stdoutSave = dup(STDOUT_FILENO); + THROW_ON_SYS_ERROR(freopen(strZ(stdoutFile), "w", stdout) == NULL, FileWriteError, "unable to reopen stdout"); + + // Not in a test wrapper to compare stdout + cmdVerify(); + + // Restore normal stdout + dup2(stdoutSave, STDOUT_FILENO); + +#define EXPECTED_OUTPUT_JSON "{"\ + "\"errors\":["\ + "{"\ + "\"level\":5,"\ + "\"message\":\"archive.info.copy does not match archive.info\""\ + "}"\ + "],"\ + "\"stanza\":\"db\","\ + "\"status\":\"ok\""\ +"}" + + TEST_STORAGE_GET(storageTest, strZ(stdoutFile), + EXPECTED_OUTPUT_JSON "\n", + .remove = true); + + /* Consume log */ + TEST_RESULT_LOG( + "P00 DETAIL: archive.info.copy does not match archive.info\n" + "P00 INFO: " EXPECTED_OUTPUT_JSON + ); + +#undef EXPECTED_OUTPUT_JSON + + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("backup.info valid, copy invalid, archive.info valid, copy invalid"); + + HRN_STORAGE_REMOVE(storageRepoWrite(), INFO_BACKUP_PATH_FILE INFO_COPY_EXT, .comment = "remove backup.info.copy"); + HRN_STORAGE_REMOVE(storageRepoWrite(), INFO_ARCHIVE_PATH_FILE INFO_COPY_EXT, .comment = "remove archive.info.copy"); + + // Redirect stdout to a file + stdoutSave = dup(STDOUT_FILENO); + THROW_ON_SYS_ERROR(freopen(strZ(stdoutFile), "w", stdout) == NULL, FileWriteError, "unable to reopen stdout"); + + // Not in a test wrapper to compare stdout + cmdVerify(); + + // Restore normal stdout + dup2(stdoutSave, STDOUT_FILENO); + +#define EXPECTED_OUTPUT_JSON "{"\ + "\"errors\":["\ + "{"\ + "\"level\":5,"\ + "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/backup.info.copy' for read\""\ + "},"\ + "{"\ + "\"level\":5,"\ + "\"message\":\"unable to open missing file '" TEST_PATH "/repo/archive/db/archive.info.copy' for read\""\ + "}"\ + "],"\ + "\"stanza\":\"db\","\ + "\"status\":\"ok\""\ +"}" + + TEST_STORAGE_GET(storageTest, strZ(stdoutFile), + EXPECTED_OUTPUT_JSON "\n", + .remove = true); + + /* Consume log */ + TEST_RESULT_LOG( + "P00 DETAIL: unable to open missing file '" TEST_PATH "/repo/backup/db/backup.info.copy' for read\n" + "P00 DETAIL: unable to open missing file '" TEST_PATH "/repo/archive/db/archive.info.copy' for read\n" + "P00 INFO: " EXPECTED_OUTPUT_JSON + ); + +#undef EXPECTED_OUTPUT_JSON + + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("backup.info and copy missing, archive.info and copy valid"); + + hrnCfgArgRawZ(argList, cfgOptVerbose, "y"); + HRN_CFG_LOAD(cfgCmdVerify, argList); + + HRN_STORAGE_REMOVE(storageRepoWrite(), INFO_BACKUP_PATH_FILE); + HRN_INFO_PUT( + storageRepoWrite(), INFO_ARCHIVE_PATH_FILE INFO_COPY_EXT, TEST_ARCHIVE_INFO_MULTI_HISTORY_BASE, + .comment = "valid and matching archive.info.copy"); + + // Redirect stdout to a file + stdoutSave = dup(STDOUT_FILENO); + THROW_ON_SYS_ERROR(freopen(strZ(stdoutFile), "w", stdout) == NULL, FileWriteError, "unable to reopen stdout"); + + // Not in a test wrapper to compare stdout + cmdVerify(); + + // Restore normal stdout + dup2(stdoutSave, STDOUT_FILENO); + +#define EXPECTED_OUTPUT_JSON "{"\ + "\"errors\":["\ + "{"\ + "\"level\":5,"\ + "\"message\":\"unable to open missing file '/home/denis/arena/pgbackrest/test/test-0/repo/backup/db/backup.info' for read\""\ + "},"\ + "{"\ + "\"level\":5,"\ + "\"message\":\"unable to open missing file '/home/denis/arena/pgbackrest/test/test-0/repo/backup/db/backup.info.copy' for read\""\ + "},"\ + "{"\ + "\"level\":0,"\ + "\"message\":\"No usable backup.info file\""\ + "}"\ + "],"\ + "\"stanza\":\"db\","\ + "\"status\":\"error\""\ +"}" + + TEST_STORAGE_GET(storageTest, strZ(stdoutFile), + EXPECTED_OUTPUT_JSON "\n", + .remove = true); + + /* Consume log */ + TEST_RESULT_LOG( + "P00 DETAIL: unable to open missing file '" TEST_PATH "/repo/backup/db/backup.info' for read\n" + "P00 DETAIL: unable to open missing file '" TEST_PATH "/repo/backup/db/backup.info.copy' for read\n" + "P00 INFO: " EXPECTED_OUTPUT_JSON + ); +#undef EXPECTED_OUTPUT_JSON + harnessLogLevelReset(); + } + // ***************************************************************************************************************************** if (testBegin("verifyFile()")) { @@ -1018,6 +1413,80 @@ testRun(void) harnessLogLevelReset(); + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("JSON output"); + + StringList *argListJSON = strLstDup(argListBase); + hrnCfgArgRawZ(argListJSON, cfgOptOutput, "json"); + HRN_CFG_LOAD(cfgCmdVerify, argListJSON); + +#define EXPECTED_OUTPUT_JSON "{"\ + "\"archives\":["\ + "{"\ + "\"archiveId\":\"9.5-1\","\ + "\"checked\":0,"\ + "\"checksumInvalid\":0,"\ + "\"missing\":0,"\ + "\"other\":0,"\ + "\"sizeInvalid\":0,"\ + "\"valid\":0"\ + "},"\ + "{"\ + "\"archiveId\":\"11-2\","\ + "\"checked\":4,"\ + "\"checksumInvalid\":1,"\ + "\"missing\":0,"\ + "\"other\":0,"\ + "\"sizeInvalid\":1,"\ + "\"valid\":2"\ + "}"\ + "],"\ + "\"backups\":[],"\ + "\"errors\":["\ + "{"\ + "\"level\":5,"\ + "\"message\":\"no backups exist in the repo\""\ + "},"\ + "{"\ + "\"level\":5,"\ + "\"message\":\"archive path '9.5-1' is empty\""\ + "},"\ + "{"\ + "\"level\":5,"\ + "\"message\":\"path '11-2/0000000100000000' does not contain any valid WAL to be processed\""\ + "},"\ + "{"\ + "\"level\":4,"\ + "\"message\":\"invalid checksum '11-2/0000000200000007/000000020000000700000FFD-a6e1a64f0813352bc2e97f116a1800377e17d2e4.gz'\","\ + "\"pid\":1"\ + "},"\ + "{"\ + "\"level\":4,"\ + "\"message\":\"invalid size '11-2/0000000200000007/000000020000000700000FFF-ee161f898c9012dd0c28b3fd1e7140b9cf411306'\","\ + "\"pid\":1"\ + "},"\ + "{"\ + "\"level\":5,"\ + "\"message\":\"archiveId: 11-2, wal start: 000000020000000700000FFD, wal stop: 000000020000000800000000\""\ + "}"\ + "],"\ + "\"stanza\":\"db\","\ + "\"status\":\"error\""\ +"}" + + TEST_RESULT_STR_Z( + verifyProcess(cfgOptionBool(cfgOptVerbose)), + EXPECTED_OUTPUT_JSON, + "verifyProcess() json, no verbose"); + +#undef EXPECTED_OUTPUT_JSON + + TEST_RESULT_LOG( + "P01 INFO: invalid checksum" + " '11-2/0000000200000007/000000020000000700000FFD-a6e1a64f0813352bc2e97f116a1800377e17d2e4.gz'\n" + "P01 INFO: invalid size" + " '11-2/0000000200000007/000000020000000700000FFF-ee161f898c9012dd0c28b3fd1e7140b9cf411306'"); + // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("no text output, verbose, with verify failures"); @@ -1040,6 +1509,75 @@ testRun(void) "P01 INFO: invalid size" " '11-2/0000000200000007/000000020000000700000FFF-ee161f898c9012dd0c28b3fd1e7140b9cf411306'"); + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("JSON output, verbose, with verify failures"); + + hrnCfgArgRawZ(argListJSON, cfgOptVerbose, "y"); + HRN_CFG_LOAD(cfgCmdVerify, argListJSON); + + // Verify text output, verbose, with verify failures + TEST_RESULT_STR_Z( + verifyProcess(cfgOptionBool(cfgOptVerbose)), + "{"\ + "\"archives\":["\ + "{"\ + "\"archiveId\":\"9.5-1\","\ + "\"checked\":0,"\ + "\"checksumInvalid\":0,"\ + "\"missing\":0,"\ + "\"other\":0,"\ + "\"sizeInvalid\":0,"\ + "\"valid\":0"\ + "},"\ + "{"\ + "\"archiveId\":\"11-2\","\ + "\"checked\":4,"\ + "\"checksumInvalid\":1,"\ + "\"missing\":0,"\ + "\"other\":0,"\ + "\"sizeInvalid\":1,"\ + "\"valid\":2"\ + "}"\ + "],"\ + "\"backups\":[],"\ + "\"errors\":["\ + "{"\ + "\"level\":5,"\ + "\"message\":\"no backups exist in the repo\""\ + "},"\ + "{"\ + "\"level\":5,"\ + "\"message\":\"archive path '9.5-1' is empty\""\ + "},"\ + "{"\ + "\"level\":5,"\ + "\"message\":\"path '11-2/0000000100000000' does not contain any valid WAL to be processed\""\ + "},"\ + "{"\ + "\"level\":4,"\ + "\"message\":\"invalid checksum '11-2/0000000200000007/000000020000000700000FFD-a6e1a64f0813352bc2e97f116a1800377e17d2e4.gz'\","\ + "\"pid\":1"\ + "},"\ + "{"\ + "\"level\":4,"\ + "\"message\":\"invalid size '11-2/0000000200000007/000000020000000700000FFF-ee161f898c9012dd0c28b3fd1e7140b9cf411306'\","\ + "\"pid\":1"\ + "},"\ + "{"\ + "\"level\":5,"\ + "\"message\":\"archiveId: 11-2, wal start: 000000020000000700000FFD, wal stop: 000000020000000800000000\""\ + "}"\ + "],"\ + "\"stanza\":\"db\","\ + "\"status\":\"error\""\ + "}", + "JSON verbose, with failures"); + TEST_RESULT_LOG( + "P01 INFO: invalid checksum" + " '11-2/0000000200000007/000000020000000700000FFD-a6e1a64f0813352bc2e97f116a1800377e17d2e4.gz'\n" + "P01 INFO: invalid size" + " '11-2/0000000200000007/000000020000000700000FFF-ee161f898c9012dd0c28b3fd1e7140b9cf411306'"); + // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("text output, verbose, with verify failures"); @@ -1349,6 +1887,88 @@ testRun(void) " Permission denied"); } + // ***************************************************************************************************************************** + if (testBegin("cmdVerify(), verifyProcess() - errors JSON")) + { + StringList *argList = strLstDup(argListBase); + hrnCfgArgRawZ(argList, cfgOptOutput, "json"); + HRN_CFG_LOAD(cfgCmdVerify, argList); + + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("valid info files, WAL files present, no backups"); + + // Store valid archive/backup info files + HRN_INFO_PUT( + storageRepoWrite(), INFO_ARCHIVE_PATH_FILE, TEST_ARCHIVE_INFO_MULTI_HISTORY_BASE, .comment = "valid archive.info"); + HRN_INFO_PUT( + storageRepoWrite(), INFO_ARCHIVE_PATH_FILE INFO_COPY_EXT, TEST_ARCHIVE_INFO_MULTI_HISTORY_BASE, + .comment = "valid archive.info.copy"); + + #define TEST_NO_CURRENT_BACKUP \ + "[db]\n" \ + TEST_BACKUP_DB2_11 \ + "\n" \ + "[db:history]\n" \ + TEST_BACKUP_DB1_HISTORY \ + "\n" \ + TEST_BACKUP_DB2_HISTORY + + HRN_INFO_PUT(storageRepoWrite(), INFO_BACKUP_PATH_FILE, TEST_NO_CURRENT_BACKUP, .comment = "no current backups"); + + HRN_STORAGE_PATH_CREATE( + storageRepoIdxWrite(0), STORAGE_REPO_BACKUP "/20181119-152800F", .comment = "prior backup path missing manifests"); + + harnessLogLevelSet(logLevelDetail); + + TEST_RESULT_STR_Z( + verifyProcess(cfgOptionBool(cfgOptVerbose)), + "{"\ + "\"archives\":[],"\ + "\"backups\":["\ + "{"\ + "\"checked\":0,"\ + "\"checksumInvalid\":0,"\ + "\"label\":\"20181119-152800F\","\ + "\"missing\":0,"\ + "\"other\":0,"\ + "\"sizeInvalid\":0,"\ + "\"status\":\"in-progress\","\ + "\"valid\":0"\ + "}"\ + "],"\ + "\"errors\":["\ + "{"\ + "\"level\":5,"\ + "\"message\":\"unable to open missing file '/home/denis/arena/pgbackrest/test/test-0/repo/backup/db/backup.info.copy' for read\""\ + "},"\ + "{"\ + "\"level\":5,"\ + "\"message\":\"no archives exist in the repo\""\ + "},"\ + "{"\ + "\"level\":5,"\ + "\"message\":\"unable to open missing file '/home/denis/arena/pgbackrest/test/test-0/repo/backup/db/20181119-152800F/backup.manifest' for read\""\ + "},"\ + "{"\ + "\"level\":4,"\ + "\"message\":\"backup '20181119-152800F' appears to be in progress, skipping\""\ + "}"\ + "],"\ + "\"stanza\":\"db\","\ + "\"status\":\"ok\""\ + "}", + "verifyProcess() JSON missing no total file verify"); + + TEST_RESULT_LOG( + "P00 DETAIL: unable to open missing file '" TEST_PATH "/repo/backup/db/backup.info.copy' for read\n" + "P00 DETAIL: no archives exist in the repo\n" + "P00 DETAIL: unable to open missing file '" TEST_PATH "/repo/backup/db/20181119-152800F/backup.manifest' for read\n" + "P00 INFO: backup '20181119-152800F' appears to be in progress, skipping" + ); + + harnessLogLevelReset(); + } + // ***************************************************************************************************************************** if (testBegin("cmdVerify()")) { @@ -1758,6 +2378,169 @@ testRun(void) " missing: 0, checksum invalid: 1, size invalid: 0, other: 0"); } + // ***************************************************************************************************************************** + if (testBegin("cmdVerify() verbose JSON")) + { + // Load Parameters + StringList *argList = strLstDup(argListBase); + hrnCfgArgRawZ(argList, cfgOptOutput, "json"); + hrnCfgArgRawZ(argList, cfgOptVerbose, "y"); + HRN_CFG_LOAD(cfgCmdVerify, argList); + + #define TEST_BACKUP_DB1_CURRENT_FULL3_DIFF1 \ + "20181119-152900F_20181119-152909D={" \ + "\"backrest-format\":5,\"backrest-version\":\"2.08dev\"," \ + "\"backup-archive-start\":\"000000010000000000000006\",\"backup-archive-stop\":\"000000010000000000000007\"," \ + "\"backup-info-repo-size\":2369186,\"backup-info-repo-size-delta\":2369186," \ + "\"backup-info-size\":20162900,\"backup-info-size-delta\":20162900," \ + "\"backup-timestamp-start\":1542640898,\"backup-timestamp-stop\":1542640911,\"backup-type\":\"full\"," \ + "\"db-id\":1,\"option-archive-check\":true,\"option-archive-copy\":false,\"option-backup-standby\":false," \ + "\"option-checksum-page\":true,\"option-compress\":true,\"option-hardlink\":false,\"option-online\":true}\n" + + #define TEST_BACKUP_DB2_CURRENT_FULL1 \ + "20201119-163000F={" \ + "\"backrest-format\":5,\"backrest-version\":\"2.08dev\"," \ + "\"backup-archive-start\":\"000000020000000000000001\",\"backup-archive-stop\":\"000000020000000000000001\"," \ + "\"backup-info-repo-size\":2369186,\"backup-info-repo-size-delta\":2369186," \ + "\"backup-info-size\":20162900,\"backup-info-size-delta\":20162900," \ + "\"backup-timestamp-start\":1542640898,\"backup-timestamp-stop\":1542640911,\"backup-type\":\"full\"," \ + "\"db-id\":2,\"option-archive-check\":true,\"option-archive-copy\":false,\"option-backup-standby\":false," \ + "\"option-checksum-page\":true,\"option-compress\":true,\"option-hardlink\":false,\"option-online\":true}\n" + + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("prior backup verification incomplete - referenced file checked verbose, text output"); + + HRN_INFO_PUT( + storageRepoWrite(), INFO_ARCHIVE_PATH_FILE, TEST_ARCHIVE_INFO_MULTI_HISTORY_BASE, .comment = "valid archive.info"); + HRN_INFO_PUT( + storageRepoWrite(), INFO_ARCHIVE_PATH_FILE INFO_COPY_EXT, TEST_ARCHIVE_INFO_MULTI_HISTORY_BASE, + .comment = "valid archive.info.copy"); + + #define TEST_BACKUP_INFO \ + "[backup:current]\n" \ + TEST_BACKUP_DB1_CURRENT_FULL3 \ + TEST_BACKUP_DB1_CURRENT_FULL3_DIFF1 \ + TEST_BACKUP_DB2_CURRENT_FULL1 \ + "\n" \ + "[db]\n" \ + TEST_BACKUP_DB2_11 \ + "\n" \ + "[db:history]\n" \ + TEST_BACKUP_DB1_HISTORY \ + "\n" \ + TEST_BACKUP_DB2_HISTORY + + HRN_INFO_PUT(storageRepoWrite(), INFO_BACKUP_PATH_FILE, TEST_BACKUP_INFO); + HRN_INFO_PUT(storageRepoWrite(), INFO_BACKUP_PATH_FILE INFO_COPY_EXT, TEST_BACKUP_INFO); + + // Create valid full backup + #define TEST_MANIFEST_FULL_DB2 \ + TEST_MANIFEST_HEADER \ + TEST_MANIFEST_DB_94 \ + TEST_MANIFEST_OPTION_ALL \ + TEST_MANIFEST_TARGET \ + TEST_MANIFEST_DB \ + TEST_MANIFEST_FILE \ + "pg_data/biind={\"bi\":1,\"bim\":3,\"checksum\":\"ffffffffffffffffffffffffffffffffffffffff\",\"size\":4" \ + ",\"timestamp\":1565282114}\n" \ + TEST_MANIFEST_FILE_DEFAULT \ + TEST_MANIFEST_LINK \ + TEST_MANIFEST_LINK_DEFAULT \ + TEST_MANIFEST_PATH \ + TEST_MANIFEST_PATH_DEFAULT + + // Write manifests for full backup + HRN_INFO_PUT( + storageRepoWrite(), STORAGE_REPO_BACKUP "/20181119-152900F/" BACKUP_MANIFEST_FILE, TEST_MANIFEST_FULL_DB2, + .comment = "valid manifest - full"); + HRN_INFO_PUT( + storageRepoWrite(), STORAGE_REPO_BACKUP "/20181119-152900F/" BACKUP_MANIFEST_FILE INFO_COPY_EXT, TEST_MANIFEST_FULL_DB2, + .comment = "valid manifest copy - full"); + HRN_STORAGE_PUT_Z( + storageRepoWrite(), STORAGE_REPO_BACKUP "/20181119-152900F/pg_data/biind.pgbi", "ZVZV", .comment = "pgbi file"); + + // Create valid diff backup + #define TEST_MANIFEST_DIFF_DB2 \ + TEST_MANIFEST_HEADER \ + TEST_MANIFEST_DB_94 \ + TEST_MANIFEST_OPTION_ALL \ + TEST_MANIFEST_TARGET \ + TEST_MANIFEST_DB \ + "\n" \ + "[target:file]\n" \ + "pg_data/PG_VERSION={\"checksum\":\"184473f470864e067ee3a22e64b47b0a1c356f29\",\"reference\":\"20181119-152900F\"" \ + ",\"size\":4,\"timestamp\":1565282114}\n" \ + "pg_data/biind={\"bi\":1,\"bim\":3,\"checksum\":\"ffffffffffffffffffffffffffffffffffffffff\"," \ + "\"reference\":\"20181119-152900F\",\"size\":4,\"timestamp\":1565282114}\n" \ + TEST_MANIFEST_FILE_DEFAULT \ + TEST_MANIFEST_LINK \ + TEST_MANIFEST_LINK_DEFAULT \ + TEST_MANIFEST_PATH \ + TEST_MANIFEST_PATH_DEFAULT + + // Write manifests for diff backup + HRN_INFO_PUT( + storageRepoWrite(), STORAGE_REPO_BACKUP "/20181119-152900F_20181119-152909D/" BACKUP_MANIFEST_FILE, + TEST_MANIFEST_DIFF_DB2, .comment = "valid manifest - diff"); + HRN_INFO_PUT( + storageRepoWrite(), STORAGE_REPO_BACKUP "/20181119-152900F_20181119-152909D/" BACKUP_MANIFEST_FILE INFO_COPY_EXT, + TEST_MANIFEST_DIFF_DB2, .comment = "valid manifest copy - diff"); + + // Put the file referenced by both backups into the full backup + HRN_STORAGE_PUT_Z(storageRepoWrite(), STORAGE_REPO_BACKUP "/20181119-152900F/pg_data/PG_VERSION", fileContents); + + TEST_RESULT_STR_Z( + verifyProcess(cfgOptionBool(cfgOptVerbose)), + "{"\ + "\"archives\":[],"\ + "\"backups\":["\ + "{"\ + "\"checked\":2,"\ + "\"checksumInvalid\":2,"\ + "\"label\":\"20181119-152900F\","\ + "\"missing\":0,"\ + "\"other\":0,"\ + "\"sizeInvalid\":0,"\ + "\"status\":\"invalid\","\ + "\"valid\":0"\ + "},"\ + "{"\ + "\"checked\":2,"\ + "\"checksumInvalid\":1,"\ + "\"label\":\"20181119-152900F_20181119-152909D\","\ + "\"missing\":0,"\ + "\"other\":0,"\ + "\"sizeInvalid\":0,"\ + "\"status\":\"invalid\","\ + "\"valid\":1"\ + "}"\ + "],"\ + "\"errors\":["\ + "{"\ + "\"level\":5,"\ + "\"message\":\"no archives exist in the repo\""\ + "},"\ + "{"\ + "\"level\":4,"\ + "\"message\":\"invalid checksum '20181119-152900F/pg_data/PG_VERSION'\","\ + "\"pid\":1"\ + "},"\ + "{"\ + "\"level\":4,"\ + "\"message\":\"invalid checksum '20181119-152900F/pg_data/biind.pgbi'\","\ + "\"pid\":1"\ + "}"\ + "],"\ + "\"stanza\":\"db\","\ + "\"status\":\"error\""\ + "}", + "verifyProcess() verbose JSON"); + + TEST_RESULT_LOG( + "P01 INFO: invalid checksum '20181119-152900F/pg_data/PG_VERSION'\n" + "P01 INFO: invalid checksum '20181119-152900F/pg_data/biind.pgbi'"); + } + // ***************************************************************************************************************************** if (testBegin("verifyProcess(), none output, not verbose, no failures")) { From d5223674b4a29f72004413386a54ba1f73597622 Mon Sep 17 00:00:00 2001 From: Denis Kovalev Date: Fri, 18 Jul 2025 09:42:50 +0300 Subject: [PATCH 02/12] fix formatting and add arguments check --- src/command/verify/verify.c | 38 ++-- test/src/module/command/verifyTest.c | 322 +++++++++++++-------------- 2 files changed, 176 insertions(+), 184 deletions(-) diff --git a/src/command/verify/verify.c b/src/command/verify/verify.c index 177f64de35..d82b184f21 100644 --- a/src/command/verify/verify.c +++ b/src/command/verify/verify.c @@ -21,6 +21,7 @@ Verify contents of the repository. #include "common/io/io.h" #include "common/log.h" #include "common/regExp.h" +#include "common/type/json.h" #include "config/config.h" #include "info/infoArchive.h" #include "info/infoBackup.h" @@ -30,7 +31,6 @@ Verify contents of the repository. #include "protocol/helper.h" #include "protocol/parallel.h" #include "storage/helper.h" -#include "common/type/json.h" /*********************************************************************************************************************************** Constants @@ -154,18 +154,17 @@ typedef struct VerifyJobData bool enableArchiveFilter; // Only check archives in the specified range const String *archiveStart; // Start of the WAL range to be verified const String *archiveStop; // End of the WAL range to be verified - VariantList *errorList; // List of errors that occurred during the job + VariantList *errorList; // List of errors that occurred during the job } VerifyJobData; /*********************************************************************************************************************************** Helper function to add a string with log level to an error list ***********************************************************************************************************************************/ - static void verifyErrorNew(VariantList *errorList, const LogLevel logLevel, const String *const message) { FUNCTION_TEST_BEGIN(); - FUNCTION_TEST_PARAM(VARIANT_LIST, errorList); + FUNCTION_TEST_PARAM(VARIANT_LIST, errorList); // Error list to add to FUNCTION_LOG_PARAM(ENUM, logLevel); // Log level FUNCTION_TEST_PARAM(STRING, message); // Error message FUNCTION_TEST_END(); @@ -197,14 +196,13 @@ verifyErrorNew(VariantList *errorList, const LogLevel logLevel, const String *co /********************************************************************************************************************************** Helper function to add a string with log level and process id to an error list ***********************************************************************************************************************************/ - static void verifyErrorPidNew(VariantList *errorList, const LogLevel logLevel, const unsigned int pid, const String *const message) { FUNCTION_TEST_BEGIN(); FUNCTION_TEST_PARAM(VARIANT_LIST, errorList); - FUNCTION_LOG_PARAM(ENUM, logLevel); // Log level - FUNCTION_TEST_PARAM(UINT, pid); // Process id + FUNCTION_LOG_PARAM(ENUM, logLevel); // Log level + FUNCTION_TEST_PARAM(UINT, pid); // Process id FUNCTION_TEST_PARAM(STRING, message); // Error message FUNCTION_TEST_END(); @@ -387,9 +385,7 @@ verifyArchiveInfoFile(VariantList *const errorList) // If the info and info.copy checksums don't match each other than one (or both) of the files could be corrupt so // log a warning but must trust main if (!strEq(verifyArchiveInfo.checksum, verifyArchiveInfoCopy.checksum)) - { verifyErrorNew(errorList, logLevelDetail, strNewZ("archive.info.copy does not match archive.info")); - } } } else @@ -445,9 +441,7 @@ verifyBackupInfoFile(VariantList *const errorList) // If the info and info.copy checksums don't match each other than one (or both) of the files could be corrupt so // log a warning but must trust main if (!strEq(verifyBackupInfo.checksum, verifyBackupInfoCopy.checksum)) - { verifyErrorNew(errorList, logLevelDetail, strNewZ("backup.info.copy does not match backup.info")); - } } } else @@ -664,6 +658,7 @@ verifyCreateArchiveIdRange( FUNCTION_TEST_PARAM_P(VERIFY_ARCHIVE_RESULT, archiveIdResult); // The result set for the archive Id being processed FUNCTION_TEST_PARAM(STRING_LIST, walFileList); // Sorted (ascending) list of WAL files in a timeline FUNCTION_TEST_PARAM_P(UINT, jobErrorTotal); // Pointer to the overall job error total + FUNCTION_TEST_PARAM(VARIANT_LIST, errorList); // List of errors that occurred during the job FUNCTION_TEST_END(); FUNCTION_AUDIT_HELPER(); @@ -1396,7 +1391,6 @@ verifyLogInvalidResult( FUNCTION_TEST_RETURN(UINT, 0); } - MEM_CONTEXT_TEMP_BEGIN(); { String *errorMsg = strNewFmt("%s '%s'", verifyErrorMsg(verifyResult), strZ(filePathName)); @@ -1421,6 +1415,7 @@ verifySetBackupCheckArchive( FUNCTION_TEST_PARAM(STRING_LIST, archiveIdList); // List of archiveIds in the archive directory FUNCTION_TEST_PARAM(INFO_PG, pgHistory); // Pointer to InfoPg of archive.info for accessing PG history FUNCTION_TEST_PARAM_P(UINT, jobErrorTotal); // Pointer to overall job error total + FUNCTION_TEST_PARAM(VARIANT_LIST, errorList); // List of errors that occurred during the job FUNCTION_TEST_END(); String *result = NULL; @@ -1568,6 +1563,7 @@ verifyRender(const List *const archiveIdResultList, const List *const backupResu FUNCTION_TEST_PARAM(LIST, backupResultList); // Result list for all backups in the repo FUNCTION_TEST_PARAM(BOOL, verboseText); // Is verbose output requested? FUNCTION_TEST_PARAM(KEY_VALUE, jsonKv); // Is JSON output requested? + FUNCTION_TEST_PARAM(VARIANT_LIST, errorList); // List of errors that occurred during the job FUNCTION_TEST_END(); FUNCTION_AUDIT_HELPER(); @@ -1587,9 +1583,7 @@ verifyRender(const List *const archiveIdResultList, const List *const backupResu } if (jsonKv == NULL && verboseText && lstEmpty(archiveIdResultList)) - { strCatZ(result, "\n archiveId: none found"); - } else { for (unsigned int archiveIdx = 0; archiveIdx < lstSize(archiveIdResultList); archiveIdx++) @@ -1606,11 +1600,9 @@ verifyRender(const List *const archiveIdResultList, const List *const backupResu kvPut(archiveKv, KEY_VALID_VAR, VARUINT(archiveIdResult->totalValidWal)); } else - { strCatFmt( result, "\n archiveId: %s, total WAL checked: %u, total valid WAL: %u", strZ(archiveIdResult->archiveId), archiveIdResult->totalWalFile, archiveIdResult->totalValidWal); - } } unsigned int errMissing = 0; @@ -1721,7 +1713,6 @@ verifyRender(const List *const archiveIdResultList, const List *const backupResu if (backupResult->totalFileVerify > 0) { - for (unsigned int invalidIdx = 0; invalidIdx < lstSize(backupResult->invalidFileList); invalidIdx++) { const VerifyInvalidFile *const invalidFile = lstGet(backupResult->invalidFileList, invalidIdx); @@ -1777,13 +1768,13 @@ verifyProcess(const bool verboseText) FUNCTION_LOG_END(); String *const result = strNew(); - KeyValue * resultKv = NULL; bool json = cfgOptionStrId(cfgOptOutput) == CFGOPTVAL_OUTPUT_JSON; MEM_CONTEXT_TEMP_BEGIN() { unsigned int errorTotal = 0; String *resultStr = strNew(); + KeyValue *resultKv = NULL; VariantList *errorList = varLstNew(); // Get the repo storage in case it is remote and encryption settings need to be pulled down @@ -1792,9 +1783,8 @@ verifyProcess(const bool verboseText) // Get a usable backup info file const InfoBackup *const backupInfo = verifyBackupInfoFile(errorList); - if (json) { + if (json) resultKv = kvNew(); - } // If a usable backup.info file is not found, then report an error in the log if (backupInfo == NULL) @@ -1898,7 +1888,7 @@ verifyProcess(const bool verboseText) { // Warn if there are no archives or there are no backups in the repo so that the callback need not try to // distinguish between having processed all of the list or if the list was missing in the first place - if (strLstEmpty(jobData.archiveIdList) || strLstEmpty(jobData.backupList)) { + if (strLstEmpty(jobData.archiveIdList) || strLstEmpty(jobData.backupList)){ String *errorMsg = strNewFmt("no %s exist in the repo", strLstEmpty(jobData.archiveIdList) ? "archives" : "backups"); verifyErrorNew(errorList, logLevelDetail, errorMsg); } @@ -2060,14 +2050,16 @@ verifyProcess(const bool verboseText) kvPut(resultKv, KEY_ERRORS_VAR, varNewVarLst(errorList)); strCat(result, jsonFromVar(varNewKv(resultKv))); - } else { + } + else + { for (unsigned int errIdx = 0; errIdx < varLstSize(errorList); errIdx++) { const KeyValue *const msg = varKv(varLstGet(errorList, errIdx)); const LogLevel logLevel = (LogLevel)varUInt(kvGet(msg, VERIFY_MSG_KEY_LEVEL)); // Print messages which did not got logged yet - if (logLevel == logLevelOff) { + if (logLevel == logLevelOff){ const String *const message = varStr(kvGet(msg, VERIFY_MSG_KEY_MESSAGE)); strCatFmt(resultStr, "\n %s", strZ(message)); } diff --git a/test/src/module/command/verifyTest.c b/test/src/module/command/verifyTest.c index f765f31698..d84483f9c6 100644 --- a/test/src/module/command/verifyTest.c +++ b/test/src/module/command/verifyTest.c @@ -263,17 +263,17 @@ testRun(void) TEST_RESULT_UINT(varLstSize(errorList), 2, "error list size"); TEST_RESULT_STR(jsonFromVar(varNewVarLst(errorList)), STR("[" - "{" - "\"level\":5," - "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/20181119-152138F/backup.manifest.copy' for read\"" - "}," - "{" - "\"level\":4," - "\"message\":\"'20181119-152138F' may not be recoverable - PG data (id 1, version 9.6, system-id " HRN_PG_SYSTEMID_95_Z ") is not in the backup.info history, skipping\"" - "}" - "]"), - "errorList does not match" - ); + "{" + "\"level\":5," + "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/20181119-152138F/backup.manifest.copy' for read\"" + "}," + "{" + "\"level\":4," + "\"message\":\"'20181119-152138F' may not be recoverable - PG data (id 1, version 9.6, system-id " HRN_PG_SYSTEMID_95_Z ") is not in the backup.info history, skipping\"" + "}" + "]"), + "errorList does not match" + ); TEST_RESULT_LOG( "P00 DETAIL: unable to open missing file '" TEST_PATH "/repo/backup/db/20181119-152138F/backup.manifest.copy'" @@ -952,7 +952,7 @@ testRun(void) // Restore normal stdout dup2(stdoutSave, STDOUT_FILENO); -#define EXPECTED_OUTPUT_JSON "{" \ + #define EXPECTED_OUTPUT_JSON "{"\ "\"errors\":[" \ "{"\ "\"level\":5,"\ @@ -980,8 +980,8 @@ testRun(void) // Check output of verify command stored in file TEST_STORAGE_GET(storageTest, strZ(stdoutFile), - EXPECTED_OUTPUT_JSON "\n", - .remove = true); + EXPECTED_OUTPUT_JSON "\n", + .remove = true); TEST_RESULT_LOG( "P00 DETAIL: invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS'" @@ -990,7 +990,7 @@ testRun(void) "P00 DETAIL: unable to open missing file '" TEST_PATH "/repo/archive/db/archive.info' for read\n" "P00 DETAIL: unable to open missing file '" TEST_PATH "/repo/archive/db/archive.info.copy' for read\n" "P00 INFO: " EXPECTED_OUTPUT_JSON - ); + ); #undef EXPECTED_OUTPUT_JSON // ------------------------------------------------------------------------------------------------------------------------- @@ -1021,7 +1021,7 @@ testRun(void) // Restore normal stdout dup2(stdoutSave, STDOUT_FILENO); -#define EXPECTED_OUTPUT_JSON "{"\ + #define EXPECTED_OUTPUT_JSON "{"\ "\"errors\":["\ "{"\ "\"level\":5,"\ @@ -1041,7 +1041,7 @@ testRun(void) // Check output of verify command stored in file TEST_STORAGE_GET(storageTest, strZ(stdoutFile), - EXPECTED_OUTPUT_JSON "\n", + EXPECTED_OUTPUT_JSON "\n", .remove = true); /* Consume log */ @@ -1052,7 +1052,7 @@ testRun(void) "P00 DETAIL: invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS'" " /archive.info.copy\n" "P00 INFO: " EXPECTED_OUTPUT_JSON - ); + ); #undef EXPECTED_OUTPUT_JSON // ------------------------------------------------------------------------------------------------------------------------- @@ -1075,7 +1075,7 @@ testRun(void) // Restore normal stdout dup2(stdoutSave, STDOUT_FILENO); -#define EXPECTED_OUTPUT_JSON "{"\ + #define EXPECTED_OUTPUT_JSON "{"\ "\"errors\":["\ "{"\ "\"level\":5,"\ @@ -1093,7 +1093,7 @@ testRun(void) // Check output of verify command stored in file TEST_STORAGE_GET(storageTest, strZ(stdoutFile), - EXPECTED_OUTPUT_JSON "\n", + EXPECTED_OUTPUT_JSON "\n", .remove = true); /* Consume log */ @@ -1123,7 +1123,7 @@ testRun(void) // Restore normal stdout dup2(stdoutSave, STDOUT_FILENO); -#define EXPECTED_OUTPUT_JSON "{"\ + #define EXPECTED_OUTPUT_JSON "{"\ "\"errors\":["\ "{"\ "\"level\":5,"\ @@ -1135,14 +1135,14 @@ testRun(void) "}" TEST_STORAGE_GET(storageTest, strZ(stdoutFile), - EXPECTED_OUTPUT_JSON "\n", + EXPECTED_OUTPUT_JSON "\n", .remove = true); /* Consume log */ TEST_RESULT_LOG( "P00 DETAIL: archive.info.copy does not match archive.info\n" "P00 INFO: " EXPECTED_OUTPUT_JSON - ); + ); #undef EXPECTED_OUTPUT_JSON @@ -1162,7 +1162,7 @@ testRun(void) // Restore normal stdout dup2(stdoutSave, STDOUT_FILENO); -#define EXPECTED_OUTPUT_JSON "{"\ + #define EXPECTED_OUTPUT_JSON "{"\ "\"errors\":["\ "{"\ "\"level\":5,"\ @@ -1178,7 +1178,7 @@ testRun(void) "}" TEST_STORAGE_GET(storageTest, strZ(stdoutFile), - EXPECTED_OUTPUT_JSON "\n", + EXPECTED_OUTPUT_JSON "\n", .remove = true); /* Consume log */ @@ -1211,15 +1211,15 @@ testRun(void) // Restore normal stdout dup2(stdoutSave, STDOUT_FILENO); -#define EXPECTED_OUTPUT_JSON "{"\ + #define EXPECTED_OUTPUT_JSON "{"\ "\"errors\":["\ "{"\ "\"level\":5,"\ - "\"message\":\"unable to open missing file '/home/denis/arena/pgbackrest/test/test-0/repo/backup/db/backup.info' for read\""\ + "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/backup.info' for read\""\ "},"\ "{"\ "\"level\":5,"\ - "\"message\":\"unable to open missing file '/home/denis/arena/pgbackrest/test/test-0/repo/backup/db/backup.info.copy' for read\""\ + "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/backup.info.copy' for read\""\ "},"\ "{"\ "\"level\":0,"\ @@ -1231,7 +1231,7 @@ testRun(void) "}" TEST_STORAGE_GET(storageTest, strZ(stdoutFile), - EXPECTED_OUTPUT_JSON "\n", + EXPECTED_OUTPUT_JSON "\n", .remove = true); /* Consume log */ @@ -1239,7 +1239,7 @@ testRun(void) "P00 DETAIL: unable to open missing file '" TEST_PATH "/repo/backup/db/backup.info' for read\n" "P00 DETAIL: unable to open missing file '" TEST_PATH "/repo/backup/db/backup.info.copy' for read\n" "P00 INFO: " EXPECTED_OUTPUT_JSON - ); + ); #undef EXPECTED_OUTPUT_JSON harnessLogLevelReset(); } @@ -1420,7 +1420,7 @@ testRun(void) hrnCfgArgRawZ(argListJSON, cfgOptOutput, "json"); HRN_CFG_LOAD(cfgCmdVerify, argListJSON); -#define EXPECTED_OUTPUT_JSON "{"\ + #define EXPECTED_OUTPUT_JSON "{"\ "\"archives\":["\ "{"\ "\"archiveId\":\"9.5-1\","\ @@ -1476,7 +1476,7 @@ testRun(void) TEST_RESULT_STR_Z( verifyProcess(cfgOptionBool(cfgOptVerbose)), - EXPECTED_OUTPUT_JSON, + EXPECTED_OUTPUT_JSON, "verifyProcess() json, no verbose"); #undef EXPECTED_OUTPUT_JSON @@ -1518,58 +1518,58 @@ testRun(void) // Verify text output, verbose, with verify failures TEST_RESULT_STR_Z( verifyProcess(cfgOptionBool(cfgOptVerbose)), - "{"\ - "\"archives\":["\ - "{"\ - "\"archiveId\":\"9.5-1\","\ - "\"checked\":0,"\ - "\"checksumInvalid\":0,"\ - "\"missing\":0,"\ - "\"other\":0,"\ - "\"sizeInvalid\":0,"\ - "\"valid\":0"\ - "},"\ - "{"\ - "\"archiveId\":\"11-2\","\ - "\"checked\":4,"\ - "\"checksumInvalid\":1,"\ - "\"missing\":0,"\ - "\"other\":0,"\ - "\"sizeInvalid\":1,"\ - "\"valid\":2"\ - "}"\ - "],"\ - "\"backups\":[],"\ - "\"errors\":["\ - "{"\ - "\"level\":5,"\ - "\"message\":\"no backups exist in the repo\""\ - "},"\ - "{"\ - "\"level\":5,"\ - "\"message\":\"archive path '9.5-1' is empty\""\ - "},"\ - "{"\ - "\"level\":5,"\ - "\"message\":\"path '11-2/0000000100000000' does not contain any valid WAL to be processed\""\ - "},"\ - "{"\ - "\"level\":4,"\ - "\"message\":\"invalid checksum '11-2/0000000200000007/000000020000000700000FFD-a6e1a64f0813352bc2e97f116a1800377e17d2e4.gz'\","\ - "\"pid\":1"\ - "},"\ - "{"\ - "\"level\":4,"\ - "\"message\":\"invalid size '11-2/0000000200000007/000000020000000700000FFF-ee161f898c9012dd0c28b3fd1e7140b9cf411306'\","\ - "\"pid\":1"\ - "},"\ - "{"\ - "\"level\":5,"\ - "\"message\":\"archiveId: 11-2, wal start: 000000020000000700000FFD, wal stop: 000000020000000800000000\""\ - "}"\ - "],"\ - "\"stanza\":\"db\","\ - "\"status\":\"error\""\ + "{" \ + "\"archives\":[" \ + "{" \ + "\"archiveId\":\"9.5-1\"," \ + "\"checked\":0," \ + "\"checksumInvalid\":0," \ + "\"missing\":0," \ + "\"other\":0," \ + "\"sizeInvalid\":0," \ + "\"valid\":0" \ + "}," \ + "{" \ + "\"archiveId\":\"11-2\"," \ + "\"checked\":4," \ + "\"checksumInvalid\":1," \ + "\"missing\":0," \ + "\"other\":0," \ + "\"sizeInvalid\":1," \ + "\"valid\":2" \ + "}" \ + "]," \ + "\"backups\":[]," \ + "\"errors\":[" \ + "{" \ + "\"level\":5," \ + "\"message\":\"no backups exist in the repo\"" \ + "}," \ + "{" \ + "\"level\":5," \ + "\"message\":\"archive path '9.5-1' is empty\"" \ + "}," \ + "{" \ + "\"level\":5," \ + "\"message\":\"path '11-2/0000000100000000' does not contain any valid WAL to be processed\"" \ + "}," \ + "{" \ + "\"level\":4," \ + "\"message\":\"invalid checksum '11-2/0000000200000007/000000020000000700000FFD-a6e1a64f0813352bc2e97f116a1800377e17d2e4.gz'\"," \ + "\"pid\":1" \ + "}," \ + "{" \ + "\"level\":4," \ + "\"message\":\"invalid size '11-2/0000000200000007/000000020000000700000FFF-ee161f898c9012dd0c28b3fd1e7140b9cf411306'\"," \ + "\"pid\":1" \ + "}," \ + "{" \ + "\"level\":5," \ + "\"message\":\"archiveId: 11-2, wal start: 000000020000000700000FFD, wal stop: 000000020000000800000000\"" \ + "}" \ + "]," \ + "\"stanza\":\"db\"," \ + "\"status\":\"error\"" \ "}", "JSON verbose, with failures"); TEST_RESULT_LOG( @@ -1922,41 +1922,41 @@ testRun(void) TEST_RESULT_STR_Z( verifyProcess(cfgOptionBool(cfgOptVerbose)), - "{"\ - "\"archives\":[],"\ - "\"backups\":["\ - "{"\ - "\"checked\":0,"\ - "\"checksumInvalid\":0,"\ - "\"label\":\"20181119-152800F\","\ - "\"missing\":0,"\ - "\"other\":0,"\ - "\"sizeInvalid\":0,"\ - "\"status\":\"in-progress\","\ - "\"valid\":0"\ - "}"\ - "],"\ - "\"errors\":["\ - "{"\ - "\"level\":5,"\ - "\"message\":\"unable to open missing file '/home/denis/arena/pgbackrest/test/test-0/repo/backup/db/backup.info.copy' for read\""\ - "},"\ - "{"\ - "\"level\":5,"\ - "\"message\":\"no archives exist in the repo\""\ - "},"\ - "{"\ - "\"level\":5,"\ - "\"message\":\"unable to open missing file '/home/denis/arena/pgbackrest/test/test-0/repo/backup/db/20181119-152800F/backup.manifest' for read\""\ - "},"\ - "{"\ - "\"level\":4,"\ - "\"message\":\"backup '20181119-152800F' appears to be in progress, skipping\""\ - "}"\ - "],"\ - "\"stanza\":\"db\","\ - "\"status\":\"ok\""\ - "}", + "{" \ + "\"archives\":[]," \ + "\"backups\":[" \ + "{" \ + "\"checked\":0," \ + "\"checksumInvalid\":0," \ + "\"label\":\"20181119-152800F\"," \ + "\"missing\":0," \ + "\"other\":0," \ + "\"sizeInvalid\":0," \ + "\"status\":\"in-progress\"," \ + "\"valid\":0" \ + "}" \ + "]," \ + "\"errors\":[" \ + "{" \ + "\"level\":5," \ + "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/backup.info.copy' for read\"" \ + "}," \ + "{" \ + "\"level\":5," \ + "\"message\":\"no archives exist in the repo\"" \ + "}," \ + "{" \ + "\"level\":5," \ + "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/20181119-152800F/backup.manifest' for read\"" \ + "}," \ + "{" \ + "\"level\":4," \ + "\"message\":\"backup '20181119-152800F' appears to be in progress, skipping\"" \ + "}" \ + "]," \ + "\"stanza\":\"db\"," \ + "\"status\":\"ok\"" \ + "}", "verifyProcess() JSON missing no total file verify"); TEST_RESULT_LOG( @@ -2491,48 +2491,48 @@ testRun(void) TEST_RESULT_STR_Z( verifyProcess(cfgOptionBool(cfgOptVerbose)), - "{"\ - "\"archives\":[],"\ - "\"backups\":["\ - "{"\ - "\"checked\":2,"\ - "\"checksumInvalid\":2,"\ - "\"label\":\"20181119-152900F\","\ - "\"missing\":0,"\ - "\"other\":0,"\ - "\"sizeInvalid\":0,"\ - "\"status\":\"invalid\","\ - "\"valid\":0"\ - "},"\ - "{"\ - "\"checked\":2,"\ - "\"checksumInvalid\":1,"\ - "\"label\":\"20181119-152900F_20181119-152909D\","\ - "\"missing\":0,"\ - "\"other\":0,"\ - "\"sizeInvalid\":0,"\ - "\"status\":\"invalid\","\ - "\"valid\":1"\ - "}"\ - "],"\ - "\"errors\":["\ - "{"\ - "\"level\":5,"\ - "\"message\":\"no archives exist in the repo\""\ - "},"\ - "{"\ - "\"level\":4,"\ - "\"message\":\"invalid checksum '20181119-152900F/pg_data/PG_VERSION'\","\ - "\"pid\":1"\ - "},"\ - "{"\ - "\"level\":4,"\ - "\"message\":\"invalid checksum '20181119-152900F/pg_data/biind.pgbi'\","\ - "\"pid\":1"\ - "}"\ - "],"\ - "\"stanza\":\"db\","\ - "\"status\":\"error\""\ + "{" \ + "\"archives\":[]," \ + "\"backups\":[" \ + "{" \ + "\"checked\":2," \ + "\"checksumInvalid\":2," \ + "\"label\":\"20181119-152900F\"," \ + "\"missing\":0," \ + "\"other\":0," \ + "\"sizeInvalid\":0," \ + "\"status\":\"invalid\"," \ + "\"valid\":0" \ + "}," \ + "{" \ + "\"checked\":2," \ + "\"checksumInvalid\":1," \ + "\"label\":\"20181119-152900F_20181119-152909D\"," \ + "\"missing\":0," \ + "\"other\":0," \ + "\"sizeInvalid\":0," \ + "\"status\":\"invalid\"," \ + "\"valid\":1" \ + "}" \ + "]," \ + "\"errors\":[" \ + "{" \ + "\"level\":5," \ + "\"message\":\"no archives exist in the repo\"" \ + "}," \ + "{" \ + "\"level\":4," \ + "\"message\":\"invalid checksum '20181119-152900F/pg_data/PG_VERSION'\"," \ + "\"pid\":1" \ + "}," \ + "{" \ + "\"level\":4," \ + "\"message\":\"invalid checksum '20181119-152900F/pg_data/biind.pgbi'\"," \ + "\"pid\":1" \ + "}" \ + "]," \ + "\"stanza\":\"db\"," \ + "\"status\":\"error\"" \ "}", "verifyProcess() verbose JSON"); From 160e78bd50a361a9b42a679b5233df4425f90703 Mon Sep 17 00:00:00 2001 From: Denis Kovalev Date: Wed, 23 Jul 2025 08:18:46 +0300 Subject: [PATCH 03/12] refactor and completely split collection and printing --- src/command/verify/verify.c | 358 +++++++++++++++++++-------- test/src/module/command/verifyTest.c | 81 +++--- 2 files changed, 304 insertions(+), 135 deletions(-) diff --git a/src/command/verify/verify.c b/src/command/verify/verify.c index d82b184f21..5a46156e1d 100644 --- a/src/command/verify/verify.c +++ b/src/command/verify/verify.c @@ -44,6 +44,7 @@ VARIANT_STRDEF_STATIC(ARCHIVE_KEY_ARCHIVEID_VAR, "archiveId"); VARIANT_STRDEF_STATIC(ARCHIVE_KEY_CHECKED_VAR, "checked"); VARIANT_STRDEF_STATIC(KEY_VALID_VAR, "valid"); VARIANT_STRDEF_STATIC(KEY_MISSING_VAR, "missing"); +VARIANT_STRDEF_STATIC(KEY_FILEERRORS_VAR, "fileErrors"); VARIANT_STRDEF_STATIC(KEY_CHECKSUMINVALID_VAR, "checksumInvalid"); VARIANT_STRDEF_STATIC(KEY_SIZEINVALID_VAR, "sizeInvalid"); VARIANT_STRDEF_STATIC(KEY_OTHER_VAR, "other"); @@ -57,6 +58,7 @@ VARIANT_STRDEF_STATIC(VERIFY_KEY_STATUS_ERROR, "error"); VARIANT_STRDEF_STATIC(VERIFY_KEY_STATUS_OK, "ok"); VARIANT_STRDEF_STATIC(VERIFY_MSG_KEY_LEVEL, "level"); VARIANT_STRDEF_STATIC(VERIFY_MSG_KEY_MESSAGE, "message"); +VARIANT_STRDEF_STATIC(VERIFY_MSG_KEY_MESSAGE_PRINT, "whenPrint"); VARIANT_STRDEF_STATIC(VERIFY_MSG_KEY_PID, "pid"); /*********************************************************************************************************************************** @@ -72,6 +74,19 @@ Data Types and Structures #define FUNCTION_LOG_VERIFY_BACKUP_RESULT_FORMAT(value, buffer, bufferSize) \ objNameToLog(&value, "VerifyBackupResult", buffer, bufferSize) +#define FUNCTION_LOG_VERIFY_MESSAGE_PRINT_TYPE \ + VerifyMessagePrint +#define FUNCTION_LOG_VERIFY_MESSAGE_PRINT_FORMAT(value, buffer, bufferSize) \ + objNameToLog(&value, "VerifyMessagePrint", buffer, bufferSize) + + +typedef enum VerifyMessagePrint +{ + printNever, + printAtVerbose, + printAlways +} VerifyMessagePrint; + // Structure for verifying repository info files typedef struct VerifyInfoFile { @@ -175,16 +190,13 @@ verifyErrorNew(VariantList *errorList, const LogLevel logLevel, const String *co MEM_CONTEXT_BEGIN(lstMemContext((List *)errorList)) { - KeyValue *const errorMsg = kvNew(); + KeyValue *errorMsg = kvNew(); kvPut(errorMsg, VERIFY_MSG_KEY_LEVEL, VARUINT(logLevel)); kvPut(errorMsg, VERIFY_MSG_KEY_MESSAGE, VARSTR(strDup(message))); varLstAdd(errorList, varNewKv(errorMsg)); - } - if (logLevel != logLevelOff) - { LOG(logLevel, 0, strZ(message)); } @@ -226,6 +238,37 @@ verifyErrorPidNew(VariantList *errorList, const LogLevel logLevel, const unsigne FUNCTION_TEST_RETURN_VOID(); } +/*********************************************************************************************************************************** +Helper function to add a message going to stdout to the message list. +***********************************************************************************************************************************/ +static void +verifyMessageNew(VariantList *messageList, const VerifyMessagePrint whenToPrint, const String *const message) +{ + FUNCTION_TEST_BEGIN(); + FUNCTION_TEST_PARAM(VARIANT_LIST, messageList); // Error list to add to + FUNCTION_LOG_PARAM(VERIFY_MESSAGE_PRINT, whenToPrint); // When this message should be rendered to text + FUNCTION_TEST_PARAM(STRING, message); // Error message + FUNCTION_TEST_END(); + + FUNCTION_AUDIT_HELPER(); + + ASSERT(message != NULL); + + MEM_CONTEXT_BEGIN(lstMemContext((List *)messageList)) + { + KeyValue *const errorMsg = kvNew(); + + kvPut(errorMsg, VERIFY_MSG_KEY_MESSAGE_PRINT, VARUINT(whenToPrint)); + kvPut(errorMsg, VERIFY_MSG_KEY_MESSAGE, VARSTR(strDup(message))); + + varLstAdd(messageList, varNewKv(errorMsg)); + } + + MEM_CONTEXT_END(); + + FUNCTION_TEST_RETURN_VOID(); +} + /*********************************************************************************************************************************** Helper function to add a file to an invalid file list ***********************************************************************************************************************************/ @@ -1552,18 +1595,41 @@ verifyCreateFileErrorsStr( FUNCTION_TEST_RETURN(STRING, result); } +/*********************************************************************************************************************************** +Create file errors KV +***********************************************************************************************************************************/ +static KeyValue * +verifyCreateFileErrorsKv( + const unsigned int errMissing, const unsigned int errChecksum, const unsigned int errSize, const unsigned int errOther) +{ + FUNCTION_TEST_BEGIN(); + FUNCTION_TEST_PARAM(UINT, errMissing); // Number of files missing + FUNCTION_TEST_PARAM(UINT, errChecksum); // Number of files with checksum errors + FUNCTION_TEST_PARAM(UINT, errSize); // Number of files with invalid size + FUNCTION_TEST_PARAM(UINT, errOther); // Number of files with other errors + FUNCTION_TEST_END(); + + + KeyValue *const result = kvNew(); + + kvPut(result, KEY_MISSING_VAR, VARUINT(errMissing)); + kvPut(result, KEY_CHECKSUMINVALID_VAR, VARUINT(errChecksum)); + kvPut(result, KEY_SIZEINVALID_VAR, VARUINT(errSize)); + kvPut(result, KEY_OTHER_VAR, VARUINT(errOther)); + + FUNCTION_TEST_RETURN(KEY_VALUE, result); +} + /*********************************************************************************************************************************** Render the results of the verify command ***********************************************************************************************************************************/ -static String * -verifyRender(const List *const archiveIdResultList, const List *const backupResultList, const bool verboseText, KeyValue *const jsonKv, VariantList *const errorList) +static KeyValue * +verifyPrepareResult(const List *const archiveIdResultList, const List *const backupResultList, bool verboseText) { FUNCTION_TEST_BEGIN(); FUNCTION_TEST_PARAM(LIST, archiveIdResultList); // Result list for all archive Ids in the repo FUNCTION_TEST_PARAM(LIST, backupResultList); // Result list for all backups in the repo FUNCTION_TEST_PARAM(BOOL, verboseText); // Is verbose output requested? - FUNCTION_TEST_PARAM(KEY_VALUE, jsonKv); // Is JSON output requested? - FUNCTION_TEST_PARAM(VARIANT_LIST, errorList); // List of errors that occurred during the job FUNCTION_TEST_END(); FUNCTION_AUDIT_HELPER(); @@ -1571,40 +1637,38 @@ verifyRender(const List *const archiveIdResultList, const List *const backupResu ASSERT(archiveIdResultList != NULL); ASSERT(backupResultList != NULL); - String *const result = strNew(); + KeyValue *resultKv = kvNew(); - // Render archive results - VariantList *archivesList = NULL; - VariantList *backupsList = NULL; - if (jsonKv != NULL) - { - archivesList = varLstNew(); - backupsList = varLstNew(); - } + // Prepare archive results + VariantList *archivesList = varLstNew(); + VariantList *backupsList = varLstNew(); + VariantList *errorList = varLstNew(); - if (jsonKv == NULL && verboseText && lstEmpty(archiveIdResultList)) - strCatZ(result, "\n archiveId: none found"); + if (lstEmpty(archiveIdResultList)) + verifyMessageNew(errorList, printAtVerbose, strNewZ("archiveId: none found")); else { for (unsigned int archiveIdx = 0; archiveIdx < lstSize(archiveIdResultList); archiveIdx++) { const VerifyArchiveResult *const archiveIdResult = lstGet(archiveIdResultList, archiveIdx); - KeyValue *const archiveKv = ((archivesList == NULL) ? NULL : kvNew()); + KeyValue *const archiveKv = kvNew(); + + // Prepare the message + String * archiveMessage = NULL; + + kvPut(archiveKv, ARCHIVE_KEY_ARCHIVEID_VAR, VARSTR(archiveIdResult->archiveId)); + kvPut(archiveKv, ARCHIVE_KEY_CHECKED_VAR, VARUINT(archiveIdResult->totalWalFile)); + kvPut(archiveKv, KEY_VALID_VAR, VARUINT(archiveIdResult->totalValidWal)); - if (verboseText || jsonKv != NULL || archiveIdResult->totalWalFile - archiveIdResult->totalValidWal != 0) + if (verboseText || archiveIdResult->totalWalFile - archiveIdResult->totalValidWal != 0) { - if (archiveKv != NULL) - { - kvPut(archiveKv, ARCHIVE_KEY_ARCHIVEID_VAR, VARSTR(archiveIdResult->archiveId)); - kvPut(archiveKv, ARCHIVE_KEY_CHECKED_VAR, VARUINT(archiveIdResult->totalWalFile)); - kvPut(archiveKv, KEY_VALID_VAR, VARUINT(archiveIdResult->totalValidWal)); - } - else - strCatFmt( - result, "\n archiveId: %s, total WAL checked: %u, total valid WAL: %u", strZ(archiveIdResult->archiveId), - archiveIdResult->totalWalFile, archiveIdResult->totalValidWal); + archiveMessage = strNew(); + strCatFmt(archiveMessage, + "archiveId: %s, total WAL checked: %u, total valid WAL: %u", strZ(archiveIdResult->archiveId), + archiveIdResult->totalWalFile, archiveIdResult->totalValidWal); } + unsigned int errMissing = 0; unsigned int errChecksum = 0; unsigned int errSize = 0; @@ -1640,34 +1704,41 @@ verifyRender(const List *const archiveIdResultList, const List *const backupResu } } + KeyValue *const fileErrorsKv = verifyCreateFileErrorsKv(errMissing, errChecksum, errSize, errOther); + kvPut(archiveKv, KEY_FILEERRORS_VAR, varNewKv(fileErrorsKv)); + // Create/append file errors string - if (jsonKv == NULL && (verboseText || errMissing + errChecksum + errSize + errOther > 0)) - strCat(result, verifyCreateFileErrorsStr(errMissing, errChecksum, errSize, errOther, verboseText)); + if (verboseText || errMissing + errChecksum + errSize + errOther > 0) + { + ASSERT(archiveMessage != NULL); + + strCat(archiveMessage, + verifyCreateFileErrorsStr(errMissing, errChecksum, errSize, errOther, verboseText)); + } } - if (archiveKv != NULL) - { - kvPut(archiveKv, KEY_MISSING_VAR, VARUINT(errMissing)); - kvPut(archiveKv, KEY_CHECKSUMINVALID_VAR, VARUINT(errChecksum)); - kvPut(archiveKv, KEY_SIZEINVALID_VAR, VARUINT(errSize)); - kvPut(archiveKv, KEY_OTHER_VAR, VARUINT(errOther)); + // Put the messsage to messages list + if (archiveMessage != NULL) + verifyMessageNew(errorList, printAlways, archiveMessage); - varLstAdd(archivesList, varNewKv(archiveKv)); - } + kvPut(archiveKv, KEY_MISSING_VAR, VARUINT(errMissing)); + kvPut(archiveKv, KEY_CHECKSUMINVALID_VAR, VARUINT(errChecksum)); + kvPut(archiveKv, KEY_SIZEINVALID_VAR, VARUINT(errSize)); + kvPut(archiveKv, KEY_OTHER_VAR, VARUINT(errOther)); + + varLstAdd(archivesList, varNewKv(archiveKv)); } } - // Render backup results - if (jsonKv == NULL && verboseText && lstEmpty(backupResultList)) - { - strCatZ(result, "\n backup: none found"); - } + // Prepare backup results + if (lstEmpty(backupResultList)) + verifyMessageNew(errorList, printAtVerbose, strNewZ("backup: none found")); else { for (unsigned int backupIdx = 0; backupIdx < lstSize(backupResultList); backupIdx++) { const VerifyBackupResult *const backupResult = lstGet(backupResultList, backupIdx); const char *status; - KeyValue *const backupKv = backupsList == NULL ? NULL : kvNew(); + KeyValue *const backupKv = kvNew(); switch (backupResult->status) { @@ -1692,18 +1763,19 @@ verifyRender(const List *const archiveIdResultList, const List *const backupResu } } - if (backupKv != NULL) - { - kvPut(backupKv, BACKUP_KEY_LABEL_VAR, VARSTR(backupResult->backupLabel)); - kvPut(backupKv, KEY_STATUS_VAR, VARSTRZ(status)); - kvPut(backupKv, BACKUP_KEY_CHECKED_VAR, VARUINT(backupResult->totalFileVerify)); - kvPut(backupKv, KEY_VALID_VAR, VARUINT(backupResult->totalFileValid)); - } - else if (verboseText || (strcmp(status, "valid") != 0 && strcmp(status, "in-progress") != 0)) + kvPut(backupKv, BACKUP_KEY_LABEL_VAR, VARSTR(backupResult->backupLabel)); + kvPut(backupKv, KEY_STATUS_VAR, VARSTRZ(status)); + kvPut(backupKv, BACKUP_KEY_CHECKED_VAR, VARUINT(backupResult->totalFileVerify)); + kvPut(backupKv, KEY_VALID_VAR, VARUINT(backupResult->totalFileValid)); + + // Prepare the message + String *backupMessage = NULL; + if (verboseText || (strcmp(status, "valid") != 0 && strcmp(status, "in-progress") != 0)) { - strCatFmt( - result, "\n backup: %s, status: %s, total files checked: %u, total valid files: %u", - strZ(backupResult->backupLabel), status, backupResult->totalFileVerify, backupResult->totalFileValid); + backupMessage = strNew(); + strCatFmt(backupMessage, + "backup: %s, status: %s, total files checked: %u, total valid files: %u", + strZ(backupResult->backupLabel), status, backupResult->totalFileVerify, backupResult->totalFileValid); } unsigned int errMissing = 0; @@ -1727,35 +1799,98 @@ verifyRender(const List *const archiveIdResultList, const List *const backupResu errOther++; } + KeyValue *const fileErrorsKv = verifyCreateFileErrorsKv(errMissing, errChecksum, errSize, errOther); + kvPut(backupKv, KEY_FILEERRORS_VAR, varNewKv(fileErrorsKv)); + // Create/append file errors string - if (backupKv == NULL && (verboseText || errMissing + errChecksum + errSize + errOther > 0)) + if (verboseText || errMissing + errChecksum + errSize + errOther > 0) { - strCat(result, verifyCreateFileErrorsStr(errMissing, errChecksum, errSize, errOther, verboseText)); + ASSERT(backupMessage != NULL); + strCat(backupMessage, verifyCreateFileErrorsStr(errMissing, errChecksum, errSize, errOther, verboseText)); } + } - if (backupKv != NULL) + // Put the messsage to messages list + if (backupMessage != NULL) + verifyMessageNew(errorList, printAlways, backupMessage); + + kvPut(backupKv, KEY_MISSING_VAR, VARUINT(errMissing)); + kvPut(backupKv, KEY_CHECKSUMINVALID_VAR, VARUINT(errChecksum)); + kvPut(backupKv, KEY_SIZEINVALID_VAR, VARUINT(errSize)); + kvPut(backupKv, KEY_OTHER_VAR, VARUINT(errOther)); + varLstAdd(backupsList, varNewKv(backupKv)); + } + } + + kvPut(resultKv, KEY_ARCHIVES_VAR, varNewVarLst(archivesList)); + kvPut(resultKv, KEY_BACKUPS_VAR, varNewVarLst(backupsList)); + kvPut(resultKv, KEY_ERRORS_VAR, varNewVarLst(errorList)); + + FUNCTION_TEST_RETURN(KEY_VALUE, resultKv); +} + +/*********************************************************************************************************************************** + * Render the results of the verify command into text + ***********************************************************************************************************************************/ +static String * +verifyRenderText(const KeyValue *const resultKv, const bool verboseText) +{ + FUNCTION_LOG_BEGIN(logLevelDebug); + FUNCTION_LOG_PARAM(KEY_VALUE, resultKv); // Result key-value pair + FUNCTION_LOG_PARAM(BOOL, verboseText); // Is verbose output requested? + FUNCTION_LOG_END(); + + ASSERT(resultKv != NULL); + + String *const result = strNew(); + MEM_CONTEXT_TEMP_BEGIN() + { + const VariantList *const errorList = kvGetList(resultKv, KEY_ERRORS_VAR); + unsigned int errorTotal = varLstSize(errorList); + String *resultStr = strNew(); + + for (unsigned int errIdx = 0; errIdx < errorTotal; errIdx++) + { + const KeyValue *const msg = varKv(varLstGet(errorList, errIdx)); + const String *const message = varStr(kvGet(msg, VERIFY_MSG_KEY_MESSAGE)); + const Variant *varMessagePrint = kvGet(msg, VERIFY_MSG_KEY_MESSAGE_PRINT); + if (varMessagePrint == NULL) + continue; + + const VerifyMessagePrint whenPrint = (VerifyMessagePrint)varUInt(varMessagePrint); + + // Print messages which were addressed to the stdout + if ((verboseText && (whenPrint == printAtVerbose)) || whenPrint == printAlways) { - kvPut(backupKv, KEY_MISSING_VAR, VARUINT(errMissing)); - kvPut(backupKv, KEY_CHECKSUMINVALID_VAR, VARUINT(errChecksum)); - kvPut(backupKv, KEY_SIZEINVALID_VAR, VARUINT(errSize)); - kvPut(backupKv, KEY_OTHER_VAR, VARUINT(errOther)); - varLstAdd(backupsList, varNewKv(backupKv)); + strCatFmt(resultStr, "\n %s", strZ(message)); } } + strCat(result, resultStr); } + MEM_CONTEXT_TEMP_END(); - if (jsonKv != NULL) - { - kvPut(jsonKv, KEY_ARCHIVES_VAR, varNewVarLst(archivesList)); - kvPut(jsonKv, KEY_BACKUPS_VAR, varNewVarLst(backupsList)); + FUNCTION_LOG_RETURN(STRING, result); +} + +static String * +verifyRenderJson(KeyValue *const resultKv) +{ + FUNCTION_LOG_BEGIN(logLevelDebug); + FUNCTION_LOG_PARAM(KEY_VALUE, resultKv); // Result key-value pair + FUNCTION_LOG_END(); + + String *const result = strNew(); - // Provide JSON based output as well to make testing easier - strCat(result, jsonFromVar(varNewKv(jsonKv))); + MEM_CONTEXT_TEMP_BEGIN() + { + strCat(result, jsonFromVar(varNewKv(resultKv))); } + MEM_CONTEXT_TEMP_END(); - FUNCTION_TEST_RETURN(STRING, result); + FUNCTION_LOG_RETURN(STRING, result); } + /*********************************************************************************************************************************** Process the verify command @@ -1767,7 +1902,7 @@ verifyProcess(const bool verboseText) FUNCTION_LOG_PARAM(BOOL, verboseText); // Is verbose output requested? FUNCTION_LOG_END(); - String *const result = strNew(); + String *result = strNew();; bool json = cfgOptionStrId(cfgOptOutput) == CFGOPTVAL_OUTPUT_JSON; MEM_CONTEXT_TEMP_BEGIN() @@ -1783,13 +1918,11 @@ verifyProcess(const bool verboseText) // Get a usable backup info file const InfoBackup *const backupInfo = verifyBackupInfoFile(errorList); - if (json) - resultKv = kvNew(); - // If a usable backup.info file is not found, then report an error in the log if (backupInfo == NULL) { - verifyErrorNew(errorList, logLevelOff, strNewZ("No usable backup.info file")); + strCatZ(resultStr, "\n No usable backup.info file"); + verifyMessageNew(errorList, printNever, strNewZ("No usable backup.info file")); errorTotal++; } @@ -1799,7 +1932,8 @@ verifyProcess(const bool verboseText) // If a usable archive.info file is not found, then report an error in the log if (archiveInfo == NULL) { - verifyErrorNew(errorList, logLevelOff, strNewZ("No usable archive.info file")); + strCatZ(resultStr, "\n No usable archive.info file"); + verifyMessageNew(errorList, printNever, strNewZ("No usable archive.info file")); errorTotal++; } @@ -1813,7 +1947,8 @@ verifyProcess(const bool verboseText) } CATCH_ANY() { - verifyErrorNew(errorList, logLevelOff, strNewZ(errorMessage())); + strCatFmt(resultStr, "\n %s", errorMessage()); + verifyMessageNew(errorList, printNever, strNewZ(errorMessage())); errorTotal++; } TRY_END(); @@ -1845,7 +1980,9 @@ verifyProcess(const bool verboseText) { if (!regExpMatchOne(backupRegExpStr, backupLabel)) { - verifyErrorNew(errorList, logLevelOff, strNewFmt("'%s' is not a valid backup label format", strZ(backupLabel))); + strCatFmt(resultStr, "\n '%s' is not a valid backup label format", strZ(backupLabel)); + + verifyMessageNew(errorList, printNever, strNewFmt("'%s' is not a valid backup label format", strZ(backupLabel))); backupLabelInvalid = true; errorTotal++; @@ -1863,7 +2000,8 @@ verifyProcess(const bool verboseText) if (!backupLabelInvalid && backupLabel != NULL && strLstEmpty(jobData.backupList)) { - verifyErrorNew(errorList, logLevelOff, strNewFmt("backup set %s is not valid", strZ(backupLabel))); + strCatFmt(resultStr, "\n backup set %s is not valid", strZ(backupLabel)); + verifyMessageNew(errorList, printNever, strNewFmt("backup set %s is not valid", strZ(backupLabel))); backupLabelInvalid = true; errorTotal++; @@ -2033,45 +2171,52 @@ verifyProcess(const bool verboseText) // ??? Need to do the final reconciliation - checking backup required WAL against, valid WAL - // Report results - resultStr = verifyRender(jobData.archiveIdResultList, jobData.backupResultList, verboseText, resultKv, errorList); + // Prepare results KV + resultKv = verifyPrepareResult(jobData.archiveIdResultList, jobData.backupResultList, verboseText); } - else if (!json && !backupLabelInvalid) + else if (!backupLabelInvalid) + { strCatZ(resultStr, "\n no archives or backups exist in the repo"); + verifyMessageNew(errorList, printNever, + strNewZ("no archives or backups exist in the repo")); + } errorTotal += jobData.jobErrorTotal; } - if (json) - { - kvPut(resultKv, VERIFY_KEY_STANZA_VAR, VARSTR(cfgOptionStr(cfgOptStanza))); - kvPut(resultKv, KEY_STATUS_VAR, errorTotal > 0 ? VERIFY_KEY_STATUS_ERROR : VERIFY_KEY_STATUS_OK); + if (resultKv == NULL) + resultKv = kvNew(); - kvPut(resultKv, KEY_ERRORS_VAR, varNewVarLst(errorList)); + kvPut(resultKv, VERIFY_KEY_STANZA_VAR, VARSTR(cfgOptionStr(cfgOptStanza))); + kvPut(resultKv, KEY_STATUS_VAR, errorTotal > 0 ? VERIFY_KEY_STATUS_ERROR : VERIFY_KEY_STATUS_OK); - strCat(result, jsonFromVar(varNewKv(resultKv))); - } - else + const Variant *resultError = kvGet(resultKv, KEY_ERRORS_VAR); + if (resultError != NULL) { - for (unsigned int errIdx = 0; errIdx < varLstSize(errorList); errIdx++) + VariantList *const resultErrorList = varVarLst(resultError); + for (unsigned int errIdx = 0; errIdx < varLstSize(resultErrorList); errIdx++) { - const KeyValue *const msg = varKv(varLstGet(errorList, errIdx)); - const LogLevel logLevel = (LogLevel)varUInt(kvGet(msg, VERIFY_MSG_KEY_LEVEL)); - - // Print messages which did not got logged yet - if (logLevel == logLevelOff){ - const String *const message = varStr(kvGet(msg, VERIFY_MSG_KEY_MESSAGE)); - strCatFmt(resultStr, "\n %s", strZ(message)); - } + Variant *item = varLstGet(resultErrorList, errIdx); + Variant *dup = varDup(item); + varLstAdd(errorList, dup); } } + + kvPut(resultKv, KEY_ERRORS_VAR, varNewVarLst(errorList)); - // If verbose output or errors then output results - if (!json && (verboseText || errorTotal > 0)) + if (json) { + // Render the results as JSON + strCat(result, verifyRenderJson(resultKv)); + } + else if (verboseText || errorTotal > 0) + { + // Render the results as text strCatFmt( - result, "stanza: %s\nstatus: %s%s", strZ(cfgOptionStr(cfgOptStanza)), - errorTotal > 0 ? VERIFY_STATUS_ERROR : VERIFY_STATUS_OK, strZ(resultStr)); + result, "stanza: %s\nstatus: %s%s%s", strZ(cfgOptionStr(cfgOptStanza)), + errorTotal > 0 ? VERIFY_STATUS_ERROR : VERIFY_STATUS_OK, + strZ(resultStr), + strZ(verifyRenderText(resultKv, verboseText))); } } MEM_CONTEXT_TEMP_END(); @@ -2079,6 +2224,7 @@ verifyProcess(const bool verboseText) FUNCTION_LOG_RETURN(STRING, result); } + /**********************************************************************************************************************************/ FN_EXTERN void cmdVerify(void) diff --git a/test/src/module/command/verifyTest.c b/test/src/module/command/verifyTest.c index d84483f9c6..bfcdc9e396 100644 --- a/test/src/module/command/verifyTest.c +++ b/test/src/module/command/verifyTest.c @@ -644,7 +644,7 @@ testRun(void) TEST_RESULT_LOG("P00 WARN: file missing 'missingfilename'"); // ------------------------------------------------------------------------------------------------------------------------- - TEST_TITLE("verifyRender() - missing file, empty invalidList"); + TEST_TITLE("verifyRender - missing file, empty invalidList"); List *archiveIdResultList = lstNewP(sizeof(VerifyArchiveResult), .comparator = archiveIdComparator); List *backupResultList = lstNewP(sizeof(VerifyBackupResult), .comparator = lstComparatorStr); @@ -665,33 +665,35 @@ testRun(void) lstAdd(archiveIdResult.walRangeList, &walRange); lstAdd(archiveIdResultList, &archiveIdResult); - KeyValue *testKv = kvNew(); - lstClear((List *)errorList); + KeyValue *resultKv = verifyPrepareResult(archiveIdResultList, backupResultList, cfgOptionBool(cfgOptVerbose)); TEST_RESULT_STR_Z( - verifyRender(archiveIdResultList, backupResultList, cfgOptionBool(cfgOptVerbose), NULL, errorList), + verifyRenderText(resultKv, cfgOptionBool(cfgOptVerbose)), "\n" " archiveId: 9.6-1, total WAL checked: 1, total valid WAL: 0", "archive: no invalid file list"); - - lstClear((List *)errorList); - TEST_RESULT_STR_Z( - verifyRender(archiveIdResultList, backupResultList, cfgOptionBool(cfgOptVerbose), testKv, errorList), + verifyRenderJson(resultKv), "{\"archives\":[" "{" "\"archiveId\":\"9.6-1\"," "\"checked\":1," "\"checksumInvalid\":0," + "\"fileErrors\":{\"checksumInvalid\":0,\"missing\":0,\"other\":0,\"sizeInvalid\":0}," "\"missing\":0," "\"other\":0," "\"sizeInvalid\":0," "\"valid\":0" "}" "]," - "\"backups\":[" - "]}", + "\"backups\":[]," + "\"errors\":[" + "{\"level\":5,\"message\":\"archiveId: 9.6-1, wal start: 0, wal stop: 2\"}," + "{\"message\":\"archiveId: 9.6-1, total WAL checked: 1, total valid WAL: 0\",\"whenPrint\":2}," + "{\"message\":\"backup: none found\",\"whenPrint\":1}]}", "archive: no invalid file list"); + // kvFree(resultKv); + VerifyInvalidFile invalidFile = { .fileName = strNewZ("file"), @@ -709,9 +711,10 @@ testRun(void) lstAdd(backupResult.invalidFileList, &invalidFile); lstAdd(backupResultList, &backupResult); - lstClear((List *)errorList); + resultKv = verifyPrepareResult(archiveIdResultList, backupResultList, cfgOptionBool(cfgOptVerbose)); + TEST_RESULT_STR_Z( - verifyRender(archiveIdResultList, backupResultList, cfgOptionBool(cfgOptVerbose), NULL, errorList), + verifyRenderText(resultKv, cfgOptionBool(cfgOptVerbose)), "\n" " archiveId: 9.6-1, total WAL checked: 1, total valid WAL: 0\n" " missing: 1\n" @@ -720,12 +723,13 @@ testRun(void) lstClear((List *)errorList); TEST_RESULT_STR_Z( - verifyRender(archiveIdResultList, backupResultList, cfgOptionBool(cfgOptVerbose), testKv, errorList), + verifyRenderJson(resultKv), "{\"archives\":[" "{" "\"archiveId\":\"9.6-1\"," "\"checked\":1," "\"checksumInvalid\":0," + "\"fileErrors\":{\"checksumInvalid\":0,\"missing\":1,\"other\":0,\"sizeInvalid\":0}," "\"missing\":1," "\"other\":0," "\"sizeInvalid\":0," @@ -736,16 +740,23 @@ testRun(void) "{" "\"checked\":1," "\"checksumInvalid\":0," + "\"fileErrors\":{\"checksumInvalid\":0,\"missing\":1,\"other\":0,\"sizeInvalid\":0}," "\"label\":\"test-backup-label\"," "\"missing\":1," "\"other\":0," "\"sizeInvalid\":0," "\"status\":\"invalid\"," "\"valid\":0" - "}" - "]}", + "}]," + "\"errors\":[" + "{\"level\":5,\"message\":\"archiveId: 9.6-1, wal start: 0, wal stop: 2\"}," + "{\"message\":\"archiveId: 9.6-1, total WAL checked: 1, total valid WAL: 0\\n missing: 1\",\"whenPrint\":2}," + "{\"message\":\"backup: test-backup-label, status: invalid, total files checked: 1, total valid files: 0\\n missing: 1\",\"whenPrint\":2}]" + "}", "archive file missing, backup file missing, no text, no verbose, json output"); + // kvFree(resultKv); + // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("verifyAddInvalidWalFile() - file missing (coverage test)"); @@ -961,8 +972,7 @@ testRun(void) "\"level\":5,"\ "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/backup.info.copy' for read\""\ "},{"\ - "\"level\":0,"\ - "\"message\":\"No usable backup.info file\""\ + "\"message\":\"No usable backup.info file\",\"whenPrint\":0"\ "},{"\ "\"level\":5,"\ "\"message\":\"unable to open missing file '" TEST_PATH "/repo/archive/db/archive.info' for read\""\ @@ -970,8 +980,7 @@ testRun(void) "\"level\":5,"\ "\"message\":\"unable to open missing file '" TEST_PATH "/repo/archive/db/archive.info.copy' for read\""\ "},{"\ - "\"level\":0,"\ - "\"message\":\"No usable archive.info file\""\ + "\"message\":\"No usable archive.info file\",\"whenPrint\":0"\ "}"\ "],"\ "\"stanza\":\"db\","\ @@ -1032,7 +1041,7 @@ testRun(void) "},{"\ "\"level\":5,\"message\":\"invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS' /archive.info.copy\""\ "},{"\ - "\"level\":0,\"message\":\"No usable archive.info file\""\ + "\"message\":\"No usable archive.info file\",\"whenPrint\":0"\ "}"\ "],"\ "\"stanza\":\"db\","\ @@ -1084,7 +1093,7 @@ testRun(void) "\"level\":5,"\ "\"message\":\"invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS' /archive.info\""\ "},{"\ - "\"level\":0,\"message\":\"backup info file and archive info file do not match\\narchive: id = 1, version = 9.5, system-id = 10000000000000090500\\nbackup : id = 2, version = 11, system-id = 10000000000000110000\\nHINT: this may be a symptom of repository corruption!\""\ + "\"message\":\"backup info file and archive info file do not match\\narchive: id = 1, version = 9.5, system-id = 10000000000000090500\\nbackup : id = 2, version = 11, system-id = 10000000000000110000\\nHINT: this may be a symptom of repository corruption!\",\"whenPrint\":0"\ "}"\ "],"\ "\"stanza\":\"db\","\ @@ -1128,7 +1137,8 @@ testRun(void) "{"\ "\"level\":5,"\ "\"message\":\"archive.info.copy does not match archive.info\""\ - "}"\ + "},"\ + "{\"message\":\"no archives or backups exist in the repo\",\"whenPrint\":0}"\ "],"\ "\"stanza\":\"db\","\ "\"status\":\"ok\""\ @@ -1171,7 +1181,8 @@ testRun(void) "{"\ "\"level\":5,"\ "\"message\":\"unable to open missing file '" TEST_PATH "/repo/archive/db/archive.info.copy' for read\""\ - "}"\ + "},"\ + "{\"message\":\"no archives or backups exist in the repo\",\"whenPrint\":0}"\ "],"\ "\"stanza\":\"db\","\ "\"status\":\"ok\""\ @@ -1222,8 +1233,7 @@ testRun(void) "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/backup.info.copy' for read\""\ "},"\ "{"\ - "\"level\":0,"\ - "\"message\":\"No usable backup.info file\""\ + "\"message\":\"No usable backup.info file\",\"whenPrint\":0"\ "}"\ "],"\ "\"stanza\":\"db\","\ @@ -1435,6 +1445,7 @@ testRun(void) "\"archiveId\":\"11-2\","\ "\"checked\":4,"\ "\"checksumInvalid\":1,"\ + "\"fileErrors\":{\"checksumInvalid\":1,\"missing\":0,\"other\":0,\"sizeInvalid\":1},"\ "\"missing\":0,"\ "\"other\":0,"\ "\"sizeInvalid\":1,"\ @@ -1468,7 +1479,9 @@ testRun(void) "{"\ "\"level\":5,"\ "\"message\":\"archiveId: 11-2, wal start: 000000020000000700000FFD, wal stop: 000000020000000800000000\""\ - "}"\ + "},"\ + "{\"message\":\"archiveId: 11-2, total WAL checked: 4, total valid WAL: 2\\n checksum invalid: 1, size invalid: 1\",\"whenPrint\":2},"\ + "{\"message\":\"backup: none found\",\"whenPrint\":1}"\ "],"\ "\"stanza\":\"db\","\ "\"status\":\"error\""\ @@ -1533,6 +1546,7 @@ testRun(void) "\"archiveId\":\"11-2\"," \ "\"checked\":4," \ "\"checksumInvalid\":1," \ + "\"fileErrors\":{\"checksumInvalid\":1,\"missing\":0,\"other\":0,\"sizeInvalid\":1}," "\"missing\":0," \ "\"other\":0," \ "\"sizeInvalid\":1," \ @@ -1563,10 +1577,13 @@ testRun(void) "\"message\":\"invalid size '11-2/0000000200000007/000000020000000700000FFF-ee161f898c9012dd0c28b3fd1e7140b9cf411306'\"," \ "\"pid\":1" \ "}," \ + "{\"message\":\"archiveId: 9.5-1, total WAL checked: 0, total valid WAL: 0\",\"whenPrint\":2}," \ "{" \ "\"level\":5," \ "\"message\":\"archiveId: 11-2, wal start: 000000020000000700000FFD, wal stop: 000000020000000800000000\"" \ - "}" \ + "}," \ + "{\"message\":\"archiveId: 11-2, total WAL checked: 4, total valid WAL: 2\\n missing: 0, checksum invalid: 1, size invalid: 1, other: 0\",\"whenPrint\":2},"\ + "{\"message\":\"backup: none found\",\"whenPrint\":1}"\ "]," \ "\"stanza\":\"db\"," \ "\"status\":\"error\"" \ @@ -1952,7 +1969,8 @@ testRun(void) "{" \ "\"level\":4," \ "\"message\":\"backup '20181119-152800F' appears to be in progress, skipping\"" \ - "}" \ + "}," \ + "{\"message\":\"archiveId: none found\",\"whenPrint\":1}"\ "]," \ "\"stanza\":\"db\"," \ "\"status\":\"ok\"" \ @@ -2497,6 +2515,7 @@ testRun(void) "{" \ "\"checked\":2," \ "\"checksumInvalid\":2," \ + "\"fileErrors\":{\"checksumInvalid\":2,\"missing\":0,\"other\":0,\"sizeInvalid\":0},"\ "\"label\":\"20181119-152900F\"," \ "\"missing\":0," \ "\"other\":0," \ @@ -2507,6 +2526,7 @@ testRun(void) "{" \ "\"checked\":2," \ "\"checksumInvalid\":1," \ + "\"fileErrors\":{\"checksumInvalid\":1,\"missing\":0,\"other\":0,\"sizeInvalid\":0},"\ "\"label\":\"20181119-152900F_20181119-152909D\"," \ "\"missing\":0," \ "\"other\":0," \ @@ -2529,7 +2549,10 @@ testRun(void) "\"level\":4," \ "\"message\":\"invalid checksum '20181119-152900F/pg_data/biind.pgbi'\"," \ "\"pid\":1" \ - "}" \ + "}," \ + "{\"message\":\"archiveId: none found\",\"whenPrint\":1},"\ + "{\"message\":\"backup: 20181119-152900F, status: invalid, total files checked: 2, total valid files: 0\\n missing: 0, checksum invalid: 2, size invalid: 0, other: 0\",\"whenPrint\":2},"\ + "{\"message\":\"backup: 20181119-152900F_20181119-152909D, status: invalid, total files checked: 2, total valid files: 1\\n missing: 0, checksum invalid: 1, size invalid: 0, other: 0\",\"whenPrint\":2}"\ "]," \ "\"stanza\":\"db\"," \ "\"status\":\"error\"" \ From 485c067cfb94a8c9c99e49b7dd6391c98cd2d665 Mon Sep 17 00:00:00 2001 From: Denis Kovalev Date: Wed, 23 Jul 2025 08:24:54 +0300 Subject: [PATCH 04/12] format code --- src/command/verify/verify.c | 34 ++++++++++++---------------- test/src/module/command/verifyTest.c | 16 ++++++------- 2 files changed, 22 insertions(+), 28 deletions(-) diff --git a/src/command/verify/verify.c b/src/command/verify/verify.c index 5a46156e1d..d7b522b99c 100644 --- a/src/command/verify/verify.c +++ b/src/command/verify/verify.c @@ -79,7 +79,6 @@ Data Types and Structures #define FUNCTION_LOG_VERIFY_MESSAGE_PRINT_FORMAT(value, buffer, bufferSize) \ objNameToLog(&value, "VerifyMessagePrint", buffer, bufferSize) - typedef enum VerifyMessagePrint { printNever, @@ -239,7 +238,7 @@ verifyErrorPidNew(VariantList *errorList, const LogLevel logLevel, const unsigne } /*********************************************************************************************************************************** -Helper function to add a message going to stdout to the message list. +Helper function to add a message going to stdout to the message list. ***********************************************************************************************************************************/ static void verifyMessageNew(VariantList *messageList, const VerifyMessagePrint whenToPrint, const String *const message) @@ -1609,7 +1608,6 @@ verifyCreateFileErrorsKv( FUNCTION_TEST_PARAM(UINT, errOther); // Number of files with other errors FUNCTION_TEST_END(); - KeyValue *const result = kvNew(); kvPut(result, KEY_MISSING_VAR, VARUINT(errMissing)); @@ -1654,7 +1652,7 @@ verifyPrepareResult(const List *const archiveIdResultList, const List *const bac KeyValue *const archiveKv = kvNew(); // Prepare the message - String * archiveMessage = NULL; + String *archiveMessage = NULL; kvPut(archiveKv, ARCHIVE_KEY_ARCHIVEID_VAR, VARSTR(archiveIdResult->archiveId)); kvPut(archiveKv, ARCHIVE_KEY_CHECKED_VAR, VARUINT(archiveIdResult->totalWalFile)); @@ -1664,11 +1662,10 @@ verifyPrepareResult(const List *const archiveIdResultList, const List *const bac { archiveMessage = strNew(); strCatFmt(archiveMessage, - "archiveId: %s, total WAL checked: %u, total valid WAL: %u", strZ(archiveIdResult->archiveId), - archiveIdResult->totalWalFile, archiveIdResult->totalValidWal); + "archiveId: %s, total WAL checked: %u, total valid WAL: %u", strZ(archiveIdResult->archiveId), + archiveIdResult->totalWalFile, archiveIdResult->totalValidWal); } - unsigned int errMissing = 0; unsigned int errChecksum = 0; unsigned int errSize = 0; @@ -1708,12 +1705,12 @@ verifyPrepareResult(const List *const archiveIdResultList, const List *const bac kvPut(archiveKv, KEY_FILEERRORS_VAR, varNewKv(fileErrorsKv)); // Create/append file errors string - if (verboseText || errMissing + errChecksum + errSize + errOther > 0) + if (verboseText || errMissing + errChecksum + errSize + errOther > 0) { ASSERT(archiveMessage != NULL); strCat(archiveMessage, - verifyCreateFileErrorsStr(errMissing, errChecksum, errSize, errOther, verboseText)); + verifyCreateFileErrorsStr(errMissing, errChecksum, errSize, errOther, verboseText)); } } @@ -1774,8 +1771,8 @@ verifyPrepareResult(const List *const archiveIdResultList, const List *const bac { backupMessage = strNew(); strCatFmt(backupMessage, - "backup: %s, status: %s, total files checked: %u, total valid files: %u", - strZ(backupResult->backupLabel), status, backupResult->totalFileVerify, backupResult->totalFileValid); + "backup: %s, status: %s, total files checked: %u, total valid files: %u", + strZ(backupResult->backupLabel), status, backupResult->totalFileVerify, backupResult->totalFileValid); } unsigned int errMissing = 0; @@ -1808,7 +1805,6 @@ verifyPrepareResult(const List *const archiveIdResultList, const List *const bac ASSERT(backupMessage != NULL); strCat(backupMessage, verifyCreateFileErrorsStr(errMissing, errChecksum, errSize, errOther, verboseText)); } - } // Put the messsage to messages list @@ -1846,7 +1842,7 @@ verifyRenderText(const KeyValue *const resultKv, const bool verboseText) String *const result = strNew(); MEM_CONTEXT_TEMP_BEGIN() { - const VariantList *const errorList = kvGetList(resultKv, KEY_ERRORS_VAR); + const VariantList *const errorList = kvGetList(resultKv, KEY_ERRORS_VAR); unsigned int errorTotal = varLstSize(errorList); String *resultStr = strNew(); @@ -1890,7 +1886,6 @@ verifyRenderJson(KeyValue *const resultKv) FUNCTION_LOG_RETURN(STRING, result); } - /*********************************************************************************************************************************** Process the verify command @@ -1902,7 +1897,7 @@ verifyProcess(const bool verboseText) FUNCTION_LOG_PARAM(BOOL, verboseText); // Is verbose output requested? FUNCTION_LOG_END(); - String *result = strNew();; + String *result = strNew(); bool json = cfgOptionStrId(cfgOptOutput) == CFGOPTVAL_OUTPUT_JSON; MEM_CONTEXT_TEMP_BEGIN() @@ -2178,7 +2173,7 @@ verifyProcess(const bool verboseText) { strCatZ(resultStr, "\n no archives or backups exist in the repo"); verifyMessageNew(errorList, printNever, - strNewZ("no archives or backups exist in the repo")); + strNewZ("no archives or backups exist in the repo")); } errorTotal += jobData.jobErrorTotal; @@ -2194,14 +2189,14 @@ verifyProcess(const bool verboseText) if (resultError != NULL) { VariantList *const resultErrorList = varVarLst(resultError); - for (unsigned int errIdx = 0; errIdx < varLstSize(resultErrorList); errIdx++) + for (unsigned int errIdx = 0; errIdx < varLstSize(resultErrorList); errIdx++) { Variant *item = varLstGet(resultErrorList, errIdx); Variant *dup = varDup(item); varLstAdd(errorList, dup); } } - + kvPut(resultKv, KEY_ERRORS_VAR, varNewVarLst(errorList)); if (json) @@ -2214,7 +2209,7 @@ verifyProcess(const bool verboseText) // Render the results as text strCatFmt( result, "stanza: %s\nstatus: %s%s%s", strZ(cfgOptionStr(cfgOptStanza)), - errorTotal > 0 ? VERIFY_STATUS_ERROR : VERIFY_STATUS_OK, + errorTotal > 0 ? VERIFY_STATUS_ERROR : VERIFY_STATUS_OK, strZ(resultStr), strZ(verifyRenderText(resultKv, verboseText))); } @@ -2224,7 +2219,6 @@ verifyProcess(const bool verboseText) FUNCTION_LOG_RETURN(STRING, result); } - /**********************************************************************************************************************************/ FN_EXTERN void cmdVerify(void) diff --git a/test/src/module/command/verifyTest.c b/test/src/module/command/verifyTest.c index bfcdc9e396..d35aa89d0a 100644 --- a/test/src/module/command/verifyTest.c +++ b/test/src/module/command/verifyTest.c @@ -1582,8 +1582,8 @@ testRun(void) "\"level\":5," \ "\"message\":\"archiveId: 11-2, wal start: 000000020000000700000FFD, wal stop: 000000020000000800000000\"" \ "}," \ - "{\"message\":\"archiveId: 11-2, total WAL checked: 4, total valid WAL: 2\\n missing: 0, checksum invalid: 1, size invalid: 1, other: 0\",\"whenPrint\":2},"\ - "{\"message\":\"backup: none found\",\"whenPrint\":1}"\ + "{\"message\":\"archiveId: 11-2, total WAL checked: 4, total valid WAL: 2\\n missing: 0, checksum invalid: 1, size invalid: 1, other: 0\",\"whenPrint\":2}," \ + "{\"message\":\"backup: none found\",\"whenPrint\":1}" \ "]," \ "\"stanza\":\"db\"," \ "\"status\":\"error\"" \ @@ -1970,7 +1970,7 @@ testRun(void) "\"level\":4," \ "\"message\":\"backup '20181119-152800F' appears to be in progress, skipping\"" \ "}," \ - "{\"message\":\"archiveId: none found\",\"whenPrint\":1}"\ + "{\"message\":\"archiveId: none found\",\"whenPrint\":1}" \ "]," \ "\"stanza\":\"db\"," \ "\"status\":\"ok\"" \ @@ -2515,7 +2515,7 @@ testRun(void) "{" \ "\"checked\":2," \ "\"checksumInvalid\":2," \ - "\"fileErrors\":{\"checksumInvalid\":2,\"missing\":0,\"other\":0,\"sizeInvalid\":0},"\ + "\"fileErrors\":{\"checksumInvalid\":2,\"missing\":0,\"other\":0,\"sizeInvalid\":0}," \ "\"label\":\"20181119-152900F\"," \ "\"missing\":0," \ "\"other\":0," \ @@ -2526,7 +2526,7 @@ testRun(void) "{" \ "\"checked\":2," \ "\"checksumInvalid\":1," \ - "\"fileErrors\":{\"checksumInvalid\":1,\"missing\":0,\"other\":0,\"sizeInvalid\":0},"\ + "\"fileErrors\":{\"checksumInvalid\":1,\"missing\":0,\"other\":0,\"sizeInvalid\":0}," \ "\"label\":\"20181119-152900F_20181119-152909D\"," \ "\"missing\":0," \ "\"other\":0," \ @@ -2550,9 +2550,9 @@ testRun(void) "\"message\":\"invalid checksum '20181119-152900F/pg_data/biind.pgbi'\"," \ "\"pid\":1" \ "}," \ - "{\"message\":\"archiveId: none found\",\"whenPrint\":1},"\ - "{\"message\":\"backup: 20181119-152900F, status: invalid, total files checked: 2, total valid files: 0\\n missing: 0, checksum invalid: 2, size invalid: 0, other: 0\",\"whenPrint\":2},"\ - "{\"message\":\"backup: 20181119-152900F_20181119-152909D, status: invalid, total files checked: 2, total valid files: 1\\n missing: 0, checksum invalid: 1, size invalid: 0, other: 0\",\"whenPrint\":2}"\ + "{\"message\":\"archiveId: none found\",\"whenPrint\":1}," \ + "{\"message\":\"backup: 20181119-152900F, status: invalid, total files checked: 2, total valid files: 0\\n missing: 0, checksum invalid: 2, size invalid: 0, other: 0\",\"whenPrint\":2}," \ + "{\"message\":\"backup: 20181119-152900F_20181119-152909D, status: invalid, total files checked: 2, total valid files: 1\\n missing: 0, checksum invalid: 1, size invalid: 0, other: 0\",\"whenPrint\":2}" \ "]," \ "\"stanza\":\"db\"," \ "\"status\":\"error\"" \ From dbc204a73212b64ff2e06944478781965cbfe099 Mon Sep 17 00:00:00 2001 From: Denis Kovalev Date: Wed, 23 Jul 2025 08:37:56 +0300 Subject: [PATCH 05/12] make unity happy --- src/command/verify/verify.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/command/verify/verify.c b/src/command/verify/verify.c index d7b522b99c..a5651ae3eb 100644 --- a/src/command/verify/verify.c +++ b/src/command/verify/verify.c @@ -49,9 +49,9 @@ VARIANT_STRDEF_STATIC(KEY_CHECKSUMINVALID_VAR, "checksumInvalid"); VARIANT_STRDEF_STATIC(KEY_SIZEINVALID_VAR, "sizeInvalid"); VARIANT_STRDEF_STATIC(KEY_OTHER_VAR, "other"); VARIANT_STRDEF_STATIC(KEY_BACKUPS_VAR, "backups"); -VARIANT_STRDEF_STATIC(BACKUP_KEY_LABEL_VAR, "label"); +VARIANT_STRDEF_STATIC(BACKUPS_KEY_LABEL_VAR, "label"); VARIANT_STRDEF_STATIC(KEY_STATUS_VAR, "status"); -VARIANT_STRDEF_STATIC(BACKUP_KEY_CHECKED_VAR, "checked"); +VARIANT_STRDEF_STATIC(BACKUPS_KEY_CHECKED_VAR, "checked"); VARIANT_STRDEF_STATIC(KEY_ERRORS_VAR, "errors"); VARIANT_STRDEF_STATIC(VERIFY_KEY_STANZA_VAR, "stanza"); VARIANT_STRDEF_STATIC(VERIFY_KEY_STATUS_ERROR, "error"); @@ -1760,9 +1760,9 @@ verifyPrepareResult(const List *const archiveIdResultList, const List *const bac } } - kvPut(backupKv, BACKUP_KEY_LABEL_VAR, VARSTR(backupResult->backupLabel)); + kvPut(backupKv, BACKUPS_KEY_LABEL_VAR, VARSTR(backupResult->backupLabel)); kvPut(backupKv, KEY_STATUS_VAR, VARSTRZ(status)); - kvPut(backupKv, BACKUP_KEY_CHECKED_VAR, VARUINT(backupResult->totalFileVerify)); + kvPut(backupKv, BACKUPS_KEY_CHECKED_VAR, VARUINT(backupResult->totalFileVerify)); kvPut(backupKv, KEY_VALID_VAR, VARUINT(backupResult->totalFileValid)); // Prepare the message From 9c75ed3d067b54a19391364905a33fcaebc38d4f Mon Sep 17 00:00:00 2001 From: Denis Kovalev Date: Wed, 23 Jul 2025 11:51:29 +0300 Subject: [PATCH 06/12] Fix formatting and add more checks --- src/command/verify/verify.c | 24 +++--- test/src/module/command/verifyTest.c | 106 ++++++++++++++++++++++++--- 2 files changed, 109 insertions(+), 21 deletions(-) diff --git a/src/command/verify/verify.c b/src/command/verify/verify.c index a5651ae3eb..51fbc824eb 100644 --- a/src/command/verify/verify.c +++ b/src/command/verify/verify.c @@ -51,7 +51,7 @@ VARIANT_STRDEF_STATIC(KEY_OTHER_VAR, "other"); VARIANT_STRDEF_STATIC(KEY_BACKUPS_VAR, "backups"); VARIANT_STRDEF_STATIC(BACKUPS_KEY_LABEL_VAR, "label"); VARIANT_STRDEF_STATIC(KEY_STATUS_VAR, "status"); -VARIANT_STRDEF_STATIC(BACKUPS_KEY_CHECKED_VAR, "checked"); +VARIANT_STRDEF_STATIC(BACKUPS_KEY_CHECKED_VAR, "checked"); VARIANT_STRDEF_STATIC(KEY_ERRORS_VAR, "errors"); VARIANT_STRDEF_STATIC(VERIFY_KEY_STANZA_VAR, "stanza"); VARIANT_STRDEF_STATIC(VERIFY_KEY_STATUS_ERROR, "error"); @@ -79,11 +79,15 @@ Data Types and Structures #define FUNCTION_LOG_VERIFY_MESSAGE_PRINT_FORMAT(value, buffer, bufferSize) \ objNameToLog(&value, "VerifyMessagePrint", buffer, bufferSize) +// Enum to specify if message should be printed on standard output typedef enum VerifyMessagePrint { - printNever, - printAtVerbose, - printAlways + printNever, // Message will not be printed to standard output but going to + // appear in JSON + printAtVerbose, // Message will be printed to standard output only at verbose + // level + printAlways // Message will be printed to standard output regarless of + // verbose level } VerifyMessagePrint; // Structure for verifying repository info files @@ -178,9 +182,9 @@ static void verifyErrorNew(VariantList *errorList, const LogLevel logLevel, const String *const message) { FUNCTION_TEST_BEGIN(); - FUNCTION_TEST_PARAM(VARIANT_LIST, errorList); // Error list to add to - FUNCTION_LOG_PARAM(ENUM, logLevel); // Log level - FUNCTION_TEST_PARAM(STRING, message); // Error message + FUNCTION_TEST_PARAM(VARIANT_LIST, errorList); // Error list to add to + FUNCTION_LOG_PARAM(ENUM, logLevel); // Log level + FUNCTION_TEST_PARAM(STRING, message); // Error message FUNCTION_TEST_END(); FUNCTION_AUDIT_HELPER(); @@ -196,6 +200,8 @@ verifyErrorNew(VariantList *errorList, const LogLevel logLevel, const String *co varLstAdd(errorList, varNewKv(errorMsg)); + // Duplicate the message to the log as soon as in appears. + // Perhaps user may want to see it immediately. LOG(logLevel, 0, strZ(message)); } @@ -211,7 +217,7 @@ static void verifyErrorPidNew(VariantList *errorList, const LogLevel logLevel, const unsigned int pid, const String *const message) { FUNCTION_TEST_BEGIN(); - FUNCTION_TEST_PARAM(VARIANT_LIST, errorList); + FUNCTION_TEST_PARAM(VARIANT_LIST, errorList); // Error list to add to FUNCTION_LOG_PARAM(ENUM, logLevel); // Log level FUNCTION_TEST_PARAM(UINT, pid); // Process id FUNCTION_TEST_PARAM(STRING, message); // Error message @@ -519,7 +525,7 @@ verifyManifestFile( FUNCTION_LOG_PARAM(BOOL, currentBackup); // Is this possibly a backup currently in progress? FUNCTION_LOG_PARAM(INFO_PG, pgHistory); // Database history FUNCTION_LOG_PARAM_P(UINT, jobErrorTotal); // Pointer to the overall job error total - FUNCTION_TEST_PARAM(LIST, errorList); // List of errors + FUNCTION_TEST_PARAM(LIST, errorList); // List of errors FUNCTION_LOG_END(); Manifest *result = NULL; diff --git a/test/src/module/command/verifyTest.c b/test/src/module/command/verifyTest.c index d35aa89d0a..9f92a1defb 100644 --- a/test/src/module/command/verifyTest.c +++ b/test/src/module/command/verifyTest.c @@ -262,18 +262,20 @@ testRun(void) TEST_RESULT_UINT(backupResult.status, backupInvalid, "manifest unusable - backup invalid"); TEST_RESULT_UINT(varLstSize(errorList), 2, "error list size"); - TEST_RESULT_STR(jsonFromVar(varNewVarLst(errorList)), STR("[" - "{" - "\"level\":5," - "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/20181119-152138F/backup.manifest.copy' for read\"" - "}," - "{" - "\"level\":4," - "\"message\":\"'20181119-152138F' may not be recoverable - PG data (id 1, version 9.6, system-id " HRN_PG_SYSTEMID_95_Z ") is not in the backup.info history, skipping\"" - "}" - "]"), - "errorList does not match" - ); + TEST_RESULT_STR_Z( + jsonFromVar(varNewVarLst(errorList)), + "[" + "{" + "\"level\":5," + "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/20181119-152138F/backup.manifest.copy' for read\"" + "}," + "{" + "\"level\":4," + "\"message\":\"'20181119-152138F' may not be recoverable - PG data (id 1, version 9.6, system-id " HRN_PG_SYSTEMID_95_Z ") is not in the backup.info history, skipping\"" + "}" + "]", + "errorList does not match" + ); TEST_RESULT_LOG( "P00 DETAIL: unable to open missing file '" TEST_PATH "/repo/backup/db/20181119-152138F/backup.manifest.copy'" @@ -312,6 +314,23 @@ testRun(void) TEST_ASSIGN(manifest, verifyManifestFile(&backupResult, NULL, false, infoPg, &jobErrorTotal, errorList), "verify manifest"); TEST_RESULT_PTR(manifest, NULL, "manifest not set - pg system-id mismatch"); TEST_RESULT_UINT(backupResult.status, backupInvalid, "manifest unusable - backup invalid"); + + TEST_RESULT_STR_Z( + jsonFromVar(varNewVarLst(errorList)), + "[" + "{" + "\"level\":5," + "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/20181119-152138F/backup.manifest' for read\"" + "}," + "{\"level\":5,\"message\":\"20181119-152138F/backup.manifest is missing or unusable, using copy\"}," + "{" + "\"level\":4," + "\"message\":\"'20181119-152138F' may not be recoverable - PG data (id 1, version 9.5, system-id 0) is not in the backup.info history, skipping\"" + "}" + "]", + "errorList does not match" + ); + TEST_RESULT_LOG( "P00 DETAIL: unable to open missing file '" TEST_PATH "/repo/backup/db/20181119-152138F/backup.manifest' for read\n" "P00 DETAIL: 20181119-152138F/backup.manifest is missing or unusable, using copy\n" @@ -347,6 +366,23 @@ testRun(void) TEST_ASSIGN(manifest, verifyManifestFile(&backupResult, NULL, false, infoPg, &jobErrorTotal, errorList), "verify manifest"); TEST_RESULT_PTR(manifest, NULL, "manifest not set - pg db-id mismatch"); TEST_RESULT_UINT(backupResult.status, backupInvalid, "manifest unusable - backup invalid"); + + TEST_RESULT_STR_Z( + jsonFromVar(varNewVarLst(errorList)), + "[" + "{" + "\"level\":5," + "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/20181119-152138F/backup.manifest' for read\"" + "}," + "{\"level\":5,\"message\":\"20181119-152138F/backup.manifest is missing or unusable, using copy\"}," + "{" + "\"level\":4," + "\"message\":\"'20181119-152138F' may not be recoverable - PG data (id 0, version 9.5, system-id " HRN_PG_SYSTEMID_95_Z ") is not in the backup.info history, skipping\"" + "}" + "]", + "errorList does not match" + ); + TEST_RESULT_LOG( "P00 DETAIL: unable to open missing file '" TEST_PATH "/repo/backup/db/20181119-152138F/backup.manifest' for read\n" "P00 DETAIL: 20181119-152138F/backup.manifest is missing or unusable, using copy\n" @@ -364,6 +400,19 @@ testRun(void) TEST_ASSIGN(manifest, verifyManifestFile(&backupResult, NULL, false, infoPg, &jobErrorTotal, errorList), "verify manifest"); TEST_RESULT_UINT(backupResult.status, backupInvalid, "manifest unusable - backup invalid"); + + TEST_RESULT_STR_Z( + jsonFromVar(varNewVarLst(errorList)), + "[" + "{" + "\"level\":5," + "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/20181119-152138F/backup.manifest' for read\"" + "}," + "{\"level\":5,\"message\":\"invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS' /20181119-152138F/backup.manifest.copy\"}" + "]", + "errorList does not match" + ); + TEST_RESULT_LOG( "P00 DETAIL: unable to open missing file '" TEST_PATH "/repo/backup/db/20181119-152138F/backup.manifest' for read\n" "P00 DETAIL: invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS'" @@ -380,6 +429,16 @@ testRun(void) TEST_ASSIGN(manifest, verifyManifestFile(&backupResult, NULL, true, infoPg, &jobErrorTotal, errorList), "verify manifest"); TEST_RESULT_PTR(manifest, NULL, "manifest not set"); TEST_RESULT_UINT(backupResult.status, backupInvalid, "manifest unusable - backup invalid"); + + TEST_RESULT_STR_Z( + jsonFromVar(varNewVarLst(errorList)), + "[" + "{\"level\":5,\"message\":\"invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS' /20181119-152138F/backup.manifest\"}," + "{\"level\":5,\"message\":\"invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS' /20181119-152138F/backup.manifest.copy\"}" + "]", + "errorList does not match" + ); + TEST_RESULT_LOG( "P00 DETAIL: invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS'" " /20181119-152138F/backup.manifest\n" @@ -407,6 +466,15 @@ testRun(void) TEST_ASSIGN(manifest, verifyManifestFile(&backupResult, NULL, true, infoPg, &jobErrorTotal, errorList), "verify manifest"); TEST_RESULT_PTR_NE(manifest, NULL, "manifest set"); TEST_RESULT_UINT(backupResult.status, backupValid, "manifest usable"); + + TEST_RESULT_STR_Z( + jsonFromVar(varNewVarLst(errorList)), + "[" + "{\"level\":5,\"message\":\"backup '20181119-152138F' manifest.copy does not match manifest\"}" + "]", + "errorList does not match" + ); + TEST_RESULT_LOG("P00 DETAIL: backup '20181119-152138F' manifest.copy does not match manifest"); harnessLogLevelReset(); @@ -445,6 +513,11 @@ testRun(void) "get range"); TEST_RESULT_STR_Z(walRangeResult->start, "000000020000000200000000", "start range"); TEST_RESULT_STR_Z(walRangeResult->stop, "000000020000000200000000", "stop range"); + TEST_RESULT_STR_Z( + jsonFromVar(varNewVarLst(errorList)), + "[]", + "errorList does not match" + ); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("Duplicate WAL only - no range, all removed from list"); @@ -641,6 +714,15 @@ testRun(void) TEST_RESULT_UINT( verifyLogInvalidResult(STORAGE_REPO_ARCHIVE_STR, verifyFileMissing, 0, STRDEF("missingfilename"), errorList), 0, "file missing message"); + TEST_RESULT_STR_Z( + jsonFromVar(varNewVarLst(errorList)), + "[" + "{\"level\":4,\"message\":\"archiveIds '12-3, 13-4' are not in the archive.info history list\"}," + "{\"level\":3,\"message\":\"file missing 'missingfilename'\",\"pid\":0}" + "]", + "errorList does not match" + ); + TEST_RESULT_LOG("P00 WARN: file missing 'missingfilename'"); // ------------------------------------------------------------------------------------------------------------------------- From f301b4d7981c2b0ea1e25cf2ff43cb89d2a4dfa2 Mon Sep 17 00:00:00 2001 From: Denis Kovalev Date: Thu, 24 Jul 2025 13:43:38 +0300 Subject: [PATCH 07/12] Move more rendering to renderText --- src/command/verify/verify.c | 209 +++++++++++++-------------- test/src/module/command/verifyTest.c | 49 +++---- 2 files changed, 118 insertions(+), 140 deletions(-) diff --git a/src/command/verify/verify.c b/src/command/verify/verify.c index 51fbc824eb..24caa90d0c 100644 --- a/src/command/verify/verify.c +++ b/src/command/verify/verify.c @@ -58,7 +58,6 @@ VARIANT_STRDEF_STATIC(VERIFY_KEY_STATUS_ERROR, "error"); VARIANT_STRDEF_STATIC(VERIFY_KEY_STATUS_OK, "ok"); VARIANT_STRDEF_STATIC(VERIFY_MSG_KEY_LEVEL, "level"); VARIANT_STRDEF_STATIC(VERIFY_MSG_KEY_MESSAGE, "message"); -VARIANT_STRDEF_STATIC(VERIFY_MSG_KEY_MESSAGE_PRINT, "whenPrint"); VARIANT_STRDEF_STATIC(VERIFY_MSG_KEY_PID, "pid"); /*********************************************************************************************************************************** @@ -74,22 +73,6 @@ Data Types and Structures #define FUNCTION_LOG_VERIFY_BACKUP_RESULT_FORMAT(value, buffer, bufferSize) \ objNameToLog(&value, "VerifyBackupResult", buffer, bufferSize) -#define FUNCTION_LOG_VERIFY_MESSAGE_PRINT_TYPE \ - VerifyMessagePrint -#define FUNCTION_LOG_VERIFY_MESSAGE_PRINT_FORMAT(value, buffer, bufferSize) \ - objNameToLog(&value, "VerifyMessagePrint", buffer, bufferSize) - -// Enum to specify if message should be printed on standard output -typedef enum VerifyMessagePrint -{ - printNever, // Message will not be printed to standard output but going to - // appear in JSON - printAtVerbose, // Message will be printed to standard output only at verbose - // level - printAlways // Message will be printed to standard output regarless of - // verbose level -} VerifyMessagePrint; - // Structure for verifying repository info files typedef struct VerifyInfoFile { @@ -247,11 +230,10 @@ verifyErrorPidNew(VariantList *errorList, const LogLevel logLevel, const unsigne Helper function to add a message going to stdout to the message list. ***********************************************************************************************************************************/ static void -verifyMessageNew(VariantList *messageList, const VerifyMessagePrint whenToPrint, const String *const message) +verifyMessageNew(VariantList *messageList, const String *const message) { FUNCTION_TEST_BEGIN(); FUNCTION_TEST_PARAM(VARIANT_LIST, messageList); // Error list to add to - FUNCTION_LOG_PARAM(VERIFY_MESSAGE_PRINT, whenToPrint); // When this message should be rendered to text FUNCTION_TEST_PARAM(STRING, message); // Error message FUNCTION_TEST_END(); @@ -262,10 +244,7 @@ verifyMessageNew(VariantList *messageList, const VerifyMessagePrint whenToPrint, MEM_CONTEXT_BEGIN(lstMemContext((List *)messageList)) { KeyValue *const errorMsg = kvNew(); - - kvPut(errorMsg, VERIFY_MSG_KEY_MESSAGE_PRINT, VARUINT(whenToPrint)); kvPut(errorMsg, VERIFY_MSG_KEY_MESSAGE, VARSTR(strDup(message))); - varLstAdd(messageList, varNewKv(errorMsg)); } @@ -1628,12 +1607,11 @@ verifyCreateFileErrorsKv( Render the results of the verify command ***********************************************************************************************************************************/ static KeyValue * -verifyPrepareResult(const List *const archiveIdResultList, const List *const backupResultList, bool verboseText) +verifyPrepareResult(const List *const archiveIdResultList, const List *const backupResultList) { FUNCTION_TEST_BEGIN(); FUNCTION_TEST_PARAM(LIST, archiveIdResultList); // Result list for all archive Ids in the repo FUNCTION_TEST_PARAM(LIST, backupResultList); // Result list for all backups in the repo - FUNCTION_TEST_PARAM(BOOL, verboseText); // Is verbose output requested? FUNCTION_TEST_END(); FUNCTION_AUDIT_HELPER(); @@ -1648,30 +1626,17 @@ verifyPrepareResult(const List *const archiveIdResultList, const List *const bac VariantList *backupsList = varLstNew(); VariantList *errorList = varLstNew(); - if (lstEmpty(archiveIdResultList)) - verifyMessageNew(errorList, printAtVerbose, strNewZ("archiveId: none found")); - else + if (!lstEmpty(archiveIdResultList)) { for (unsigned int archiveIdx = 0; archiveIdx < lstSize(archiveIdResultList); archiveIdx++) { const VerifyArchiveResult *const archiveIdResult = lstGet(archiveIdResultList, archiveIdx); KeyValue *const archiveKv = kvNew(); - // Prepare the message - String *archiveMessage = NULL; - kvPut(archiveKv, ARCHIVE_KEY_ARCHIVEID_VAR, VARSTR(archiveIdResult->archiveId)); kvPut(archiveKv, ARCHIVE_KEY_CHECKED_VAR, VARUINT(archiveIdResult->totalWalFile)); kvPut(archiveKv, KEY_VALID_VAR, VARUINT(archiveIdResult->totalValidWal)); - if (verboseText || archiveIdResult->totalWalFile - archiveIdResult->totalValidWal != 0) - { - archiveMessage = strNew(); - strCatFmt(archiveMessage, - "archiveId: %s, total WAL checked: %u, total valid WAL: %u", strZ(archiveIdResult->archiveId), - archiveIdResult->totalWalFile, archiveIdResult->totalValidWal); - } - unsigned int errMissing = 0; unsigned int errChecksum = 0; unsigned int errSize = 0; @@ -1709,21 +1674,8 @@ verifyPrepareResult(const List *const archiveIdResultList, const List *const bac KeyValue *const fileErrorsKv = verifyCreateFileErrorsKv(errMissing, errChecksum, errSize, errOther); kvPut(archiveKv, KEY_FILEERRORS_VAR, varNewKv(fileErrorsKv)); - - // Create/append file errors string - if (verboseText || errMissing + errChecksum + errSize + errOther > 0) - { - ASSERT(archiveMessage != NULL); - - strCat(archiveMessage, - verifyCreateFileErrorsStr(errMissing, errChecksum, errSize, errOther, verboseText)); - } } - // Put the messsage to messages list - if (archiveMessage != NULL) - verifyMessageNew(errorList, printAlways, archiveMessage); - kvPut(archiveKv, KEY_MISSING_VAR, VARUINT(errMissing)); kvPut(archiveKv, KEY_CHECKSUMINVALID_VAR, VARUINT(errChecksum)); kvPut(archiveKv, KEY_SIZEINVALID_VAR, VARUINT(errSize)); @@ -1733,9 +1685,7 @@ verifyPrepareResult(const List *const archiveIdResultList, const List *const bac } } // Prepare backup results - if (lstEmpty(backupResultList)) - verifyMessageNew(errorList, printAtVerbose, strNewZ("backup: none found")); - else + if (!lstEmpty(backupResultList)) { for (unsigned int backupIdx = 0; backupIdx < lstSize(backupResultList); backupIdx++) { @@ -1771,16 +1721,6 @@ verifyPrepareResult(const List *const archiveIdResultList, const List *const bac kvPut(backupKv, BACKUPS_KEY_CHECKED_VAR, VARUINT(backupResult->totalFileVerify)); kvPut(backupKv, KEY_VALID_VAR, VARUINT(backupResult->totalFileValid)); - // Prepare the message - String *backupMessage = NULL; - if (verboseText || (strcmp(status, "valid") != 0 && strcmp(status, "in-progress") != 0)) - { - backupMessage = strNew(); - strCatFmt(backupMessage, - "backup: %s, status: %s, total files checked: %u, total valid files: %u", - strZ(backupResult->backupLabel), status, backupResult->totalFileVerify, backupResult->totalFileValid); - } - unsigned int errMissing = 0; unsigned int errChecksum = 0; unsigned int errSize = 0; @@ -1804,19 +1744,8 @@ verifyPrepareResult(const List *const archiveIdResultList, const List *const bac KeyValue *const fileErrorsKv = verifyCreateFileErrorsKv(errMissing, errChecksum, errSize, errOther); kvPut(backupKv, KEY_FILEERRORS_VAR, varNewKv(fileErrorsKv)); - - // Create/append file errors string - if (verboseText || errMissing + errChecksum + errSize + errOther > 0) - { - ASSERT(backupMessage != NULL); - strCat(backupMessage, verifyCreateFileErrorsStr(errMissing, errChecksum, errSize, errOther, verboseText)); - } } - // Put the messsage to messages list - if (backupMessage != NULL) - verifyMessageNew(errorList, printAlways, backupMessage); - kvPut(backupKv, KEY_MISSING_VAR, VARUINT(errMissing)); kvPut(backupKv, KEY_CHECKSUMINVALID_VAR, VARUINT(errChecksum)); kvPut(backupKv, KEY_SIZEINVALID_VAR, VARUINT(errSize)); @@ -1848,26 +1777,103 @@ verifyRenderText(const KeyValue *const resultKv, const bool verboseText) String *const result = strNew(); MEM_CONTEXT_TEMP_BEGIN() { - const VariantList *const errorList = kvGetList(resultKv, KEY_ERRORS_VAR); - unsigned int errorTotal = varLstSize(errorList); + const VariantList *const errorList = kvGetList(resultKv, KEY_ERRORS_VAR); String *resultStr = strNew(); - for (unsigned int errIdx = 0; errIdx < errorTotal; errIdx++) + const Variant *const varStatus = kvGet(resultKv, KEY_STATUS_VAR); + + // Show stanza and status if we completed all verifyProcess + if (varStatus != NULL) + strCatFmt( + resultStr, "stanza: %s\nstatus: %s", strZ(cfgOptionStr(cfgOptStanza)), + strZ(varStr(varStatus))); + + const VariantList *const archivesList = kvGetList(resultKv, KEY_ARCHIVES_VAR); + + if (verboseText && varLstEmpty(archivesList)) + strCatZ(resultStr, "\n archiveId: none found"); + else { - const KeyValue *const msg = varKv(varLstGet(errorList, errIdx)); - const String *const message = varStr(kvGet(msg, VERIFY_MSG_KEY_MESSAGE)); - const Variant *varMessagePrint = kvGet(msg, VERIFY_MSG_KEY_MESSAGE_PRINT); - if (varMessagePrint == NULL) - continue; + for (unsigned int archiveIdx = 0; archiveIdx < varLstSize(archivesList); archiveIdx++) + { + Variant *const archiveKv = varLstGet(archivesList, archiveIdx); + if (archiveKv == NULL) + continue; - const VerifyMessagePrint whenPrint = (VerifyMessagePrint)varUInt(varMessagePrint); + const Variant *const archiveId = kvGet(varKv(archiveKv), ARCHIVE_KEY_ARCHIVEID_VAR); + const Variant *const totalWalFile = kvGet(varKv(archiveKv), ARCHIVE_KEY_CHECKED_VAR); + const Variant *const totalValidWAL = kvGet(varKv(archiveKv), KEY_VALID_VAR); - // Print messages which were addressed to the stdout - if ((verboseText && (whenPrint == printAtVerbose)) || whenPrint == printAlways) + if (verboseText || varUInt(totalWalFile) - varUInt(totalValidWAL) != 0) + { + strCatFmt(resultStr,"\n archiveId: %s, total WAL checked: %u, total valid WAL: %u", + strZ(varStr(archiveId)), varUInt(totalWalFile), varUInt(totalValidWAL)); + } + + unsigned int errMissing = varUInt(kvGet(varKv(archiveKv), KEY_MISSING_VAR)); + unsigned int errChecksum = varUInt(kvGet(varKv(archiveKv), KEY_CHECKSUMINVALID_VAR)); + unsigned int errSize = varUInt(kvGet(varKv(archiveKv), KEY_SIZEINVALID_VAR)); + unsigned int errOther = varUInt(kvGet(varKv(archiveKv), KEY_OTHER_VAR)); + + if (varUInt(totalWalFile) > 0 && (verboseText || errMissing + errChecksum + errSize + errOther > 0)) + { + strCat(resultStr, + verifyCreateFileErrorsStr(errMissing, errChecksum, errSize, errOther, verboseText)); + } + } + } + + const VariantList *const backupsList = kvGetList(resultKv, KEY_BACKUPS_VAR); + + if (verboseText && varLstEmpty(backupsList)) + strCatZ(resultStr, "\n backup: none found"); + else + { + for (unsigned int backupIdx = 0; backupIdx < varLstSize(backupsList); backupIdx++) { - strCatFmt(resultStr, "\n %s", strZ(message)); + Variant *const backupKv = varLstGet(backupsList, backupIdx); + if (backupKv == NULL) + continue; + + const Variant *const varLabel = kvGet(varKv(backupKv), BACKUPS_KEY_LABEL_VAR); + const Variant *const varStatus = kvGet(varKv(backupKv), KEY_STATUS_VAR); + const Variant *const varTotalFileVerify = kvGet(varKv(backupKv), BACKUPS_KEY_CHECKED_VAR); + const Variant *const varTotalFileValid = kvGet(varKv(backupKv), KEY_VALID_VAR); + + const char *const status = strZ(varStr(varStatus)); + + if (verboseText || (strcmp(status, "valid") != 0 && strcmp(status, "in-progress") != 0)) + { + strCatFmt(resultStr, + "\n backup: %s, status: %s, total files checked: %u, total valid files: %u", + strZ(varStr(varLabel)), status, varUInt(varTotalFileVerify), varUInt(varTotalFileValid)); + } + + unsigned int errMissing = varUInt(kvGet(varKv(backupKv), KEY_MISSING_VAR)); + unsigned int errChecksum = varUInt(kvGet(varKv(backupKv), KEY_CHECKSUMINVALID_VAR)); + unsigned int errSize = varUInt(kvGet(varKv(backupKv), KEY_SIZEINVALID_VAR)); + unsigned int errOther = varUInt(kvGet(varKv(backupKv), KEY_OTHER_VAR)); + + if (varUInt(varTotalFileVerify) > 0 && (verboseText || errMissing + errChecksum + errSize + errOther > 0)) + { + strCat(resultStr, + verifyCreateFileErrorsStr(errMissing, errChecksum, errSize, errOther, verboseText)); + } } } + + // Render messages which does not have a log level + for (unsigned int errIdx = 0; errIdx < varLstSize(errorList); errIdx++) + { + const KeyValue *const msg = varKv(varLstGet(errorList, errIdx)); + const String *const message = varStr(kvGet(msg, VERIFY_MSG_KEY_MESSAGE)); + const Variant *varLevel = kvGet(msg, VERIFY_MSG_KEY_LEVEL); + + if (varLevel != NULL) + continue; + + strCatFmt(resultStr, "\n %s", strZ(message)); + } strCat(result, resultStr); } MEM_CONTEXT_TEMP_END(); @@ -1909,7 +1915,6 @@ verifyProcess(const bool verboseText) MEM_CONTEXT_TEMP_BEGIN() { unsigned int errorTotal = 0; - String *resultStr = strNew(); KeyValue *resultKv = NULL; VariantList *errorList = varLstNew(); @@ -1922,8 +1927,7 @@ verifyProcess(const bool verboseText) // If a usable backup.info file is not found, then report an error in the log if (backupInfo == NULL) { - strCatZ(resultStr, "\n No usable backup.info file"); - verifyMessageNew(errorList, printNever, strNewZ("No usable backup.info file")); + verifyMessageNew(errorList, strNewZ("No usable backup.info file")); errorTotal++; } @@ -1933,8 +1937,7 @@ verifyProcess(const bool verboseText) // If a usable archive.info file is not found, then report an error in the log if (archiveInfo == NULL) { - strCatZ(resultStr, "\n No usable archive.info file"); - verifyMessageNew(errorList, printNever, strNewZ("No usable archive.info file")); + verifyMessageNew(errorList, strNewZ("No usable archive.info file")); errorTotal++; } @@ -1948,8 +1951,7 @@ verifyProcess(const bool verboseText) } CATCH_ANY() { - strCatFmt(resultStr, "\n %s", errorMessage()); - verifyMessageNew(errorList, printNever, strNewZ(errorMessage())); + verifyMessageNew(errorList, strNewZ(errorMessage())); errorTotal++; } TRY_END(); @@ -1981,9 +1983,7 @@ verifyProcess(const bool verboseText) { if (!regExpMatchOne(backupRegExpStr, backupLabel)) { - strCatFmt(resultStr, "\n '%s' is not a valid backup label format", strZ(backupLabel)); - - verifyMessageNew(errorList, printNever, strNewFmt("'%s' is not a valid backup label format", strZ(backupLabel))); + verifyMessageNew(errorList, strNewFmt("'%s' is not a valid backup label format", strZ(backupLabel))); backupLabelInvalid = true; errorTotal++; @@ -2001,8 +2001,7 @@ verifyProcess(const bool verboseText) if (!backupLabelInvalid && backupLabel != NULL && strLstEmpty(jobData.backupList)) { - strCatFmt(resultStr, "\n backup set %s is not valid", strZ(backupLabel)); - verifyMessageNew(errorList, printNever, strNewFmt("backup set %s is not valid", strZ(backupLabel))); + verifyMessageNew(errorList, strNewFmt("backup set %s is not valid", strZ(backupLabel))); backupLabelInvalid = true; errorTotal++; @@ -2173,13 +2172,11 @@ verifyProcess(const bool verboseText) // ??? Need to do the final reconciliation - checking backup required WAL against, valid WAL // Prepare results KV - resultKv = verifyPrepareResult(jobData.archiveIdResultList, jobData.backupResultList, verboseText); + resultKv = verifyPrepareResult(jobData.archiveIdResultList, jobData.backupResultList); } else if (!backupLabelInvalid) { - strCatZ(resultStr, "\n no archives or backups exist in the repo"); - verifyMessageNew(errorList, printNever, - strNewZ("no archives or backups exist in the repo")); + verifyMessageNew(errorList, strNewZ("no archives or backups exist in the repo")); } errorTotal += jobData.jobErrorTotal; @@ -2213,11 +2210,7 @@ verifyProcess(const bool verboseText) else if (verboseText || errorTotal > 0) { // Render the results as text - strCatFmt( - result, "stanza: %s\nstatus: %s%s%s", strZ(cfgOptionStr(cfgOptStanza)), - errorTotal > 0 ? VERIFY_STATUS_ERROR : VERIFY_STATUS_OK, - strZ(resultStr), - strZ(verifyRenderText(resultKv, verboseText))); + strCat(result, verifyRenderText(resultKv, verboseText)); } } MEM_CONTEXT_TEMP_END(); diff --git a/test/src/module/command/verifyTest.c b/test/src/module/command/verifyTest.c index 9f92a1defb..51a3462313 100644 --- a/test/src/module/command/verifyTest.c +++ b/test/src/module/command/verifyTest.c @@ -747,7 +747,7 @@ testRun(void) lstAdd(archiveIdResult.walRangeList, &walRange); lstAdd(archiveIdResultList, &archiveIdResult); - KeyValue *resultKv = verifyPrepareResult(archiveIdResultList, backupResultList, cfgOptionBool(cfgOptVerbose)); + KeyValue *resultKv = verifyPrepareResult(archiveIdResultList, backupResultList); TEST_RESULT_STR_Z( verifyRenderText(resultKv, cfgOptionBool(cfgOptVerbose)), @@ -769,13 +769,10 @@ testRun(void) "]," "\"backups\":[]," "\"errors\":[" - "{\"level\":5,\"message\":\"archiveId: 9.6-1, wal start: 0, wal stop: 2\"}," - "{\"message\":\"archiveId: 9.6-1, total WAL checked: 1, total valid WAL: 0\",\"whenPrint\":2}," - "{\"message\":\"backup: none found\",\"whenPrint\":1}]}", + "{\"level\":5,\"message\":\"archiveId: 9.6-1, wal start: 0, wal stop: 2\"}" + "]}", "archive: no invalid file list"); - // kvFree(resultKv); - VerifyInvalidFile invalidFile = { .fileName = strNewZ("file"), @@ -793,7 +790,7 @@ testRun(void) lstAdd(backupResult.invalidFileList, &invalidFile); lstAdd(backupResultList, &backupResult); - resultKv = verifyPrepareResult(archiveIdResultList, backupResultList, cfgOptionBool(cfgOptVerbose)); + resultKv = verifyPrepareResult(archiveIdResultList, backupResultList); TEST_RESULT_STR_Z( verifyRenderText(resultKv, cfgOptionBool(cfgOptVerbose)), @@ -831,14 +828,11 @@ testRun(void) "\"valid\":0" "}]," "\"errors\":[" - "{\"level\":5,\"message\":\"archiveId: 9.6-1, wal start: 0, wal stop: 2\"}," - "{\"message\":\"archiveId: 9.6-1, total WAL checked: 1, total valid WAL: 0\\n missing: 1\",\"whenPrint\":2}," - "{\"message\":\"backup: test-backup-label, status: invalid, total files checked: 1, total valid files: 0\\n missing: 1\",\"whenPrint\":2}]" + "{\"level\":5,\"message\":\"archiveId: 9.6-1, wal start: 0, wal stop: 2\"}" + "]" "}", "archive file missing, backup file missing, no text, no verbose, json output"); - // kvFree(resultKv); - // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("verifyAddInvalidWalFile() - file missing (coverage test)"); @@ -1054,7 +1048,7 @@ testRun(void) "\"level\":5,"\ "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/backup.info.copy' for read\""\ "},{"\ - "\"message\":\"No usable backup.info file\",\"whenPrint\":0"\ + "\"message\":\"No usable backup.info file\""\ "},{"\ "\"level\":5,"\ "\"message\":\"unable to open missing file '" TEST_PATH "/repo/archive/db/archive.info' for read\""\ @@ -1062,7 +1056,7 @@ testRun(void) "\"level\":5,"\ "\"message\":\"unable to open missing file '" TEST_PATH "/repo/archive/db/archive.info.copy' for read\""\ "},{"\ - "\"message\":\"No usable archive.info file\",\"whenPrint\":0"\ + "\"message\":\"No usable archive.info file\""\ "}"\ "],"\ "\"stanza\":\"db\","\ @@ -1123,7 +1117,7 @@ testRun(void) "},{"\ "\"level\":5,\"message\":\"invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS' /archive.info.copy\""\ "},{"\ - "\"message\":\"No usable archive.info file\",\"whenPrint\":0"\ + "\"message\":\"No usable archive.info file\""\ "}"\ "],"\ "\"stanza\":\"db\","\ @@ -1175,7 +1169,7 @@ testRun(void) "\"level\":5,"\ "\"message\":\"invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS' /archive.info\""\ "},{"\ - "\"message\":\"backup info file and archive info file do not match\\narchive: id = 1, version = 9.5, system-id = 10000000000000090500\\nbackup : id = 2, version = 11, system-id = 10000000000000110000\\nHINT: this may be a symptom of repository corruption!\",\"whenPrint\":0"\ + "\"message\":\"backup info file and archive info file do not match\\narchive: id = 1, version = 9.5, system-id = 10000000000000090500\\nbackup : id = 2, version = 11, system-id = 10000000000000110000\\nHINT: this may be a symptom of repository corruption!\""\ "}"\ "],"\ "\"stanza\":\"db\","\ @@ -1220,7 +1214,7 @@ testRun(void) "\"level\":5,"\ "\"message\":\"archive.info.copy does not match archive.info\""\ "},"\ - "{\"message\":\"no archives or backups exist in the repo\",\"whenPrint\":0}"\ + "{\"message\":\"no archives or backups exist in the repo\"}"\ "],"\ "\"stanza\":\"db\","\ "\"status\":\"ok\""\ @@ -1264,7 +1258,7 @@ testRun(void) "\"level\":5,"\ "\"message\":\"unable to open missing file '" TEST_PATH "/repo/archive/db/archive.info.copy' for read\""\ "},"\ - "{\"message\":\"no archives or backups exist in the repo\",\"whenPrint\":0}"\ + "{\"message\":\"no archives or backups exist in the repo\"}"\ "],"\ "\"stanza\":\"db\","\ "\"status\":\"ok\""\ @@ -1315,7 +1309,7 @@ testRun(void) "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/backup.info.copy' for read\""\ "},"\ "{"\ - "\"message\":\"No usable backup.info file\",\"whenPrint\":0"\ + "\"message\":\"No usable backup.info file\""\ "}"\ "],"\ "\"stanza\":\"db\","\ @@ -1561,9 +1555,7 @@ testRun(void) "{"\ "\"level\":5,"\ "\"message\":\"archiveId: 11-2, wal start: 000000020000000700000FFD, wal stop: 000000020000000800000000\""\ - "},"\ - "{\"message\":\"archiveId: 11-2, total WAL checked: 4, total valid WAL: 2\\n checksum invalid: 1, size invalid: 1\",\"whenPrint\":2},"\ - "{\"message\":\"backup: none found\",\"whenPrint\":1}"\ + "}"\ "],"\ "\"stanza\":\"db\","\ "\"status\":\"error\""\ @@ -1659,13 +1651,10 @@ testRun(void) "\"message\":\"invalid size '11-2/0000000200000007/000000020000000700000FFF-ee161f898c9012dd0c28b3fd1e7140b9cf411306'\"," \ "\"pid\":1" \ "}," \ - "{\"message\":\"archiveId: 9.5-1, total WAL checked: 0, total valid WAL: 0\",\"whenPrint\":2}," \ "{" \ "\"level\":5," \ "\"message\":\"archiveId: 11-2, wal start: 000000020000000700000FFD, wal stop: 000000020000000800000000\"" \ - "}," \ - "{\"message\":\"archiveId: 11-2, total WAL checked: 4, total valid WAL: 2\\n missing: 0, checksum invalid: 1, size invalid: 1, other: 0\",\"whenPrint\":2}," \ - "{\"message\":\"backup: none found\",\"whenPrint\":1}" \ + "}" \ "]," \ "\"stanza\":\"db\"," \ "\"status\":\"error\"" \ @@ -2051,8 +2040,7 @@ testRun(void) "{" \ "\"level\":4," \ "\"message\":\"backup '20181119-152800F' appears to be in progress, skipping\"" \ - "}," \ - "{\"message\":\"archiveId: none found\",\"whenPrint\":1}" \ + "}" \ "]," \ "\"stanza\":\"db\"," \ "\"status\":\"ok\"" \ @@ -2631,10 +2619,7 @@ testRun(void) "\"level\":4," \ "\"message\":\"invalid checksum '20181119-152900F/pg_data/biind.pgbi'\"," \ "\"pid\":1" \ - "}," \ - "{\"message\":\"archiveId: none found\",\"whenPrint\":1}," \ - "{\"message\":\"backup: 20181119-152900F, status: invalid, total files checked: 2, total valid files: 0\\n missing: 0, checksum invalid: 2, size invalid: 0, other: 0\",\"whenPrint\":2}," \ - "{\"message\":\"backup: 20181119-152900F_20181119-152909D, status: invalid, total files checked: 2, total valid files: 1\\n missing: 0, checksum invalid: 1, size invalid: 0, other: 0\",\"whenPrint\":2}" \ + "}" \ "]," \ "\"stanza\":\"db\"," \ "\"status\":\"error\"" \ From d356b628b9aa2c8adbc9c62c37a0723776144f8d Mon Sep 17 00:00:00 2001 From: Denis Kovalev Date: Thu, 24 Jul 2025 13:59:04 +0300 Subject: [PATCH 08/12] rename errors to messages in JSON and move resultKv to the parameter --- src/command/verify/verify.c | 46 +++++++++++++--------------- test/src/module/command/verifyTest.c | 30 +++++++++--------- 2 files changed, 37 insertions(+), 39 deletions(-) diff --git a/src/command/verify/verify.c b/src/command/verify/verify.c index 24caa90d0c..fd25d24eb7 100644 --- a/src/command/verify/verify.c +++ b/src/command/verify/verify.c @@ -52,7 +52,7 @@ VARIANT_STRDEF_STATIC(KEY_BACKUPS_VAR, "backups"); VARIANT_STRDEF_STATIC(BACKUPS_KEY_LABEL_VAR, "label"); VARIANT_STRDEF_STATIC(KEY_STATUS_VAR, "status"); VARIANT_STRDEF_STATIC(BACKUPS_KEY_CHECKED_VAR, "checked"); -VARIANT_STRDEF_STATIC(KEY_ERRORS_VAR, "errors"); +VARIANT_STRDEF_STATIC(KEY_MESSAGES_VAR, "messages"); VARIANT_STRDEF_STATIC(VERIFY_KEY_STANZA_VAR, "stanza"); VARIANT_STRDEF_STATIC(VERIFY_KEY_STATUS_ERROR, "error"); VARIANT_STRDEF_STATIC(VERIFY_KEY_STATUS_OK, "ok"); @@ -1606,12 +1606,13 @@ verifyCreateFileErrorsKv( /*********************************************************************************************************************************** Render the results of the verify command ***********************************************************************************************************************************/ -static KeyValue * -verifyPrepareResult(const List *const archiveIdResultList, const List *const backupResultList) +static void +verifyPrepareResult(const List *const archiveIdResultList, const List *const backupResultList, KeyValue *resultKv) { FUNCTION_TEST_BEGIN(); FUNCTION_TEST_PARAM(LIST, archiveIdResultList); // Result list for all archive Ids in the repo FUNCTION_TEST_PARAM(LIST, backupResultList); // Result list for all backups in the repo + FUNCTION_TEST_PARAM(KEY_VALUE, resultKv); // Result key-value pair FUNCTION_TEST_END(); FUNCTION_AUDIT_HELPER(); @@ -1619,12 +1620,10 @@ verifyPrepareResult(const List *const archiveIdResultList, const List *const bac ASSERT(archiveIdResultList != NULL); ASSERT(backupResultList != NULL); - KeyValue *resultKv = kvNew(); - // Prepare archive results VariantList *archivesList = varLstNew(); VariantList *backupsList = varLstNew(); - VariantList *errorList = varLstNew(); + VariantList *messageList = varLstNew(); if (!lstEmpty(archiveIdResultList)) { @@ -1651,7 +1650,7 @@ verifyPrepareResult(const List *const archiveIdResultList, const List *const bac String *errorMsg = strNewFmt( "archiveId: %s, wal start: %s, wal stop: %s", strZ(archiveIdResult->archiveId), strZ(walRange->start), strZ(walRange->stop)); - verifyErrorNew(errorList, logLevelDetail, errorMsg); + verifyErrorNew(messageList, logLevelDetail, errorMsg); unsigned int invalidIdx = 0; @@ -1756,9 +1755,9 @@ verifyPrepareResult(const List *const archiveIdResultList, const List *const bac kvPut(resultKv, KEY_ARCHIVES_VAR, varNewVarLst(archivesList)); kvPut(resultKv, KEY_BACKUPS_VAR, varNewVarLst(backupsList)); - kvPut(resultKv, KEY_ERRORS_VAR, varNewVarLst(errorList)); + kvPut(resultKv, KEY_MESSAGES_VAR, varNewVarLst(messageList)); - FUNCTION_TEST_RETURN(KEY_VALUE, resultKv); + FUNCTION_TEST_RETURN_VOID(); } /*********************************************************************************************************************************** @@ -1777,7 +1776,7 @@ verifyRenderText(const KeyValue *const resultKv, const bool verboseText) String *const result = strNew(); MEM_CONTEXT_TEMP_BEGIN() { - const VariantList *const errorList = kvGetList(resultKv, KEY_ERRORS_VAR); + const VariantList *const messageList = kvGetList(resultKv, KEY_MESSAGES_VAR); String *resultStr = strNew(); const Variant *const varStatus = kvGet(resultKv, KEY_STATUS_VAR); @@ -1863,9 +1862,9 @@ verifyRenderText(const KeyValue *const resultKv, const bool verboseText) } // Render messages which does not have a log level - for (unsigned int errIdx = 0; errIdx < varLstSize(errorList); errIdx++) + for (unsigned int errIdx = 0; errIdx < varLstSize(messageList); errIdx++) { - const KeyValue *const msg = varKv(varLstGet(errorList, errIdx)); + const KeyValue *const msg = varKv(varLstGet(messageList, errIdx)); const String *const message = varStr(kvGet(msg, VERIFY_MSG_KEY_MESSAGE)); const Variant *varLevel = kvGet(msg, VERIFY_MSG_KEY_LEVEL); @@ -1915,7 +1914,8 @@ verifyProcess(const bool verboseText) MEM_CONTEXT_TEMP_BEGIN() { unsigned int errorTotal = 0; - KeyValue *resultKv = NULL; + KeyValue *resultKv = kvNew(); +; VariantList *errorList = varLstNew(); // Get the repo storage in case it is remote and encryption settings need to be pulled down @@ -2172,7 +2172,7 @@ verifyProcess(const bool verboseText) // ??? Need to do the final reconciliation - checking backup required WAL against, valid WAL // Prepare results KV - resultKv = verifyPrepareResult(jobData.archiveIdResultList, jobData.backupResultList); + verifyPrepareResult(jobData.archiveIdResultList, jobData.backupResultList, resultKv); } else if (!backupLabelInvalid) { @@ -2182,25 +2182,21 @@ verifyProcess(const bool verboseText) errorTotal += jobData.jobErrorTotal; } - if (resultKv == NULL) - resultKv = kvNew(); - kvPut(resultKv, VERIFY_KEY_STANZA_VAR, VARSTR(cfgOptionStr(cfgOptStanza))); kvPut(resultKv, KEY_STATUS_VAR, errorTotal > 0 ? VERIFY_KEY_STATUS_ERROR : VERIFY_KEY_STATUS_OK); - const Variant *resultError = kvGet(resultKv, KEY_ERRORS_VAR); - if (resultError != NULL) + const Variant *resultMessages = kvGet(resultKv, KEY_MESSAGES_VAR); + if (resultMessages != NULL) { - VariantList *const resultErrorList = varVarLst(resultError); - for (unsigned int errIdx = 0; errIdx < varLstSize(resultErrorList); errIdx++) + VariantList *const resultMessagesList = varVarLst(resultMessages); + for (unsigned int errIdx = 0; errIdx < varLstSize(resultMessagesList); errIdx++) { - Variant *item = varLstGet(resultErrorList, errIdx); - Variant *dup = varDup(item); - varLstAdd(errorList, dup); + Variant *item = varLstGet(resultMessagesList, errIdx); + varLstAdd(errorList, varDup(item)); } } - kvPut(resultKv, KEY_ERRORS_VAR, varNewVarLst(errorList)); + kvPut(resultKv, KEY_MESSAGES_VAR, varNewVarLst(errorList)); if (json) { diff --git a/test/src/module/command/verifyTest.c b/test/src/module/command/verifyTest.c index 51a3462313..8d82d24eb4 100644 --- a/test/src/module/command/verifyTest.c +++ b/test/src/module/command/verifyTest.c @@ -747,7 +747,8 @@ testRun(void) lstAdd(archiveIdResult.walRangeList, &walRange); lstAdd(archiveIdResultList, &archiveIdResult); - KeyValue *resultKv = verifyPrepareResult(archiveIdResultList, backupResultList); + KeyValue *resultKv = kvNew(); + verifyPrepareResult(archiveIdResultList, backupResultList, resultKv); TEST_RESULT_STR_Z( verifyRenderText(resultKv, cfgOptionBool(cfgOptVerbose)), @@ -768,7 +769,7 @@ testRun(void) "}" "]," "\"backups\":[]," - "\"errors\":[" + "\"messages\":[" "{\"level\":5,\"message\":\"archiveId: 9.6-1, wal start: 0, wal stop: 2\"}" "]}", "archive: no invalid file list"); @@ -790,7 +791,8 @@ testRun(void) lstAdd(backupResult.invalidFileList, &invalidFile); lstAdd(backupResultList, &backupResult); - resultKv = verifyPrepareResult(archiveIdResultList, backupResultList); + resultKv = kvNew(); + verifyPrepareResult(archiveIdResultList, backupResultList, resultKv); TEST_RESULT_STR_Z( verifyRenderText(resultKv, cfgOptionBool(cfgOptVerbose)), @@ -827,7 +829,7 @@ testRun(void) "\"status\":\"invalid\"," "\"valid\":0" "}]," - "\"errors\":[" + "\"messages\":[" "{\"level\":5,\"message\":\"archiveId: 9.6-1, wal start: 0, wal stop: 2\"}" "]" "}", @@ -1040,7 +1042,7 @@ testRun(void) dup2(stdoutSave, STDOUT_FILENO); #define EXPECTED_OUTPUT_JSON "{"\ - "\"errors\":[" \ + "\"messages\":[" \ "{"\ "\"level\":5,"\ "\"message\":\"invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS' /backup.info\""\ @@ -1107,7 +1109,7 @@ testRun(void) dup2(stdoutSave, STDOUT_FILENO); #define EXPECTED_OUTPUT_JSON "{"\ - "\"errors\":["\ + "\"messages\":["\ "{"\ "\"level\":5,"\ "\"message\":\"invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS' /backup.info\""\ @@ -1161,7 +1163,7 @@ testRun(void) dup2(stdoutSave, STDOUT_FILENO); #define EXPECTED_OUTPUT_JSON "{"\ - "\"errors\":["\ + "\"messages\":["\ "{"\ "\"level\":5,"\ "\"message\":\"backup.info.copy does not match backup.info\""\ @@ -1209,7 +1211,7 @@ testRun(void) dup2(stdoutSave, STDOUT_FILENO); #define EXPECTED_OUTPUT_JSON "{"\ - "\"errors\":["\ + "\"messages\":["\ "{"\ "\"level\":5,"\ "\"message\":\"archive.info.copy does not match archive.info\""\ @@ -1249,7 +1251,7 @@ testRun(void) dup2(stdoutSave, STDOUT_FILENO); #define EXPECTED_OUTPUT_JSON "{"\ - "\"errors\":["\ + "\"messages\":["\ "{"\ "\"level\":5,"\ "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/backup.info.copy' for read\""\ @@ -1299,7 +1301,7 @@ testRun(void) dup2(stdoutSave, STDOUT_FILENO); #define EXPECTED_OUTPUT_JSON "{"\ - "\"errors\":["\ + "\"messages\":["\ "{"\ "\"level\":5,"\ "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/backup.info' for read\""\ @@ -1529,7 +1531,7 @@ testRun(void) "}"\ "],"\ "\"backups\":[],"\ - "\"errors\":["\ + "\"messages\":["\ "{"\ "\"level\":5,"\ "\"message\":\"no backups exist in the repo\""\ @@ -1628,7 +1630,7 @@ testRun(void) "}" \ "]," \ "\"backups\":[]," \ - "\"errors\":[" \ + "\"messages\":[" \ "{" \ "\"level\":5," \ "\"message\":\"no backups exist in the repo\"" \ @@ -2024,7 +2026,7 @@ testRun(void) "\"valid\":0" \ "}" \ "]," \ - "\"errors\":[" \ + "\"messages\":[" \ "{" \ "\"level\":5," \ "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/backup.info.copy' for read\"" \ @@ -2605,7 +2607,7 @@ testRun(void) "\"valid\":1" \ "}" \ "]," \ - "\"errors\":[" \ + "\"messages\":[" \ "{" \ "\"level\":5," \ "\"message\":\"no archives exist in the repo\"" \ From b34b569b420f46d5bede4031f0e858cdf82c8ce3 Mon Sep 17 00:00:00 2001 From: Denis Kovalev Date: Thu, 24 Jul 2025 14:19:50 +0300 Subject: [PATCH 09/12] format code --- src/command/verify/verify.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/command/verify/verify.c b/src/command/verify/verify.c index fd25d24eb7..7f0f7e7dec 100644 --- a/src/command/verify/verify.c +++ b/src/command/verify/verify.c @@ -1776,20 +1776,20 @@ verifyRenderText(const KeyValue *const resultKv, const bool verboseText) String *const result = strNew(); MEM_CONTEXT_TEMP_BEGIN() { - const VariantList *const messageList = kvGetList(resultKv, KEY_MESSAGES_VAR); + const VariantList *const messageList = kvGetList(resultKv, KEY_MESSAGES_VAR); String *resultStr = strNew(); const Variant *const varStatus = kvGet(resultKv, KEY_STATUS_VAR); // Show stanza and status if we completed all verifyProcess - if (varStatus != NULL) + if (varStatus != NULL) strCatFmt( - resultStr, "stanza: %s\nstatus: %s", strZ(cfgOptionStr(cfgOptStanza)), - strZ(varStr(varStatus))); - + resultStr, "stanza: %s\nstatus: %s", strZ(cfgOptionStr(cfgOptStanza)), + strZ(varStr(varStatus))); + const VariantList *const archivesList = kvGetList(resultKv, KEY_ARCHIVES_VAR); - if (verboseText && varLstEmpty(archivesList)) + if (verboseText && varLstEmpty(archivesList)) strCatZ(resultStr, "\n archiveId: none found"); else { @@ -1806,7 +1806,7 @@ verifyRenderText(const KeyValue *const resultKv, const bool verboseText) if (verboseText || varUInt(totalWalFile) - varUInt(totalValidWAL) != 0) { strCatFmt(resultStr,"\n archiveId: %s, total WAL checked: %u, total valid WAL: %u", - strZ(varStr(archiveId)), varUInt(totalWalFile), varUInt(totalValidWAL)); + strZ(varStr(archiveId)), varUInt(totalWalFile), varUInt(totalValidWAL)); } unsigned int errMissing = varUInt(kvGet(varKv(archiveKv), KEY_MISSING_VAR)); @@ -1824,7 +1824,7 @@ verifyRenderText(const KeyValue *const resultKv, const bool verboseText) const VariantList *const backupsList = kvGetList(resultKv, KEY_BACKUPS_VAR); - if (verboseText && varLstEmpty(backupsList)) + if (verboseText && varLstEmpty(backupsList)) strCatZ(resultStr, "\n backup: none found"); else { @@ -1844,8 +1844,8 @@ verifyRenderText(const KeyValue *const resultKv, const bool verboseText) if (verboseText || (strcmp(status, "valid") != 0 && strcmp(status, "in-progress") != 0)) { strCatFmt(resultStr, - "\n backup: %s, status: %s, total files checked: %u, total valid files: %u", - strZ(varStr(varLabel)), status, varUInt(varTotalFileVerify), varUInt(varTotalFileValid)); + "\n backup: %s, status: %s, total files checked: %u, total valid files: %u", + strZ(varStr(varLabel)), status, varUInt(varTotalFileVerify), varUInt(varTotalFileValid)); } unsigned int errMissing = varUInt(kvGet(varKv(backupKv), KEY_MISSING_VAR)); @@ -1853,10 +1853,10 @@ verifyRenderText(const KeyValue *const resultKv, const bool verboseText) unsigned int errSize = varUInt(kvGet(varKv(backupKv), KEY_SIZEINVALID_VAR)); unsigned int errOther = varUInt(kvGet(varKv(backupKv), KEY_OTHER_VAR)); - if (varUInt(varTotalFileVerify) > 0 && (verboseText || errMissing + errChecksum + errSize + errOther > 0)) + if (varUInt(varTotalFileVerify) > 0 && (verboseText || errMissing + errChecksum + errSize + errOther > 0)) { - strCat(resultStr, - verifyCreateFileErrorsStr(errMissing, errChecksum, errSize, errOther, verboseText)); + strCat(resultStr, + verifyCreateFileErrorsStr(errMissing, errChecksum, errSize, errOther, verboseText)); } } } @@ -1915,7 +1915,6 @@ verifyProcess(const bool verboseText) { unsigned int errorTotal = 0; KeyValue *resultKv = kvNew(); -; VariantList *errorList = varLstNew(); // Get the repo storage in case it is remote and encryption settings need to be pulled down @@ -2191,7 +2190,7 @@ verifyProcess(const bool verboseText) VariantList *const resultMessagesList = varVarLst(resultMessages); for (unsigned int errIdx = 0; errIdx < varLstSize(resultMessagesList); errIdx++) { - Variant *item = varLstGet(resultMessagesList, errIdx); + Variant *item = varLstGet(resultMessagesList, errIdx); varLstAdd(errorList, varDup(item)); } } From d519663da288d68573879f37eca6ddfcf5530f56 Mon Sep 17 00:00:00 2001 From: Denis Kovalev Date: Thu, 24 Jul 2025 18:03:00 +0300 Subject: [PATCH 10/12] rename errorList to messageList --- src/command/verify/verify.c | 132 ++++++++++++++++++------------------ 1 file changed, 66 insertions(+), 66 deletions(-) diff --git a/src/command/verify/verify.c b/src/command/verify/verify.c index 7f0f7e7dec..9b3fef78a2 100644 --- a/src/command/verify/verify.c +++ b/src/command/verify/verify.c @@ -155,17 +155,17 @@ typedef struct VerifyJobData bool enableArchiveFilter; // Only check archives in the specified range const String *archiveStart; // Start of the WAL range to be verified const String *archiveStop; // End of the WAL range to be verified - VariantList *errorList; // List of errors that occurred during the job + VariantList *messageList; // List of errors that occurred during the job } VerifyJobData; /*********************************************************************************************************************************** Helper function to add a string with log level to an error list ***********************************************************************************************************************************/ static void -verifyErrorNew(VariantList *errorList, const LogLevel logLevel, const String *const message) +verifyErrorNew(VariantList *messageList, const LogLevel logLevel, const String *const message) { FUNCTION_TEST_BEGIN(); - FUNCTION_TEST_PARAM(VARIANT_LIST, errorList); // Error list to add to + FUNCTION_TEST_PARAM(VARIANT_LIST, messageList); // Error list to add to FUNCTION_LOG_PARAM(ENUM, logLevel); // Log level FUNCTION_TEST_PARAM(STRING, message); // Error message FUNCTION_TEST_END(); @@ -174,14 +174,14 @@ verifyErrorNew(VariantList *errorList, const LogLevel logLevel, const String *co ASSERT(message != NULL); - MEM_CONTEXT_BEGIN(lstMemContext((List *)errorList)) + MEM_CONTEXT_BEGIN(lstMemContext((List *)messageList)) { KeyValue *errorMsg = kvNew(); kvPut(errorMsg, VERIFY_MSG_KEY_LEVEL, VARUINT(logLevel)); kvPut(errorMsg, VERIFY_MSG_KEY_MESSAGE, VARSTR(strDup(message))); - varLstAdd(errorList, varNewKv(errorMsg)); + varLstAdd(messageList, varNewKv(errorMsg)); // Duplicate the message to the log as soon as in appears. // Perhaps user may want to see it immediately. @@ -197,10 +197,10 @@ verifyErrorNew(VariantList *errorList, const LogLevel logLevel, const String *co Helper function to add a string with log level and process id to an error list ***********************************************************************************************************************************/ static void -verifyErrorPidNew(VariantList *errorList, const LogLevel logLevel, const unsigned int pid, const String *const message) +verifyErrorPidNew(VariantList *messageList, const LogLevel logLevel, const unsigned int pid, const String *const message) { FUNCTION_TEST_BEGIN(); - FUNCTION_TEST_PARAM(VARIANT_LIST, errorList); // Error list to add to + FUNCTION_TEST_PARAM(VARIANT_LIST, messageList); // Error list to add to FUNCTION_LOG_PARAM(ENUM, logLevel); // Log level FUNCTION_TEST_PARAM(UINT, pid); // Process id FUNCTION_TEST_PARAM(STRING, message); // Error message @@ -210,7 +210,7 @@ verifyErrorPidNew(VariantList *errorList, const LogLevel logLevel, const unsigne ASSERT(message != NULL); - MEM_CONTEXT_BEGIN(lstMemContext((List *)errorList)) + MEM_CONTEXT_BEGIN(lstMemContext((List *)messageList)) { KeyValue *const errorMsg = kvNew(); @@ -218,7 +218,7 @@ verifyErrorPidNew(VariantList *errorList, const LogLevel logLevel, const unsigne kvPut(errorMsg, VERIFY_MSG_KEY_MESSAGE, VARSTR(strDup(message))); kvPut(errorMsg, VERIFY_MSG_KEY_PID, VARUINT(pid)); - varLstAdd(errorList, varNewKv(errorMsg)); + varLstAdd(messageList, varNewKv(errorMsg)); } LOG_PID(logLevel, pid, 0, strZ(message)); MEM_CONTEXT_END(); @@ -317,13 +317,13 @@ verifyFileLoad(const String *const pathFileName, const String *const cipherPass) Get status of info files in the repository ***********************************************************************************************************************************/ static VerifyInfoFile -verifyInfoFile(const String *const pathFileName, const bool keepFile, const String *const cipherPass, VariantList *const errorList) +verifyInfoFile(const String *const pathFileName, const bool keepFile, const String *const cipherPass, VariantList *const messageList) { FUNCTION_LOG_BEGIN(logLevelDebug); FUNCTION_LOG_PARAM(STRING, pathFileName); // Fully qualified path/file name FUNCTION_LOG_PARAM(BOOL, keepFile); // Should the file be kept in memory? FUNCTION_TEST_PARAM(STRING, cipherPass); // Password to open file if encrypted - FUNCTION_TEST_PARAM(LIST, errorList); // List of errors + FUNCTION_TEST_PARAM(LIST, messageList); // List of errors FUNCTION_LOG_END(); FUNCTION_AUDIT_STRUCT(); @@ -368,7 +368,7 @@ verifyInfoFile(const String *const pathFileName, const bool keepFile, const Stri if (result.errorCode == errorTypeCode(&ChecksumError)) strCat(errorMsg, strNewFmt(" %s", strZ(pathFileName))); - verifyErrorNew(errorList, logLevelDetail, errorMsg); + verifyErrorNew(messageList, logLevelDetail, errorMsg); } TRY_END(); } @@ -381,10 +381,10 @@ verifyInfoFile(const String *const pathFileName, const bool keepFile, const Stri Get the archive.info file ***********************************************************************************************************************************/ static InfoArchive * -verifyArchiveInfoFile(VariantList *const errorList) +verifyArchiveInfoFile(VariantList *const messageList) { FUNCTION_LOG_BEGIN(logLevelDebug); - FUNCTION_TEST_PARAM(LIST, errorList); // List of errors + FUNCTION_TEST_PARAM(LIST, messageList); // List of errors FUNCTION_LOG_END(); InfoArchive *result = NULL; @@ -394,7 +394,7 @@ verifyArchiveInfoFile(VariantList *const errorList) // Get the main info file const VerifyInfoFile verifyArchiveInfo = verifyInfoFile( INFO_ARCHIVE_PATH_FILE_STR, true, cfgOptionStrNull(cfgOptRepoCipherPass), - errorList); + messageList); // If the main file did not error, then report on the copy's status and check checksums if (verifyArchiveInfo.errorCode == 0) @@ -404,7 +404,7 @@ verifyArchiveInfoFile(VariantList *const errorList) // Attempt to load the copy and report on it's status but don't keep it in memory const VerifyInfoFile verifyArchiveInfoCopy = verifyInfoFile( - INFO_ARCHIVE_PATH_FILE_COPY_STR, false, cfgOptionStrNull(cfgOptRepoCipherPass), errorList); + INFO_ARCHIVE_PATH_FILE_COPY_STR, false, cfgOptionStrNull(cfgOptRepoCipherPass), messageList); // If the copy loaded successfully, then check the checksums if (verifyArchiveInfoCopy.errorCode == 0) @@ -412,14 +412,14 @@ verifyArchiveInfoFile(VariantList *const errorList) // If the info and info.copy checksums don't match each other than one (or both) of the files could be corrupt so // log a warning but must trust main if (!strEq(verifyArchiveInfo.checksum, verifyArchiveInfoCopy.checksum)) - verifyErrorNew(errorList, logLevelDetail, strNewZ("archive.info.copy does not match archive.info")); + verifyErrorNew(messageList, logLevelDetail, strNewZ("archive.info.copy does not match archive.info")); } } else { // Attempt to load the copy const VerifyInfoFile verifyArchiveInfoCopy = verifyInfoFile( - INFO_ARCHIVE_PATH_FILE_COPY_STR, true, cfgOptionStrNull(cfgOptRepoCipherPass), errorList); + INFO_ARCHIVE_PATH_FILE_COPY_STR, true, cfgOptionStrNull(cfgOptRepoCipherPass), messageList); // If loaded successfully, then return the copy as usable if (verifyArchiveInfoCopy.errorCode == 0) @@ -438,10 +438,10 @@ verifyArchiveInfoFile(VariantList *const errorList) Get the backup.info file ***********************************************************************************************************************************/ static InfoBackup * -verifyBackupInfoFile(VariantList *const errorList) +verifyBackupInfoFile(VariantList *const messageList) { FUNCTION_LOG_BEGIN(logLevelDebug); - FUNCTION_TEST_PARAM(LIST, errorList); // List of errors + FUNCTION_TEST_PARAM(LIST, messageList); // List of errors FUNCTION_LOG_END(); InfoBackup *result = NULL; @@ -450,7 +450,7 @@ verifyBackupInfoFile(VariantList *const errorList) { // Get the main info file const VerifyInfoFile verifyBackupInfo = verifyInfoFile( - INFO_BACKUP_PATH_FILE_STR, true, cfgOptionStrNull(cfgOptRepoCipherPass), errorList); + INFO_BACKUP_PATH_FILE_STR, true, cfgOptionStrNull(cfgOptRepoCipherPass), messageList); // If the main file did not error, then report on the copy's status and check checksums if (verifyBackupInfo.errorCode == 0) @@ -460,7 +460,7 @@ verifyBackupInfoFile(VariantList *const errorList) // Attempt to load the copy and report on it's status but don't keep it in memory const VerifyInfoFile verifyBackupInfoCopy = verifyInfoFile( - INFO_BACKUP_PATH_FILE_COPY_STR, false, cfgOptionStrNull(cfgOptRepoCipherPass), errorList); + INFO_BACKUP_PATH_FILE_COPY_STR, false, cfgOptionStrNull(cfgOptRepoCipherPass), messageList); // If the copy loaded successfully, then check the checksums if (verifyBackupInfoCopy.errorCode == 0) @@ -468,14 +468,14 @@ verifyBackupInfoFile(VariantList *const errorList) // If the info and info.copy checksums don't match each other than one (or both) of the files could be corrupt so // log a warning but must trust main if (!strEq(verifyBackupInfo.checksum, verifyBackupInfoCopy.checksum)) - verifyErrorNew(errorList, logLevelDetail, strNewZ("backup.info.copy does not match backup.info")); + verifyErrorNew(messageList, logLevelDetail, strNewZ("backup.info.copy does not match backup.info")); } } else { // Attempt to load the copy const VerifyInfoFile verifyBackupInfoCopy = verifyInfoFile( - INFO_BACKUP_PATH_FILE_COPY_STR, true, cfgOptionStrNull(cfgOptRepoCipherPass), errorList); + INFO_BACKUP_PATH_FILE_COPY_STR, true, cfgOptionStrNull(cfgOptRepoCipherPass), messageList); // If loaded successfully, then return the copy as usable if (verifyBackupInfoCopy.errorCode == 0) @@ -496,7 +496,7 @@ Get the manifest file static Manifest * verifyManifestFile( VerifyBackupResult *const backupResult, const String *const cipherPass, bool currentBackup, const InfoPg *const pgHistory, - unsigned int *const jobErrorTotal, VariantList *const errorList) + unsigned int *const jobErrorTotal, VariantList *const messageList) { FUNCTION_LOG_BEGIN(logLevelDebug); FUNCTION_LOG_PARAM_P(VERIFY_BACKUP_RESULT, backupResult); // The result set for the backup being processed @@ -504,7 +504,7 @@ verifyManifestFile( FUNCTION_LOG_PARAM(BOOL, currentBackup); // Is this possibly a backup currently in progress? FUNCTION_LOG_PARAM(INFO_PG, pgHistory); // Database history FUNCTION_LOG_PARAM_P(UINT, jobErrorTotal); // Pointer to the overall job error total - FUNCTION_TEST_PARAM(LIST, errorList); // List of errors + FUNCTION_TEST_PARAM(LIST, messageList); // List of errors FUNCTION_LOG_END(); Manifest *result = NULL; @@ -514,7 +514,7 @@ verifyManifestFile( const String *const fileName = strNewFmt(STORAGE_REPO_BACKUP "/%s/" BACKUP_MANIFEST_FILE, strZ(backupResult->backupLabel)); // Get the main manifest file - const VerifyInfoFile verifyManifestInfo = verifyInfoFile(fileName, true, cipherPass, errorList); + const VerifyInfoFile verifyManifestInfo = verifyInfoFile(fileName, true, cipherPass, messageList); // If the main file did not error, then report on the copy's status and check checksums if (verifyManifestInfo.errorCode == 0) @@ -528,7 +528,7 @@ verifyManifestFile( // Attempt to load the copy and report on it's status but don't keep it in memory const VerifyInfoFile verifyManifestInfoCopy = verifyInfoFile( - strNewFmt("%s%s", strZ(fileName), INFO_COPY_EXT), false, cipherPass, errorList); + strNewFmt("%s%s", strZ(fileName), INFO_COPY_EXT), false, cipherPass, messageList); // If the copy loaded successfully, then check the checksums if (verifyManifestInfoCopy.errorCode == 0) @@ -538,7 +538,7 @@ verifyManifestFile( if (!strEq(verifyManifestInfo.checksum, verifyManifestInfoCopy.checksum)) { String *errorMsg = strNewFmt("backup '%s' manifest.copy does not match manifest", strZ(backupResult->backupLabel)); - verifyErrorNew(errorList, logLevelDetail, errorMsg); + verifyErrorNew(messageList, logLevelDetail, errorMsg); } } } @@ -552,13 +552,13 @@ verifyManifestFile( currentBackup = false; const VerifyInfoFile verifyManifestInfoCopy = verifyInfoFile( - strNewFmt("%s%s", strZ(fileName), INFO_COPY_EXT), true, cipherPass, errorList); + strNewFmt("%s%s", strZ(fileName), INFO_COPY_EXT), true, cipherPass, messageList); // If loaded successfully, then return the copy as usable if (verifyManifestInfoCopy.errorCode == 0) { String *errorMsg = strNewFmt("%s/backup.manifest is missing or unusable, using copy", strZ(backupResult->backupLabel)); - verifyErrorNew(errorList, logLevelDetail, errorMsg); + verifyErrorNew(messageList, logLevelDetail, errorMsg); result = verifyManifestInfoCopy.manifest; } @@ -568,7 +568,7 @@ verifyManifestFile( backupResult->status = backupMissingManifest; String *errorMsg = strNewFmt("manifest missing for '%s' - backup may have expired", strZ(backupResult->backupLabel)); - verifyErrorNew(errorList, logLevelDetail, errorMsg); + verifyErrorNew(messageList, logLevelDetail, errorMsg); } } else @@ -576,7 +576,7 @@ verifyManifestFile( backupResult->status = backupInProgress; String *errorMsg = strNewFmt("backup '%s' appears to be in progress, skipping", strZ(backupResult->backupLabel)); - verifyErrorNew(errorList, logLevelInfo, errorMsg); + verifyErrorNew(messageList, logLevelInfo, errorMsg); } } @@ -607,7 +607,7 @@ verifyManifestFile( " history, skipping", strZ(backupResult->backupLabel), manData->pgId, strZ(pgVersionToStr(manData->pgVersion)), manData->pgSystemId); - verifyErrorNew(errorList, logLevelInfo, errorMsg); + verifyErrorNew(messageList, logLevelInfo, errorMsg); manifestFree(result); result = NULL; @@ -679,13 +679,13 @@ Populate the WAL ranges from the provided, sorted, WAL files list for a given ar ***********************************************************************************************************************************/ static void verifyCreateArchiveIdRange( - const VerifyArchiveResult *const archiveIdResult, StringList *const walFileList, unsigned int *const jobErrorTotal, VariantList *const errorList) + const VerifyArchiveResult *const archiveIdResult, StringList *const walFileList, unsigned int *const jobErrorTotal, VariantList *const messageList) { FUNCTION_TEST_BEGIN(); FUNCTION_TEST_PARAM_P(VERIFY_ARCHIVE_RESULT, archiveIdResult); // The result set for the archive Id being processed FUNCTION_TEST_PARAM(STRING_LIST, walFileList); // Sorted (ascending) list of WAL files in a timeline FUNCTION_TEST_PARAM_P(UINT, jobErrorTotal); // Pointer to the overall job error total - FUNCTION_TEST_PARAM(VARIANT_LIST, errorList); // List of errors that occurred during the job + FUNCTION_TEST_PARAM(VARIANT_LIST, messageList); // List of errors that occurred during the job FUNCTION_TEST_END(); FUNCTION_AUDIT_HELPER(); @@ -718,7 +718,7 @@ verifyCreateArchiveIdRange( if (strEq(walSegment, strSubN(strLstGet(walFileList, walFileIdx + 1), 0, WAL_SEGMENT_NAME_SIZE))) { String *errorMsg = strNewFmt("duplicate WAL '%s' for '%s' exists, skipping", strZ(walSegment), strZ(archiveIdResult->archiveId)); - verifyErrorNew(errorList, logLevelInfo, errorMsg); + verifyErrorNew(messageList, logLevelInfo, errorMsg); (*jobErrorTotal)++; @@ -986,7 +986,7 @@ verifyArchive(VerifyJobData *const jobData) // log archiveResult->totalWalFile += strLstSize(jobData->walFileList); - verifyCreateArchiveIdRange(archiveResult, jobData->walFileList, &jobData->jobErrorTotal, jobData->errorList); + verifyCreateArchiveIdRange(archiveResult, jobData->walFileList, &jobData->jobErrorTotal, jobData->messageList); } } @@ -1032,7 +1032,7 @@ verifyArchive(VerifyJobData *const jobData) String *errorMsg = strNewFmt( "path '%s/%s' does not contain any valid WAL to be processed", strZ(archiveResult->archiveId), strZ(walPath)); - verifyErrorNew(jobData->errorList, logLevelDetail, errorMsg); + verifyErrorNew(jobData->messageList, logLevelDetail, errorMsg); strLstRemoveIdx(jobData->walPathList, 0); } @@ -1054,7 +1054,7 @@ verifyArchive(VerifyJobData *const jobData) { // Log that no WAL paths exist in the archive Id dir - remove the archive Id from the list (nothing to process) String *errorMsg = strNewFmt("archive path '%s' is empty", strZ(strLstGet(jobData->archiveIdList, 0))); - verifyErrorNew(jobData->errorList, logLevelDetail, errorMsg); + verifyErrorNew(jobData->messageList, logLevelDetail, errorMsg); strLstRemoveIdx(jobData->archiveIdList, 0); } } @@ -1111,7 +1111,7 @@ verifyBackup(VerifyJobData *const jobData) // Get a usable backup manifest file Manifest *const manifest = verifyManifestFile( - backupResult, jobData->manifestCipherPass, inProgressBackup, jobData->pgHistory, &jobData->jobErrorTotal, jobData->errorList); + backupResult, jobData->manifestCipherPass, inProgressBackup, jobData->pgHistory, &jobData->jobErrorTotal, jobData->messageList); // If a usable backup.manifest file is not found if (manifest == NULL) @@ -1301,7 +1301,7 @@ verifyBackup(VerifyJobData *const jobData) // Nothing to process so report an error, free the manifest, set the status, and remove the backup from processing // list String *errorMsg = strNewFmt("backup '%s' manifest does not contain any target files to verify", strZ(backupResult->backupLabel)); - verifyErrorNew(jobData->errorList, logLevelInfo, errorMsg); + verifyErrorNew(jobData->messageList, logLevelInfo, errorMsg); jobData->jobErrorTotal++; @@ -1392,14 +1392,14 @@ Helper function to output a log message based on job result that is not verifyOk ***********************************************************************************************************************************/ static unsigned int verifyLogInvalidResult( - const String *const fileType, const VerifyResult verifyResult, const unsigned int processId, const String *const filePathName, VariantList *const errorList) + const String *const fileType, const VerifyResult verifyResult, const unsigned int processId, const String *const filePathName, VariantList *const messageList) { FUNCTION_TEST_BEGIN(); FUNCTION_TEST_PARAM(STRING, fileType); // Indicates archive or backup file FUNCTION_TEST_PARAM(ENUM, verifyResult); // Result code from the verifyFile() function FUNCTION_TEST_PARAM(UINT, processId); // Process Id reporting the result FUNCTION_TEST_PARAM(STRING, filePathName); // File for which results are being reported - FUNCTION_TEST_PARAM(LIST, errorList); // List of error messages + FUNCTION_TEST_PARAM(LIST, messageList); // List of error messages FUNCTION_TEST_END(); ASSERT(fileType != NULL); @@ -1412,7 +1412,7 @@ verifyLogInvalidResult( MEM_CONTEXT_TEMP_BEGIN(); { String *errorMsg = strNewFmt("%s '%s'", verifyErrorMsg(verifyResult), strZ(filePathName)); - verifyErrorPidNew(errorList, logLevelWarn, processId, errorMsg); + verifyErrorPidNew(messageList, logLevelWarn, processId, errorMsg); } MEM_CONTEXT_TEMP_END(); FUNCTION_TEST_RETURN(UINT, 0); @@ -1421,7 +1421,7 @@ verifyLogInvalidResult( MEM_CONTEXT_TEMP_BEGIN(); { String *errorMsg = strNewFmt("%s '%s'", verifyErrorMsg(verifyResult), strZ(filePathName)); - verifyErrorPidNew(errorList, logLevelInfo, processId, errorMsg); + verifyErrorPidNew(messageList, logLevelInfo, processId, errorMsg); } MEM_CONTEXT_TEMP_END(); @@ -1434,7 +1434,7 @@ Helper function to set the currently processing backup label, if any, and check static String * verifySetBackupCheckArchive( const StringList *const backupList, const InfoBackup *const backupInfo, const StringList *const archiveIdList, - const InfoPg *const pgHistory, unsigned int *const jobErrorTotal, VariantList *const errorList) + const InfoPg *const pgHistory, unsigned int *const jobErrorTotal, VariantList *const messageList) { FUNCTION_TEST_BEGIN(); FUNCTION_TEST_PARAM(STRING_LIST, backupList); // List of backup labels in the backup directory @@ -1442,7 +1442,7 @@ verifySetBackupCheckArchive( FUNCTION_TEST_PARAM(STRING_LIST, archiveIdList); // List of archiveIds in the archive directory FUNCTION_TEST_PARAM(INFO_PG, pgHistory); // Pointer to InfoPg of archive.info for accessing PG history FUNCTION_TEST_PARAM_P(UINT, jobErrorTotal); // Pointer to overall job error total - FUNCTION_TEST_PARAM(VARIANT_LIST, errorList); // List of errors that occurred during the job + FUNCTION_TEST_PARAM(VARIANT_LIST, messageList); // List of errors that occurred during the job FUNCTION_TEST_END(); String *result = NULL; @@ -1492,7 +1492,7 @@ verifySetBackupCheckArchive( if (!strEmpty(missingFromHistory)) { String *errorMsg = strNewFmt("archiveIds '%s' are not in the archive.info history list", strZ(missingFromHistory)); - verifyErrorNew(errorList, logLevelInfo, errorMsg); + verifyErrorNew(messageList, logLevelInfo, errorMsg); (*jobErrorTotal)++; } @@ -1915,28 +1915,28 @@ verifyProcess(const bool verboseText) { unsigned int errorTotal = 0; KeyValue *resultKv = kvNew(); - VariantList *errorList = varLstNew(); + VariantList *messageList = varLstNew(); // Get the repo storage in case it is remote and encryption settings need to be pulled down const Storage *const storage = storageRepo(); // Get a usable backup info file - const InfoBackup *const backupInfo = verifyBackupInfoFile(errorList); + const InfoBackup *const backupInfo = verifyBackupInfoFile(messageList); // If a usable backup.info file is not found, then report an error in the log if (backupInfo == NULL) { - verifyMessageNew(errorList, strNewZ("No usable backup.info file")); + verifyMessageNew(messageList, strNewZ("No usable backup.info file")); errorTotal++; } // Get a usable archive info file - const InfoArchive *const archiveInfo = verifyArchiveInfoFile(errorList); + const InfoArchive *const archiveInfo = verifyArchiveInfoFile(messageList); // If a usable archive.info file is not found, then report an error in the log if (archiveInfo == NULL) { - verifyMessageNew(errorList, strNewZ("No usable archive.info file")); + verifyMessageNew(messageList, strNewZ("No usable archive.info file")); errorTotal++; } @@ -1950,7 +1950,7 @@ verifyProcess(const bool verboseText) } CATCH_ANY() { - verifyMessageNew(errorList, strNewZ(errorMessage())); + verifyMessageNew(messageList, strNewZ(errorMessage())); errorTotal++; } TRY_END(); @@ -1970,7 +1970,7 @@ verifyProcess(const bool verboseText) .walCipherPass = infoPgCipherPass(infoArchivePg(archiveInfo)), .archiveIdResultList = lstNewP(sizeof(VerifyArchiveResult), .comparator = archiveIdComparator), .backupResultList = lstNewP(sizeof(VerifyBackupResult), .comparator = lstComparatorStr), - .errorList = errorList, + .messageList = messageList, }; // Use backup label if specified via --set @@ -1982,7 +1982,7 @@ verifyProcess(const bool verboseText) { if (!regExpMatchOne(backupRegExpStr, backupLabel)) { - verifyMessageNew(errorList, strNewFmt("'%s' is not a valid backup label format", strZ(backupLabel))); + verifyMessageNew(messageList, strNewFmt("'%s' is not a valid backup label format", strZ(backupLabel))); backupLabelInvalid = true; errorTotal++; @@ -2000,7 +2000,7 @@ verifyProcess(const bool verboseText) if (!backupLabelInvalid && backupLabel != NULL && strLstEmpty(jobData.backupList)) { - verifyMessageNew(errorList, strNewFmt("backup set %s is not valid", strZ(backupLabel))); + verifyMessageNew(messageList, strNewFmt("backup set %s is not valid", strZ(backupLabel))); backupLabelInvalid = true; errorTotal++; @@ -2027,7 +2027,7 @@ verifyProcess(const bool verboseText) // distinguish between having processed all of the list or if the list was missing in the first place if (strLstEmpty(jobData.archiveIdList) || strLstEmpty(jobData.backupList)){ String *errorMsg = strNewFmt("no %s exist in the repo", strLstEmpty(jobData.archiveIdList) ? "archives" : "backups"); - verifyErrorNew(errorList, logLevelDetail, errorMsg); + verifyErrorNew(messageList, logLevelDetail, errorMsg); } // If there are no archives to process, then set the processing flag to skip to processing the backups @@ -2036,7 +2036,7 @@ verifyProcess(const bool verboseText) // Set current backup if there is one and verify the archive history on disk is in the database history jobData.currentBackup = verifySetBackupCheckArchive( - jobData.backupList, backupInfo, jobData.archiveIdList, jobData.pgHistory, &jobData.jobErrorTotal, errorList); + jobData.backupList, backupInfo, jobData.archiveIdList, jobData.pgHistory, &jobData.jobErrorTotal, messageList); // Create the parallel executor ProtocolParallel *const parallelExec = protocolParallelNew( @@ -2102,7 +2102,7 @@ verifyProcess(const bool verboseText) else { jobData.jobErrorTotal += verifyLogInvalidResult( - fileType, verifyResult, processId, filePathName, errorList); + fileType, verifyResult, processId, filePathName, messageList); // Add invalid file to the WAL range verifyAddInvalidWalFile( @@ -2118,7 +2118,7 @@ verifyProcess(const bool verboseText) else { jobData.jobErrorTotal += verifyLogInvalidResult( - fileType, verifyResult, processId, filePathName, errorList); + fileType, verifyResult, processId, filePathName, messageList); backupResult->status = backupInvalid; verifyInvalidFileAdd(backupResult->invalidFileList, verifyResult, filePathName); } @@ -2131,7 +2131,7 @@ verifyProcess(const bool verboseText) String *errorMsg = strNewFmt( "%s %s: [%d] %s", verifyErrorMsg(verifyOtherError), strZ(filePathName), protocolParallelJobErrorCode(job), strZ(protocolParallelJobErrorMessage(job))); - verifyErrorPidNew(errorList, logLevelInfo, processId, errorMsg); + verifyErrorPidNew(messageList, logLevelInfo, processId, errorMsg); jobData.jobErrorTotal++; @@ -2175,7 +2175,7 @@ verifyProcess(const bool verboseText) } else if (!backupLabelInvalid) { - verifyMessageNew(errorList, strNewZ("no archives or backups exist in the repo")); + verifyMessageNew(messageList, strNewZ("no archives or backups exist in the repo")); } errorTotal += jobData.jobErrorTotal; @@ -2191,11 +2191,11 @@ verifyProcess(const bool verboseText) for (unsigned int errIdx = 0; errIdx < varLstSize(resultMessagesList); errIdx++) { Variant *item = varLstGet(resultMessagesList, errIdx); - varLstAdd(errorList, varDup(item)); + varLstAdd(messageList, varDup(item)); } } - kvPut(resultKv, KEY_MESSAGES_VAR, varNewVarLst(errorList)); + kvPut(resultKv, KEY_MESSAGES_VAR, varNewVarLst(messageList)); if (json) { From 5200ad88f197cc8dd1c9590b60bc022db22cb4f1 Mon Sep 17 00:00:00 2001 From: Denis Kovalev Date: Thu, 24 Jul 2025 18:20:02 +0300 Subject: [PATCH 11/12] reformat JSONs --- test/src/module/command/verifyTest.c | 702 ++++++++++++++------------- 1 file changed, 364 insertions(+), 338 deletions(-) diff --git a/test/src/module/command/verifyTest.c b/test/src/module/command/verifyTest.c index 8d82d24eb4..f36a975b92 100644 --- a/test/src/module/command/verifyTest.c +++ b/test/src/module/command/verifyTest.c @@ -265,14 +265,14 @@ testRun(void) TEST_RESULT_STR_Z( jsonFromVar(varNewVarLst(errorList)), "[" - "{" - "\"level\":5," - "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/20181119-152138F/backup.manifest.copy' for read\"" - "}," - "{" - "\"level\":4," - "\"message\":\"'20181119-152138F' may not be recoverable - PG data (id 1, version 9.6, system-id " HRN_PG_SYSTEMID_95_Z ") is not in the backup.info history, skipping\"" - "}" + "{" + "\"level\":5," + "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/20181119-152138F/backup.manifest.copy' for read\"" + "}," + "{" + "\"level\":4," + "\"message\":\"'20181119-152138F' may not be recoverable - PG data (id 1, version 9.6, system-id " HRN_PG_SYSTEMID_95_Z ") is not in the backup.info history, skipping\"" + "}" "]", "errorList does not match" ); @@ -318,15 +318,15 @@ testRun(void) TEST_RESULT_STR_Z( jsonFromVar(varNewVarLst(errorList)), "[" - "{" - "\"level\":5," - "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/20181119-152138F/backup.manifest' for read\"" - "}," - "{\"level\":5,\"message\":\"20181119-152138F/backup.manifest is missing or unusable, using copy\"}," - "{" - "\"level\":4," - "\"message\":\"'20181119-152138F' may not be recoverable - PG data (id 1, version 9.5, system-id 0) is not in the backup.info history, skipping\"" - "}" + "{" + "\"level\":5," + "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/20181119-152138F/backup.manifest' for read\"" + "}," + "{\"level\":5,\"message\":\"20181119-152138F/backup.manifest is missing or unusable, using copy\"}," + "{" + "\"level\":4," + "\"message\":\"'20181119-152138F' may not be recoverable - PG data (id 1, version 9.5, system-id 0) is not in the backup.info history, skipping\"" + "}" "]", "errorList does not match" ); @@ -370,15 +370,18 @@ testRun(void) TEST_RESULT_STR_Z( jsonFromVar(varNewVarLst(errorList)), "[" - "{" - "\"level\":5," - "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/20181119-152138F/backup.manifest' for read\"" - "}," - "{\"level\":5,\"message\":\"20181119-152138F/backup.manifest is missing or unusable, using copy\"}," - "{" - "\"level\":4," - "\"message\":\"'20181119-152138F' may not be recoverable - PG data (id 0, version 9.5, system-id " HRN_PG_SYSTEMID_95_Z ") is not in the backup.info history, skipping\"" - "}" + "{" + "\"level\":5," + "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/20181119-152138F/backup.manifest' for read\"" + "}," + "{" + "\"level\":5," + "\"message\":\"20181119-152138F/backup.manifest is missing or unusable, using copy\"" + "}," + "{" + "\"level\":4," + "\"message\":\"'20181119-152138F' may not be recoverable - PG data (id 0, version 9.5, system-id " HRN_PG_SYSTEMID_95_Z ") is not in the backup.info history, skipping\"" + "}" "]", "errorList does not match" ); @@ -404,11 +407,14 @@ testRun(void) TEST_RESULT_STR_Z( jsonFromVar(varNewVarLst(errorList)), "[" - "{" - "\"level\":5," - "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/20181119-152138F/backup.manifest' for read\"" - "}," - "{\"level\":5,\"message\":\"invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS' /20181119-152138F/backup.manifest.copy\"}" + "{" + "\"level\":5," + "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/20181119-152138F/backup.manifest' for read\"" + "}," + "{" + "\"level\":5," + "\"message\":\"invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS' /20181119-152138F/backup.manifest.copy\"" + "}" "]", "errorList does not match" ); @@ -433,8 +439,14 @@ testRun(void) TEST_RESULT_STR_Z( jsonFromVar(varNewVarLst(errorList)), "[" - "{\"level\":5,\"message\":\"invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS' /20181119-152138F/backup.manifest\"}," - "{\"level\":5,\"message\":\"invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS' /20181119-152138F/backup.manifest.copy\"}" + "{" + "\"level\":5," + "\"message\":\"invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS' /20181119-152138F/backup.manifest\"" + "}," + "{" + "\"level\":5," + "\"message\":\"invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS' /20181119-152138F/backup.manifest.copy\"" + "}" "]", "errorList does not match" ); @@ -470,7 +482,10 @@ testRun(void) TEST_RESULT_STR_Z( jsonFromVar(varNewVarLst(errorList)), "[" - "{\"level\":5,\"message\":\"backup '20181119-152138F' manifest.copy does not match manifest\"}" + "{" + "\"level\":5," + "\"message\":\"backup '20181119-152138F' manifest.copy does not match manifest\"" + "}" "]", "errorList does not match" ); @@ -717,8 +732,15 @@ testRun(void) TEST_RESULT_STR_Z( jsonFromVar(varNewVarLst(errorList)), "[" - "{\"level\":4,\"message\":\"archiveIds '12-3, 13-4' are not in the archive.info history list\"}," - "{\"level\":3,\"message\":\"file missing 'missingfilename'\",\"pid\":0}" + "{" + "\"level\":4," + "\"message\":\"archiveIds '12-3, 13-4' are not in the archive.info history list\"" + "}," + "{" + "\"level\":3," + "\"message\":\"file missing 'missingfilename'\"," + "\"pid\":0" + "}" "]", "errorList does not match" ); @@ -756,22 +778,24 @@ testRun(void) " archiveId: 9.6-1, total WAL checked: 1, total valid WAL: 0", "archive: no invalid file list"); TEST_RESULT_STR_Z( verifyRenderJson(resultKv), - "{\"archives\":[" "{" - "\"archiveId\":\"9.6-1\"," - "\"checked\":1," - "\"checksumInvalid\":0," - "\"fileErrors\":{\"checksumInvalid\":0,\"missing\":0,\"other\":0,\"sizeInvalid\":0}," - "\"missing\":0," - "\"other\":0," - "\"sizeInvalid\":0," - "\"valid\":0" - "}" - "]," - "\"backups\":[]," - "\"messages\":[" - "{\"level\":5,\"message\":\"archiveId: 9.6-1, wal start: 0, wal stop: 2\"}" - "]}", + "\"archives\":[" + "{" + "\"archiveId\":\"9.6-1\"," + "\"checked\":1," + "\"checksumInvalid\":0," + "\"fileErrors\":{\"checksumInvalid\":0,\"missing\":0,\"other\":0,\"sizeInvalid\":0}," + "\"missing\":0," + "\"other\":0," + "\"sizeInvalid\":0," + "\"valid\":0" + "}" + "]," + "\"backups\":[]," + "\"messages\":[" + "{\"level\":5,\"message\":\"archiveId: 9.6-1, wal start: 0, wal stop: 2\"}" + "]" + "}", "archive: no invalid file list"); VerifyInvalidFile invalidFile = @@ -805,33 +829,35 @@ testRun(void) lstClear((List *)errorList); TEST_RESULT_STR_Z( verifyRenderJson(resultKv), - "{\"archives\":[" - "{" - "\"archiveId\":\"9.6-1\"," - "\"checked\":1," - "\"checksumInvalid\":0," - "\"fileErrors\":{\"checksumInvalid\":0,\"missing\":1,\"other\":0,\"sizeInvalid\":0}," - "\"missing\":1," - "\"other\":0," - "\"sizeInvalid\":0," - "\"valid\":0" - "}" - "]," - "\"backups\":[" "{" - "\"checked\":1," - "\"checksumInvalid\":0," - "\"fileErrors\":{\"checksumInvalid\":0,\"missing\":1,\"other\":0,\"sizeInvalid\":0}," - "\"label\":\"test-backup-label\"," - "\"missing\":1," - "\"other\":0," - "\"sizeInvalid\":0," - "\"status\":\"invalid\"," - "\"valid\":0" - "}]," - "\"messages\":[" - "{\"level\":5,\"message\":\"archiveId: 9.6-1, wal start: 0, wal stop: 2\"}" - "]" + "\"archives\":[" + "{" + "\"archiveId\":\"9.6-1\"," + "\"checked\":1," + "\"checksumInvalid\":0," + "\"fileErrors\":{\"checksumInvalid\":0,\"missing\":1,\"other\":0,\"sizeInvalid\":0}," + "\"missing\":1," + "\"other\":0," + "\"sizeInvalid\":0," + "\"valid\":0" + "}" + "]," + "\"backups\":[" + "{" + "\"checked\":1," + "\"checksumInvalid\":0," + "\"fileErrors\":{\"checksumInvalid\":0,\"missing\":1,\"other\":0,\"sizeInvalid\":0}," + "\"label\":\"test-backup-label\"," + "\"missing\":1," + "\"other\":0," + "\"sizeInvalid\":0," + "\"status\":\"invalid\"," + "\"valid\":0" + "}" + "]," + "\"messages\":[" + "{\"level\":5,\"message\":\"archiveId: 9.6-1, wal start: 0, wal stop: 2\"}" + "]" "}", "archive file missing, backup file missing, no text, no verbose, json output"); @@ -1044,21 +1070,21 @@ testRun(void) #define EXPECTED_OUTPUT_JSON "{"\ "\"messages\":[" \ "{"\ - "\"level\":5,"\ - "\"message\":\"invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS' /backup.info\""\ + "\"level\":5,"\ + "\"message\":\"invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS' /backup.info\""\ "},{"\ - "\"level\":5,"\ - "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/backup.info.copy' for read\""\ + "\"level\":5,"\ + "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/backup.info.copy' for read\""\ "},{"\ - "\"message\":\"No usable backup.info file\""\ + "\"message\":\"No usable backup.info file\""\ "},{"\ - "\"level\":5,"\ - "\"message\":\"unable to open missing file '" TEST_PATH "/repo/archive/db/archive.info' for read\""\ + "\"level\":5,"\ + "\"message\":\"unable to open missing file '" TEST_PATH "/repo/archive/db/archive.info' for read\""\ "},{"\ - "\"level\":5,"\ - "\"message\":\"unable to open missing file '" TEST_PATH "/repo/archive/db/archive.info.copy' for read\""\ + "\"level\":5,"\ + "\"message\":\"unable to open missing file '" TEST_PATH "/repo/archive/db/archive.info.copy' for read\""\ "},{"\ - "\"message\":\"No usable archive.info file\""\ + "\"message\":\"No usable archive.info file\""\ "}"\ "],"\ "\"stanza\":\"db\","\ @@ -1109,22 +1135,22 @@ testRun(void) dup2(stdoutSave, STDOUT_FILENO); #define EXPECTED_OUTPUT_JSON "{"\ - "\"messages\":["\ - "{"\ - "\"level\":5,"\ - "\"message\":\"invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS' /backup.info\""\ - "},{"\ - "\"level\":5,"\ - "\"message\":\"unable to open missing file '" TEST_PATH "/repo/archive/db/archive.info' for read\""\ - "},{"\ - "\"level\":5,\"message\":\"invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS' /archive.info.copy\""\ - "},{"\ - "\"message\":\"No usable archive.info file\""\ - "}"\ - "],"\ - "\"stanza\":\"db\","\ - "\"status\":\"error\""\ - "}" + "\"messages\":["\ + "{"\ + "\"level\":5,"\ + "\"message\":\"invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS' /backup.info\""\ + "},{"\ + "\"level\":5,"\ + "\"message\":\"unable to open missing file '" TEST_PATH "/repo/archive/db/archive.info' for read\""\ + "},{"\ + "\"level\":5,\"message\":\"invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS' /archive.info.copy\""\ + "},{"\ + "\"message\":\"No usable archive.info file\""\ + "}"\ + "],"\ + "\"stanza\":\"db\","\ + "\"status\":\"error\""\ + "}" // Check output of verify command stored in file TEST_STORAGE_GET(storageTest, strZ(stdoutFile), @@ -1163,20 +1189,20 @@ testRun(void) dup2(stdoutSave, STDOUT_FILENO); #define EXPECTED_OUTPUT_JSON "{"\ - "\"messages\":["\ - "{"\ - "\"level\":5,"\ - "\"message\":\"backup.info.copy does not match backup.info\""\ - "},{"\ - "\"level\":5,"\ - "\"message\":\"invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS' /archive.info\""\ - "},{"\ - "\"message\":\"backup info file and archive info file do not match\\narchive: id = 1, version = 9.5, system-id = 10000000000000090500\\nbackup : id = 2, version = 11, system-id = 10000000000000110000\\nHINT: this may be a symptom of repository corruption!\""\ - "}"\ - "],"\ - "\"stanza\":\"db\","\ - "\"status\":\"error\""\ -"}" + "\"messages\":["\ + "{"\ + "\"level\":5,"\ + "\"message\":\"backup.info.copy does not match backup.info\""\ + "},{"\ + "\"level\":5,"\ + "\"message\":\"invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS' /archive.info\""\ + "},{"\ + "\"message\":\"backup info file and archive info file do not match\\narchive: id = 1, version = 9.5, system-id = 10000000000000090500\\nbackup : id = 2, version = 11, system-id = 10000000000000110000\\nHINT: this may be a symptom of repository corruption!\""\ + "}"\ + "],"\ + "\"stanza\":\"db\","\ + "\"status\":\"error\""\ + "}" // Check output of verify command stored in file TEST_STORAGE_GET(storageTest, strZ(stdoutFile), @@ -1211,16 +1237,16 @@ testRun(void) dup2(stdoutSave, STDOUT_FILENO); #define EXPECTED_OUTPUT_JSON "{"\ - "\"messages\":["\ - "{"\ - "\"level\":5,"\ - "\"message\":\"archive.info.copy does not match archive.info\""\ - "},"\ - "{\"message\":\"no archives or backups exist in the repo\"}"\ - "],"\ - "\"stanza\":\"db\","\ - "\"status\":\"ok\""\ -"}" + "\"messages\":["\ + "{"\ + "\"level\":5,"\ + "\"message\":\"archive.info.copy does not match archive.info\""\ + "},"\ + "{\"message\":\"no archives or backups exist in the repo\"}"\ + "],"\ + "\"stanza\":\"db\","\ + "\"status\":\"ok\""\ + "}" TEST_STORAGE_GET(storageTest, strZ(stdoutFile), EXPECTED_OUTPUT_JSON "\n", @@ -1251,20 +1277,20 @@ testRun(void) dup2(stdoutSave, STDOUT_FILENO); #define EXPECTED_OUTPUT_JSON "{"\ - "\"messages\":["\ - "{"\ - "\"level\":5,"\ - "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/backup.info.copy' for read\""\ - "},"\ - "{"\ - "\"level\":5,"\ - "\"message\":\"unable to open missing file '" TEST_PATH "/repo/archive/db/archive.info.copy' for read\""\ - "},"\ - "{\"message\":\"no archives or backups exist in the repo\"}"\ - "],"\ - "\"stanza\":\"db\","\ - "\"status\":\"ok\""\ -"}" + "\"messages\":["\ + "{"\ + "\"level\":5,"\ + "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/backup.info.copy' for read\""\ + "},"\ + "{"\ + "\"level\":5,"\ + "\"message\":\"unable to open missing file '" TEST_PATH "/repo/archive/db/archive.info.copy' for read\""\ + "},"\ + "{\"message\":\"no archives or backups exist in the repo\"}"\ + "],"\ + "\"stanza\":\"db\","\ + "\"status\":\"ok\""\ + "}" TEST_STORAGE_GET(storageTest, strZ(stdoutFile), EXPECTED_OUTPUT_JSON "\n", @@ -1301,22 +1327,22 @@ testRun(void) dup2(stdoutSave, STDOUT_FILENO); #define EXPECTED_OUTPUT_JSON "{"\ - "\"messages\":["\ - "{"\ - "\"level\":5,"\ - "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/backup.info' for read\""\ - "},"\ - "{"\ - "\"level\":5,"\ - "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/backup.info.copy' for read\""\ - "},"\ - "{"\ - "\"message\":\"No usable backup.info file\""\ - "}"\ - "],"\ - "\"stanza\":\"db\","\ - "\"status\":\"error\""\ -"}" + "\"messages\":["\ + "{"\ + "\"level\":5,"\ + "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/backup.info' for read\""\ + "},"\ + "{"\ + "\"level\":5,"\ + "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/backup.info.copy' for read\""\ + "},"\ + "{"\ + "\"message\":\"No usable backup.info file\""\ + "}"\ + "],"\ + "\"stanza\":\"db\","\ + "\"status\":\"error\""\ + "}" TEST_STORAGE_GET(storageTest, strZ(stdoutFile), EXPECTED_OUTPUT_JSON "\n", @@ -1509,59 +1535,59 @@ testRun(void) HRN_CFG_LOAD(cfgCmdVerify, argListJSON); #define EXPECTED_OUTPUT_JSON "{"\ - "\"archives\":["\ - "{"\ - "\"archiveId\":\"9.5-1\","\ - "\"checked\":0,"\ - "\"checksumInvalid\":0,"\ - "\"missing\":0,"\ - "\"other\":0,"\ - "\"sizeInvalid\":0,"\ - "\"valid\":0"\ - "},"\ - "{"\ - "\"archiveId\":\"11-2\","\ - "\"checked\":4,"\ - "\"checksumInvalid\":1,"\ - "\"fileErrors\":{\"checksumInvalid\":1,\"missing\":0,\"other\":0,\"sizeInvalid\":1},"\ - "\"missing\":0,"\ - "\"other\":0,"\ - "\"sizeInvalid\":1,"\ - "\"valid\":2"\ - "}"\ - "],"\ - "\"backups\":[],"\ - "\"messages\":["\ - "{"\ - "\"level\":5,"\ - "\"message\":\"no backups exist in the repo\""\ - "},"\ - "{"\ - "\"level\":5,"\ - "\"message\":\"archive path '9.5-1' is empty\""\ - "},"\ - "{"\ - "\"level\":5,"\ - "\"message\":\"path '11-2/0000000100000000' does not contain any valid WAL to be processed\""\ - "},"\ - "{"\ - "\"level\":4,"\ - "\"message\":\"invalid checksum '11-2/0000000200000007/000000020000000700000FFD-a6e1a64f0813352bc2e97f116a1800377e17d2e4.gz'\","\ - "\"pid\":1"\ - "},"\ - "{"\ - "\"level\":4,"\ - "\"message\":\"invalid size '11-2/0000000200000007/000000020000000700000FFF-ee161f898c9012dd0c28b3fd1e7140b9cf411306'\","\ - "\"pid\":1"\ - "},"\ - "{"\ - "\"level\":5,"\ - "\"message\":\"archiveId: 11-2, wal start: 000000020000000700000FFD, wal stop: 000000020000000800000000\""\ - "}"\ - "],"\ - "\"stanza\":\"db\","\ - "\"status\":\"error\""\ -"}" + "\"archives\":["\ + "{"\ + "\"archiveId\":\"9.5-1\","\ + "\"checked\":0,"\ + "\"checksumInvalid\":0,"\ + "\"missing\":0,"\ + "\"other\":0,"\ + "\"sizeInvalid\":0,"\ + "\"valid\":0"\ + "},"\ + "{"\ + "\"archiveId\":\"11-2\","\ + "\"checked\":4,"\ + "\"checksumInvalid\":1,"\ + "\"fileErrors\":{\"checksumInvalid\":1,\"missing\":0,\"other\":0,\"sizeInvalid\":1},"\ + "\"missing\":0,"\ + "\"other\":0,"\ + "\"sizeInvalid\":1,"\ + "\"valid\":2"\ + "}"\ + "],"\ + "\"backups\":[],"\ + "\"messages\":["\ + "{"\ + "\"level\":5,"\ + "\"message\":\"no backups exist in the repo\""\ + "},"\ + "{"\ + "\"level\":5,"\ + "\"message\":\"archive path '9.5-1' is empty\""\ + "},"\ + "{"\ + "\"level\":5,"\ + "\"message\":\"path '11-2/0000000100000000' does not contain any valid WAL to be processed\""\ + "},"\ + "{"\ + "\"level\":4,"\ + "\"message\":\"invalid checksum '11-2/0000000200000007/000000020000000700000FFD-a6e1a64f0813352bc2e97f116a1800377e17d2e4.gz'\","\ + "\"pid\":1"\ + "},"\ + "{"\ + "\"level\":4,"\ + "\"message\":\"invalid size '11-2/0000000200000007/000000020000000700000FFF-ee161f898c9012dd0c28b3fd1e7140b9cf411306'\","\ + "\"pid\":1"\ + "},"\ + "{"\ + "\"level\":5,"\ + "\"message\":\"archiveId: 11-2, wal start: 000000020000000700000FFD, wal stop: 000000020000000800000000\""\ + "}"\ + "],"\ + "\"stanza\":\"db\","\ + "\"status\":\"error\""\ + "}" TEST_RESULT_STR_Z( verifyProcess(cfgOptionBool(cfgOptVerbose)), @@ -1608,58 +1634,58 @@ testRun(void) TEST_RESULT_STR_Z( verifyProcess(cfgOptionBool(cfgOptVerbose)), "{" \ - "\"archives\":[" \ - "{" \ - "\"archiveId\":\"9.5-1\"," \ - "\"checked\":0," \ - "\"checksumInvalid\":0," \ - "\"missing\":0," \ - "\"other\":0," \ - "\"sizeInvalid\":0," \ - "\"valid\":0" \ - "}," \ - "{" \ - "\"archiveId\":\"11-2\"," \ - "\"checked\":4," \ - "\"checksumInvalid\":1," \ - "\"fileErrors\":{\"checksumInvalid\":1,\"missing\":0,\"other\":0,\"sizeInvalid\":1}," - "\"missing\":0," \ - "\"other\":0," \ - "\"sizeInvalid\":1," \ - "\"valid\":2" \ - "}" \ - "]," \ - "\"backups\":[]," \ - "\"messages\":[" \ - "{" \ - "\"level\":5," \ - "\"message\":\"no backups exist in the repo\"" \ - "}," \ - "{" \ - "\"level\":5," \ - "\"message\":\"archive path '9.5-1' is empty\"" \ - "}," \ - "{" \ - "\"level\":5," \ - "\"message\":\"path '11-2/0000000100000000' does not contain any valid WAL to be processed\"" \ - "}," \ - "{" \ - "\"level\":4," \ - "\"message\":\"invalid checksum '11-2/0000000200000007/000000020000000700000FFD-a6e1a64f0813352bc2e97f116a1800377e17d2e4.gz'\"," \ - "\"pid\":1" \ - "}," \ - "{" \ - "\"level\":4," \ - "\"message\":\"invalid size '11-2/0000000200000007/000000020000000700000FFF-ee161f898c9012dd0c28b3fd1e7140b9cf411306'\"," \ - "\"pid\":1" \ - "}," \ - "{" \ - "\"level\":5," \ - "\"message\":\"archiveId: 11-2, wal start: 000000020000000700000FFD, wal stop: 000000020000000800000000\"" \ - "}" \ - "]," \ - "\"stanza\":\"db\"," \ - "\"status\":\"error\"" \ + "\"archives\":[" \ + "{" \ + "\"archiveId\":\"9.5-1\"," \ + "\"checked\":0," \ + "\"checksumInvalid\":0," \ + "\"missing\":0," \ + "\"other\":0," \ + "\"sizeInvalid\":0," \ + "\"valid\":0" \ + "}," \ + "{" \ + "\"archiveId\":\"11-2\"," \ + "\"checked\":4," \ + "\"checksumInvalid\":1," \ + "\"fileErrors\":{\"checksumInvalid\":1,\"missing\":0,\"other\":0,\"sizeInvalid\":1}," + "\"missing\":0," \ + "\"other\":0," \ + "\"sizeInvalid\":1," \ + "\"valid\":2" \ + "}" \ + "]," \ + "\"backups\":[]," \ + "\"messages\":[" \ + "{" \ + "\"level\":5," \ + "\"message\":\"no backups exist in the repo\"" \ + "}," \ + "{" \ + "\"level\":5," \ + "\"message\":\"archive path '9.5-1' is empty\"" \ + "}," \ + "{" \ + "\"level\":5," \ + "\"message\":\"path '11-2/0000000100000000' does not contain any valid WAL to be processed\"" \ + "}," \ + "{" \ + "\"level\":4," \ + "\"message\":\"invalid checksum '11-2/0000000200000007/000000020000000700000FFD-a6e1a64f0813352bc2e97f116a1800377e17d2e4.gz'\"," \ + "\"pid\":1" \ + "}," \ + "{" \ + "\"level\":4," \ + "\"message\":\"invalid size '11-2/0000000200000007/000000020000000700000FFF-ee161f898c9012dd0c28b3fd1e7140b9cf411306'\"," \ + "\"pid\":1" \ + "}," \ + "{" \ + "\"level\":5," \ + "\"message\":\"archiveId: 11-2, wal start: 000000020000000700000FFD, wal stop: 000000020000000800000000\"" \ + "}" \ + "]," \ + "\"stanza\":\"db\"," \ + "\"status\":\"error\"" \ "}", "JSON verbose, with failures"); TEST_RESULT_LOG( @@ -2013,39 +2039,39 @@ testRun(void) TEST_RESULT_STR_Z( verifyProcess(cfgOptionBool(cfgOptVerbose)), "{" \ - "\"archives\":[]," \ - "\"backups\":[" \ - "{" \ - "\"checked\":0," \ - "\"checksumInvalid\":0," \ - "\"label\":\"20181119-152800F\"," \ - "\"missing\":0," \ - "\"other\":0," \ - "\"sizeInvalid\":0," \ - "\"status\":\"in-progress\"," \ - "\"valid\":0" \ - "}" \ - "]," \ - "\"messages\":[" \ - "{" \ - "\"level\":5," \ - "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/backup.info.copy' for read\"" \ - "}," \ - "{" \ - "\"level\":5," \ - "\"message\":\"no archives exist in the repo\"" \ - "}," \ - "{" \ - "\"level\":5," \ - "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/20181119-152800F/backup.manifest' for read\"" \ - "}," \ - "{" \ - "\"level\":4," \ - "\"message\":\"backup '20181119-152800F' appears to be in progress, skipping\"" \ - "}" \ - "]," \ - "\"stanza\":\"db\"," \ - "\"status\":\"ok\"" \ + "\"archives\":[]," \ + "\"backups\":[" \ + "{" \ + "\"checked\":0," \ + "\"checksumInvalid\":0," \ + "\"label\":\"20181119-152800F\"," \ + "\"missing\":0," \ + "\"other\":0," \ + "\"sizeInvalid\":0," \ + "\"status\":\"in-progress\"," \ + "\"valid\":0" \ + "}" \ + "]," \ + "\"messages\":[" \ + "{" \ + "\"level\":5," \ + "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/backup.info.copy' for read\"" \ + "}," \ + "{" \ + "\"level\":5," \ + "\"message\":\"no archives exist in the repo\"" \ + "}," \ + "{" \ + "\"level\":5," \ + "\"message\":\"unable to open missing file '" TEST_PATH "/repo/backup/db/20181119-152800F/backup.manifest' for read\"" \ + "}," \ + "{" \ + "\"level\":4," \ + "\"message\":\"backup '20181119-152800F' appears to be in progress, skipping\"" \ + "}" \ + "]," \ + "\"stanza\":\"db\"," \ + "\"status\":\"ok\"" \ "}", "verifyProcess() JSON missing no total file verify"); @@ -2582,49 +2608,49 @@ testRun(void) TEST_RESULT_STR_Z( verifyProcess(cfgOptionBool(cfgOptVerbose)), "{" \ - "\"archives\":[]," \ - "\"backups\":[" \ - "{" \ - "\"checked\":2," \ - "\"checksumInvalid\":2," \ - "\"fileErrors\":{\"checksumInvalid\":2,\"missing\":0,\"other\":0,\"sizeInvalid\":0}," \ - "\"label\":\"20181119-152900F\"," \ - "\"missing\":0," \ - "\"other\":0," \ - "\"sizeInvalid\":0," \ - "\"status\":\"invalid\"," \ - "\"valid\":0" \ - "}," \ - "{" \ - "\"checked\":2," \ - "\"checksumInvalid\":1," \ - "\"fileErrors\":{\"checksumInvalid\":1,\"missing\":0,\"other\":0,\"sizeInvalid\":0}," \ - "\"label\":\"20181119-152900F_20181119-152909D\"," \ - "\"missing\":0," \ - "\"other\":0," \ - "\"sizeInvalid\":0," \ - "\"status\":\"invalid\"," \ - "\"valid\":1" \ - "}" \ - "]," \ - "\"messages\":[" \ - "{" \ - "\"level\":5," \ - "\"message\":\"no archives exist in the repo\"" \ - "}," \ - "{" \ - "\"level\":4," \ - "\"message\":\"invalid checksum '20181119-152900F/pg_data/PG_VERSION'\"," \ - "\"pid\":1" \ - "}," \ - "{" \ - "\"level\":4," \ - "\"message\":\"invalid checksum '20181119-152900F/pg_data/biind.pgbi'\"," \ - "\"pid\":1" \ - "}" \ - "]," \ - "\"stanza\":\"db\"," \ - "\"status\":\"error\"" \ + "\"archives\":[]," \ + "\"backups\":[" \ + "{" \ + "\"checked\":2," \ + "\"checksumInvalid\":2," \ + "\"fileErrors\":{\"checksumInvalid\":2,\"missing\":0,\"other\":0,\"sizeInvalid\":0}," \ + "\"label\":\"20181119-152900F\"," \ + "\"missing\":0," \ + "\"other\":0," \ + "\"sizeInvalid\":0," \ + "\"status\":\"invalid\"," \ + "\"valid\":0" \ + "}," \ + "{" \ + "\"checked\":2," \ + "\"checksumInvalid\":1," \ + "\"fileErrors\":{\"checksumInvalid\":1,\"missing\":0,\"other\":0,\"sizeInvalid\":0}," \ + "\"label\":\"20181119-152900F_20181119-152909D\"," \ + "\"missing\":0," \ + "\"other\":0," \ + "\"sizeInvalid\":0," \ + "\"status\":\"invalid\"," \ + "\"valid\":1" \ + "}" \ + "]," \ + "\"messages\":[" \ + "{" \ + "\"level\":5," \ + "\"message\":\"no archives exist in the repo\"" \ + "}," \ + "{" \ + "\"level\":4," \ + "\"message\":\"invalid checksum '20181119-152900F/pg_data/PG_VERSION'\"," \ + "\"pid\":1" \ + "}," \ + "{" \ + "\"level\":4," \ + "\"message\":\"invalid checksum '20181119-152900F/pg_data/biind.pgbi'\"," \ + "\"pid\":1" \ + "}" \ + "]," \ + "\"stanza\":\"db\"," \ + "\"status\":\"error\"" \ "}", "verifyProcess() verbose JSON"); From 2e3752ade6cd3aa516364c2aeb30568e4628569e Mon Sep 17 00:00:00 2001 From: Denis Kovalev Date: Thu, 24 Jul 2025 18:59:25 +0300 Subject: [PATCH 12/12] persuade uncrustify --- test/src/module/command/verifyTest.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/test/src/module/command/verifyTest.c b/test/src/module/command/verifyTest.c index f36a975b92..2a5100974b 100644 --- a/test/src/module/command/verifyTest.c +++ b/test/src/module/command/verifyTest.c @@ -264,6 +264,7 @@ testRun(void) TEST_RESULT_STR_Z( jsonFromVar(varNewVarLst(errorList)), + // {uncrustify_off - indentation} "[" "{" "\"level\":5," @@ -274,6 +275,7 @@ testRun(void) "\"message\":\"'20181119-152138F' may not be recoverable - PG data (id 1, version 9.6, system-id " HRN_PG_SYSTEMID_95_Z ") is not in the backup.info history, skipping\"" "}" "]", + // {uncrustify_on} "errorList does not match" ); @@ -317,6 +319,7 @@ testRun(void) TEST_RESULT_STR_Z( jsonFromVar(varNewVarLst(errorList)), + // {uncrustify_off - indentation} "[" "{" "\"level\":5," @@ -328,6 +331,7 @@ testRun(void) "\"message\":\"'20181119-152138F' may not be recoverable - PG data (id 1, version 9.5, system-id 0) is not in the backup.info history, skipping\"" "}" "]", + // {uncrustify_on} "errorList does not match" ); @@ -369,6 +373,7 @@ testRun(void) TEST_RESULT_STR_Z( jsonFromVar(varNewVarLst(errorList)), + // {uncrustify_off - indentation} "[" "{" "\"level\":5," @@ -383,6 +388,7 @@ testRun(void) "\"message\":\"'20181119-152138F' may not be recoverable - PG data (id 0, version 9.5, system-id " HRN_PG_SYSTEMID_95_Z ") is not in the backup.info history, skipping\"" "}" "]", + // {uncrustify_on} "errorList does not match" ); @@ -406,6 +412,7 @@ testRun(void) TEST_RESULT_STR_Z( jsonFromVar(varNewVarLst(errorList)), + // {uncrustify_off - indentation} "[" "{" "\"level\":5," @@ -416,6 +423,7 @@ testRun(void) "\"message\":\"invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS' /20181119-152138F/backup.manifest.copy\"" "}" "]", + // {uncrustify_on} "errorList does not match" ); @@ -438,6 +446,7 @@ testRun(void) TEST_RESULT_STR_Z( jsonFromVar(varNewVarLst(errorList)), + // {uncrustify_off - indentation} "[" "{" "\"level\":5," @@ -448,6 +457,7 @@ testRun(void) "\"message\":\"invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS' /20181119-152138F/backup.manifest.copy\"" "}" "]", + // {uncrustify_on} "errorList does not match" ); @@ -481,12 +491,14 @@ testRun(void) TEST_RESULT_STR_Z( jsonFromVar(varNewVarLst(errorList)), + // {uncrustify_off - indentation} "[" "{" "\"level\":5," "\"message\":\"backup '20181119-152138F' manifest.copy does not match manifest\"" "}" "]", + // {uncrustify_on} "errorList does not match" ); @@ -731,6 +743,7 @@ testRun(void) 0, "file missing message"); TEST_RESULT_STR_Z( jsonFromVar(varNewVarLst(errorList)), + // {uncrustify_off - indentation} "[" "{" "\"level\":4," @@ -742,6 +755,7 @@ testRun(void) "\"pid\":0" "}" "]", + // {uncrustify_on} "errorList does not match" ); @@ -778,6 +792,7 @@ testRun(void) " archiveId: 9.6-1, total WAL checked: 1, total valid WAL: 0", "archive: no invalid file list"); TEST_RESULT_STR_Z( verifyRenderJson(resultKv), + // {uncrustify_off - indentation} "{" "\"archives\":[" "{" @@ -796,6 +811,7 @@ testRun(void) "{\"level\":5,\"message\":\"archiveId: 9.6-1, wal start: 0, wal stop: 2\"}" "]" "}", + // {uncrustify_on} "archive: no invalid file list"); VerifyInvalidFile invalidFile = @@ -829,6 +845,7 @@ testRun(void) lstClear((List *)errorList); TEST_RESULT_STR_Z( verifyRenderJson(resultKv), + // {uncrustify_off - indentation} "{" "\"archives\":[" "{" @@ -859,6 +876,7 @@ testRun(void) "{\"level\":5,\"message\":\"archiveId: 9.6-1, wal start: 0, wal stop: 2\"}" "]" "}", + // {uncrustify_on} "archive file missing, backup file missing, no text, no verbose, json output"); // ------------------------------------------------------------------------------------------------------------------------- @@ -1633,6 +1651,7 @@ testRun(void) // Verify text output, verbose, with verify failures TEST_RESULT_STR_Z( verifyProcess(cfgOptionBool(cfgOptVerbose)), + // {uncrustify_off - indentation} "{" \ "\"archives\":[" \ "{" \ @@ -1687,6 +1706,7 @@ testRun(void) "\"stanza\":\"db\"," \ "\"status\":\"error\"" \ "}", + // {uncrustify_on} "JSON verbose, with failures"); TEST_RESULT_LOG( "P01 INFO: invalid checksum" @@ -2038,6 +2058,7 @@ testRun(void) TEST_RESULT_STR_Z( verifyProcess(cfgOptionBool(cfgOptVerbose)), + // {uncrustify_off - indentation} "{" \ "\"archives\":[]," \ "\"backups\":[" \ @@ -2073,6 +2094,7 @@ testRun(void) "\"stanza\":\"db\"," \ "\"status\":\"ok\"" \ "}", + // {uncrustify_on} "verifyProcess() JSON missing no total file verify"); TEST_RESULT_LOG( @@ -2607,6 +2629,7 @@ testRun(void) TEST_RESULT_STR_Z( verifyProcess(cfgOptionBool(cfgOptVerbose)), + // {uncrustify_off - indentation} "{" \ "\"archives\":[]," \ "\"backups\":[" \ @@ -2652,6 +2675,7 @@ testRun(void) "\"stanza\":\"db\"," \ "\"status\":\"error\"" \ "}", + // {uncrustify_on} "verifyProcess() verbose JSON"); TEST_RESULT_LOG(