1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2025-01-30 05:39:12 +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
***********************************************************************************************************************************/
#define HRN_INFO_PUT(storage, file, info, ...) \
TEST_RESULT_VOID( \
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__}))))
do \
{ \
hrnTestLogPrefix(__LINE__); \
hrnStoragePut( \
storage, file, harnessInfoChecksumZ(info), "put info", (HrnStoragePutParam){VAR_PARAM_INIT, __VA_ARGS__}); \
} \
while (0)
/***********************************************************************************************************************************
Functions

View File

@ -175,15 +175,17 @@ hrnStorageInfoListCallback(void *callbackData, const StorageInfo *info)
/**********************************************************************************************************************************/
void
testStorageGet(
const int line, const Storage *const storage, const char *const file, const char *const expected, TestStorageGetParam param)
testStorageGet(const Storage *const storage, const char *const file, const char *const expected, const TestStorageGetParam param)
{
hrnTestLogPrefix(line);
hrnTestResultBegin(__func__, false);
ASSERT(storage != NULL);
ASSERT(file != NULL);
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);
@ -191,6 +193,23 @@ testStorageGet(
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
hrnStorageListCallback(void *list, const StorageInfo *info)
@ -213,21 +232,21 @@ hrnStorageListCallback(void *list, const StorageInfo *info)
void
hrnStorageList(
const int line, const Storage *const storage, const char *const path, const char *const expected,
const HrnStorageListParam param)
const Storage *const storage, const char *const path, const char *const expected, const HrnStorageListParam param)
{
// Log list test
hrnTestLogPrefix(line);
hrnTestResultBegin(__func__, false);
ASSERT(storage != NULL);
const String *const pathFull = storagePathP(storage, STR(path));
printf("list%s contents of '%s'\n", param.remove ? "/remove": "", strZ(pathFull));
fflush(stdout);
printf("list%s contents of '%s'", param.remove ? "/remove": "", strZ(pathFull));
hrnTestResultComment(param.comment);
// Generate a list of files/paths/etc
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
if (param.remove)
@ -284,11 +303,12 @@ hrnStorageList(
/**********************************************************************************************************************************/
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);
ASSERT(storage != NULL);
const char *const pathFull = strZ(storagePathP(storage, STR(path)));
// 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;
}
printf("chmod '%04o' on '%s'\n", param.mode, pathFull);
fflush(stdout);
printf("chmod '%04o' on '%s'", param.mode, pathFull);
hrnTestResultComment(param.comment);
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
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
String *fileStr = strNewZ(file);
compressExtCat(fileStr, param.compressType);
@ -325,10 +352,14 @@ hrnStoragePut(const Storage *storage, const char *file, const Buffer *buffer, Hr
IoFilterGroup *filterGroup = ioWriteFilterGroup(storageWriteIo(destination));
// Add compression filter
String *const filter = strNew();
if (param.compressType != compressTypeNone)
{
ASSERT(param.compressType == compressTypeGz || param.compressType == compressTypeBz2);
ioFilterGroupAdd(filterGroup, compressFilter(param.compressType, 1));
strCatFmt(filter, "cmp[%s]", strZ(compressTypeStr(param.compressType)));
}
// Add encrypted filter
@ -339,55 +370,51 @@ hrnStoragePut(const Storage *storage, const char *file, const Buffer *buffer, Hr
param.cipherPass = TEST_CIPHER_PASS;
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
storagePutP(destination, buffer);
}
const char *
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);
hrnTestResultEnd();
}
/**********************************************************************************************************************************/
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);
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)));
printf("time '%" PRId64 "' on '%s'\n", (int64_t)modified, pathFull);
fflush(stdout);
printf("time '%" PRId64 "' on '%s'", (int64_t)modified, pathFull);
hrnTestResultComment(param.comment);
THROW_ON_SYS_ERROR_FMT(
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 "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
***********************************************************************************************************************************/
@ -24,15 +17,41 @@ typedef struct TestStorageGetParam
{
VAR_PARAM_HEADER;
bool remove; // Remove file after testing?
const char *comment; // Comment
} TestStorageGetParam;
#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, ...) \
TEST_STORAGE_GET(storage, file, "", __VA_ARGS__)
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
@ -40,18 +59,24 @@ List files in a path and optionally remove them
typedef struct HrnStorageListParam
{
VAR_PARAM_HEADER;
bool remove;
bool remove; // Remove files after testing?
bool noRecurse; // Do not recurse into subdirectories
const char *comment; // Comment
} HrnStorageListParam;
#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, ...) \
TEST_STORAGE_LIST(storage, path, NULL, __VA_ARGS__)
void hrnStorageList(
const int line, const Storage *const storage, const char *const path, const char *const expected,
const HrnStorageListParam param);
const Storage *const storage, const char *const path, const char *const expected, const HrnStorageListParam param);
/***********************************************************************************************************************************
Change the mode of a path/file
@ -60,12 +85,18 @@ typedef struct HrnStorageModeParam
{
VAR_PARAM_HEADER;
mode_t mode; // Mode to set -- reset to default if not provided
const char *comment; // Comment
} HrnStorageModeParam;
#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
@ -76,12 +107,16 @@ typedef struct HrnStoragePutParam
CompressType compressType;
CipherType cipherType;
const char *cipherPass;
const char *comment; // Comment
} HrnStoragePutParam;
#define HRN_STORAGE_PUT(storage, file, buffer, ...) \
TEST_RESULT_VOID( \
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__}))))
do \
{ \
hrnTestLogPrefix(__LINE__); \
hrnStoragePut(storage, file, buffer, NULL, (HrnStoragePutParam){VAR_PARAM_INIT, __VA_ARGS__}); \
} \
while (0)
#define HRN_STORAGE_PUT_EMPTY(storage, file, ...) \
HRN_STORAGE_PUT(storage, file, NULL, __VA_ARGS__)
@ -89,24 +124,47 @@ typedef struct HrnStoragePutParam
#define HRN_STORAGE_PUT_Z(storage, file, stringz, ...) \
HRN_STORAGE_PUT(storage, file, BUFSTRZ(stringz), __VA_ARGS__)
void hrnStoragePut(const Storage *storage, const char *file, const Buffer *buffer, HrnStoragePutParam param);
const char *hrnStoragePutLog(const Storage *storage, const char *file, const Buffer *buffer, HrnStoragePutParam param);
void hrnStoragePut(
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
***********************************************************************************************************************************/
#define TEST_STORAGE_REMOVE(storage, path) \
TEST_RESULT_VOID( \
storageRemoveP(storage, STR(path), .errorOnMissing = true), \
strZ(strNewFmt("remove file '%s'", strZ(storagePathP(storage, STR(path))))))
typedef struct TestStorageRemoveParam
{
VAR_PARAM_HEADER;
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
***********************************************************************************************************************************/
#define HRN_STORAGE_TIME(storage, path, time) \
hrnStorageTime(__LINE__, storage, path, time)
typedef struct HrnStorageTimeParam
{
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

View File

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