1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2025-02-07 13:42:41 +02:00

Improve storage harness/test macros.

Make the macros more consistent in format and make sure that each macro outputs a line number before doing any work so when errors happen it is clear where they happened.

Add noRecurse option to TEST_STORAGE_LIST().

Add comment option to all storage macros.
This commit is contained in:
David Steele 2021-05-28 14:39:43 -04:00
parent 0a43be0183
commit c8427682ea
5 changed files with 184 additions and 81 deletions

View File

@ -10,9 +10,13 @@ Harness for Generating Test Info Files
Write info to a file and add the checksum Write info to a file and add the checksum
***********************************************************************************************************************************/ ***********************************************************************************************************************************/
#define HRN_INFO_PUT(storage, file, info, ...) \ #define HRN_INFO_PUT(storage, file, info, ...) \
TEST_RESULT_VOID( \ do \
hrnStoragePut(storage, file, harnessInfoChecksumZ(info), (HrnStoragePutParam){VAR_PARAM_INIT, __VA_ARGS__}), \ { \
strZ(strNewFmt("put info %s", hrnStoragePutLog(storage, file, LF_BUF, (HrnStoragePutParam){VAR_PARAM_INIT, __VA_ARGS__})))) hrnTestLogPrefix(__LINE__); \
hrnStoragePut( \
storage, file, harnessInfoChecksumZ(info), "put info", (HrnStoragePutParam){VAR_PARAM_INIT, __VA_ARGS__}); \
} \
while (0)
/*********************************************************************************************************************************** /***********************************************************************************************************************************
Functions Functions

View File

@ -175,15 +175,17 @@ hrnStorageInfoListCallback(void *callbackData, const StorageInfo *info)
/**********************************************************************************************************************************/ /**********************************************************************************************************************************/
void void
testStorageGet( testStorageGet(const Storage *const storage, const char *const file, const char *const expected, const TestStorageGetParam param)
const int line, const Storage *const storage, const char *const file, const char *const expected, TestStorageGetParam param)
{ {
hrnTestLogPrefix(line);
hrnTestResultBegin(__func__, false); hrnTestResultBegin(__func__, false);
ASSERT(storage != NULL);
ASSERT(file != NULL);
const String *const fileFull = storagePathP(storage, STR(file)); const String *const fileFull = storagePathP(storage, STR(file));
printf("test content of '%s'\n", strZ(fileFull));
fflush(stdout); printf("test content of '%s'", strZ(fileFull));
hrnTestResultComment(param.comment);
hrnTestResultZ(strZ(strNewBuf(storageGetP(storageNewReadP(storage, fileFull)))), expected, harnessTestResultOperationEq); hrnTestResultZ(strZ(strNewBuf(storageGetP(storageNewReadP(storage, fileFull)))), expected, harnessTestResultOperationEq);
@ -191,6 +193,23 @@ testStorageGet(
storageRemoveP(storage, fileFull, .errorOnMissing = true); storageRemoveP(storage, fileFull, .errorOnMissing = true);
} }
/**********************************************************************************************************************************/
void
testStorageExists(const Storage *const storage, const char *const file, const TestStorageExistsParam param)
{
hrnTestResultBegin(__func__, false);
ASSERT(storage != NULL);
ASSERT(file != NULL);
const String *const fileFull = storagePathP(storage, STR(file));
printf("file exists '%s'", strZ(fileFull));
hrnTestResultComment(param.comment);
hrnTestResultBool(storageExistsP(storage, fileFull), true);
}
/**********************************************************************************************************************************/ /**********************************************************************************************************************************/
static void static void
hrnStorageListCallback(void *list, const StorageInfo *info) hrnStorageListCallback(void *list, const StorageInfo *info)
@ -213,21 +232,21 @@ hrnStorageListCallback(void *list, const StorageInfo *info)
void void
hrnStorageList( hrnStorageList(
const int line, const Storage *const storage, const char *const path, const char *const expected, const Storage *const storage, const char *const path, const char *const expected, const HrnStorageListParam param)
const HrnStorageListParam param)
{ {
// Log list test // Log list test
hrnTestLogPrefix(line);
hrnTestResultBegin(__func__, false); hrnTestResultBegin(__func__, false);
ASSERT(storage != NULL);
const String *const pathFull = storagePathP(storage, STR(path)); const String *const pathFull = storagePathP(storage, STR(path));
printf("list%s contents of '%s'\n", param.remove ? "/remove": "", strZ(pathFull)); printf("list%s contents of '%s'", param.remove ? "/remove": "", strZ(pathFull));
fflush(stdout); hrnTestResultComment(param.comment);
// Generate a list of files/paths/etc // Generate a list of files/paths/etc
List *list = lstNewP(sizeof(StorageInfo)); List *list = lstNewP(sizeof(StorageInfo));
storageInfoListP(storage, pathFull, hrnStorageListCallback, list, .sortOrder = sortOrderAsc, .recurse = true); storageInfoListP(storage, pathFull, hrnStorageListCallback, list, .sortOrder = sortOrderAsc, .recurse = !param.noRecurse);
// Remove files if requested // Remove files if requested
if (param.remove) if (param.remove)
@ -284,11 +303,12 @@ hrnStorageList(
/**********************************************************************************************************************************/ /**********************************************************************************************************************************/
void void
hrnStorageMode(const int line, const Storage *const storage, const char *const path, HrnStorageModeParam param) hrnStorageMode(const Storage *const storage, const char *const path, HrnStorageModeParam param)
{ {
hrnTestLogPrefix(line);
hrnTestResultBegin(__func__, false); hrnTestResultBegin(__func__, false);
ASSERT(storage != NULL);
const char *const pathFull = strZ(storagePathP(storage, STR(path))); const char *const pathFull = strZ(storagePathP(storage, STR(path)));
// If no mode specified then default the mode based on the file type // If no mode specified then default the mode based on the file type
@ -304,8 +324,8 @@ hrnStorageMode(const int line, const Storage *const storage, const char *const p
param.mode = STORAGE_MODE_FILE_DEFAULT; param.mode = STORAGE_MODE_FILE_DEFAULT;
} }
printf("chmod '%04o' on '%s'\n", param.mode, pathFull); printf("chmod '%04o' on '%s'", param.mode, pathFull);
fflush(stdout); hrnTestResultComment(param.comment);
THROW_ON_SYS_ERROR_FMT(chmod(pathFull, param.mode) == -1, FileModeError, "unable to set mode on '%s'", pathFull); THROW_ON_SYS_ERROR_FMT(chmod(pathFull, param.mode) == -1, FileModeError, "unable to set mode on '%s'", pathFull);
@ -314,8 +334,15 @@ hrnStorageMode(const int line, const Storage *const storage, const char *const p
/**********************************************************************************************************************************/ /**********************************************************************************************************************************/
void void
hrnStoragePut(const Storage *storage, const char *file, const Buffer *buffer, HrnStoragePutParam param) hrnStoragePut(
const Storage *const storage, const char *const file, const Buffer *const buffer, const char *const logPrefix,
HrnStoragePutParam param)
{ {
hrnTestResultBegin(__func__, false);
ASSERT(storage != NULL);
ASSERT(file != NULL);
// Add compression extension to file name // Add compression extension to file name
String *fileStr = strNewZ(file); String *fileStr = strNewZ(file);
compressExtCat(fileStr, param.compressType); compressExtCat(fileStr, param.compressType);
@ -325,10 +352,14 @@ hrnStoragePut(const Storage *storage, const char *file, const Buffer *buffer, Hr
IoFilterGroup *filterGroup = ioWriteFilterGroup(storageWriteIo(destination)); IoFilterGroup *filterGroup = ioWriteFilterGroup(storageWriteIo(destination));
// Add compression filter // Add compression filter
String *const filter = strNew();
if (param.compressType != compressTypeNone) if (param.compressType != compressTypeNone)
{ {
ASSERT(param.compressType == compressTypeGz || param.compressType == compressTypeBz2); ASSERT(param.compressType == compressTypeGz || param.compressType == compressTypeBz2);
ioFilterGroupAdd(filterGroup, compressFilter(param.compressType, 1)); ioFilterGroupAdd(filterGroup, compressFilter(param.compressType, 1));
strCatFmt(filter, "cmp[%s]", strZ(compressTypeStr(param.compressType)));
} }
// Add encrypted filter // Add encrypted filter
@ -339,55 +370,51 @@ hrnStoragePut(const Storage *storage, const char *file, const Buffer *buffer, Hr
param.cipherPass = TEST_CIPHER_PASS; param.cipherPass = TEST_CIPHER_PASS;
ioFilterGroupAdd(filterGroup, cipherBlockNew(cipherModeEncrypt, param.cipherType, BUFSTRZ(param.cipherPass), NULL)); ioFilterGroupAdd(filterGroup, cipherBlockNew(cipherModeEncrypt, param.cipherType, BUFSTRZ(param.cipherPass), NULL));
strCatFmt(filter, "%senc[%s,%s]", strEmpty(filter) ? "" : "/", strZ(strIdToStr(param.cipherType)), param.cipherPass);
} }
// Add file name
printf(
"%s %s%s%s'%s%s'", logPrefix != NULL ? logPrefix : "put file", buffer == NULL || bufEmpty(buffer) ? "(empty) " : "",
strZ(filter), strEmpty(filter) ? "" : " ", strZ(storagePathP(storage, fileStr)), strZ(compressExtStr(param.compressType)));
hrnTestResultComment(param.comment);
// Put file // Put file
storagePutP(destination, buffer); storagePutP(destination, buffer);
}
const char * hrnTestResultEnd();
hrnStoragePutLog(const Storage *storage, const char *file, const Buffer *buffer, HrnStoragePutParam param)
{
// Empty if buffer is NULL
String *log = strNewZ(buffer == NULL || bufEmpty(buffer) ? "(empty) " : "");
// Add compression detail
if (param.compressType != compressTypeNone)
strCatFmt(log, "cmp[%s]", strZ(compressTypeStr(param.compressType)));
// Add encryption detail
if (param.cipherType != 0 && param.cipherType != cipherTypeNone)
{
if (param.cipherPass == NULL)
param.cipherPass = TEST_CIPHER_PASS;
if (param.compressType != compressTypeNone)
strCatZ(log, "/");
strCatFmt(log, "enc[%s,%s]", strZ(strIdToStr(param.cipherType)), param.cipherPass);
}
// Add a space if compression/encryption defined
if (param.compressType != compressTypeNone || (param.cipherType != 0 && param.cipherType != cipherTypeNone))
strCatZ(log, " ");
// Add file name
strCatFmt(log, "'%s%s'", strZ(storagePathP(storage, STR(file))), strZ(compressExtStr(param.compressType)));
return strZ(log);
} }
/**********************************************************************************************************************************/ /**********************************************************************************************************************************/
void void
hrnStorageTime(const int line, const Storage *const storage, const char *const path, const time_t modified) hrnStorageRemove(const Storage *const storage, const char *const file, const TestStorageRemoveParam param)
{ {
hrnTestLogPrefix(line);
hrnTestResultBegin(__func__, false); hrnTestResultBegin(__func__, false);
ASSERT(storage != NULL);
ASSERT(file != NULL);
printf("remove file '%s'", strZ(storagePathP(storage, STR(file))));
hrnTestResultComment(param.comment);
storageRemoveP(storage, STR(file), .errorOnMissing = true);
hrnTestResultEnd();
}
/**********************************************************************************************************************************/
void
hrnStorageTime(const Storage *const storage, const char *const path, const time_t modified, const HrnStorageTimeParam param)
{
hrnTestResultBegin(__func__, false);
ASSERT(storage != NULL);
const char *const pathFull = strZ(storagePathP(storage, path == NULL ? NULL : STR(path))); const char *const pathFull = strZ(storagePathP(storage, path == NULL ? NULL : STR(path)));
printf("time '%" PRId64 "' on '%s'\n", (int64_t)modified, pathFull); printf("time '%" PRId64 "' on '%s'", (int64_t)modified, pathFull);
fflush(stdout); hrnTestResultComment(param.comment);
THROW_ON_SYS_ERROR_FMT( THROW_ON_SYS_ERROR_FMT(
utime(pathFull, &((struct utimbuf){.actime = modified, .modtime = modified})) == -1, FileInfoError, utime(pathFull, &((struct utimbuf){.actime = modified, .modtime = modified})) == -1, FileInfoError,

View File

@ -10,13 +10,6 @@ Helper functions for testing storage and related functions.
#include "common/crypto/common.h" #include "common/crypto/common.h"
#include "storage/storage.intern.h" #include "storage/storage.intern.h"
/***********************************************************************************************************************************
Check file exists
***********************************************************************************************************************************/
#define TEST_STORAGE_EXISTS(storage, file) \
TEST_RESULT_BOOL( \
storageExistsP(storage, STR(file)), true, strZ(strNewFmt("file exists '%s'", strZ(storagePathP(storage, STR(file))))))
/*********************************************************************************************************************************** /***********************************************************************************************************************************
Get a file and test it against the specified content Get a file and test it against the specified content
***********************************************************************************************************************************/ ***********************************************************************************************************************************/
@ -24,15 +17,41 @@ typedef struct TestStorageGetParam
{ {
VAR_PARAM_HEADER; VAR_PARAM_HEADER;
bool remove; // Remove file after testing? bool remove; // Remove file after testing?
const char *comment; // Comment
} TestStorageGetParam; } TestStorageGetParam;
#define TEST_STORAGE_GET(storage, file, content, ...) \ #define TEST_STORAGE_GET(storage, file, content, ...) \
testStorageGet(__LINE__, storage, file, content, (TestStorageGetParam){VAR_PARAM_INIT, __VA_ARGS__}) do \
{ \
hrnTestLogPrefix(__LINE__); \
testStorageGet(storage, file, content, (TestStorageGetParam){VAR_PARAM_INIT, __VA_ARGS__}); \
} \
while (0)
#define TEST_STORAGE_GET_EMPTY(storage, file, ...) \ #define TEST_STORAGE_GET_EMPTY(storage, file, ...) \
TEST_STORAGE_GET(storage, file, "", __VA_ARGS__) TEST_STORAGE_GET(storage, file, "", __VA_ARGS__)
void testStorageGet( void testStorageGet(
const int line, const Storage *const storage, const char *const file, const char *const expected, TestStorageGetParam param); const Storage *const storage, const char *const file, const char *const expected, const TestStorageGetParam param);
/***********************************************************************************************************************************
Check file exists
***********************************************************************************************************************************/
typedef struct TestStorageExistsParam
{
VAR_PARAM_HEADER;
const char *comment; // Comment
} TestStorageExistsParam;
#define TEST_STORAGE_EXISTS(storage, file, ...) \
do \
{ \
hrnTestLogPrefix(__LINE__); \
testStorageExists(storage, file, (TestStorageExistsParam){VAR_PARAM_INIT, __VA_ARGS__}); \
} \
while (0)
void testStorageExists(const Storage *const storage, const char *const file, const TestStorageExistsParam param);
/*********************************************************************************************************************************** /***********************************************************************************************************************************
List files in a path and optionally remove them List files in a path and optionally remove them
@ -40,18 +59,24 @@ List files in a path and optionally remove them
typedef struct HrnStorageListParam typedef struct HrnStorageListParam
{ {
VAR_PARAM_HEADER; VAR_PARAM_HEADER;
bool remove; bool remove; // Remove files after testing?
bool noRecurse; // Do not recurse into subdirectories
const char *comment; // Comment
} HrnStorageListParam; } HrnStorageListParam;
#define TEST_STORAGE_LIST(storage, path, expected, ...) \ #define TEST_STORAGE_LIST(storage, path, expected, ...) \
hrnStorageList(__LINE__, storage, path, expected, (HrnStorageListParam){VAR_PARAM_INIT, __VA_ARGS__}) do \
{ \
hrnTestLogPrefix(__LINE__); \
hrnStorageList(storage, path, expected, (HrnStorageListParam){VAR_PARAM_INIT, __VA_ARGS__}); \
} \
while (0)
#define TEST_STORAGE_LIST_EMPTY(storage, path, ...) \ #define TEST_STORAGE_LIST_EMPTY(storage, path, ...) \
TEST_STORAGE_LIST(storage, path, NULL, __VA_ARGS__) TEST_STORAGE_LIST(storage, path, NULL, __VA_ARGS__)
void hrnStorageList( void hrnStorageList(
const int line, const Storage *const storage, const char *const path, const char *const expected, const Storage *const storage, const char *const path, const char *const expected, const HrnStorageListParam param);
const HrnStorageListParam param);
/*********************************************************************************************************************************** /***********************************************************************************************************************************
Change the mode of a path/file Change the mode of a path/file
@ -60,12 +85,18 @@ typedef struct HrnStorageModeParam
{ {
VAR_PARAM_HEADER; VAR_PARAM_HEADER;
mode_t mode; // Mode to set -- reset to default if not provided mode_t mode; // Mode to set -- reset to default if not provided
const char *comment; // Comment
} HrnStorageModeParam; } HrnStorageModeParam;
#define HRN_STORAGE_MODE(storage, path, ...) \ #define HRN_STORAGE_MODE(storage, path, ...) \
hrnStorageMode(__LINE__, storage, path, (HrnStorageModeParam){VAR_PARAM_INIT, __VA_ARGS__}) do \
{ \
hrnTestLogPrefix(__LINE__); \
hrnStorageMode(storage, path, (HrnStorageModeParam){VAR_PARAM_INIT, __VA_ARGS__}); \
} \
while (0)
void hrnStorageMode(const int line, const Storage *const storage, const char *const path, HrnStorageModeParam param); void hrnStorageMode(const Storage *const storage, const char *const path, HrnStorageModeParam param);
/*********************************************************************************************************************************** /***********************************************************************************************************************************
Put a file with optional compression and/or encryption Put a file with optional compression and/or encryption
@ -76,12 +107,16 @@ typedef struct HrnStoragePutParam
CompressType compressType; CompressType compressType;
CipherType cipherType; CipherType cipherType;
const char *cipherPass; const char *cipherPass;
const char *comment; // Comment
} HrnStoragePutParam; } HrnStoragePutParam;
#define HRN_STORAGE_PUT(storage, file, buffer, ...) \ #define HRN_STORAGE_PUT(storage, file, buffer, ...) \
TEST_RESULT_VOID( \ do \
hrnStoragePut(storage, file, buffer, (HrnStoragePutParam){VAR_PARAM_INIT, __VA_ARGS__}), \ { \
strZ(strNewFmt("put file %s", hrnStoragePutLog(storage, file, buffer, (HrnStoragePutParam){VAR_PARAM_INIT, __VA_ARGS__})))) hrnTestLogPrefix(__LINE__); \
hrnStoragePut(storage, file, buffer, NULL, (HrnStoragePutParam){VAR_PARAM_INIT, __VA_ARGS__}); \
} \
while (0)
#define HRN_STORAGE_PUT_EMPTY(storage, file, ...) \ #define HRN_STORAGE_PUT_EMPTY(storage, file, ...) \
HRN_STORAGE_PUT(storage, file, NULL, __VA_ARGS__) HRN_STORAGE_PUT(storage, file, NULL, __VA_ARGS__)
@ -89,24 +124,47 @@ typedef struct HrnStoragePutParam
#define HRN_STORAGE_PUT_Z(storage, file, stringz, ...) \ #define HRN_STORAGE_PUT_Z(storage, file, stringz, ...) \
HRN_STORAGE_PUT(storage, file, BUFSTRZ(stringz), __VA_ARGS__) HRN_STORAGE_PUT(storage, file, BUFSTRZ(stringz), __VA_ARGS__)
void hrnStoragePut(const Storage *storage, const char *file, const Buffer *buffer, HrnStoragePutParam param); void hrnStoragePut(
const char *hrnStoragePutLog(const Storage *storage, const char *file, const Buffer *buffer, HrnStoragePutParam param); const Storage *const storage, const char *const file, const Buffer *const buffer, const char *const logPrefix,
HrnStoragePutParam param);
/*********************************************************************************************************************************** /***********************************************************************************************************************************
Remove a file and error if it does not exist Remove a file and error if it does not exist
***********************************************************************************************************************************/ ***********************************************************************************************************************************/
#define TEST_STORAGE_REMOVE(storage, path) \ typedef struct TestStorageRemoveParam
TEST_RESULT_VOID( \ {
storageRemoveP(storage, STR(path), .errorOnMissing = true), \ VAR_PARAM_HEADER;
strZ(strNewFmt("remove file '%s'", strZ(storagePathP(storage, STR(path)))))) const char *comment; // Comment
} TestStorageRemoveParam;
#define TEST_STORAGE_REMOVE(storage, file, ...) \
do \
{ \
hrnTestLogPrefix(__LINE__); \
hrnStorageRemove(storage, file, (TestStorageRemoveParam){VAR_PARAM_INIT, __VA_ARGS__}); \
} \
while (0)
void hrnStorageRemove(const Storage *const storage, const char *const file, const TestStorageRemoveParam param);
/*********************************************************************************************************************************** /***********************************************************************************************************************************
Change the time of a path/file Change the time of a path/file
***********************************************************************************************************************************/ ***********************************************************************************************************************************/
#define HRN_STORAGE_TIME(storage, path, time) \ typedef struct HrnStorageTimeParam
hrnStorageTime(__LINE__, storage, path, time) {
VAR_PARAM_HEADER;
const char *comment; // Comment
} HrnStorageTimeParam;
void hrnStorageTime(const int line, const Storage *const storage, const char *const path, const time_t modified); #define HRN_STORAGE_TIME(storage, path, time, ...) \
do \
{ \
hrnTestLogPrefix(__LINE__); \
hrnStorageTime(storage, path, time, (HrnStorageTimeParam){VAR_PARAM_INIT, __VA_ARGS__}); \
} \
while (0)
void hrnStorageTime(const Storage *const storage, const char *const path, const time_t modified, const HrnStorageTimeParam param);
/*********************************************************************************************************************************** /***********************************************************************************************************************************
Dummy interface for constructing test storage drivers. All required functions are stubbed out so this interface can be copied and Dummy interface for constructing test storage drivers. All required functions are stubbed out so this interface can be copied and

View File

@ -388,6 +388,19 @@ hrnTestResultBegin(const char *const statement, const bool result)
harnessTestLocal.logLastLineNo = 0; harnessTestLocal.logLastLineNo = 0;
} }
/**********************************************************************************************************************************/
void
hrnTestResultComment(const char *const comment)
{
if (comment != NULL)
printf(" (%s)\n", comment);
else
puts("");
fflush(stdout);
}
/**********************************************************************************************************************************/
bool bool
hrnTestResultException(void) hrnTestResultException(void)
{ {

View File

@ -53,6 +53,7 @@ void hrnTestLogPrefix(const int lineNo);
// Begin/end result test so an exception during the test will give a useful message about what happened and where // Begin/end result test so an exception during the test will give a useful message about what happened and where
void hrnTestResultBegin(const char *const statement, const bool result); void hrnTestResultBegin(const char *const statement, const bool result);
void hrnTestResultComment(const char *const comment);
bool hrnTestResultException(void); bool hrnTestResultException(void);
void hrnTestResultEnd(void); void hrnTestResultEnd(void);