1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2025-03-03 14:52:21 +02:00

Add stack trace macros to all functions.

Low-level functions only include stack trace in test builds while higher-level functions ship with stack trace built-in. Stack traces include all parameters passed to the function but production builds only create the parameter list when the log level is set high enough, i.e. debug or trace depending on the function.
This commit is contained in:
David Steele 2018-05-18 11:57:32 -04:00
parent abb9651f4c
commit 52bc073234
141 changed files with 6489 additions and 1179 deletions

View File

@ -25,6 +25,10 @@
</release-improvement-list>
<release-development-list>
<release-item>
<p>Add stack trace macros to all functions. Low-level functions only include stack trace in test builds while higher-level functions ship with stack trace built-in. Stack traces include all parameters passed to the function but production builds only create the parameter list when the log level is set high enough, i.e. <id>debug</id> or <id>trace</id> depending on the function.</p>
</release-item>
<release-item>
<p>Build <path>libc</path> using links rather than referencing the C files in <path>src</path> directly. The C library builds with different options which should not be reused for the C binary or vice versa.</p>
</release-item>

View File

@ -15,7 +15,10 @@ use ExtUtils::MakeMaker;
use File::Basename qw(dirname);
use lib dirname($0) . '/lib';
use lib dirname($0) . '/build/lib';
use pgBackRest::LibCAuto;
use pgBackRestLibC::BuildParam;
####################################################################################################################################
# Storage object to use for all file operations
@ -77,6 +80,7 @@ my @stryCFile =
'cipher/cipher.c',
'cipher/random.c',
'command/command.c',
'common/debug.c',
'common/encode.c',
'common/encode/base64.c',
'common/error.c',
@ -86,7 +90,9 @@ my @stryCFile =
'common/log.c',
'common/memContext.c',
'common/regExp.c',
'common/stackTrace.c',
'common/time.c',
'common/type/convert.c',
'common/type/buffer.c',
'common/type/keyValue.c',
'common/type/list.c',
@ -142,15 +148,7 @@ WriteMakefile
VERSION_FROM => 'lib/' . BACKREST_NAME . '/LibC.pm',
AUTHOR => 'David Steele <david@pgbackrest.org>',
CCFLAGS => join(' ', qw(
-Wfatal-errors -Wall -Wextra -Wwrite-strings -Wno-clobbered -Wno-missing-field-initializers
-o $@
-std=c99
-D_FILE_OFFSET_BITS=64
-funroll-loops
-ftree-vectorize
$(CFLAGS)
)),
CCFLAGS => join(' ', buildParamCCAll()),
INC => join(' ', qw(
-I.

View File

@ -0,0 +1,46 @@
####################################################################################################################################
# Parameters used by LibC builds
####################################################################################################################################
package pgBackRestLibC::BuildParam;
use strict;
use warnings FATAL => qw(all);
use Carp qw(confess);
use English '-no_match_vars';
use Exporter qw(import);
our @EXPORT = qw();
####################################################################################################################################
# All CC params used for a debug build
####################################################################################################################################
sub buildParamCCDebug
{
return qw(
-Wfatal-errors -Wall -Wextra -Wwrite-strings -Wno-clobbered -Wno-missing-field-initializers
-o $@
-std=c99
-D_FILE_OFFSET_BITS=64
$(CFLAGS));
}
push @EXPORT, qw(buildParamCCDebug);
####################################################################################################################################
# All CC params used for a production build
####################################################################################################################################
sub buildParamCCAll
{
my @stryParams = buildParamCCDebug;
push(@stryParams, qw(
-DNDEBUG
-funroll-loops
-ftree-vectorize));
return @stryParams;
}
push @EXPORT, qw(buildParamCCAll);
1;

View File

@ -59,17 +59,20 @@ SRCS = \
command/archive/push/push.c \
command/help/help.c \
command/command.c \
common/fork.c \
common/debug.c \
common/error.c \
common/exit.c \
common/fork.c \
common/io/handle.c \
common/ini.c \
common/lock.c \
common/log.c \
common/memContext.c \
common/regExp.c \
common/stackTrace.c \
common/time.c \
common/type/buffer.c \
common/type/convert.c \
common/type/keyValue.c \
common/type/list.c \
common/type/string.c \

View File

@ -6,6 +6,7 @@ Block Cipher
#include <openssl/evp.h>
#include <openssl/err.h>
#include "common/debug.h"
#include "common/memContext.h"
#include "cipher/block.h"
#include "cipher/random.h"
@ -45,6 +46,18 @@ New block encrypt/decrypt object
CipherBlock *
cipherBlockNew(CipherMode mode, const char *cipherName, const unsigned char *pass, size_t passSize, const char *digestName)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(ENUM, mode);
FUNCTION_DEBUG_PARAM(STRINGZ, cipherName);
FUNCTION_DEBUG_PARAM(UCHARP, pass);
FUNCTION_DEBUG_PARAM(SIZE, passSize);
FUNCTION_DEBUG_PARAM(STRINGZ, digestName);
FUNCTION_DEBUG_ASSERT(cipherName != NULL);
FUNCTION_DEBUG_ASSERT(pass != NULL);
FUNCTION_DEBUG_ASSERT(passSize > 0);
FUNCTION_DEBUG_END();
// Only need to init once.
if (!cipherIsInit())
cipherInit();
@ -90,7 +103,7 @@ cipherBlockNew(CipherMode mode, const char *cipherName, const unsigned char *pas
}
MEM_CONTEXT_NEW_END();
return this;
FUNCTION_DEBUG_RESULT(CIPHER_BLOCK, this);
}
/***********************************************************************************************************************************
@ -99,6 +112,13 @@ Determine how large the destination buffer should be
size_t
cipherBlockProcessSize(CipherBlock *this, size_t sourceSize)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(CIPHER_BLOCK, this);
FUNCTION_DEBUG_PARAM(SIZE, sourceSize);
FUNCTION_DEBUG_ASSERT(this != NULL);
FUNCTION_DEBUG_END();
// Destination size is source size plus one extra block
size_t destinationSize = sourceSize + EVP_MAX_BLOCK_LENGTH;
@ -106,7 +126,7 @@ cipherBlockProcessSize(CipherBlock *this, size_t sourceSize)
if (this->mode == cipherModeEncrypt && !this->saltDone)
destinationSize += CIPHER_BLOCK_MAGIC_SIZE + PKCS5_SALT_LEN;
return destinationSize;
FUNCTION_DEBUG_RESULT(SIZE, destinationSize);
}
/***********************************************************************************************************************************
@ -115,6 +135,17 @@ Encrypt/decrypt data
size_t
cipherBlockProcess(CipherBlock *this, const unsigned char *source, size_t sourceSize, unsigned char *destination)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(CIPHER_BLOCK, this);
FUNCTION_DEBUG_PARAM(UCHARP, source);
FUNCTION_DEBUG_PARAM(SIZE, sourceSize);
FUNCTION_DEBUG_PARAM(UCHARP, destination);
FUNCTION_DEBUG_ASSERT(this != NULL);
FUNCTION_DEBUG_ASSERT(source != NULL);
FUNCTION_DEBUG_ASSERT(destination != NULL);
FUNCTION_DEBUG_END();
// Actual destination size
size_t destinationSize = 0;
@ -212,7 +243,7 @@ cipherBlockProcess(CipherBlock *this, const unsigned char *source, size_t source
}
// Return actual destination size
return destinationSize;
FUNCTION_DEBUG_RESULT(SIZE, destinationSize);
}
/***********************************************************************************************************************************
@ -221,6 +252,14 @@ Flush the remaining data
size_t
cipherBlockFlush(CipherBlock *this, unsigned char *destination)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(CIPHER_BLOCK, this);
FUNCTION_DEBUG_PARAM(UCHARP, destination);
FUNCTION_DEBUG_ASSERT(this != NULL);
FUNCTION_DEBUG_ASSERT(destination != NULL);
FUNCTION_DEBUG_END();
// Actual destination size
size_t destinationSize = 0;
@ -233,7 +272,7 @@ cipherBlockFlush(CipherBlock *this, unsigned char *destination)
THROW(CipherError, "unable to flush");
// Return actual destination size
return destinationSize;
FUNCTION_DEBUG_RESULT(SIZE, destinationSize);
}
/***********************************************************************************************************************************
@ -242,10 +281,18 @@ Free memory
void
cipherBlockFree(CipherBlock *this)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(CIPHER_BLOCK, this);
FUNCTION_DEBUG_ASSERT(this != NULL);
FUNCTION_DEBUG_END();
// Free cipher context
if (this->cipherContext)
EVP_CIPHER_CTX_cleanup(this->cipherContext);
// Free mem context
memContextFree(this->memContext);
FUNCTION_DEBUG_RESULT_VOID();
}

View File

@ -21,4 +21,12 @@ size_t cipherBlockProcess(CipherBlock *this, const unsigned char *source, size_t
size_t cipherBlockFlush(CipherBlock *this, unsigned char *destination);
void cipherBlockFree(CipherBlock *this);
/***********************************************************************************************************************************
Macros for function logging
***********************************************************************************************************************************/
#define FUNCTION_DEBUG_CIPHER_BLOCK_TYPE \
CipherBlock *
#define FUNCTION_DEBUG_CIPHER_BLOCK_FORMAT(value, buffer, bufferSize) \
objToLog(value, "CipherBlock", buffer, bufferSize)
#endif

View File

@ -6,6 +6,7 @@ Cipher General Init and Free
#include <openssl/err.h>
#include "cipher/cipher.h"
#include "common/debug.h"
/***********************************************************************************************************************************
Flag to indicate if OpenSSL has already been initialized
@ -18,6 +19,8 @@ Initialize ciphers
void
cipherInit()
{
FUNCTION_DEBUG_VOID(logLevelTrace);
if (!cipherInitDone)
{
ERR_load_crypto_strings();
@ -25,6 +28,8 @@ cipherInit()
cipherInitDone = true;
}
FUNCTION_DEBUG_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -33,23 +38,6 @@ Have the ciphers been initialized?
bool
cipherIsInit()
{
return cipherInitDone;
}
/***********************************************************************************************************************************
Free ciphers
***********************************************************************************************************************************/
void
cipherFree()
{
if (cipherInitDone)
{
FIPS_mode_set(0);
EVP_cleanup();
CRYPTO_cleanup_all_ex_data();
ERR_remove_thread_state(NULL);
ERR_free_strings();
cipherInitDone = false;
}
FUNCTION_TEST_VOID();
FUNCTION_TEST_RESULT(BOOL, cipherInitDone);
}

View File

@ -20,6 +20,5 @@ Functions
***********************************************************************************************************************************/
void cipherInit();
bool cipherIsInit();
void cipherFree();
#endif

View File

@ -4,6 +4,8 @@ Cipher
#include <openssl/rand.h>
#include "cipher/random.h"
#include "common/debug.h"
#include "common/error.h"
/***********************************************************************************************************************************
Generate random bytes
@ -11,5 +13,15 @@ Generate random bytes
void
randomBytes(unsigned char *buffer, size_t size)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(UCHARP, buffer);
FUNCTION_DEBUG_PARAM(SIZE, size);
FUNCTION_DEBUG_ASSERT(buffer != NULL);
FUNCTION_DEBUG_ASSERT(size > 0);
FUNCTION_DEBUG_END();
RAND_bytes(buffer, (int)size);
FUNCTION_DEBUG_RESULT_VOID();
}

View File

@ -7,6 +7,7 @@ Archive Push Command
#include "command/archive/common.h"
#include "common/assert.h"
#include "common/debug.h"
#include "common/log.h"
#include "common/memContext.h"
#include "common/wait.h"
@ -19,6 +20,12 @@ Check for ok/error status files in the spool in/out directory
bool
archiveAsyncStatus(ArchiveMode archiveMode, const String *walSegment, bool confessOnError)
{
FUNCTION_DEBUG_BEGIN(logLevelDebug);
FUNCTION_DEBUG_PARAM(ENUM, archiveMode);
FUNCTION_DEBUG_PARAM(STRING, walSegment);
FUNCTION_DEBUG_PARAM(BOOL, confessOnError);
FUNCTION_DEBUG_END();
bool result = false;
MEM_CONTEXT_TEMP_BEGIN()
@ -98,7 +105,7 @@ archiveAsyncStatus(ArchiveMode archiveMode, const String *walSegment, bool confe
}
MEM_CONTEXT_TEMP_END();
return result;
FUNCTION_DEBUG_RESULT(BOOL, result);
}
/***********************************************************************************************************************************
@ -107,10 +114,16 @@ Get the next WAL segment given a WAL segment and WAL segment size
String *
walSegmentNext(const String *walSegment, size_t walSegmentSize, uint pgVersion)
{
ASSERT_DEBUG(walSegment != NULL);
ASSERT_DEBUG(strSize(walSegment) == 24);
ASSERT_DEBUG(UINT32_MAX % walSegmentSize == walSegmentSize - 1);
ASSERT_DEBUG(pgVersion >= PG_VERSION_11 || walSegmentSize == 16 * 1024 * 1024);
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(STRING, walSegment);
FUNCTION_DEBUG_PARAM(SIZE, walSegmentSize);
FUNCTION_DEBUG_PARAM(UINT, pgVersion);
FUNCTION_DEBUG_ASSERT(walSegment != NULL);
FUNCTION_DEBUG_ASSERT(strSize(walSegment) == 24);
FUNCTION_DEBUG_ASSERT(UINT32_MAX % walSegmentSize == walSegmentSize - 1);
FUNCTION_DEBUG_ASSERT(pgVersion >= PG_VERSION_11 || walSegmentSize == 16 * 1024 * 1024);
FUNCTION_DEBUG_END();
// Extract WAL parts
uint32_t timeline = 0;
@ -141,7 +154,7 @@ walSegmentNext(const String *walSegment, size_t walSegmentSize, uint pgVersion)
}
MEM_CONTEXT_TEMP_END();
return strNewFmt("%08X%08X%08X", timeline, major, minor);
FUNCTION_DEBUG_RESULT(STRING, strNewFmt("%08X%08X%08X", timeline, major, minor));
}
/***********************************************************************************************************************************
@ -150,7 +163,13 @@ Build a list of WAL segments based on a beginning WAL and number of WAL in the r
StringList *
walSegmentRange(const String *walSegmentBegin, size_t walSegmentSize, uint pgVersion, uint range)
{
ASSERT_DEBUG(range > 0);
FUNCTION_DEBUG_BEGIN(logLevelDebug);
FUNCTION_DEBUG_PARAM(STRING, walSegmentBegin);
FUNCTION_DEBUG_PARAM(SIZE, walSegmentSize);
FUNCTION_DEBUG_PARAM(UINT, pgVersion);
FUNCTION_DEBUG_ASSERT(range > 0);
FUNCTION_DEBUG_END();
StringList *result = NULL;
@ -177,5 +196,5 @@ walSegmentRange(const String *walSegmentBegin, size_t walSegmentSize, uint pgVer
}
MEM_CONTEXT_TEMP_END();
return result;
FUNCTION_DEBUG_RESULT(STRING_LIST, result);
}

View File

@ -6,6 +6,8 @@ Archive Get Command
#include "command/archive/common.h"
#include "command/command.h"
#include "common/assert.h"
#include "common/debug.h"
#include "common/fork.h"
#include "common/log.h"
#include "common/memContext.h"
@ -23,6 +25,16 @@ Clean the queue and prepare a list of WAL segments that the async process should
static StringList *
queueNeed(const String *walSegment, bool found, size_t queueSize, size_t walSegmentSize, uint pgVersion)
{
FUNCTION_DEBUG_BEGIN(logLevelDebug);
FUNCTION_DEBUG_PARAM(STRING, walSegment);
FUNCTION_DEBUG_PARAM(BOOL, found);
FUNCTION_DEBUG_PARAM(SIZE, queueSize);
FUNCTION_DEBUG_PARAM(SIZE, walSegmentSize);
FUNCTION_DEBUG_PARAM(UINT, pgVersion);
FUNCTION_DEBUG_ASSERT(walSegment != NULL);
FUNCTION_DEBUG_END();
StringList *result = strLstNew();
MEM_CONTEXT_TEMP_BEGIN()
@ -76,7 +88,7 @@ queueNeed(const String *walSegment, bool found, size_t queueSize, size_t walSegm
}
MEM_CONTEXT_TEMP_END();
return result;
FUNCTION_DEBUG_RESULT(STRING_LIST, result);
}
/***********************************************************************************************************************************
@ -85,6 +97,8 @@ Push a WAL segment to the repository
int
cmdArchiveGet()
{
FUNCTION_DEBUG_VOID(logLevelDebug);
int result = 1;
MEM_CONTEXT_TEMP_BEGIN()
@ -98,9 +112,9 @@ cmdArchiveGet()
THROW(ParamRequiredError, "WAL segment to get required");
if (strLstSize(commandParam) == 1)
THROW(ParamRequiredError, "Path to copy WAL segment required");
THROW(ParamRequiredError, "path to copy WAL segment required");
THROW(ParamRequiredError, "extra parameters found");
THROW(ParamInvalidError, "extra parameters found");
}
// Get the segment name
@ -270,5 +284,5 @@ cmdArchiveGet()
}
MEM_CONTEXT_TEMP_END();
return result;
FUNCTION_DEBUG_RESULT(INT, result);
}

View File

@ -5,6 +5,7 @@ Archive Push Command
#include "command/archive/common.h"
#include "command/command.h"
#include "common/debug.h"
#include "common/fork.h"
#include "common/log.h"
#include "common/memContext.h"
@ -20,6 +21,8 @@ Push a WAL segment to the repository
void
cmdArchivePush()
{
FUNCTION_DEBUG_VOID(logLevelDebug);
MEM_CONTEXT_TEMP_BEGIN()
{
// Make sure there is a parameter to retrieve the WAL segment from
@ -123,4 +126,6 @@ cmdArchivePush()
THROW(AssertError, "archive-push in C does not support synchronous mode");
}
MEM_CONTEXT_TEMP_END();
FUNCTION_DEBUG_RESULT_VOID();
}

View File

@ -4,25 +4,23 @@ Common Command Routines
#include <string.h>
#include "common/assert.h"
#include "common/debug.h"
#include "common/log.h"
#include "common/memContext.h"
#include "config/config.h"
#include "version.h"
/***********************************************************************************************************************************
Debug Asserts
***********************************************************************************************************************************/
// The command must be set
#define ASSERT_DEBUG_COMMAND_SET() \
ASSERT_DEBUG(cfgCommand() != cfgCmdNone)
/***********************************************************************************************************************************
Begin the command
***********************************************************************************************************************************/
void
cmdBegin(bool logOption)
{
ASSERT_DEBUG_COMMAND_SET();
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(BOOL, logOption);
FUNCTION_DEBUG_ASSERT(cfgCommand() != cfgCmdNone);
FUNCTION_DEBUG_END();
// This is fairly expensive log message to generate so skip it if it won't be output
if (logWill(cfgLogLevelDefault()))
@ -134,10 +132,12 @@ cmdBegin(bool logOption)
}
}
LOG_ANY(cfgLogLevelDefault(), 0, strPtr(info));
LOG(cfgLogLevelDefault(), 0, strPtr(info));
}
MEM_CONTEXT_TEMP_END();
}
FUNCTION_DEBUG_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -146,8 +146,13 @@ End the command
void
cmdEnd(int code, const String *errorMessage)
{
ASSERT_DEBUG_COMMAND_SET();
ASSERT_DEBUG(code == 0 || errorMessage != NULL);
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(INT, code);
FUNCTION_DEBUG_PARAM(STRING, errorMessage);
FUNCTION_DEBUG_ASSERT(cfgCommand() != cfgCmdNone);
FUNCTION_DEBUG_ASSERT(code == 0 || errorMessage != NULL);
FUNCTION_DEBUG_END();
// Skip this log message if it won't be output. It's not too expensive but since we skipped cmdBegin(), may as well.
if (logWill(cfgLogLevelDefault()))
@ -162,8 +167,10 @@ cmdEnd(int code, const String *errorMessage)
else
strCat(info, strPtr(errorMessage));
LOG_ANY(cfgLogLevelDefault(), 0, strPtr(info));
LOG(cfgLogLevelDefault(), 0, strPtr(info));
}
MEM_CONTEXT_TEMP_END();
}
FUNCTION_DEBUG_RESULT_VOID();
}

View File

@ -5,6 +5,8 @@ Help Command
#include <sys/types.h>
#include <unistd.h>
#include "common/assert.h"
#include "common/debug.h"
#include "common/io/handle.h"
#include "common/memContext.h"
#include "config/config.h"
@ -22,6 +24,16 @@ Helper function for helpRender() to make output look good on a console
static String *
helpRenderText(const String *text, size_t indent, bool indentFirst, size_t length)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(STRING, text);
FUNCTION_DEBUG_PARAM(SIZE, indent);
FUNCTION_DEBUG_PARAM(BOOL, indentFirst);
FUNCTION_DEBUG_PARAM(SIZE, length);
FUNCTION_DEBUG_ASSERT(text != NULL);
FUNCTION_DEBUG_ASSERT(length > 0);
FUNCTION_DEBUG_END();
String *result = strNew("");
// Split the text into paragraphs
@ -54,7 +66,7 @@ helpRenderText(const String *text, size_t indent, bool indentFirst, size_t lengt
}
}
return result;
FUNCTION_DEBUG_RESULT(STRING, result);
}
/***********************************************************************************************************************************
@ -63,6 +75,10 @@ Helper function for helpRender() to output values as strings
static String *
helpRenderValue(const Variant *value)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(VARIANT, value);
FUNCTION_DEBUG_END();
String *result = NULL;
if (value != NULL)
@ -109,7 +125,7 @@ helpRenderValue(const Variant *value)
result = varStrForce(value);
}
return result;
FUNCTION_DEBUG_RESULT(STRING, result);
}
/***********************************************************************************************************************************
@ -118,6 +134,8 @@ Render help to a string
static String *
helpRender()
{
FUNCTION_DEBUG_VOID(logLevelDebug);
String *result = strNew(PGBACKREST_NAME " " PGBACKREST_VERSION);
MEM_CONTEXT_TEMP_BEGIN()
@ -358,7 +376,7 @@ helpRender()
}
MEM_CONTEXT_TEMP_END();
return result;
FUNCTION_DEBUG_RESULT(STRING, result);
}
/***********************************************************************************************************************************
@ -367,9 +385,13 @@ Render help and output to stdout
void
cmdHelp()
{
FUNCTION_DEBUG_VOID(logLevelDebug);
MEM_CONTEXT_TEMP_BEGIN()
{
ioHandleWriteOneStr(STDOUT_FILENO, helpRender());
}
MEM_CONTEXT_TEMP_END();
FUNCTION_DEBUG_RESULT_VOID();
}

View File

@ -10,10 +10,12 @@ Assert Routines
For very important asserts that are shipped with the production code
***********************************************************************************************************************************/
#define ASSERT(condition) \
{ \
if (!(condition)) \
THROW_FMT(AssertError, "assertion '%s' failed", #condition); \
}
do \
{ \
if (!(condition)) \
THROW_FMT(AssertError, "assertion '%s' failed", #condition); \
} \
while (0)
/***********************************************************************************************************************************
Used for assertions that should only be run when debugging. Ideal for conditions that need to be tested during development but
@ -21,10 +23,12 @@ be too expensive to ship with the production code.
***********************************************************************************************************************************/
#ifndef NDEBUG
#define ASSERT_DEBUG(condition) \
{ \
if (!(condition)) \
THROW_FMT(AssertError, "debug assertion '%s' failed", #condition); \
}
do \
{ \
if (!(condition)) \
THROW_FMT(AssertError, "debug assertion '%s' failed", #condition); \
} \
while (0)
#else
#define ASSERT_DEBUG(condition)
#endif

47
src/common/debug.c Normal file
View File

@ -0,0 +1,47 @@
/***********************************************************************************************************************************
Debug Routines
***********************************************************************************************************************************/
#include <stdio.h>
#include "common/debug.h"
/***********************************************************************************************************************************
Convert object to a zero-terminated string for logging
***********************************************************************************************************************************/
size_t
objToLog(const void *object, const char *objectName, char *buffer, size_t bufferSize)
{
size_t result = 0;
if (object == NULL)
result = (size_t)snprintf(buffer, bufferSize, "null");
else
result = (size_t)snprintf(buffer, bufferSize, "{%s}", objectName);
return result;
}
/***********************************************************************************************************************************
Convert pointer to a zero-terminated string for logging
***********************************************************************************************************************************/
size_t
ptrToLog(const void *pointer, const char *pointerName, char *buffer, size_t bufferSize)
{
size_t result = 0;
if (pointer == NULL)
result = (size_t)snprintf(buffer, bufferSize, "null");
else
result = (size_t)snprintf(buffer, bufferSize, "(%s)", pointerName);
return result;
}
/***********************************************************************************************************************************
Convert zero-terminated string for logging
***********************************************************************************************************************************/
size_t
strzToLog(const char *string, char *buffer, size_t bufferSize)
{
return (size_t)snprintf(buffer, bufferSize, string == NULL ? "%s" : "\"%s\"", string == NULL ? "null" : string);
}

View File

@ -4,6 +4,9 @@ Debug Routines
#ifndef COMMON_DEBUG_H
#define COMMON_DEBUG_H
#include "common/stackTrace.h"
#include "common/type/convert.h"
/***********************************************************************************************************************************
NDEBUG indicates to C library routines that debugging is off -- set a more readable flag to use when debugging is on
***********************************************************************************************************************************/
@ -21,4 +24,294 @@ Extern variables that are needed for unit testing
static
#endif
/***********************************************************************************************************************************
Base function debugging macros
In debug mode parameters will always be recorded in the stack trace while in production mode they will only be recorded when the log
level is set to debug or trace.
***********************************************************************************************************************************/
#define FUNCTION_DEBUG_LEVEL() \
FUNCTION_DEBUG_logLevel
#ifdef DEBUG
#define FUNCTION_DEBUG_BEGIN_BASE(logLevel) \
LogLevel FUNCTION_DEBUG_LEVEL() = STACK_TRACE_PUSH(logLevel); \
\
{ \
stackTraceParamLog();
#define FUNCTION_DEBUG_END_BASE() \
LOG_WILL(FUNCTION_DEBUG_LEVEL(), 0, "(%s)", stackTraceParam()); \
}
#define FUNCTION_DEBUG_PARAM_BASE_BEGIN() \
stackTraceTestStop() \
#define FUNCTION_DEBUG_PARAM_BASE_END() \
stackTraceTestStart()
#else
#define FUNCTION_DEBUG_BEGIN_BASE(logLevel) \
LogLevel FUNCTION_DEBUG_LEVEL() = STACK_TRACE_PUSH(logLevel); \
\
if (logWill(FUNCTION_DEBUG_LEVEL())) \
{ \
stackTraceParamLog()
#define FUNCTION_DEBUG_END_BASE() \
LOG(FUNCTION_DEBUG_LEVEL(), 0, "(%s)", stackTraceParam()); \
}
#define FUNCTION_DEBUG_PARAM_BASE_BEGIN()
#define FUNCTION_DEBUG_PARAM_BASE_END()
#endif
/***********************************************************************************************************************************
General purpose function debugging macros
FUNCTION_DEBUG_VOID() is provided as a shortcut for functions that have no parameters.
***********************************************************************************************************************************/
#define FUNCTION_DEBUG_BEGIN(logLevel) \
FUNCTION_DEBUG_BEGIN_BASE(logLevel)
#define FUNCTION_DEBUG_END() \
FUNCTION_DEBUG_END_BASE()
#define FUNCTION_DEBUG_VOID(logLevel) \
FUNCTION_DEBUG_BEGIN_BASE(logLevel); \
FUNCTION_DEBUG_END_BASE()
#define FUNCTION_DEBUG_PARAM(typeMacroPrefix, param) \
FUNCTION_DEBUG_PARAM_BASE_BEGIN(); \
stackTraceParamAdd(FUNCTION_DEBUG_##typeMacroPrefix##_FORMAT(param, stackTraceParamBuffer(#param), STACK_TRACE_PARAM_MAX)); \
FUNCTION_DEBUG_PARAM_BASE_END()
#define FUNCTION_DEBUG_PARAM_PTR(typeName, param) \
FUNCTION_DEBUG_PARAM_BASE_BEGIN(); \
stackTraceParamAdd(ptrToLog(param, typeName, stackTraceParamBuffer(#param), STACK_TRACE_PARAM_MAX )); \
FUNCTION_DEBUG_PARAM_BASE_END()
/***********************************************************************************************************************************
Functions and macros to render various data types
***********************************************************************************************************************************/
size_t objToLog(const void *object, const char *objectName, char *buffer, size_t bufferSize);
size_t ptrToLog(const void *pointer, const char *pointerName, char *buffer, size_t bufferSize);
size_t strzToLog(const char *string, char *buffer, size_t bufferSize);
#define FUNCTION_DEBUG_BOOL_TYPE \
bool
#define FUNCTION_DEBUG_BOOL_FORMAT(value, buffer, bufferSize) \
cvtBoolToZ(value, buffer, bufferSize)
#define FUNCTION_DEBUG_BOOLP_TYPE \
bool *
#define FUNCTION_DEBUG_BOOLP_FORMAT(value, buffer, bufferSize) \
ptrToLog(value, "bool *", buffer, bufferSize)
#define FUNCTION_DEBUG_CHARP_TYPE \
char *
#define FUNCTION_DEBUG_CHARP_FORMAT(value, buffer, bufferSize) \
ptrToLog(value, "char *", buffer, bufferSize)
#define FUNCTION_DEBUG_CONST_CHARPP_TYPE \
const char **
#define FUNCTION_DEBUG_CONST_CHARPP_FORMAT(value, buffer, bufferSize) \
ptrToLog(value, "char **", buffer, bufferSize)
#define FUNCTION_DEBUG_CHARPY_TYPE \
char *[]
#define FUNCTION_DEBUG_CHARPY_FORMAT(value, buffer, bufferSize) \
ptrToLog(value, "char *[]", buffer, bufferSize)
#define FUNCTION_DEBUG_DOUBLE_TYPE \
double
#define FUNCTION_DEBUG_DOUBLE_FORMAT(value, buffer, bufferSize) \
cvtDoubleToZ(value, buffer, bufferSize)
#define FUNCTION_DEBUG_DOUBLEP_TYPE \
double *
#define FUNCTION_DEBUG_DOUBLEP_FORMAT(value, buffer, bufferSize) \
ptrToLog(value, "double *", buffer, bufferSize)
#define FUNCTION_DEBUG_INT_TYPE \
int
#define FUNCTION_DEBUG_INT_FORMAT(value, buffer, bufferSize) \
cvtIntToZ(value, buffer, bufferSize)
#define FUNCTION_DEBUG_INTP_TYPE \
int *
#define FUNCTION_DEBUG_INTP_FORMAT(value, buffer, bufferSize) \
ptrToLog(value, "int *", buffer, bufferSize)
#define FUNCTION_DEBUG_INT64_TYPE \
int64_t
#define FUNCTION_DEBUG_INT64_FORMAT(value, buffer, bufferSize) \
cvtInt64ToZ(value, buffer, bufferSize)
#define FUNCTION_DEBUG_ENUM_TYPE \
unsigned int
#define FUNCTION_DEBUG_ENUM_FORMAT(value, buffer, bufferSize) \
FUNCTION_DEBUG_UINT_FORMAT(value, buffer, bufferSize)
#define FUNCTION_DEBUG_FUNCTIONP_FORMAT(value, buffer, bufferSize) \
ptrToLog(value == NULL ? NULL : (void *)1, "function *", buffer, bufferSize)
#define FUNCTION_DEBUG_MODE_TYPE \
mode_t
#define FUNCTION_DEBUG_MODE_FORMAT(value, buffer, bufferSize) \
cvtModeToZ(value, buffer, bufferSize)
#define FUNCTION_DEBUG_UCHARP_TYPE \
unsigned char *
#define FUNCTION_DEBUG_UCHARP_FORMAT(value, buffer, bufferSize) \
ptrToLog(value, "unsigned char *", buffer, bufferSize)
#define FUNCTION_DEBUG_SIZE_TYPE \
size_t
#define FUNCTION_DEBUG_SIZE_FORMAT(value, buffer, bufferSize) \
cvtSizeToZ(value, buffer, bufferSize)
#define FUNCTION_DEBUG_UINT_TYPE \
unsigned int
#define FUNCTION_DEBUG_UINT_FORMAT(value, buffer, bufferSize) \
cvtUIntToZ(value, buffer, bufferSize)
#define FUNCTION_DEBUG_UINT16_TYPE \
uint16_t
#define FUNCTION_DEBUG_UINT16_FORMAT(value, buffer, bufferSize) \
FUNCTION_DEBUG_UINT_FORMAT(value, buffer, bufferSize)
#define FUNCTION_DEBUG_UINT32_TYPE \
uint32_t
#define FUNCTION_DEBUG_UINT32_FORMAT(value, buffer, bufferSize) \
FUNCTION_DEBUG_UINT_FORMAT(value, buffer, bufferSize)
#define FUNCTION_DEBUG_UINT64_TYPE \
uint64_t
#define FUNCTION_DEBUG_UINT64_FORMAT(value, buffer, bufferSize) \
cvtUInt64ToZ(value, buffer, bufferSize)
#define FUNCTION_DEBUG_VOIDP_TYPE \
void *
#define FUNCTION_DEBUG_VOIDP_FORMAT(value, buffer, bufferSize) \
ptrToLog(value, "void *", buffer, bufferSize)
#define FUNCTION_DEBUG_VOIDPP_TYPE \
void **
#define FUNCTION_DEBUG_VOIDPP_FORMAT(value, buffer, bufferSize) \
ptrToLog(value, "void **", buffer, bufferSize)
#define FUNCTION_DEBUG_STRINGZ_TYPE \
const char *
#define FUNCTION_DEBUG_STRINGZ_FORMAT(value, buffer, bufferSize) \
strzToLog(value, buffer, bufferSize)
/***********************************************************************************************************************************
Assert function to be used with function debugging
The assert statement is compiled into production code but only runs when the log level >= debug
***********************************************************************************************************************************/
#define FUNCTION_DEBUG_ASSERT(condition) \
do \
{ \
if (!(condition)) \
THROW_FMT(AssertError, "function debug assertion '%s' failed", #condition); \
} \
while (0)
/***********************************************************************************************************************************
Macros to return function results (or void)
***********************************************************************************************************************************/
#define FUNCTION_DEBUG_RESULT(typeMacroPrefix, result) \
do \
{ \
FUNCTION_DEBUG_##typeMacroPrefix##_TYPE FUNCTION_DEBUG_RESULT_result = result; \
\
STACK_TRACE_POP(); \
\
if (logWill(FUNCTION_DEBUG_LEVEL())) \
{ \
char buffer[STACK_TRACE_PARAM_MAX]; \
\
FUNCTION_DEBUG_##typeMacroPrefix##_FORMAT(FUNCTION_DEBUG_RESULT_result, buffer, sizeof(buffer)); \
LOG(FUNCTION_DEBUG_LEVEL(), 0, "=> %s", buffer); \
} \
\
return FUNCTION_DEBUG_RESULT_result; \
} \
while(0)
#define FUNCTION_DEBUG_RESULT_VOID() \
do \
{ \
STACK_TRACE_POP(); \
\
LOG_WILL(FUNCTION_DEBUG_LEVEL(), 0, "=> void"); \
} \
while(0)
/***********************************************************************************************************************************
Function Test Macros
In debug builds these macros will update the stack trace with function names and parameters but not log. In production builds all
test macros are compiled out.
***********************************************************************************************************************************/
#ifdef DEBUG
#define FUNCTION_TEST_BEGIN() \
if (stackTraceTest()) \
{ \
STACK_TRACE_PUSH(logLevelDebug); \
stackTraceParamLog()
#define FUNCTION_TEST_PARAM(typeMacroPrefix, param) \
FUNCTION_DEBUG_PARAM(typeMacroPrefix, param)
#define FUNCTION_TEST_PARAM_PTR(typeName, param) \
FUNCTION_DEBUG_PARAM_PTR(typeName, param)
#define FUNCTION_TEST_END() \
}
#define FUNCTION_TEST_VOID() \
FUNCTION_TEST_BEGIN(); \
FUNCTION_TEST_END();
#define FUNCTION_TEST_ASSERT(condition) \
do \
{ \
if (!(condition)) \
THROW_FMT(AssertError, "function test assertion '%s' failed", #condition); \
} \
while (0)
#define FUNCTION_TEST_RESULT(typeMacroPrefix, result) \
do \
{ \
FUNCTION_DEBUG_##typeMacroPrefix##_TYPE FUNCTION_DEBUG_RESULT_result = result; \
\
if (stackTraceTest()) \
STACK_TRACE_POP(); \
\
return FUNCTION_DEBUG_RESULT_result; \
} \
while(0);
#define FUNCTION_TEST_RESULT_VOID() \
do \
{ \
if (stackTraceTest()) \
STACK_TRACE_POP(); \
} \
while(0);
#else
#define FUNCTION_TEST_BEGIN()
#define FUNCTION_TEST_PARAM(typeMacroPrefix, param)
#define FUNCTION_TEST_PARAM_PTR(typeName, param)
#define FUNCTION_TEST_END()
#define FUNCTION_TEST_VOID()
#define FUNCTION_TEST_ASSERT(condition)
#define FUNCTION_TEST_RESULT(typeMacroPrefix, result) \
return result
#define FUNCTION_TEST_RESULT_VOID()
#endif
#endif

View File

@ -6,6 +6,7 @@ Binary to String Encode/Decode
#include "common/encode.h"
#include "common/encode/base64.h"
#include "common/debug.h"
#include "common/error.h"
/***********************************************************************************************************************************
@ -20,10 +21,19 @@ Encode binary data to a printable string
void
encodeToStr(EncodeType encodeType, const unsigned char *source, size_t sourceSize, char *destination)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, encodeType);
FUNCTION_TEST_PARAM(UCHARP, source);
FUNCTION_TEST_PARAM(SIZE, sourceSize);
FUNCTION_TEST_PARAM(CHARP, destination);
FUNCTION_TEST_END();
if (encodeType == encodeBase64)
encodeToStrBase64(source, sourceSize, destination);
else
ENCODE_TYPE_INVALID_ERROR(encodeType);
FUNCTION_TEST_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -32,6 +42,11 @@ Size of the string returned by encodeToStr()
size_t
encodeToStrSize(EncodeType encodeType, size_t sourceSize)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, encodeType);
FUNCTION_TEST_PARAM(SIZE, sourceSize);
FUNCTION_TEST_END();
size_t destinationSize = 0;
if (encodeType == encodeBase64)
@ -39,7 +54,7 @@ encodeToStrSize(EncodeType encodeType, size_t sourceSize)
else
ENCODE_TYPE_INVALID_ERROR(encodeType);
return destinationSize;
FUNCTION_TEST_RESULT(SIZE, destinationSize);
}
/***********************************************************************************************************************************
@ -48,10 +63,18 @@ Decode a string to binary data
void
decodeToBin(EncodeType encodeType, const char *source, unsigned char *destination)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, encodeType);
FUNCTION_TEST_PARAM(CHARP, source);
FUNCTION_TEST_PARAM(UCHARP, destination);
FUNCTION_TEST_END();
if (encodeType == encodeBase64)
decodeToBinBase64(source, destination);
else
ENCODE_TYPE_INVALID_ERROR(encodeType);
FUNCTION_TEST_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -60,6 +83,11 @@ Size of the binary data returned by decodeToBin()
size_t
decodeToBinSize(EncodeType encodeType, const char *source)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, encodeType);
FUNCTION_TEST_PARAM(CHARP, source);
FUNCTION_TEST_END();
size_t destinationSize = 0;
if (encodeType == encodeBase64)
@ -67,7 +95,7 @@ decodeToBinSize(EncodeType encodeType, const char *source)
else
ENCODE_TYPE_INVALID_ERROR(encodeType);
return destinationSize;
FUNCTION_TEST_RESULT(SIZE, destinationSize);
}
/***********************************************************************************************************************************
@ -76,6 +104,11 @@ Check that the encoded string is valid
bool
decodeToBinValid(EncodeType encodeType, const char *source)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, encodeType);
FUNCTION_TEST_PARAM(CHARP, source);
FUNCTION_TEST_END();
bool valid = true;
TRY_BEGIN()
@ -88,7 +121,7 @@ decodeToBinValid(EncodeType encodeType, const char *source)
}
TRY_END();
return valid;
FUNCTION_TEST_RESULT(BOOL, valid);
}
/***********************************************************************************************************************************
@ -97,8 +130,15 @@ Validate the encoded string
void
decodeToBinValidate(EncodeType encodeType, const char *source)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, encodeType);
FUNCTION_TEST_PARAM(CHARP, source);
FUNCTION_TEST_END();
if (encodeType == encodeBase64)
decodeToBinValidateBase64(source);
else
ENCODE_TYPE_INVALID_ERROR(encodeType);
FUNCTION_TEST_RESULT_VOID();
}

View File

@ -4,6 +4,7 @@ Base64 Binary to String Encode/Decode
#include <string.h>
#include "common/encode/base64.h"
#include "common/debug.h"
#include "common/error.h"
/***********************************************************************************************************************************
@ -14,6 +15,15 @@ static const char encodeBase64Lookup[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijkl
void
encodeToStrBase64(const unsigned char *source, size_t sourceSize, char *destination)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(UCHARP, source);
FUNCTION_TEST_PARAM(SIZE, sourceSize);
FUNCTION_TEST_PARAM(CHARP, destination);
FUNCTION_TEST_ASSERT(source != NULL);
FUNCTION_TEST_ASSERT(destination != NULL);
FUNCTION_TEST_END();
unsigned int destinationIdx = 0;
// Encode the string from three bytes to four characters
@ -56,6 +66,8 @@ encodeToStrBase64(const unsigned char *source, size_t sourceSize, char *destinat
// Zero-terminate the string
destination[destinationIdx] = 0;
FUNCTION_TEST_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -64,6 +76,10 @@ Size of the destination param required by encodeToStrBase64() minus space for th
size_t
encodeToStrSizeBase64(size_t sourceSize)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(SIZE, sourceSize);
FUNCTION_TEST_END();
// Calculate how many groups of three are in the source
size_t encodeGroupTotal = sourceSize / 3;
@ -72,7 +88,7 @@ encodeToStrSizeBase64(size_t sourceSize)
encodeGroupTotal++;
// Four characters are needed to encode each group
return encodeGroupTotal * 4;
FUNCTION_TEST_RESULT(SIZE, encodeGroupTotal * 4);
}
/***********************************************************************************************************************************
@ -101,6 +117,11 @@ static const int decodeBase64Lookup[256] =
void
decodeToBinBase64(const char *source, unsigned char *destination)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(CHARP, source);
FUNCTION_TEST_PARAM(UCHARP, destination);
FUNCTION_TEST_END();
// Validate encoded string
decodeToBinValidateBase64(source);
@ -127,6 +148,8 @@ decodeToBinBase64(const char *source, unsigned char *destination)
(((decodeBase64Lookup[(int)source[sourceIdx + 2]] << 6) & 0xc0) | decodeBase64Lookup[(int)source[sourceIdx + 3]]);
}
}
FUNCTION_TEST_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -135,6 +158,10 @@ Size of the destination param required by decodeToBinBase64()
size_t
decodeToBinSizeBase64(const char *source)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(CHARP, source);
FUNCTION_TEST_END();
// Validate encoded string
decodeToBinValidateBase64(source);
@ -152,7 +179,7 @@ decodeToBinSizeBase64(const char *source)
destinationSize--;
}
return destinationSize;
FUNCTION_TEST_RESULT(SIZE, destinationSize);
}
/***********************************************************************************************************************************
@ -161,6 +188,10 @@ Validate the encoded string
void
decodeToBinValidateBase64(const char *source)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(CHARP, source);
FUNCTION_TEST_END();
// Check for the correct length
size_t sourceSize = strlen(source);
@ -188,4 +219,6 @@ decodeToBinValidateBase64(const char *source)
THROW_FMT(FormatError, "base64 invalid character found at position %u", sourceIdx);
}
}
FUNCTION_TEST_RESULT_VOID();
}

View File

@ -7,6 +7,7 @@ Error Handler
#include <string.h>
#include "common/error.h"
#include "common/stackTrace.h"
/***********************************************************************************************************************************
Represents an error type
@ -38,7 +39,7 @@ typedef enum {errorStateBegin, errorStateTry, errorStateCatch, errorStateFinal,
/***********************************************************************************************************************************
Track error handling
***********************************************************************************************************************************/
struct
static struct
{
// Array of jump buffers
jmp_buf jumpList[ERROR_TRY_MAX];
@ -57,8 +58,10 @@ struct
{
const ErrorType *errorType; // Error type
const char *fileName; // Source file where the error occurred
const char *functionName; // Function where the error occurred
int fileLine; // Source file line where the error occurred
const char *message; // Description of the error
const char *stackTrace; // Stack trace
} error;
} errorContext;
@ -75,6 +78,7 @@ The temp buffer is required because the error message being passed might be the
static char messageBuffer[ERROR_MESSAGE_BUFFER_SIZE];
static char messageBufferTemp[ERROR_MESSAGE_BUFFER_SIZE];
static char stackTraceBuffer[ERROR_MESSAGE_BUFFER_SIZE];
/***********************************************************************************************************************************
Error type code
@ -128,6 +132,14 @@ errorTypeParent(const ErrorType *errorType)
return errorType->parentType;
}
/***********************************************************************************************************************************
Get the depth of the current try statement (0 if none)
***********************************************************************************************************************************/
unsigned int errorTryDepth()
{
return (unsigned int)errorContext.tryTotal;
}
/***********************************************************************************************************************************
Does the child error type extend the parent error type?
***********************************************************************************************************************************/
@ -177,6 +189,15 @@ errorFileName()
return errorContext.error.fileName;
}
/***********************************************************************************************************************************
Error function name
***********************************************************************************************************************************/
const char *
errorFunctionName()
{
return errorContext.error.functionName;
}
/***********************************************************************************************************************************
Error file line number
***********************************************************************************************************************************/
@ -204,6 +225,15 @@ errorName()
return errorTypeName(errorType());
}
/***********************************************************************************************************************************
Error stack trace
***********************************************************************************************************************************/
const char *
errorStackTrace()
{
return errorContext.error.stackTrace;
}
/***********************************************************************************************************************************
Is this error an instance of the error type?
***********************************************************************************************************************************/
@ -265,11 +295,11 @@ errorInternalJump()
Begin the try block
***********************************************************************************************************************************/
bool
errorInternalTry(const char *fileName, int fileLine)
errorInternalTry(const char *fileName, const char *functionName, int fileLine)
{
// If try total has been exceeded then throw an error
if (errorContext.tryTotal >= ERROR_TRY_MAX)
errorInternalThrowFmt(&AssertError, fileName, fileLine, "too many nested try blocks");
errorInternalThrowFmt(&AssertError, fileName, functionName, fileLine, "too many nested try blocks");
// Increment try total
errorContext.tryTotal++;
@ -315,6 +345,9 @@ errorInternalProcess(bool catch)
errorContext.tryList[errorContext.tryTotal].uncaught = false;
return true;
}
// Else if just entering error state clean up the stack
else if (errorContext.tryList[errorContext.tryTotal].state == errorStateTry)
stackTraceClean(errorTryDepth());
// Increment the state
errorContext.tryList[errorContext.tryTotal].state++;
@ -345,23 +378,34 @@ errorInternalProcess(bool catch)
Throw an error
***********************************************************************************************************************************/
void
errorInternalThrow(const ErrorType *errorType, const char *fileName, int fileLine, const char *message)
errorInternalThrow(const ErrorType *errorType, const char *fileName, const char *functionName, int fileLine, const char *message)
{
// Setup error data
errorContext.error.errorType = errorType;
errorContext.error.fileName = fileName;
errorContext.error.functionName = functionName;
errorContext.error.fileLine = fileLine;
// Assign message to the error
strcpy(messageBuffer, message);
errorContext.error.message = (const char *)messageBuffer;
// Generate the stack trace for the error
if (stackTraceToZ(
stackTraceBuffer, sizeof(stackTraceBuffer), fileName, functionName, (unsigned int)fileLine) >= sizeof(stackTraceBuffer))
{
// Indicate that the stack trace was truncated
}
errorContext.error.stackTrace = (const char *)stackTraceBuffer;
// Propogate the error
errorInternalPropagate();
}
void
errorInternalThrowFmt(const ErrorType *errorType, const char *fileName, int fileLine, const char *format, ...)
errorInternalThrowFmt(
const ErrorType *errorType, const char *fileName, const char *functionName, int fileLine, const char *format, ...)
{
// Format message
va_list argument;
@ -369,39 +413,26 @@ errorInternalThrowFmt(const ErrorType *errorType, const char *fileName, int file
vsnprintf(messageBufferTemp, ERROR_MESSAGE_BUFFER_SIZE - 1, format, argument);
va_end(argument);
errorInternalThrow(errorType, fileName, fileLine, messageBufferTemp);
errorInternalThrow(errorType, fileName, functionName, fileLine, messageBufferTemp);
}
/***********************************************************************************************************************************
Throw a system error
***********************************************************************************************************************************/
void
errorInternalThrowSys(int errNo, const ErrorType *errorType, const char *fileName, int fileLine, const char *message)
errorInternalThrowSys(
int errNo, const ErrorType *errorType, const char *fileName, const char *functionName, int fileLine, const char *message)
{
// Setup error data
errorContext.error.errorType = errorType;
errorContext.error.fileName = fileName;
errorContext.error.fileLine = fileLine;
// Append the system message
// Format message with system message appended
snprintf(messageBufferTemp, ERROR_MESSAGE_BUFFER_SIZE - 1, "%s: [%d] %s", message, errNo, strerror(errNo));
// Assign message to the error
strcpy(messageBuffer, messageBufferTemp);
errorContext.error.message = (const char *)messageBuffer;
// Propogate the error
errorInternalPropagate();
errorInternalThrow(errorType, fileName, functionName, fileLine, messageBufferTemp);
}
void
errorInternalThrowSysFmt(int errNo, const ErrorType *errorType, const char *fileName, int fileLine, const char *format, ...)
errorInternalThrowSysFmt(
int errNo, const ErrorType *errorType, const char *fileName, const char *functionName, int fileLine, const char *format, ...)
{
// Setup error data
errorContext.error.errorType = errorType;
errorContext.error.fileName = fileName;
errorContext.error.fileLine = fileLine;
// Format message
va_list argument;
va_start(argument, format);
@ -411,10 +442,5 @@ errorInternalThrowSysFmt(int errNo, const ErrorType *errorType, const char *file
// Append the system message
snprintf(messageBufferTemp + messageSize, ERROR_MESSAGE_BUFFER_SIZE - 1 - messageSize, ": [%d] %s", errNo, strerror(errNo));
// Assign message to the error
strcpy(messageBuffer, messageBufferTemp);
errorContext.error.message = (const char *)messageBuffer;
// Propogate the error
errorInternalPropagate();
errorInternalThrow(errorType, fileName, functionName, fileLine, messageBufferTemp);
}

View File

@ -68,10 +68,17 @@ Functions to get information about the current error
const ErrorType *errorType();
int errorCode();
const char *errorFileName();
const char *errorFunctionName();
int errorFileLine();
bool errorInstanceOf(const ErrorType *errorTypeTest);
const char *errorMessage();
const char *errorName();
bool errorInstanceOf(const ErrorType *errorTypeTest);
const char *errorStackTrace();
/***********************************************************************************************************************************
Functions to get information about the try stack
***********************************************************************************************************************************/
unsigned int errorTryDepth();
/***********************************************************************************************************************************
Begin a block where errors can be thrown
@ -79,7 +86,7 @@ Begin a block where errors can be thrown
#define TRY_BEGIN() \
do \
{ \
if (errorInternalTry(__FILE__, __LINE__) && setjmp(*errorInternalJump()) >= 0) \
if (errorInternalTry(__FILE__, __func__, __LINE__) && setjmp(*errorInternalJump()) >= 0) \
{ \
while (errorInternalProcess(false)) \
if (errorInternalStateTry())
@ -118,39 +125,39 @@ error information to stderr.
The seldom used "THROWP" variants allow an error to be thrown with a pointer to the error type.
***********************************************************************************************************************************/
#define THROW(errorType, message) \
errorInternalThrow(&errorType, __FILE__, __LINE__, message)
errorInternalThrow(&errorType, __FILE__, __func__, __LINE__, message)
#define THROW_FMT(errorType, ...) \
errorInternalThrowFmt(&errorType, __FILE__, __LINE__, __VA_ARGS__)
errorInternalThrowFmt(&errorType, __FILE__, __func__, __LINE__, __VA_ARGS__)
#define THROWP(errorType, message) \
errorInternalThrow(errorType, __FILE__, __LINE__, message)
errorInternalThrow(errorType, __FILE__, __func__, __LINE__, message)
#define THROWP_FMT(errorType, ...) \
errorInternalThrowFmt(errorType, __FILE__, __LINE__, __VA_ARGS__)
errorInternalThrowFmt(errorType, __FILE__, __func__, __LINE__, __VA_ARGS__)
#define THROW_CODE(errorCode, message) \
errorInternalThrow(errorTypeFromCode(errorCode), __FILE__, __LINE__, message)
errorInternalThrow(errorTypeFromCode(errorCode), __FILE__, __func__, __LINE__, message)
#define THROW_CODE_FMT(errorCode, ...) \
errorInternalThrowFmt(errorTypeFromCode(errorCode), __FILE__, __LINE__, __VA_ARGS__)
errorInternalThrowFmt(errorTypeFromCode(errorCode), __FILE__, __func__, __LINE__, __VA_ARGS__)
/***********************************************************************************************************************************
Throw an error when a system call fails
***********************************************************************************************************************************/
#define THROW_SYS_ERROR(errorType, message) \
errorInternalThrowSys(errno, &errorType, __FILE__, __LINE__, message)
errorInternalThrowSys(errno, &errorType, __FILE__, __func__, __LINE__, message)
#define THROW_SYS_ERROR_FMT(errorType, ...) \
errorInternalThrowSysFmt(errno, &errorType, __FILE__, __LINE__, __VA_ARGS__)
errorInternalThrowSysFmt(errno, &errorType, __FILE__, __func__, __LINE__, __VA_ARGS__)
#define THROWP_SYS_ERROR(errorType, message) \
errorInternalThrowSys(errno, errorType, __FILE__, __LINE__, message)
errorInternalThrowSys(errno, errorType, __FILE__, __func__, __LINE__, message)
#define THROWP_SYS_ERROR_FMT(errorType, ...) \
errorInternalThrowSysFmt(errno, errorType, __FILE__, __LINE__, __VA_ARGS__)
errorInternalThrowSysFmt(errno, errorType, __FILE__, __func__, __LINE__, __VA_ARGS__)
#define THROW_SYS_ERROR_CODE(errNo, errorType, message) \
errorInternalThrowSys(errNo, &errorType, __FILE__, __LINE__, message)
errorInternalThrowSys(errNo, &errorType, __FILE__, __func__, __LINE__, message)
#define THROW_SYS_ERROR_CODE_FMT(errNo, errorType, ...) \
errorInternalThrowSysFmt(errNo, &errorType, __FILE__, __LINE__, __VA_ARGS__)
errorInternalThrowSysFmt(errNo, &errorType, __FILE__, __func__, __LINE__, __VA_ARGS__)
#define THROWP_SYS_ERROR_CODE(errNo, errorType, message) \
errorInternalThrowSys(errNo, errorType, __FILE__, __LINE__, message)
errorInternalThrowSys(errNo, errorType, __FILE__, __func__, __LINE__, message)
#define THROWP_SYS_ERROR_CODE_FMT(errNo, errorType, ...) \
errorInternalThrowSysFmt(errNo, errorType, __FILE__, __LINE__, __VA_ARGS__)
errorInternalThrowSysFmt(errNo, errorType, __FILE__, __func__, __LINE__, __VA_ARGS__)
/***********************************************************************************************************************************
Rethrow the current error
@ -163,7 +170,7 @@ Internal functions
These functions are used by the macros to implement the error handler and should never be called independently.
***********************************************************************************************************************************/
bool errorInternalTry(const char *fileName, int fileLine);
bool errorInternalTry(const char *fileName, const char *functionName, int fileLine);
jmp_buf *errorInternalJump();
bool errorInternalStateTry();
bool errorInternalStateCatch(const ErrorType *errorTypeCatch);
@ -171,14 +178,24 @@ bool errorInternalStateFinal();
bool errorInternalProcess(bool catch);
void errorInternalPropagate() __attribute__((__noreturn__));
void errorInternalThrow(
const ErrorType *errorType, const char *fileName, int fileLine, const char *message) __attribute__((__noreturn__));
const ErrorType *errorType, const char *fileName, const char *functionName, int fileLine, const char *message)
__attribute__((__noreturn__));
void errorInternalThrowFmt(
const ErrorType *errorType, const char *fileName, int fileLine, const char *format, ...)
__attribute__((__noreturn__)) __attribute__((format(printf, 4, 5)));
const ErrorType *errorType, const char *fileName, const char *functionName, int fileLine, const char *format, ...)
__attribute__((format(printf, 5, 6))) __attribute__((__noreturn__));
void errorInternalThrowSys(
int errNo, const ErrorType *errorType, const char *fileName, int fileLine, const char *message);
int errNo, const ErrorType *errorType, const char *fileName, const char *functionName, int fileLine, const char *message)
__attribute__((__noreturn__));
void errorInternalThrowSysFmt(
int errNo, const ErrorType *errorType, const char *fileName, int fileLine, const char *format, ...)
__attribute__((format(printf, 5, 6)));
int errNo, const ErrorType *errorType, const char *fileName, const char *functionName, int fileLine, const char *format, ...)
__attribute__((format(printf, 6, 7))) __attribute__((__noreturn__));
/***********************************************************************************************************************************
Macros for function logging
***********************************************************************************************************************************/
#define FUNCTION_DEBUG_ERROR_TYPE_TYPE \
ErrorType *
#define FUNCTION_DEBUG_ERROR_TYPE_FORMAT(value, buffer, bufferSize) \
objToLog(value, "ErrorType", buffer, bufferSize)
#endif

View File

@ -5,6 +5,7 @@ Exit Routines
#include <string.h>
#include "command/command.h"
#include "common/debug.h"
#include "common/error.h"
#include "common/exit.h"
#include "common/lock.h"
@ -18,6 +19,10 @@ Return signal names
static const char *
exitSignalName(int signalType)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(INT, signalType);
FUNCTION_TEST_END();
const char *name = NULL;
switch (signalType)
@ -44,7 +49,7 @@ exitSignalName(int signalType)
THROW(AssertError, "no name for signal none");
}
return name;
FUNCTION_TEST_RESULT(STRINGZ, name);
}
/***********************************************************************************************************************************
@ -53,7 +58,13 @@ Catch signals
static void
exitOnSignal(int signalType)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(INT, signalType);
FUNCTION_DEBUG_END();
exit(exitSafe(errorTypeCode(&TermError), false, (SignalType)signalType));
FUNCTION_DEBUG_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -62,9 +73,13 @@ Setup signal handlers
void
exitInit()
{
FUNCTION_DEBUG_VOID(logLevelTrace);
signal(SIGHUP, exitOnSignal);
signal(SIGINT, exitOnSignal);
signal(SIGTERM, exitOnSignal);
FUNCTION_DEBUG_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -73,12 +88,37 @@ Do cleanup and return result code
int
exitSafe(int result, bool error, SignalType signalType)
{
FUNCTION_DEBUG_BEGIN(logLevelDebug);
FUNCTION_DEBUG_PARAM(INT, result);
FUNCTION_DEBUG_PARAM(BOOL, error);
FUNCTION_DEBUG_PARAM(ENUM, signalType);
FUNCTION_DEBUG_END();
// Report error if one was thrown
if (error)
{
// Don't log the error if it has already been logged by Perl
if (strcmp(errorMessage(), PERL_EMBED_ERROR) != 0)
LOG_ANY(errorCode() == errorTypeCode(&AssertError) ? logLevelAssert : logLevelError, errorCode(), errorMessage());
{
LogLevel logLevel = errorCode() == errorTypeCode(&AssertError) ? logLevelAssert : logLevelError;
// Assert errors always output a stack trace
if (logLevel == logLevelAssert)
LOG(logLevel, errorCode(), "%s\nSTACK TRACE:\n%s", errorMessage(), errorStackTrace());
else
{
// Log just the error to non-debug levels
LOG_INTERNAL(logLevel, LOG_LEVEL_MIN, logLevelDetail, errorCode(), errorMessage());
// Log the stack trace debug levels
if (logWill(logLevelDebug))
{
LOG_INTERNAL(
logLevel, logLevelDebug, LOG_LEVEL_MAX, errorCode(), "%s\nSTACK TRACE:\n%s", errorMessage(),
errorStackTrace());
}
}
}
result = errorCode();
}
@ -126,5 +166,5 @@ exitSafe(int result, bool error, SignalType signalType)
}
// Return result - caller should immediate pass this result to exit()
return result;
FUNCTION_DEBUG_RESULT(INT, result);
}

View File

@ -3,6 +3,7 @@ Fork Handler
***********************************************************************************************************************************/
#include <unistd.h>
#include "common/debug.h"
#include "common/error.h"
/***********************************************************************************************************************************
@ -12,6 +13,8 @@ startup because the parent process may continue to run and perform work for some
void
forkDetach()
{
FUNCTION_DEBUG_VOID(logLevelTrace);
if (chdir("/") == -1) // {uncoverable - should never fail}
THROW_SYS_ERROR(PathMissingError, "unable to change directory to '/'"); // {uncoverable+}
@ -26,4 +29,6 @@ forkDetach()
if (close(STDERR_FILENO) == -1) // {uncoverable - should never fail}
THROW_SYS_ERROR(FileCloseError, "unable to close stderr"); // {uncoverable+}
FUNCTION_DEBUG_RESULT_VOID();
}

View File

@ -5,6 +5,7 @@ Ini Handler
#include <stdlib.h>
#include <string.h>
#include "common/debug.h"
#include "common/memContext.h"
#include "common/ini.h"
#include "common/type/keyValue.h"
@ -49,6 +50,16 @@ Internal function to get an ini value
static const Variant *
iniGetInternal(const Ini *this, const String *section, const String *key)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(INI, this);
FUNCTION_TEST_PARAM(STRING, section);
FUNCTION_TEST_PARAM(STRING, key);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(section != NULL);
FUNCTION_TEST_ASSERT(key != NULL);
FUNCTION_TEST_END();
const Variant *result = NULL;
MEM_CONTEXT_TEMP_BEGIN()
@ -62,7 +73,7 @@ iniGetInternal(const Ini *this, const String *section, const String *key)
}
MEM_CONTEXT_TEMP_END();
return result;
FUNCTION_TEST_RESULT(CONST_VARIANT, result);
}
/***********************************************************************************************************************************
@ -71,6 +82,16 @@ Get an ini value -- error if it does not exist
const Variant *
iniGet(const Ini *this, const String *section, const String *key)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(INI, this);
FUNCTION_TEST_PARAM(STRING, section);
FUNCTION_TEST_PARAM(STRING, key);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(section != NULL);
FUNCTION_TEST_ASSERT(key != NULL);
FUNCTION_TEST_END();
// Get the value
const Variant *result = iniGetInternal(this, section, key);
@ -79,6 +100,8 @@ iniGet(const Ini *this, const String *section, const String *key)
THROW_FMT(FormatError, "section '%s', key '%s' does not exist", strPtr(section), strPtr(key));
return result;
FUNCTION_TEST_RESULT(CONST_VARIANT, result);
}
/***********************************************************************************************************************************
@ -87,6 +110,17 @@ Get an ini value -- if it does not exist then return specified default
const Variant *
iniGetDefault(const Ini *this, const String *section, const String *key, Variant *defaultValue)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(INI, this);
FUNCTION_TEST_PARAM(STRING, section);
FUNCTION_TEST_PARAM(STRING, key);
FUNCTION_TEST_PARAM(VARIANT, defaultValue);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(section != NULL);
FUNCTION_TEST_ASSERT(key != NULL);
FUNCTION_TEST_END();
// Get the value
const Variant *result = iniGetInternal(this, section, key);
@ -94,7 +128,7 @@ iniGetDefault(const Ini *this, const String *section, const String *key, Variant
if (result == NULL)
result = defaultValue;
return result;
FUNCTION_TEST_RESULT(CONST_VARIANT, result);
}
/***********************************************************************************************************************************
@ -103,6 +137,14 @@ Get a list of keys for a section
StringList *
iniSectionKeyList(const Ini *this, const String *section)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(INI, this);
FUNCTION_TEST_PARAM(STRING, section);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(section != NULL);
FUNCTION_TEST_END();
StringList *result = NULL;
MEM_CONTEXT_TEMP_BEGIN()
@ -121,7 +163,7 @@ iniSectionKeyList(const Ini *this, const String *section)
}
MEM_CONTEXT_TEMP_END();
return result;
FUNCTION_TEST_RESULT(STRING_LIST, result);
}
/***********************************************************************************************************************************
@ -130,6 +172,13 @@ Parse ini from a string
void
iniParse(Ini *this, const String *content)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(INI, this);
FUNCTION_TEST_PARAM(STRING, content);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
MEM_CONTEXT_BEGIN(this->memContext)
{
kvFree(this->store);
@ -195,6 +244,8 @@ iniParse(Ini *this, const String *content)
}
}
MEM_CONTEXT_END()
FUNCTION_TEST_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -203,6 +254,14 @@ Load ini from a file
void
iniLoad(Ini *this, const String *fileName)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(INI, this);
FUNCTION_TEST_PARAM(STRING, fileName);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(fileName != NULL);
FUNCTION_TEST_END();
MEM_CONTEXT_BEGIN(this->memContext)
{
// Set the filename
@ -215,6 +274,8 @@ iniLoad(Ini *this, const String *fileName)
MEM_CONTEXT_TEMP_END();
}
MEM_CONTEXT_END()
FUNCTION_TEST_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -223,6 +284,18 @@ Set an ini value
void
iniSet(Ini *this, const String *section, const String *key, const Variant *value)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(INI, this);
FUNCTION_TEST_PARAM(STRING, section);
FUNCTION_TEST_PARAM(STRING, key);
FUNCTION_TEST_PARAM(VARIANT, value);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(section != NULL);
FUNCTION_TEST_ASSERT(key != NULL);
FUNCTION_TEST_ASSERT(value != NULL);
FUNCTION_TEST_END();
MEM_CONTEXT_TEMP_BEGIN()
{
Variant *sectionKey = varNewStr(section);
@ -234,6 +307,8 @@ iniSet(Ini *this, const String *section, const String *key, const Variant *value
kvAdd(sectionKv, varNewStr(key), value);
}
MEM_CONTEXT_TEMP_END();
FUNCTION_TEST_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -242,5 +317,12 @@ Free the ini
void
iniFree(Ini *this)
{
memContextFree(this->memContext);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(INI, this);
FUNCTION_TEST_END();
if (this != NULL)
memContextFree(this->memContext);
FUNCTION_TEST_RESULT_VOID();
}

View File

@ -24,4 +24,12 @@ void iniSet(Ini *this, const String *section, const String *key, const Variant *
void iniFree(Ini *this);
/***********************************************************************************************************************************
Macros for function logging
***********************************************************************************************************************************/
#define FUNCTION_DEBUG_INI_TYPE \
Ini *
#define FUNCTION_DEBUG_INI_FORMAT(value, buffer, bufferSize) \
objToLog(value, "Ini", buffer, bufferSize)
#endif

View File

@ -3,6 +3,7 @@ Handle IO
***********************************************************************************************************************************/
#include <unistd.h>
#include "common/debug.h"
#include "common/error.h"
#include "common/io/handle.h"
@ -12,6 +13,15 @@ Write a string to the specified handle
void
ioHandleWriteOneStr(int handle, const String *string)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(INT, handle);
FUNCTION_DEBUG_PARAM(STRING, string);
FUNCTION_DEBUG_ASSERT(string != NULL);
FUNCTION_DEBUG_END();
if (write(handle, strPtr(string), strSize(string)) != (int)strSize(string))
THROW_SYS_ERROR_FMT(FileWriteError, "unable to write to %zu byte(s) to handle", strSize(string));
FUNCTION_DEBUG_RESULT_VOID();
}

View File

@ -8,6 +8,7 @@ Lock Handler
#include <unistd.h>
#include "common/assert.h"
#include "common/debug.h"
#include "common/io/handle.h"
#include "common/lock.h"
#include "common/memContext.h"
@ -38,6 +39,12 @@ Acquire a lock using a file on the local filesystem
static int
lockAcquireFile(const String *lockFile, double lockTimeout, bool failOnNoLock)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(STRING, lockFile);
FUNCTION_DEBUG_PARAM(DOUBLE, lockTimeout);
FUNCTION_DEBUG_PARAM(BOOL, failOnNoLock);
FUNCTION_DEBUG_END();
int result = -1;
// Timeout can't be negative
@ -112,7 +119,7 @@ lockAcquireFile(const String *lockFile, double lockTimeout, bool failOnNoLock)
}
MEM_CONTEXT_TEMP_END();
return result;
FUNCTION_DEBUG_RESULT(INT, result);
}
/***********************************************************************************************************************************
@ -121,6 +128,11 @@ Release the current lock
static void
lockReleaseFile(int lockHandle, const String *lockFile)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(INT, lockHandle);
FUNCTION_DEBUG_PARAM(STRING, lockFile);
FUNCTION_DEBUG_END();
// Can't release lock if there isn't one
ASSERT_DEBUG(lockHandle != -1);
@ -128,6 +140,8 @@ lockReleaseFile(int lockHandle, const String *lockFile)
// right before the delete which means the file locked by the other process will get deleted.
storageRemoveNP(storageLocalWrite(), lockFile);
close(lockHandle);
FUNCTION_DEBUG_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -139,6 +153,14 @@ backup), but the stanza commands all need to lock both.
bool
lockAcquire(const String *lockPath, const String *stanza, LockType lockType, double lockTimeout, bool failOnNoLock)
{
FUNCTION_DEBUG_BEGIN(logLevelDebug);
FUNCTION_DEBUG_PARAM(STRING, lockPath);
FUNCTION_DEBUG_PARAM(STRING, stanza);
FUNCTION_DEBUG_PARAM(ENUM, lockType);
FUNCTION_DEBUG_PARAM(DOUBLE, lockTimeout);
FUNCTION_DEBUG_PARAM(BOOL, failOnNoLock);
FUNCTION_DEBUG_END();
bool result = false;
// Don't allow failures when locking more than one file. This makes cleanup difficult and there are no known use cases.
@ -186,7 +208,7 @@ lockAcquire(const String *lockPath, const String *stanza, LockType lockType, dou
}
MEM_CONTEXT_END();
return result;
FUNCTION_DEBUG_RESULT(BOOL, result);
}
/***********************************************************************************************************************************
@ -196,6 +218,10 @@ and the master process won't try to free it.
bool
lockClear(bool failOnNoLock)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(BOOL, failOnNoLock);
FUNCTION_DEBUG_END();
bool result = false;
if (lockTypeHeld == lockTypeNone)
@ -216,7 +242,7 @@ lockClear(bool failOnNoLock)
result = true;
}
return result;
FUNCTION_DEBUG_RESULT(BOOL, result);
}
/***********************************************************************************************************************************
@ -225,6 +251,10 @@ Release a lock type
bool
lockRelease(bool failOnNoLock)
{
FUNCTION_DEBUG_BEGIN(logLevelDebug);
FUNCTION_DEBUG_PARAM(BOOL, failOnNoLock);
FUNCTION_DEBUG_END();
bool result = false;
if (lockTypeHeld == lockTypeNone)
@ -248,5 +278,5 @@ lockRelease(bool failOnNoLock)
result = true;
}
return result;
FUNCTION_DEBUG_RESULT(BOOL, result);
}

View File

@ -36,25 +36,22 @@ static bool logFileBanner = false;
DEBUG_UNIT_EXTERN bool logTimestamp = false;
/***********************************************************************************************************************************
Debug Asserts
Test Asserts
***********************************************************************************************************************************/
#define ASSERT_DEBUG_MESSAGE_LOG_LEVEL_VALID(logLevel) \
ASSERT_DEBUG(logLevel > logLevelOff)
#define FUNCTION_TEST_ASSERT_LOG_LEVEL(logLevel) \
FUNCTION_TEST_ASSERT(logLevel >= LOG_LEVEL_MIN && logLevel <= LOG_LEVEL_MAX)
/***********************************************************************************************************************************
Log buffer
Log buffer -- used to format log header and message
***********************************************************************************************************************************/
#define LOG_BUFFER_SIZE 32768
char logBuffer[LOG_BUFFER_SIZE];
char logFormat[LOG_BUFFER_SIZE];
static char logBuffer[LOG_BUFFER_SIZE];
/***********************************************************************************************************************************
Convert log level to string and vice versa
***********************************************************************************************************************************/
#define LOG_LEVEL_TOTAL 9
#define LOG_LEVEL_TOTAL (LOG_LEVEL_MAX + 1)
const char *logLevelList[LOG_LEVEL_TOTAL] =
static const char *logLevelList[LOG_LEVEL_TOTAL] =
{
"OFF",
"ASSERT",
@ -70,6 +67,12 @@ const char *logLevelList[LOG_LEVEL_TOTAL] =
LogLevel
logLevelEnum(const char *logLevel)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRINGZ, logLevel);
FUNCTION_TEST_ASSERT(logLevel != NULL);
FUNCTION_TEST_END();
LogLevel result = logLevelOff;
// Search for the log level
@ -81,16 +84,19 @@ logLevelEnum(const char *logLevel)
if (result == LOG_LEVEL_TOTAL)
THROW_FMT(AssertError, "log level '%s' not found", logLevel);
return result;
FUNCTION_TEST_RESULT(ENUM, result);
}
const char *
logLevelStr(LogLevel logLevel)
{
if (logLevel >= LOG_LEVEL_TOTAL)
THROW_FMT(AssertError, "invalid log level '%u'", logLevel);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, logLevel);
return logLevelList[logLevel];
FUNCTION_TEST_ASSERT(logLevel <= LOG_LEVEL_MAX);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(STRINGZ, logLevelList[logLevel]);
}
/***********************************************************************************************************************************
@ -99,10 +105,23 @@ Initialize the log system
void
logInit(LogLevel logLevelStdOutParam, LogLevel logLevelStdErrParam, LogLevel logLevelFileParam, bool logTimestampParam)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, logLevelStdOutParam);
FUNCTION_TEST_PARAM(ENUM, logLevelStdErrParam);
FUNCTION_TEST_PARAM(ENUM, logLevelFileParam);
FUNCTION_TEST_PARAM(BOOL, logTimestampParam);
FUNCTION_TEST_ASSERT(logLevelStdOutParam <= LOG_LEVEL_MAX);
FUNCTION_TEST_ASSERT(logLevelStdErrParam <= LOG_LEVEL_MAX);
FUNCTION_TEST_ASSERT(logLevelFileParam <= LOG_LEVEL_MAX);
FUNCTION_TEST_END();
logLevelStdOut = logLevelStdOutParam;
logLevelStdErr = logLevelStdErrParam;
logLevelFile = logLevelFileParam;
logTimestamp = logTimestampParam;
FUNCTION_TEST_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -111,6 +130,12 @@ Set the log file
void
logFileSet(const char *logFile)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRINGZ, logFile);
FUNCTION_TEST_ASSERT(logFile != NULL);
FUNCTION_TEST_END();
// Close the file handle if it is already open
if (logHandleFile != -1)
{
@ -133,6 +158,8 @@ logFileSet(const char *logFile)
// Output the banner on first log message
logFileBanner = false;
}
FUNCTION_TEST_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -143,29 +170,69 @@ This is useful for log messages that are expensive to generate and should be ski
static bool
logWillFile(LogLevel logLevel)
{
ASSERT_DEBUG_MESSAGE_LOG_LEVEL_VALID(logLevel)
return logLevel <= logLevelFile && logHandleFile != -1;
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, logLevel);
FUNCTION_TEST_ASSERT_LOG_LEVEL(logLevel);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(ENUM, logLevel <= logLevelFile && logHandleFile != -1);
}
static bool
logWillStdErr(LogLevel logLevel)
{
ASSERT_DEBUG_MESSAGE_LOG_LEVEL_VALID(logLevel)
return logLevel <= logLevelStdErr;
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, logLevel);
FUNCTION_TEST_ASSERT_LOG_LEVEL(logLevel);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(ENUM, logLevel <= logLevelStdErr);
}
static bool
logWillStdOut(LogLevel logLevel)
{
ASSERT_DEBUG_MESSAGE_LOG_LEVEL_VALID(logLevel)
return logLevel <= logLevelStdOut;
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, logLevel);
FUNCTION_TEST_ASSERT_LOG_LEVEL(logLevel);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(ENUM, logLevel <= logLevelStdOut);
}
bool
logWill(LogLevel logLevel)
{
ASSERT_DEBUG_MESSAGE_LOG_LEVEL_VALID(logLevel)
return logWillStdOut(logLevel) || logWillStdErr(logLevel) || logWillFile(logLevel);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, logLevel);
FUNCTION_TEST_ASSERT_LOG_LEVEL(logLevel);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(BOOL, logWillStdOut(logLevel) || logWillStdErr(logLevel) || logWillFile(logLevel));
}
/***********************************************************************************************************************************
Determine if the log level is in the specified range
***********************************************************************************************************************************/
static bool
logRange(LogLevel logLevel, LogLevel logRangeMin, LogLevel logRangeMax)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, logLevel);
FUNCTION_TEST_PARAM(ENUM, logRangeMin);
FUNCTION_TEST_PARAM(ENUM, logRangeMax);
FUNCTION_TEST_ASSERT_LOG_LEVEL(logLevel);
FUNCTION_TEST_ASSERT_LOG_LEVEL(logRangeMin);
FUNCTION_TEST_ASSERT_LOG_LEVEL(logRangeMax);
FUNCTION_TEST_ASSERT(logRangeMin <= logRangeMax);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(BOOL, logLevel >= logRangeMin && logLevel <= logRangeMax);
}
/***********************************************************************************************************************************
@ -174,17 +241,93 @@ Internal write function that handles errors
static void
logWrite(int handle, const char *message, size_t messageSize, const char *errorDetail)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(INT, handle);
FUNCTION_TEST_PARAM(STRINGZ, message);
FUNCTION_TEST_PARAM(SIZE, messageSize);
FUNCTION_TEST_PARAM(STRINGZ, errorDetail);
FUNCTION_TEST_ASSERT(handle != -1);
FUNCTION_TEST_ASSERT(message != NULL);
FUNCTION_TEST_ASSERT(messageSize != 0);
FUNCTION_TEST_ASSERT(errorDetail != NULL);
FUNCTION_TEST_END();
if ((size_t)write(handle, message, messageSize) != messageSize)
THROW_SYS_ERROR_FMT(FileWriteError, "unable to write %s", errorDetail);
FUNCTION_TEST_RESULT_VOID();
}
/***********************************************************************************************************************************
Write out log message and indent subsequent lines
***********************************************************************************************************************************/
static void
logWriteIndent(int handle, const char *message, size_t indentSize, const char *errorDetail)
{
// Indent buffer -- used to write out indent space without having to loop
static const char indentBuffer[] = " ";
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(INT, handle);
FUNCTION_TEST_PARAM(STRINGZ, message);
FUNCTION_TEST_PARAM(SIZE, indentSize);
FUNCTION_TEST_PARAM(STRINGZ, errorDetail);
FUNCTION_TEST_ASSERT(handle != -1);
FUNCTION_TEST_ASSERT(message != NULL);
FUNCTION_TEST_ASSERT(indentSize > 0 && indentSize < sizeof(indentBuffer));
FUNCTION_TEST_ASSERT(errorDetail != NULL);
FUNCTION_TEST_END();
// Indent all lines after the first
const char *linefeedPtr = strchr(message, '\n');
bool first = true;
while (linefeedPtr != NULL)
{
if (!first)
logWrite(handle, indentBuffer, indentSize, errorDetail);
else
first = false;
logWrite(handle, message, (size_t)(linefeedPtr - message + 1), errorDetail);
message += (size_t)(linefeedPtr - message + 1);
linefeedPtr = strchr(message, '\n');
}
FUNCTION_TEST_RESULT_VOID();
}
/***********************************************************************************************************************************
General log function
***********************************************************************************************************************************/
void
logInternal(LogLevel logLevel, const char *fileName, const char *functionName, int code, const char *format, ...)
logInternal(
LogLevel logLevel, LogLevel logRangeMin, LogLevel logRangeMax, const char *fileName, const char *functionName, int code,
const char *format, ...)
{
ASSERT_DEBUG_MESSAGE_LOG_LEVEL_VALID(logLevel)
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, logLevel);
FUNCTION_TEST_PARAM(ENUM, logRangeMin);
FUNCTION_TEST_PARAM(ENUM, logRangeMax);
FUNCTION_TEST_PARAM(STRINGZ, fileName);
FUNCTION_TEST_PARAM(STRINGZ, functionName);
FUNCTION_TEST_PARAM(INT, code);
FUNCTION_TEST_PARAM(STRINGZ, format);
FUNCTION_TEST_ASSERT_LOG_LEVEL(logLevel);
FUNCTION_TEST_ASSERT_LOG_LEVEL(logRangeMin);
FUNCTION_TEST_ASSERT_LOG_LEVEL(logRangeMax);
FUNCTION_TEST_ASSERT(logRangeMin <= logRangeMax);
FUNCTION_TEST_ASSERT(fileName != NULL);
FUNCTION_TEST_ASSERT(functionName != NULL);
FUNCTION_TEST_ASSERT(
(code == 0 && logLevel > logLevelError) || (logLevel == logLevelError && code != errorTypeCode(&AssertError)) ||
(logLevel == logLevelAssert && code == errorTypeCode(&AssertError)));
FUNCTION_TEST_ASSERT(format != NULL);
FUNCTION_TEST_END();
size_t bufferPos = 0; // Current position in the buffer
@ -194,65 +337,43 @@ logInternal(LogLevel logLevel, const char *fileName, const char *functionName, i
TimeMSec logTimeMSec = timeMSec();
time_t logTimeSec = (time_t)(logTimeMSec / MSEC_PER_SEC);
bufferPos += strftime(logBuffer + bufferPos, LOG_BUFFER_SIZE - bufferPos, "%Y-%m-%d %H:%M:%S", localtime(&logTimeSec));
bufferPos += strftime(logBuffer + bufferPos, sizeof(logBuffer) - bufferPos, "%Y-%m-%d %H:%M:%S", localtime(&logTimeSec));
bufferPos += (size_t)snprintf(
logBuffer + bufferPos, LOG_BUFFER_SIZE - bufferPos, ".%03d ", (int)(logTimeMSec % 1000));
logBuffer + bufferPos, sizeof(logBuffer) - bufferPos, ".%03d ", (int)(logTimeMSec % 1000));
}
// Add process and aligned log level
bufferPos += (size_t)snprintf(
logBuffer + bufferPos, LOG_BUFFER_SIZE - bufferPos, "P00 %*s: ", 6, logLevelStr(logLevel));
bufferPos += (size_t)snprintf(logBuffer + bufferPos, sizeof(logBuffer) - bufferPos, "P00 %*s: ", 6, logLevelStr(logLevel));
// Position after the timestamp and process id for output to stderr
size_t messageStdErrPos = bufferPos - strlen(logLevelStr(logLevel)) - 2;
// When writing to stderr the timestamp, process, and log level alignment will be skipped
char *logBufferStdErr = logBuffer + bufferPos - strlen(logLevelStr(logLevel)) - 2;
// Check that error code matches log level
ASSERT_DEBUG(
code == 0 || (logLevel == logLevelError && code != errorTypeCode(&AssertError)) ||
(logLevel == logLevelAssert && code == errorTypeCode(&AssertError)));
// Set the indent size -- this will need to be adjusted for stderr
size_t indentSize = bufferPos;
// Add code
// Add error code
if (code != 0)
bufferPos += (size_t)snprintf(logBuffer + bufferPos, LOG_BUFFER_SIZE - bufferPos, "[%03d]: ", code);
bufferPos += (size_t)snprintf(logBuffer + bufferPos, sizeof(logBuffer) - bufferPos, "[%03d]: ", code);
// Add debug info
if (logLevel >= logLevelDebug)
{
bufferPos += (size_t)snprintf(
logBuffer + bufferPos, LOG_BUFFER_SIZE - bufferPos, "%s:%s(): ", fileName, functionName);
}
// Format message
va_list argumentList;
va_start(argumentList, format);
if (logLevel <= logLevelStdErr || strchr(format, '\n') == NULL)
bufferPos += (size_t)vsnprintf(logBuffer + bufferPos, LOG_BUFFER_SIZE - bufferPos, format, argumentList);
else
{
vsnprintf(logFormat, LOG_BUFFER_SIZE, format, argumentList);
// Indent all lines after the first
const char *formatPtr = logFormat;
const char *linefeedPtr = strchr(logFormat, '\n');
int indentSize = 12;
while (linefeedPtr != NULL)
// Adding padding for debug and trace levels
for (unsigned int paddingIdx = 0; paddingIdx < ((logLevel - logLevelDebug + 1) * 4); paddingIdx++)
{
strncpy(logBuffer + bufferPos, formatPtr, (size_t)(linefeedPtr - formatPtr + 1));
bufferPos += (size_t)(linefeedPtr - formatPtr + 1);
formatPtr = linefeedPtr + 1;
linefeedPtr = strchr(formatPtr, '\n');
for (int indentIdx = 0; indentIdx < indentSize; indentIdx++)
logBuffer[bufferPos++] = ' ';
logBuffer[bufferPos++] = ' ';
indentSize++;
}
strcpy(logBuffer + bufferPos, formatPtr);
bufferPos += strlen(formatPtr);
bufferPos += (size_t)snprintf(
logBuffer + bufferPos, LOG_BUFFER_SIZE - bufferPos, "%.*s::%s: ", (int)strlen(fileName) - 2, fileName,
functionName);
}
// Format message -- this will need to be indented later
va_list argumentList;
va_start(argumentList, format);
bufferPos += (size_t)vsnprintf(logBuffer + bufferPos, LOG_BUFFER_SIZE - bufferPos, format, argumentList);
va_end(argumentList);
// Add linefeed
@ -261,12 +382,15 @@ logInternal(LogLevel logLevel, const char *fileName, const char *functionName, i
// Determine where to log the message based on log-level-stderr
if (logWillStdErr(logLevel))
logWrite(logHandleStdErr, logBuffer + messageStdErrPos, bufferPos - messageStdErrPos, "log to stderr");
else if (logWillStdOut(logLevel))
logWrite(logHandleStdOut, logBuffer, bufferPos, "log to stdout");
{
if (logRange(logLevelStdErr, logRangeMin, logRangeMax))
logWriteIndent(logHandleStdErr, logBufferStdErr, indentSize - (size_t)(logBufferStdErr - logBuffer), "log to stderr");
}
else if (logWillStdOut(logLevel) && logRange(logLevelStdOut, logRangeMin, logRangeMax))
logWriteIndent(logHandleStdOut, logBuffer, indentSize, "log to stdout");
// Log to file
if (logWillFile(logLevel))
if (logWillFile(logLevel) && logRange(logLevelFile, logRangeMin, logRangeMax))
{
// If the banner has not been written
if (!logFileBanner)
@ -284,6 +408,8 @@ logInternal(LogLevel logLevel, const char *fileName, const char *functionName, i
logFileBanner = true;
}
logWrite(logHandleFile, logBuffer, bufferPos, "log to file");
logWriteIndent(logHandleFile, logBuffer, indentSize, "log to file");
}
FUNCTION_TEST_RESULT_VOID();
}

View File

@ -6,6 +6,13 @@ Log Handler
#include <stdbool.h>
/***********************************************************************************************************************************
Max size allowed for a single log message including header
***********************************************************************************************************************************/
#ifndef LOG_BUFFER_SIZE
#define LOG_BUFFER_SIZE ((size_t)(32 * 1024))
#endif
/***********************************************************************************************************************************
Log types
***********************************************************************************************************************************/
@ -22,6 +29,9 @@ typedef enum
logLevelTrace,
} LogLevel;
#define LOG_LEVEL_MIN logLevelAssert
#define LOG_LEVEL_MAX logLevelTrace
/***********************************************************************************************************************************
Expose internal data for unit testing/debugging
***********************************************************************************************************************************/
@ -53,27 +63,37 @@ Macros
Only call logInternal() if the message will be logged to one of the available outputs.
***********************************************************************************************************************************/
#define LOG_ANY(logLevel, code, ...) \
#define LOG_INTERNAL(logLevel, logRangeMin, logRangeMax, code, ...) \
logInternal(logLevel, logRangeMin, logRangeMax, __FILE__, __func__, code, __VA_ARGS__)
#define LOG(logLevel, code, ...) \
LOG_INTERNAL(logLevel, LOG_LEVEL_MIN, LOG_LEVEL_MAX, code, __VA_ARGS__)
#define LOG_WILL(logLevel, code, ...) \
do \
{ \
if (logWill(logLevel)) \
logInternal(logLevel, __FILE__, __func__, code, __VA_ARGS__); \
}
LOG(logLevel, code, __VA_ARGS__); \
} while(0)
#define LOG_ASSERT(...) \
LOG_ANY(logLevelAssert, errorTypeCode(&AssertError), __VA_ARGS__)
LOG_WILL(logLevelAssert, errorTypeCode(&AssertError), __VA_ARGS__)
#define LOG_ERROR(code, ...) \
LOG_ANY(logLevelError, code, __VA_ARGS__)
#define LOG_DEBUG(...) \
LOG_ANY(logLevelDebug, 0, __VA_ARGS__)
#define LOG_INFO(...) \
LOG_ANY(logLevelInfo, 0, __VA_ARGS__)
LOG_WILL(logLevelError, code, __VA_ARGS__)
#define LOG_WARN(...) \
LOG_ANY(logLevelWarn, 0, __VA_ARGS__)
LOG_WILL(logLevelWarn, 0, __VA_ARGS__)
#define LOG_INFO(...) \
LOG_WILL(logLevelInfo, 0, __VA_ARGS__)
#define LOG_DETAIL(...) \
LOG_WILL(logLevelDetail, 0, __VA_ARGS__)
#define LOG_TRACE(...) \
LOG_WILL(logLevelTrace, 0, __VA_ARGS__)
/***********************************************************************************************************************************
Internal Functions
***********************************************************************************************************************************/
void logInternal(
LogLevel logLevel, const char *fileName, const char *functionName, int code, const char *format, ...);
LogLevel logLevel, LogLevel logRangeMin, LogLevel logRangeMax, const char *fileName, const char *functionName,
int code, const char *format, ...);
#endif

View File

@ -5,6 +5,7 @@ Memory Context Manager
#include <string.h>
#include "common/assert.h"
#include "common/debug.h"
#include "common/error.h"
#include "common/memContext.h"
@ -64,6 +65,11 @@ Wrapper around malloc()
static void *
memAllocInternal(size_t size, bool zero)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(SIZE, size);
FUNCTION_TEST_PARAM(BOOL, zero);
FUNCTION_TEST_END();
// Allocate memory
void *buffer = malloc(size);
@ -76,7 +82,7 @@ memAllocInternal(size_t size, bool zero)
memset(buffer, 0, size);
// Return the buffer
return buffer;
FUNCTION_TEST_RESULT(VOIDP, buffer);
}
/***********************************************************************************************************************************
@ -85,6 +91,15 @@ Wrapper around realloc()
static void *
memReAllocInternal(void *bufferOld, size_t sizeOld, size_t sizeNew, bool zeroNew)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(VOIDP, bufferOld);
FUNCTION_TEST_PARAM(SIZE, sizeOld);
FUNCTION_TEST_PARAM(SIZE, sizeNew);
FUNCTION_TEST_PARAM(BOOL, zeroNew);
FUNCTION_TEST_ASSERT(bufferOld != NULL);
FUNCTION_TEST_END();
// Allocate memory
void *bufferNew = realloc(bufferOld, sizeNew);
@ -97,7 +112,7 @@ memReAllocInternal(void *bufferOld, size_t sizeOld, size_t sizeNew, bool zeroNew
memset((unsigned char *)bufferNew + sizeOld, 0, sizeNew - sizeOld);
// Return the buffer
return bufferNew;
FUNCTION_TEST_RESULT(VOIDP, bufferNew);
}
/***********************************************************************************************************************************
@ -106,12 +121,15 @@ Wrapper around free()
static void
memFreeInternal(void *buffer)
{
// Error if pointer is null
if (buffer == NULL)
THROW(MemoryError, "unable to free null pointer");
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(VOIDP, buffer);
FUNCTION_TEST_ASSERT(buffer != NULL);
FUNCTION_TEST_END();
// Free the buffer
free(buffer);
FUNCTION_TEST_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -120,6 +138,13 @@ Find space for a new mem context
static unsigned int
memContextNewIndex(MemContext *memContext, bool allowFree)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(MEM_CONTEXT, memContext);
FUNCTION_TEST_PARAM(BOOL, allowFree);
FUNCTION_TEST_ASSERT(memContext != NULL);
FUNCTION_TEST_END();
// Try to find space for the new context
unsigned int contextIdx;
@ -160,7 +185,7 @@ memContextNewIndex(MemContext *memContext, bool allowFree)
}
}
return contextIdx;
FUNCTION_TEST_RESULT(UINT, contextIdx);
}
/***********************************************************************************************************************************
@ -169,6 +194,12 @@ Create a new memory context
MemContext *
memContextNew(const char *name)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRINGZ, name);
FUNCTION_TEST_ASSERT(name != NULL);
FUNCTION_TEST_END();
// Check context name length
if (strlen(name) == 0 || strlen(name) > MEM_CONTEXT_NAME_SIZE)
THROW_FMT(AssertError, "context name length must be > 0 and <= %d", MEM_CONTEXT_NAME_SIZE);
@ -197,7 +228,7 @@ memContextNew(const char *name)
this->contextParent = memContextCurrent();
// Return context
return this;
FUNCTION_TEST_RESULT(MEM_CONTEXT, this);
}
/***********************************************************************************************************************************
@ -206,6 +237,15 @@ Register a callback to be called just before the context is freed
void
memContextCallback(MemContext *this, void (*callbackFunction)(void *), void *callbackArgument)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(MEM_CONTEXT, this);
FUNCTION_TEST_PARAM(FUNCTIONP, callbackFunction);
FUNCTION_TEST_PARAM(VOIDP, callbackArgument);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(callbackFunction != NULL);
FUNCTION_TEST_END();
// Error if context is not active
if (this->state != memContextStateActive)
THROW(AssertError, "cannot assign callback to inactive context");
@ -221,6 +261,8 @@ memContextCallback(MemContext *this, void (*callbackFunction)(void *), void *cal
// Set callback function and argument
this->callbackFunction = callbackFunction;
this->callbackArgument = callbackArgument;
FUNCTION_TEST_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -229,6 +271,11 @@ Allocate memory in the memory context and optionally zero it.
static void *
memContextAlloc(size_t size, bool zero)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(SIZE, size);
FUNCTION_TEST_PARAM(BOOL, zero);
FUNCTION_TEST_END();
// Find space for the new allocation
unsigned int allocIdx;
@ -270,7 +317,7 @@ memContextAlloc(size_t size, bool zero)
memContextCurrent()->allocList[allocIdx].buffer = memAllocInternal(size, zero);
// Return buffer
return memContextCurrent()->allocList[allocIdx].buffer;
FUNCTION_TEST_RESULT(VOIDP, memContextCurrent()->allocList[allocIdx].buffer);
}
/***********************************************************************************************************************************
@ -279,9 +326,11 @@ Find a memory allocation
static unsigned int
memFind(const void *buffer)
{
// Error if buffer is null
if (buffer == NULL)
THROW(AssertError, "unable to find null allocation");
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(VOIDP, buffer);
FUNCTION_TEST_ASSERT(buffer != NULL);
FUNCTION_TEST_END();
// Find memory allocation
unsigned int allocIdx;
@ -294,7 +343,7 @@ memFind(const void *buffer)
if (allocIdx == memContextCurrent()->allocListSize)
THROW(AssertError, "unable to find allocation");
return allocIdx;
FUNCTION_TEST_RESULT(UINT, allocIdx);
}
/***********************************************************************************************************************************
@ -303,7 +352,11 @@ Allocate zeroed memory in the memory context
void *
memNew(size_t size)
{
return memContextAlloc(size, true);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(SIZE, size);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(VOIDP, memContextAlloc(size, true));
}
/***********************************************************************************************************************************
@ -312,6 +365,13 @@ Grow allocated memory without initializing the new portion
void *
memGrowRaw(const void *buffer, size_t size)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(VOIDP, buffer);
FUNCTION_TEST_PARAM(SIZE, size);
FUNCTION_TEST_ASSERT(buffer != NULL);
FUNCTION_TEST_END();
// Find the allocation
MemContextAlloc *alloc = &(memContextCurrent()->allocList[memFind(buffer)]);
@ -319,7 +379,7 @@ memGrowRaw(const void *buffer, size_t size)
alloc->buffer = memReAllocInternal(alloc->buffer, alloc->size, size, false);
alloc->size = (unsigned int)size;
return alloc->buffer;
FUNCTION_TEST_RESULT(VOIDP, alloc->buffer);
}
/***********************************************************************************************************************************
@ -328,7 +388,11 @@ Allocate memory in the memory context without initializing it
void *
memNewRaw(size_t size)
{
return memContextAlloc(size, false);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(SIZE, size);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(VOIDP, memContextAlloc(size, false));
}
/***********************************************************************************************************************************
@ -337,12 +401,20 @@ Free a memory allocation in the context
void
memFree(void *buffer)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(VOIDP, buffer);
FUNCTION_TEST_ASSERT(buffer != NULL);
FUNCTION_TEST_END();
// Find the allocation
MemContextAlloc *alloc = &(memContextCurrent()->allocList[memFind(buffer)]);
// Free the buffer
memFreeInternal(alloc->buffer);
alloc->active = false;
FUNCTION_TEST_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -353,6 +425,13 @@ This is generally used to move objects to a new context once they have been succ
void
memContextMove(MemContext *this, MemContext *parentNew)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(MEM_CONTEXT, this);
FUNCTION_TEST_PARAM(MEM_CONTEXT, parentNew);
FUNCTION_TEST_ASSERT(parentNew != NULL);
FUNCTION_TEST_END();
// Only move if a valid mem context is provided
if (this != NULL)
{
@ -382,6 +461,8 @@ memContextMove(MemContext *this, MemContext *parentNew)
// Assign new parent
this->contextParent = parentNew;
}
FUNCTION_TEST_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -390,6 +471,12 @@ Switch to the specified context and return the old context
MemContext *
memContextSwitch(MemContext *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(MEM_CONTEXT, this);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
// Error if context is not active
if (this->state != memContextStateActive)
THROW(AssertError, "cannot switch to inactive context");
@ -397,7 +484,7 @@ memContextSwitch(MemContext *this)
MemContext *memContextOld = memContextCurrent();
contextCurrent = this;
return memContextOld;
FUNCTION_TEST_RESULT(MEM_CONTEXT, memContextOld);
}
/***********************************************************************************************************************************
@ -406,7 +493,8 @@ Return the top context
MemContext *
memContextTop()
{
return &contextTop;
FUNCTION_TEST_VOID();
FUNCTION_TEST_RESULT(MEM_CONTEXT, &contextTop);
}
/***********************************************************************************************************************************
@ -415,7 +503,8 @@ Return the current context
MemContext *
memContextCurrent()
{
return contextCurrent;
FUNCTION_TEST_VOID();
FUNCTION_TEST_RESULT(MEM_CONTEXT, contextCurrent);
}
/***********************************************************************************************************************************
@ -424,11 +513,17 @@ Return the context name
const char *
memContextName(MemContext *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(MEM_CONTEXT, this);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
// Error if context is not active
if (this->state != memContextStateActive)
THROW(AssertError, "cannot get name for inactive context");
return this->name;
FUNCTION_TEST_RESULT(STRINGZ, this->name);
}
/***********************************************************************************************************************************
@ -437,62 +532,70 @@ memContextFree - free all memory used by the context and all child contexts
void
memContextFree(MemContext *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(MEM_CONTEXT, this);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
// If context is already freeing then return if memContextFree() is called again - this can happen in callbacks
if (this->state == memContextStateFreeing)
return;
// Current context cannot be freed unless it is top (top is never really freed, just the stuff under it)
if (this == memContextCurrent() && this != memContextTop())
THROW_FMT(AssertError, "cannot free current context '%s'", this->name);
// Error if context is not active
if (this->state != memContextStateActive)
THROW(AssertError, "cannot free inactive context");
// Free child contexts
if (this->contextChildListSize > 0)
for (unsigned int contextIdx = 0; contextIdx < this->contextChildListSize; contextIdx++)
if (this->contextChildList[contextIdx] && this->contextChildList[contextIdx]->state == memContextStateActive)
memContextFree(this->contextChildList[contextIdx]);
// Set state to freeing now that there are no child contexts. Child contexts might need to interact with their parent while
// freeing so the parent needs to remain active until they are all gone.
this->state = memContextStateFreeing;
// Execute callback if defined
if (this->callbackFunction)
this->callbackFunction(this->callbackArgument);
// Free child context allocations
if (this->contextChildListSize > 0)
if (this->state != memContextStateFreeing)
{
for (unsigned int contextIdx = 0; contextIdx < this->contextChildListSize; contextIdx++)
if (this->contextChildList[contextIdx])
memFreeInternal(this->contextChildList[contextIdx]);
// Current context cannot be freed unless it is top (top is never really freed, just the stuff under it)
if (this == memContextCurrent() && this != memContextTop())
THROW_FMT(AssertError, "cannot free current context '%s'", this->name);
memFreeInternal(this->contextChildList);
this->contextChildListSize = 0;
}
// Error if context is not active
if (this->state != memContextStateActive)
THROW(AssertError, "cannot free inactive context");
// Free memory allocations
if (this->allocListSize > 0)
{
for (unsigned int allocIdx = 0; allocIdx < this->allocListSize; allocIdx++)
// Free child contexts
if (this->contextChildListSize > 0)
for (unsigned int contextIdx = 0; contextIdx < this->contextChildListSize; contextIdx++)
if (this->contextChildList[contextIdx] && this->contextChildList[contextIdx]->state == memContextStateActive)
memContextFree(this->contextChildList[contextIdx]);
// Set state to freeing now that there are no child contexts. Child contexts might need to interact with their parent while
// freeing so the parent needs to remain active until they are all gone.
this->state = memContextStateFreeing;
// Execute callback if defined
if (this->callbackFunction)
this->callbackFunction(this->callbackArgument);
// Free child context allocations
if (this->contextChildListSize > 0)
{
MemContextAlloc *alloc = &(this->allocList[allocIdx]);
for (unsigned int contextIdx = 0; contextIdx < this->contextChildListSize; contextIdx++)
if (this->contextChildList[contextIdx])
memFreeInternal(this->contextChildList[contextIdx]);
if (alloc->active)
memFreeInternal(alloc->buffer);
memFreeInternal(this->contextChildList);
this->contextChildListSize = 0;
}
memFreeInternal(this->allocList);
this->allocListSize = 0;
// Free memory allocations
if (this->allocListSize > 0)
{
for (unsigned int allocIdx = 0; allocIdx < this->allocListSize; allocIdx++)
{
MemContextAlloc *alloc = &(this->allocList[allocIdx]);
if (alloc->active)
memFreeInternal(alloc->buffer);
}
memFreeInternal(this->allocList);
this->allocListSize = 0;
}
// Make top context active again
if (this == memContextTop())
this->state = memContextStateActive;
// Else reset the memory context so it can be reused
else
memset(this, 0, sizeof(MemContext));
}
// Make top context active again
if (this == memContextTop())
this->state = memContextStateActive;
// Else reset the memory context so it can be reused
else
memset(this, 0, sizeof(MemContext));
FUNCTION_TEST_RESULT_VOID();
}

View File

@ -188,4 +188,12 @@ MEM_CONTEXT_TEMP_END();
} \
}
/***********************************************************************************************************************************
Macros for function logging
***********************************************************************************************************************************/
#define FUNCTION_DEBUG_MEM_CONTEXT_TYPE \
MemContext *
#define FUNCTION_DEBUG_MEM_CONTEXT_FORMAT(value, buffer, bufferSize) \
objToLog(value, "MemContext", buffer, bufferSize)
#endif

View File

@ -4,6 +4,7 @@ Regular Expression Handler
#include <regex.h>
#include <sys/types.h>
#include "common/debug.h"
#include "common/memContext.h"
#include "common/regExp.h"
@ -22,9 +23,15 @@ Handle errors
static void
regExpError(int error)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(INT, error);
FUNCTION_TEST_END();
char buffer[4096];
regerror(error, NULL, buffer, sizeof(buffer));
THROW(FormatError, buffer);
FUNCTION_TEST_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -33,6 +40,12 @@ New regular expression handler
RegExp *
regExpNew(const String *expression)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, expression);
FUNCTION_TEST_ASSERT(expression != NULL);
FUNCTION_TEST_END();
RegExp *this = NULL;
MEM_CONTEXT_NEW_BEGIN("RegExp")
@ -54,7 +67,7 @@ regExpNew(const String *expression)
}
MEM_CONTEXT_NEW_END();
return this;
FUNCTION_TEST_RESULT(REGEXP, this);
}
/***********************************************************************************************************************************
@ -63,6 +76,14 @@ Match on a regular expression
bool
regExpMatch(RegExp *this, const String *string)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(REGEXP, this);
FUNCTION_TEST_PARAM(STRING, string);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(string != NULL);
FUNCTION_TEST_END();
// Test for a match
int result = regexec(&this->regExp, strPtr(string), 0, NULL, 0);
@ -70,7 +91,7 @@ regExpMatch(RegExp *this, const String *string)
if (result != 0 && result != REG_NOMATCH) // {uncoverable - no error condition known}
regExpError(result); // {+uncoverable}
return result == 0;
FUNCTION_TEST_RESULT(BOOL, result == 0);
}
/***********************************************************************************************************************************
@ -79,11 +100,17 @@ Free regular expression
void
regExpFree(RegExp *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(REGEXP, this);
FUNCTION_TEST_END();
if (this != NULL)
{
regfree(&this->regExp);
memContextFree(this->memContext);
}
FUNCTION_TEST_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -92,6 +119,14 @@ Match a regular expression in one call for brevity
bool
regExpMatchOne(const String *expression, const String *string)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, expression);
FUNCTION_TEST_PARAM(STRING, string);
FUNCTION_TEST_ASSERT(expression != NULL);
FUNCTION_TEST_ASSERT(string != NULL);
FUNCTION_TEST_END();
bool result = false;
RegExp *regExp = regExpNew(expression);
@ -105,5 +140,5 @@ regExpMatchOne(const String *expression, const String *string)
}
TRY_END();
return result;
FUNCTION_TEST_RESULT(BOOL, result);
}

View File

@ -20,4 +20,12 @@ void regExpFree(RegExp *this);
bool regExpMatchOne(const String *expression, const String *string);
/***********************************************************************************************************************************
Macros for function logging
***********************************************************************************************************************************/
#define FUNCTION_DEBUG_REGEXP_TYPE \
RegExp *
#define FUNCTION_DEBUG_REGEXP_FORMAT(value, buffer, bufferSize) \
objToLog(value, "RegExp", buffer, bufferSize)
#endif

363
src/common/stackTrace.c Normal file
View File

@ -0,0 +1,363 @@
/***********************************************************************************************************************************
Stack Trace Handler
***********************************************************************************************************************************/
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#ifdef WITH_BACKTRACE
#include <backtrace.h>
#include <backtrace-supported.h>
#endif
#include "common/assert.h"
#include "common/error.h"
#include "common/log.h"
#include "common/stackTrace.h"
/***********************************************************************************************************************************
Max call stack depth
***********************************************************************************************************************************/
#define STACK_TRACE_MAX 128
/***********************************************************************************************************************************
Track stack trace
***********************************************************************************************************************************/
static int stackSize = 0;
typedef struct StackTraceData
{
const char *fileName;
const char *functionName;
unsigned int fileLine;
LogLevel functionLogLevel;
unsigned int tryDepth;
char *param;
size_t paramSize;
bool paramOverflow;
bool paramLog;
} StackTraceData;
static StackTraceData stackTrace[STACK_TRACE_MAX];
/***********************************************************************************************************************************
Buffer to hold function parameters
***********************************************************************************************************************************/
static char functionParamBuffer[32 * 1024];
struct backtrace_state *backTraceState = NULL;
/***********************************************************************************************************************************
Backtrace init and callbacks
***********************************************************************************************************************************/
#ifdef WITH_BACKTRACE
void
stackTraceInit(const char *exe)
{
if (backTraceState == NULL)
backTraceState = backtrace_create_state(exe, false, NULL, NULL);
}
static int
backTraceCallback(void *data, uintptr_t pc, const char *filename, int lineno, const char *function)
{
(void)(data);
(void)(pc);
(void)(filename);
(void)(function);
if (stackSize > 0)
stackTrace[stackSize - 1].fileLine = (unsigned int)lineno;
return 1;
}
static void
backTraceCallbackError(void *data, const char *msg, int errnum)
{
(void)data;
(void)msg;
(void)errnum;
}
#endif
/***********************************************************************************************************************************
Flag to enable/disable test function logging
***********************************************************************************************************************************/
#ifndef NDEBUG
bool stackTraceTestFlag = true;
void
stackTraceTestStart()
{
stackTraceTestFlag = true;
}
void
stackTraceTestStop()
{
stackTraceTestFlag = false;
}
bool
stackTraceTest()
{
return stackTraceTestFlag;
}
#endif
/***********************************************************************************************************************************
Push a new function onto the trace stack
***********************************************************************************************************************************/
LogLevel
stackTracePush(const char *fileName, const char *functionName, LogLevel functionLogLevel)
{
ASSERT(stackSize < STACK_TRACE_MAX - 1);
// Get line number from backtrace if available
#ifdef WITH_BACKTRACE
backtrace_full(backTraceState, 2, backTraceCallback, backTraceCallbackError, NULL);
#endif
// This struct could be holding old trace data so init to zero
StackTraceData *data = &stackTrace[stackSize];
memset(data, 0, sizeof(StackTraceData));
// Set function info
data->fileName = fileName;
data->functionName = functionName;
data->tryDepth = errorTryDepth();
// Set param pointer
if (stackSize == 0)
{
data->param = functionParamBuffer;
data->functionLogLevel = functionLogLevel;
}
else
{
StackTraceData *dataPrior = &stackTrace[stackSize - 1];
data->param = dataPrior->param + dataPrior->paramSize + 1;
// Log level cannot be lower than the prior function
if (functionLogLevel < dataPrior->functionLogLevel)
data->functionLogLevel = dataPrior->functionLogLevel;
else
data->functionLogLevel = functionLogLevel;
}
stackSize++;
return data->functionLogLevel;
}
/***********************************************************************************************************************************
Get parameters for the top function on the stack
***********************************************************************************************************************************/
static const char *
stackTraceParamIdx(int stackIdx)
{
ASSERT_DEBUG(stackSize > 0);
ASSERT_DEBUG(stackIdx < stackSize);
StackTraceData *data = &stackTrace[stackIdx];
if (data->paramLog)
{
if (data->paramOverflow)
return "!!! buffer overflow - parameters not available !!!";
if (data->paramSize == 0)
return "void";
return data->param;
}
return "debug log level required for parameters";
}
const char *
stackTraceParam()
{
return stackTraceParamIdx(stackSize - 1);
}
/***********************************************************************************************************************************
Get the next location where a parameter can be added in the param buffer
***********************************************************************************************************************************/
char *
stackTraceParamBuffer(const char *paramName)
{
ASSERT_DEBUG(stackSize > 0);
StackTraceData *data = &stackTrace[stackSize - 1];
size_t paramNameSize = strlen(paramName);
// Make sure that adding this parameter will not overflow the buffer
if ((size_t)(data->param - functionParamBuffer) + data->paramSize + paramNameSize + 4 >
sizeof(functionParamBuffer) - (STACK_TRACE_PARAM_MAX * 2))
{
// Set overflow to true
data->paramOverflow = true;
// There's no way to stop the parameter from being formatted so we reserve a space at the end where the format can safely
// take place and not disturb the rest of the buffer. Hopefully overflows just won't happen but we need to be prepared in
// case of runaway recursion or some other issue that fills the buffer because we don't want a segfault.
return functionParamBuffer + sizeof(functionParamBuffer) - STACK_TRACE_PARAM_MAX;
}
// Add a comma if a parameter is already in the list
if (data->paramSize != 0)
{
data->param[data->paramSize++] = ',';
data->param[data->paramSize++] = ' ';
}
// Add the parameter name
strcpy(data->param + data->paramSize, paramName);
data->paramSize += paramNameSize;
// Add param/value separator
data->param[data->paramSize++] = ':';
data->param[data->paramSize++] = ' ';
return data->param + data->paramSize;
}
/***********************************************************************************************************************************
Add a parameter to the function on the top of the stack
***********************************************************************************************************************************/
void
stackTraceParamAdd(size_t bufferSize)
{
ASSERT_DEBUG(stackSize > 0);
StackTraceData *data = &stackTrace[stackSize - 1];
if (!data->paramOverflow)
data->paramSize += bufferSize;
}
/***********************************************************************************************************************************
Mark that parameters are being logged -- it none appear then the function is void
***********************************************************************************************************************************/
void
stackTraceParamLog()
{
ASSERT_DEBUG(stackSize > 0);
stackTrace[stackSize - 1].paramLog = true;
}
/***********************************************************************************************************************************
Pop a function from the stack trace
***********************************************************************************************************************************/
#ifdef NDEBUG
void
stackTracePop()
{
stackSize--;
}
#else
void
stackTracePop(const char *fileName, const char *functionName)
{
ASSERT_DEBUG(stackSize > 0);
stackSize--;
StackTraceData *data = &stackTrace[stackSize];
if (strcmp(data->fileName, fileName) != 0 || strcmp(data->functionName, functionName) != 0)
THROW_FMT(AssertError, "popping %s:%s but expected %s:%s", fileName, functionName, data->fileName, data->functionName);
}
#endif
/***********************************************************************************************************************************
Stack trace format
***********************************************************************************************************************************/
static size_t
stackTraceFmt(char *buffer, size_t bufferSize, size_t bufferUsed, const char *format, ...)
{
va_list argumentList;
va_start(argumentList, format);
int result = vsnprintf(
buffer + bufferUsed, bufferUsed < bufferSize ? bufferSize - bufferUsed : 0, format, argumentList);
va_end(argumentList);
return (size_t)result;
}
/***********************************************************************************************************************************
Generate the stack trace
***********************************************************************************************************************************/
size_t
stackTraceToZ(char *buffer, size_t bufferSize, const char *fileName, const char *functionName, unsigned int fileLine)
{
size_t result = 0;
const char *param = "test build required for parameters";
int stackIdx = stackSize - 1;
// If the current function passed in is the same as the top function on the stack then use the parameters for that function
if (stackSize > 0 && strcmp(fileName, stackTrace[stackIdx].fileName) == 0 &&
strcmp(functionName, stackTrace[stackIdx].functionName) == 0)
{
param = stackTraceParamIdx(stackSize - 1);
stackIdx--;
}
// Output the current function
result = stackTraceFmt(
buffer, bufferSize, 0, "%.*s:%s:%u:(%s)", (int)(strlen(fileName) - 2), fileName, functionName, fileLine, param);
// Output stack if there is anything on it
if (stackIdx >= 0)
{
// If the function passed in was not at the top of the stack then some functions are missing
if (stackIdx == stackSize - 1)
result += stackTraceFmt(buffer, bufferSize, result, "\n ... function(s) ommitted ...");
// Output the rest of the stack
for (; stackIdx >= 0; stackIdx--)
{
StackTraceData *data = &stackTrace[stackIdx];
result += stackTraceFmt(
buffer, bufferSize, result, "\n%.*s:%s"
#ifdef WITH_BACKTRACE
":%u"
#endif
":(%s)", (int)(strlen(data->fileName) - 2), data->fileName, data->functionName,
#ifdef WITH_BACKTRACE
data->fileLine,
#endif
stackTraceParamIdx(stackIdx));
}
}
return result;
}
/***********************************************************************************************************************************
Clean the stack at and below the try level
Called by the error to cleanup the stack when an exception occurs.
***********************************************************************************************************************************/
void
stackTraceClean(unsigned int tryDepth)
{
while (stackSize > 0 && stackTrace[stackSize - 1].tryDepth >= tryDepth)
stackSize--;
}

59
src/common/stackTrace.h Normal file
View File

@ -0,0 +1,59 @@
/***********************************************************************************************************************************
Stack Trace Handler
***********************************************************************************************************************************/
#ifndef COMMON_STACKTRACE_H
#define COMMON_STACKTRACE_H
#include <sys/types.h>
#include "common/log.h"
/***********************************************************************************************************************************
Maximum size of a single parameter (including NULL terminator)
***********************************************************************************************************************************/
#define STACK_TRACE_PARAM_MAX 256
/***********************************************************************************************************************************
Macros to access internal functions
***********************************************************************************************************************************/
#define STACK_TRACE_PUSH(logLevel) \
stackTracePush(__FILE__, __func__, logLevel)
#ifdef NDEBUG
#define STACK_TRACE_POP() \
stackTracePop();
#else
#define STACK_TRACE_POP() \
stackTracePop(__FILE__, __func__);
#endif
/***********************************************************************************************************************************
Internal Functions
***********************************************************************************************************************************/
#ifdef WITH_BACKTRACE
void stackTraceInit(const char *exe);
#endif
#ifndef NDEBUG
void stackTraceTestStart();
void stackTraceTestStop();
bool stackTraceTest();
#endif
LogLevel stackTracePush(const char *fileName, const char *functionName, LogLevel functionLogLevel);
#ifdef NDEBUG
void stackTracePop();
#else
void stackTracePop(const char *fileName, const char *functionName);
#endif
size_t stackTraceToZ(char *buffer, size_t bufferSize, const char *fileName, const char *functionName, unsigned int fileLine);
void stackTraceParamLog();
const char *stackTraceParam();
char *stackTraceParamBuffer(const char *param);
void stackTraceParamAdd(size_t bufferSize);
void stackTraceClean(unsigned int tryDepth);
#endif

View File

@ -4,6 +4,7 @@ Time Management
#include "stdio.h"
#include "sys/time.h"
#include "common/debug.h"
#include "common/time.h"
/***********************************************************************************************************************************
@ -17,9 +18,12 @@ Epoch time in milliseconds
TimeMSec
timeMSec()
{
FUNCTION_TEST_VOID();
struct timeval currentTime;
gettimeofday(&currentTime, NULL);
return ((TimeMSec)currentTime.tv_sec * MSEC_PER_SEC) + (TimeMSec)currentTime.tv_usec / MSEC_PER_USEC;
FUNCTION_TEST_RESULT(UINT64, ((TimeMSec)currentTime.tv_sec * MSEC_PER_SEC) + (TimeMSec)currentTime.tv_usec / MSEC_PER_USEC);
}
/***********************************************************************************************************************************
@ -28,8 +32,14 @@ Sleep for specified milliseconds
void
sleepMSec(TimeMSec sleepMSec)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(UINT64, sleepMSec);
FUNCTION_TEST_END();
struct timeval delay;
delay.tv_sec = (time_t)(sleepMSec / MSEC_PER_SEC);
delay.tv_usec = (time_t)(sleepMSec % MSEC_PER_SEC * 1000);
select(0, NULL, NULL, NULL, &delay);
FUNCTION_TEST_RESULT_VOID();
}

View File

@ -1,9 +1,11 @@
/***********************************************************************************************************************************
String Handler
***********************************************************************************************************************************/
#include <stdio.h>
#include <string.h>
#include "common/assert.h"
#include "common/debug.h"
#include "common/type/buffer.h"
/***********************************************************************************************************************************
@ -22,6 +24,10 @@ Create a new buffer
Buffer *
bufNew(size_t size)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(SIZE, size);
FUNCTION_TEST_END();
Buffer *this = NULL;
MEM_CONTEXT_NEW_BEGIN("Buffer")
@ -37,7 +43,7 @@ bufNew(size_t size)
}
MEM_CONTEXT_NEW_END();
return this;
FUNCTION_TEST_RESULT(BUFFER, this);
}
/***********************************************************************************************************************************
@ -46,13 +52,18 @@ Create a new buffer from a C buffer
Buffer *
bufNewC(size_t size, const void *buffer)
{
// Create object
Buffer *this = bufNew(size);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(SIZE, size);
FUNCTION_TEST_PARAM(VOIDP, buffer);
// Copy the data
FUNCTION_TEST_ASSERT(buffer != NULL);
FUNCTION_TEST_END();
// Create object and copy data
Buffer *this = bufNew(size);
memcpy(this->buffer, buffer, this->size);
return this;
FUNCTION_TEST_RESULT(BUFFER, this);
}
/***********************************************************************************************************************************
@ -61,13 +72,19 @@ Create a new buffer from a string
Buffer *
bufNewStr(const String *string)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, string);
FUNCTION_TEST_ASSERT(string != NULL);
FUNCTION_TEST_END();
// Create object
Buffer *this = bufNew(strSize(string));
// Copy the data
memcpy(this->buffer, strPtr(string), this->size);
return this;
FUNCTION_TEST_RESULT(BUFFER, this);
}
/***********************************************************************************************************************************
@ -76,7 +93,12 @@ Append the contents of another buffer
Buffer *
bufCat(Buffer *this, const Buffer *cat)
{
ASSERT_DEBUG(this != NULL);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(BUFFER, this);
FUNCTION_TEST_PARAM(BUFFER, cat);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
if (cat != NULL && cat->size > 0)
{
@ -86,7 +108,7 @@ bufCat(Buffer *this, const Buffer *cat)
memcpy(this->buffer + sizeOld, cat->buffer, cat->size);
}
return this;
FUNCTION_TEST_RESULT(BUFFER, this);
}
/***********************************************************************************************************************************
@ -95,15 +117,20 @@ Are two buffers equal?
bool
bufEq(const Buffer *this, const Buffer *compare)
{
bool result = false;
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(BUFFER, this);
FUNCTION_TEST_PARAM(BUFFER, compare);
ASSERT_DEBUG(this != NULL);
ASSERT_DEBUG(compare != NULL);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(compare != NULL);
FUNCTION_TEST_END();
bool result = false;
if (this->size == compare->size)
result = memcmp(this->buffer, compare->buffer, compare->size) == 0;
return result;
FUNCTION_TEST_RESULT(BOOL, result);
}
/***********************************************************************************************************************************
@ -112,10 +139,17 @@ Move buffer to a new mem context
Buffer *
bufMove(Buffer *this, MemContext *parentNew)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(BUFFER, this);
FUNCTION_TEST_PARAM(MEM_CONTEXT, parentNew);
FUNCTION_TEST_ASSERT(parentNew != NULL);
FUNCTION_TEST_END();
if (this != NULL)
memContextMove(this->memContext, parentNew);
return this;
FUNCTION_TEST_RESULT(BUFFER, this);
}
/***********************************************************************************************************************************
@ -124,7 +158,13 @@ Return buffer ptr
unsigned char *
bufPtr(const Buffer *this)
{
return this->buffer;
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(BUFFER, this);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(UCHARP, this->buffer);
}
/***********************************************************************************************************************************
@ -133,6 +173,13 @@ Resize the buffer
Buffer *
bufResize(Buffer *this, size_t size)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(BUFFER, this);
FUNCTION_TEST_PARAM(SIZE, size);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
// Only resize if it the new size is different
if (this->size != size)
{
@ -167,7 +214,7 @@ bufResize(Buffer *this, size_t size)
}
}
return this;
FUNCTION_TEST_RESULT(BUFFER, this);
}
/***********************************************************************************************************************************
@ -176,7 +223,37 @@ Return buffer size
size_t
bufSize(const Buffer *this)
{
return this->size;
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(BUFFER, this);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(SIZE, this->size);
}
/***********************************************************************************************************************************
Convert to a zero-terminated string for logging
***********************************************************************************************************************************/
size_t
bufToLog(const Buffer *this, char *buffer, size_t bufferSize)
{
size_t result = 0;
MEM_CONTEXT_TEMP_BEGIN()
{
String *string = NULL;
if (this == NULL)
string = strNew("null");
else
string = strNewFmt("{size: %zu}", this->size);
result = (size_t)snprintf(buffer, bufferSize, "%s", strPtr(string));
}
MEM_CONTEXT_TEMP_END();
return result;
}
/***********************************************************************************************************************************
@ -185,6 +262,12 @@ Free the buffer
void
bufFree(Buffer *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(BUFFER, this);
FUNCTION_TEST_END();
if (this != NULL)
memContextFree(this->memContext);
FUNCTION_TEST_RESULT_VOID();
}

View File

@ -26,4 +26,14 @@ size_t bufSize(const Buffer *this);
unsigned char *bufPtr(const Buffer *this);
void bufFree(Buffer *this);
/***********************************************************************************************************************************
Macros for function logging
***********************************************************************************************************************************/
size_t bufToLog(const Buffer *this, char *buffer, size_t bufferSize);
#define FUNCTION_DEBUG_BUFFER_TYPE \
Buffer *
#define FUNCTION_DEBUG_BUFFER_FORMAT(value, buffer, bufferSize) \
bufToLog(value, buffer, bufferSize)
#endif

266
src/common/type/convert.c Normal file
View File

@ -0,0 +1,266 @@
/***********************************************************************************************************************************
Convert Base Data Types
***********************************************************************************************************************************/
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "common/assert.h"
#include "common/debug.h"
#include "common/type/convert.h"
/***********************************************************************************************************************************
Convert uint64 to zero-terminated string
***********************************************************************************************************************************/
size_t
cvtBoolToZ(bool value, char *buffer, size_t bufferSize)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(BOOL, value);
FUNCTION_TEST_PARAM(CHARP, buffer);
FUNCTION_TEST_PARAM(SIZE, bufferSize);
FUNCTION_TEST_ASSERT(buffer != NULL);
FUNCTION_TEST_END();
size_t result = (size_t)snprintf(buffer, bufferSize, "%s", value ? "true" : "false");
if (result >= bufferSize)
THROW(AssertError, "buffer overflow");
FUNCTION_TEST_RESULT(SIZE, result);
}
/***********************************************************************************************************************************
Convert double to zero-terminated string and vice versa
***********************************************************************************************************************************/
size_t
cvtDoubleToZ(double value, char *buffer, size_t bufferSize)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(DOUBLE, value);
FUNCTION_TEST_PARAM(CHARP, buffer);
FUNCTION_TEST_PARAM(SIZE, bufferSize);
FUNCTION_TEST_ASSERT(buffer != NULL);
FUNCTION_TEST_END();
// Convert to a string
size_t result = (size_t)snprintf(buffer, bufferSize, "%lf", value);
if (result >= bufferSize)
THROW(AssertError, "buffer overflow");
// Any formatted double should be at least 8 characters, i.e. 0.000000
ASSERT_DEBUG(strlen(buffer) >= 8);
// Any formatted double should have a decimal point
ASSERT_DEBUG(strchr(buffer, '.') != NULL);
// Strip off any final 0s and the decimal point if there are no non-zero digits after it
char *end = buffer + strlen(buffer) - 1;
while (*end == '0' || *end == '.')
{
// It should not be possible to go past the beginning because format "%lf" will always write a decimal point
ASSERT_DEBUG(end > buffer);
end--;
if (*(end + 1) == '.')
break;
}
// Zero terminate the string
end[1] = 0;
// Return string length
FUNCTION_TEST_RESULT(SIZE, (size_t)(end - buffer + 1));
}
double
cvtZToDouble(const char *value)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(CHARP, value);
FUNCTION_TEST_ASSERT(value != NULL);
FUNCTION_TEST_END();
double result = 0;
sscanf(value, "%lf", &result);
if (result == 0 && strcmp(value, "0") != 0)
THROW_FMT(FormatError, "unable to convert string '%s' to double", value);
FUNCTION_TEST_RESULT(DOUBLE, result);
}
/***********************************************************************************************************************************
Convert int to zero-terminated string and vice versa
***********************************************************************************************************************************/
size_t
cvtIntToZ(int value, char *buffer, size_t bufferSize)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(INT, value);
FUNCTION_TEST_PARAM(CHARP, buffer);
FUNCTION_TEST_PARAM(SIZE, bufferSize);
FUNCTION_TEST_ASSERT(buffer != NULL);
FUNCTION_TEST_END();
size_t result = (size_t)snprintf(buffer, bufferSize, "%d", value);
if (result >= bufferSize)
THROW(AssertError, "buffer overflow");
FUNCTION_TEST_RESULT(SIZE, result);
}
int
cvtZToInt(const char *value)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(CHARP, value);
FUNCTION_TEST_ASSERT(value != NULL);
FUNCTION_TEST_END();
int result = atoi(value);
if (result == 0 && strcmp(value, "0") != 0)
THROW_FMT(FormatError, "unable to convert string '%s' to int", value);
FUNCTION_TEST_RESULT(INT, result);
}
/***********************************************************************************************************************************
Convert int64 to zero-terminated string and vice versa
***********************************************************************************************************************************/
size_t
cvtInt64ToZ(int64_t value, char *buffer, size_t bufferSize)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(INT64, value);
FUNCTION_TEST_PARAM(CHARP, buffer);
FUNCTION_TEST_PARAM(SIZE, bufferSize);
FUNCTION_TEST_ASSERT(buffer != NULL);
FUNCTION_TEST_END();
size_t result = (size_t)snprintf(buffer, bufferSize, "%" PRId64, value);
if (result >= bufferSize)
THROW(AssertError, "buffer overflow");
FUNCTION_TEST_RESULT(SIZE, result);
}
int64_t
cvtZToInt64(const char *value)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(CHARP, value);
FUNCTION_TEST_ASSERT(value != NULL);
FUNCTION_TEST_END();
int64_t result = atoll(value);
char buffer[32];
snprintf(buffer, sizeof(buffer), "%" PRId64, result);
if (strcmp(value, buffer) != 0)
THROW_FMT(FormatError, "unable to convert string '%s' to int64", value);
FUNCTION_TEST_RESULT(INT64, result);
}
/***********************************************************************************************************************************
Convert mode to zero-terminated string
***********************************************************************************************************************************/
size_t
cvtModeToZ(mode_t value, char *buffer, size_t bufferSize)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(MODE, value);
FUNCTION_TEST_PARAM(CHARP, buffer);
FUNCTION_TEST_PARAM(SIZE, bufferSize);
FUNCTION_TEST_ASSERT(buffer != NULL);
FUNCTION_TEST_END();
size_t result = (size_t)snprintf(buffer, bufferSize, "%04o", value);
if (result >= bufferSize)
THROW(AssertError, "buffer overflow");
FUNCTION_TEST_RESULT(SIZE, result);
}
/***********************************************************************************************************************************
Convert size to zero-terminated string
***********************************************************************************************************************************/
size_t
cvtSizeToZ(size_t value, char *buffer, size_t bufferSize)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(SIZE, value);
FUNCTION_TEST_PARAM(CHARP, buffer);
FUNCTION_TEST_PARAM(SIZE, bufferSize);
FUNCTION_TEST_ASSERT(buffer != NULL);
FUNCTION_TEST_END();
size_t result = (size_t)snprintf(buffer, bufferSize, "%zu", value);
if (result >= bufferSize)
THROW(AssertError, "buffer overflow");
FUNCTION_TEST_RESULT(SIZE, result);
}
/***********************************************************************************************************************************
Convert uint to zero-terminated string
***********************************************************************************************************************************/
size_t
cvtUIntToZ(unsigned int value, char *buffer, size_t bufferSize)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(UINT, value);
FUNCTION_TEST_PARAM(CHARP, buffer);
FUNCTION_TEST_PARAM(SIZE, bufferSize);
FUNCTION_TEST_ASSERT(buffer != NULL);
FUNCTION_TEST_END();
size_t result = (size_t)snprintf(buffer, bufferSize, "%u", value);
if (result >= bufferSize)
THROW(AssertError, "buffer overflow");
FUNCTION_TEST_RESULT(SIZE, result);
}
/***********************************************************************************************************************************
Convert uint64 to zero-terminated string
***********************************************************************************************************************************/
size_t
cvtUInt64ToZ(uint64_t value, char *buffer, size_t bufferSize)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(UINT64, value);
FUNCTION_TEST_PARAM(CHARP, buffer);
FUNCTION_TEST_PARAM(SIZE, bufferSize);
FUNCTION_TEST_ASSERT(buffer != NULL);
FUNCTION_TEST_END();
size_t result = (size_t)snprintf(buffer, bufferSize, "%" PRIu64, value);
if (result >= bufferSize)
THROW(AssertError, "buffer overflow");
FUNCTION_TEST_RESULT(SIZE, result);
}

32
src/common/type/convert.h Normal file
View File

@ -0,0 +1,32 @@
/***********************************************************************************************************************************
Convert Base Data Types
***********************************************************************************************************************************/
#ifndef COMMON_TYPE_CONVERT_H
#define COMMON_TYPE_CONVERT_H
#include <inttypes.h>
#include <sys/types.h>
/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/
size_t cvtDoubleToZ(double value, char *buffer, size_t bufferSize);
double cvtZToDouble(const char *value);
size_t cvtIntToZ(int value, char *buffer, size_t bufferSize);
int cvtZToInt(const char *value);
size_t cvtInt64ToZ(int64_t value, char *buffer, size_t bufferSize);
int64_t cvtZToInt64(const char *value);
size_t cvtModeToZ(mode_t value, char *buffer, size_t bufferSize);
size_t cvtSizeToZ(size_t value, char *buffer, size_t bufferSize);
size_t cvtUIntToZ(unsigned int value, char *buffer, size_t bufferSize);
size_t cvtUInt64ToZ(uint64_t value, char *buffer, size_t bufferSize);
size_t cvtBoolToZ(bool value, char *buffer, size_t bufferSize);
#endif

View File

@ -3,6 +3,7 @@ Key Value Handler
***********************************************************************************************************************************/
#include <limits.h>
#include "common/debug.h"
#include "common/memContext.h"
#include "common/type/keyValue.h"
#include "common/type/list.h"
@ -38,9 +39,11 @@ Create a new key/value store
KeyValue *
kvNew()
{
FUNCTION_TEST_VOID();
KeyValue *this = NULL;
MEM_CONTEXT_NEW_BEGIN("keyValue")
MEM_CONTEXT_NEW_BEGIN("KeyValue")
{
// Allocate state and set context
this = memNew(sizeof(KeyValue));
@ -52,7 +55,7 @@ kvNew()
}
MEM_CONTEXT_NEW_END();
return this;
FUNCTION_TEST_RESULT(KEY_VALUE, this);
}
/***********************************************************************************************************************************
@ -61,6 +64,12 @@ Duplicate key/value store
KeyValue *
kvDup(const KeyValue *source)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(KEY_VALUE, source);
FUNCTION_TEST_ASSERT(source != NULL);
FUNCTION_TEST_END();
KeyValue *this = kvNew();
// Duplicate all key/values
@ -79,7 +88,7 @@ kvDup(const KeyValue *source)
this->keyList = varLstDup(source->keyList);
return this;
FUNCTION_TEST_RESULT(KEY_VALUE, this);
}
/***********************************************************************************************************************************
@ -88,23 +97,30 @@ Get key index if it exists
static unsigned int
kvGetIdx(const KeyValue *this, const Variant *key)
{
// Search for the key
unsigned int listIdx = 0;
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(KEY_VALUE, this);
FUNCTION_TEST_PARAM(VARIANT, key);
for (; listIdx < lstSize(this->list); listIdx++)
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(key != NULL);
FUNCTION_TEST_END();
// Search for the key
unsigned int result = KEY_NOT_FOUND;
for (unsigned int listIdx = 0; listIdx < lstSize(this->list); listIdx++)
{
const KeyValuePair *pair = (const KeyValuePair *)lstGet(this->list, listIdx);
// Break if the key matches
if (varEq(key, pair->key))
{
result = listIdx;
break;
}
}
// If key was not found
if (listIdx == lstSize(this->list))
return KEY_NOT_FOUND;
return listIdx;
FUNCTION_TEST_RESULT(UINT, result);
}
/***********************************************************************************************************************************
@ -113,7 +129,13 @@ Get list of keys
const VariantList *
kvKeyList(const KeyValue *this)
{
return this->keyList;
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(KEY_VALUE, this);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(VARIANT_LIST, this->keyList);
}
/***********************************************************************************************************************************
@ -124,6 +146,15 @@ Handles the common logic for the external put functions. The correct mem context
static void
kvPutInternal(KeyValue *this, const Variant *key, Variant *value)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(KEY_VALUE, this);
FUNCTION_TEST_PARAM(VARIANT, key);
FUNCTION_TEST_PARAM(VARIANT, value);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(key != NULL);
FUNCTION_TEST_END();
// Find the key
unsigned int listIdx = kvGetIdx(this, key);
@ -151,6 +182,8 @@ kvPutInternal(KeyValue *this, const Variant *key, Variant *value)
pair->value = value;
}
FUNCTION_TEST_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -159,13 +192,22 @@ Put key/value pair
KeyValue *
kvPut(KeyValue *this, const Variant *key, const Variant *value)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(KEY_VALUE, this);
FUNCTION_TEST_PARAM(VARIANT, key);
FUNCTION_TEST_PARAM(VARIANT, value);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(key != NULL);
FUNCTION_TEST_END();
MEM_CONTEXT_BEGIN(this->memContext)
{
kvPutInternal(this, key, varDup(value));
}
MEM_CONTEXT_END();
return this;
FUNCTION_TEST_RESULT(KEY_VALUE, this);
}
/***********************************************************************************************************************************
@ -174,6 +216,15 @@ Add value to key -- if the key does not exist then this works the same as kvPut(
KeyValue *
kvAdd(KeyValue *this, const Variant *key, const Variant *value)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(KEY_VALUE, this);
FUNCTION_TEST_PARAM(VARIANT, key);
FUNCTION_TEST_PARAM(VARIANT, value);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(key != NULL);
FUNCTION_TEST_END();
MEM_CONTEXT_BEGIN(this->memContext)
{
// Find the key
@ -193,7 +244,7 @@ kvAdd(KeyValue *this, const Variant *key, const Variant *value)
pair->value = varDup(value);
else if (varType(pair->value) != varTypeVariantList)
{
Variant *valueList = varNewVarLstEmpty();
Variant *valueList = varNewVarLst(varLstNew());
varLstAdd(varVarLst(valueList), pair->value);
varLstAdd(varVarLst(valueList), varDup(value));
pair->value = valueList;
@ -204,7 +255,7 @@ kvAdd(KeyValue *this, const Variant *key, const Variant *value)
}
MEM_CONTEXT_END();
return this;
FUNCTION_TEST_RESULT(KEY_VALUE, this);
}
/***********************************************************************************************************************************
@ -216,6 +267,14 @@ key/value store.
KeyValue *
kvPutKv(KeyValue *this, const Variant *key)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(KEY_VALUE, this);
FUNCTION_TEST_PARAM(VARIANT, key);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(key != NULL);
FUNCTION_TEST_END();
KeyValue *result = NULL;
MEM_CONTEXT_BEGIN(this->memContext)
@ -227,7 +286,7 @@ kvPutKv(KeyValue *this, const Variant *key)
}
MEM_CONTEXT_END();
return result;
FUNCTION_TEST_RESULT(KEY_VALUE, result);
}
/***********************************************************************************************************************************
@ -236,6 +295,14 @@ Get a value using the key
const Variant *
kvGet(const KeyValue *this, const Variant *key)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(KEY_VALUE, this);
FUNCTION_TEST_PARAM(VARIANT, key);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(key != NULL);
FUNCTION_TEST_END();
Variant *result = NULL;
// Find the key
@ -244,7 +311,7 @@ kvGet(const KeyValue *this, const Variant *key)
if (listIdx != KEY_NOT_FOUND)
result = ((KeyValuePair *)lstGet(this->list, listIdx))->value;
return result;
FUNCTION_TEST_RESULT(VARIANT, result);
}
/***********************************************************************************************************************************
@ -253,6 +320,14 @@ Get a value as a list (even if there is only one value) using the key
VariantList *
kvGetList(const KeyValue *this, const Variant *key)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(KEY_VALUE, this);
FUNCTION_TEST_PARAM(VARIANT, key);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(key != NULL);
FUNCTION_TEST_END();
VariantList *result = NULL;
// Get the value
@ -264,7 +339,7 @@ kvGetList(const KeyValue *this, const Variant *key)
else
result = varLstAdd(varLstNew(), varDup(value));
return result;
FUNCTION_TEST_RESULT(VARIANT_LIST, result);
}
/***********************************************************************************************************************************
@ -273,5 +348,12 @@ Free the string
void
kvFree(KeyValue *this)
{
memContextFree(this->memContext);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(KEY_VALUE, this);
FUNCTION_TEST_END();
if (this != NULL)
memContextFree(this->memContext);
FUNCTION_TEST_RESULT_VOID();
}

View File

@ -24,4 +24,12 @@ const Variant *kvGet(const KeyValue *this, const Variant *key);
VariantList *kvGetList(const KeyValue *this, const Variant *key);
void kvFree(KeyValue *this);
/***********************************************************************************************************************************
Macros for function logging
***********************************************************************************************************************************/
#define FUNCTION_DEBUG_KEY_VALUE_TYPE \
KeyValue *
#define FUNCTION_DEBUG_KEY_VALUE_FORMAT(value, buffer, bufferSize) \
objToLog(value, "KeyValue", buffer, bufferSize)
#endif

View File

@ -2,9 +2,11 @@
List Handler
***********************************************************************************************************************************/
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "common/debug.h"
#include "common/type/list.h"
/***********************************************************************************************************************************
@ -25,6 +27,8 @@ Create a new list
List *
lstNew(size_t itemSize)
{
FUNCTION_TEST_VOID();
List *this = NULL;
MEM_CONTEXT_NEW_BEGIN("List")
@ -36,8 +40,7 @@ lstNew(size_t itemSize)
}
MEM_CONTEXT_NEW_END();
// Return buffer
return this;
FUNCTION_TEST_RESULT(LIST, this);
}
/***********************************************************************************************************************************
@ -46,6 +49,14 @@ Add an item to the end of the list
List *
lstAdd(List *this, const void *item)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(LIST, this);
FUNCTION_TEST_PARAM(VOIDP, item);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(item != NULL);
FUNCTION_TEST_END();
// If list size = max then allocate more space
if (this->listSize == this->listSizeMax)
{
@ -70,8 +81,7 @@ lstAdd(List *this, const void *item)
memcpy(this->list + (this->listSize * this->itemSize), item, this->itemSize);
this->listSize++;
// Return list
return this;
FUNCTION_TEST_RESULT(LIST, this);
}
/***********************************************************************************************************************************
@ -80,12 +90,19 @@ Get an item from the list
void *
lstGet(const List *this, unsigned int listIdx)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(LIST, this);
FUNCTION_TEST_PARAM(UINT, listIdx);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
// Ensure list index is in range
if (listIdx >= this->listSize)
THROW_FMT(AssertError, "cannot get index %u from list with %u value(s)", listIdx, this->listSize);
// Return pointer to list item
return this->list + (listIdx * this->itemSize);
FUNCTION_TEST_RESULT(VOIDP, this->list + (listIdx * this->itemSize));
}
/***********************************************************************************************************************************
@ -94,7 +111,13 @@ Return the memory context for this list
MemContext *
lstMemContext(const List *this)
{
return this->memContext;
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(LIST, this);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(MEM_CONTEXT, this->memContext);
}
/***********************************************************************************************************************************
@ -103,10 +126,17 @@ Move the string list
List *
lstMove(List *this, MemContext *parentNew)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(LIST, this);
FUNCTION_TEST_PARAM(MEM_CONTEXT, parentNew);
FUNCTION_TEST_ASSERT(parentNew != NULL);
FUNCTION_TEST_END();
if (this != NULL)
memContextMove(this->memContext, parentNew);
return this;
FUNCTION_TEST_RESULT(LIST, this);
}
/***********************************************************************************************************************************
@ -115,7 +145,13 @@ Return list size
unsigned int
lstSize(const List *this)
{
return this->listSize;
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(LIST, this);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(UINT, this->listSize);
}
/***********************************************************************************************************************************
@ -124,9 +160,41 @@ List sort
List *
lstSort(List *this, int (*comparator)(const void *, const void*))
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(LIST, this);
FUNCTION_TEST_PARAM(FUNCTIONP, comparator);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(comparator != NULL);
FUNCTION_TEST_END();
qsort(this->list, this->listSize, this->itemSize, comparator);
return this;
FUNCTION_TEST_RESULT(LIST, this);
}
/***********************************************************************************************************************************
Convert to a zero-terminated string for logging
***********************************************************************************************************************************/
size_t
lstToLog(const List *this, char *buffer, size_t bufferSize)
{
size_t result = 0;
MEM_CONTEXT_TEMP_BEGIN()
{
String *string = NULL;
if (this == NULL)
string = strNew("null");
else
string = strNewFmt("{size: %u}", this->listSize);
result = (size_t)snprintf(buffer, bufferSize, "%s", strPtr(string));
}
MEM_CONTEXT_TEMP_END();
return result;
}
/***********************************************************************************************************************************
@ -135,6 +203,12 @@ Free the string
void
lstFree(List *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(LIST, this);
FUNCTION_TEST_END();
if (this != NULL)
memContextFree(this->memContext);
FUNCTION_TEST_RESULT_VOID();
}

View File

@ -29,4 +29,14 @@ unsigned int lstSize(const List *this);
List *lstSort(List *this, int (*comparator)(const void *, const void*));
void lstFree(List *this);
/***********************************************************************************************************************************
Macros for function logging
***********************************************************************************************************************************/
size_t lstToLog(const List *this, char *buffer, size_t bufferSize);
#define FUNCTION_DEBUG_LIST_TYPE \
List *
#define FUNCTION_DEBUG_LIST_FORMAT(value, buffer, bufferSize) \
lstToLog(value, buffer, bufferSize)
#endif

View File

@ -8,6 +8,7 @@ String Handler
#include <string.h>
#include "common/assert.h"
#include "common/debug.h"
#include "common/memContext.h"
#include "common/type/string.h"
@ -27,6 +28,12 @@ Create a new string from a zero-terminated string
String *
strNew(const char *string)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRINGZ, string);
FUNCTION_TEST_ASSERT(string != NULL);
FUNCTION_TEST_END();
// Create object
String *this = memNew(sizeof(String));
this->memContext = memContextCurrent();
@ -36,8 +43,7 @@ strNew(const char *string)
this->buffer = memNewRaw(this->size + 1);
strcpy(this->buffer, string);
// Return buffer
return this;
FUNCTION_TEST_RESULT(STRING, this);
}
/***********************************************************************************************************************************
@ -49,6 +55,12 @@ character will be used as a string.
String *
strNewBuf(const Buffer *buffer)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(BUFFER, buffer);
FUNCTION_TEST_ASSERT(buffer != NULL);
FUNCTION_TEST_END();
// Create object
String *this = memNew(sizeof(String));
this->memContext = memContextCurrent();
@ -59,8 +71,7 @@ strNewBuf(const Buffer *buffer)
memcpy(this->buffer, (char *)bufPtr(buffer), this->size);
this->buffer[this->size] = 0;
// Return buffer
return this;
FUNCTION_TEST_RESULT(STRING, this);
}
/***********************************************************************************************************************************
@ -69,6 +80,12 @@ Create a new string from a format string with parameters (i.e. sprintf)
String *
strNewFmt(const char *format, ...)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRINGZ, format);
FUNCTION_TEST_ASSERT(format != NULL);
FUNCTION_TEST_END();
// Create object
String *this = memNew(sizeof(String));
this->memContext = memContextCurrent();
@ -85,8 +102,7 @@ strNewFmt(const char *format, ...)
vsnprintf(this->buffer, this->size + 1, format, argumentList);
va_end(argumentList);
// Return buffer
return this;
FUNCTION_TEST_RESULT(STRING, this);
}
/***********************************************************************************************************************************
@ -97,6 +113,13 @@ The string may or may not be zero-terminated but we'll use that nomeclature sinc
String *
strNewN(const char *string, size_t size)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(CHARP, string);
FUNCTION_TEST_PARAM(SIZE, size);
FUNCTION_TEST_ASSERT(string != NULL);
FUNCTION_TEST_END();
// Create object
String *this = memNew(sizeof(String));
this->memContext = memContextCurrent();
@ -108,7 +131,7 @@ strNewN(const char *string, size_t size)
this->buffer[this->size] = 0;
// Return buffer
return this;
FUNCTION_TEST_RESULT(STRING, this);
}
/***********************************************************************************************************************************
@ -117,12 +140,18 @@ Return the file part of a string (i.e. everything after the last / or the entire
String *
strBase(const String *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, this);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
const char *end = this->buffer + this->size;
while (end > this->buffer && *(end - 1) != '/')
end--;
return strNew(end);
FUNCTION_TEST_RESULT(STRING, strNew(end));
}
/***********************************************************************************************************************************
@ -131,19 +160,35 @@ Does the string begin with the specified string?
bool
strBeginsWith(const String *this, const String *beginsWith)
{
return strBeginsWithZ(this, strPtr(beginsWith));
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, this);
FUNCTION_TEST_PARAM(STRING, beginsWith);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(beginsWith != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(BOOL, strBeginsWithZ(this, strPtr(beginsWith)));
}
bool
strBeginsWithZ(const String *this, const char *beginsWith)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, this);
FUNCTION_TEST_PARAM(STRINGZ, beginsWith);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(beginsWith != NULL);
FUNCTION_TEST_END();
bool result = false;
unsigned int beginsWithSize = (unsigned int)strlen(beginsWith);
if (this->size >= beginsWithSize)
result = strncmp(strPtr(this), beginsWith, beginsWithSize) == 0;
return result;
FUNCTION_TEST_RESULT(BOOL, result);
}
/***********************************************************************************************************************************
@ -152,6 +197,14 @@ Append a string
String *
strCat(String *this, const char *cat)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, this);
FUNCTION_TEST_PARAM(STRINGZ, cat);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(cat != NULL);
FUNCTION_TEST_END();
// Determine length of string to append
size_t sizeGrow = strlen(cat);
@ -165,7 +218,7 @@ strCat(String *this, const char *cat)
strcpy(this->buffer + this->size, cat);
this->size += sizeGrow;
return this;
FUNCTION_TEST_RESULT(STRING, this);
}
/***********************************************************************************************************************************
@ -174,6 +227,14 @@ Append a formatted string
String *
strCatFmt(String *this, const char *format, ...)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, this);
FUNCTION_TEST_PARAM(STRINGZ, format);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(format != NULL);
FUNCTION_TEST_END();
// Determine how long the allocated string needs to be
va_list argumentList;
va_start(argumentList, format);
@ -193,8 +254,7 @@ strCatFmt(String *this, const char *format, ...)
this->size += sizeGrow;
// Return buffer
return this;
FUNCTION_TEST_RESULT(STRING, this);
}
/***********************************************************************************************************************************
@ -203,13 +263,29 @@ C-style string compare
int
strCmp(const String *this, const String *compare)
{
return strcmp(strPtr(this), strPtr(compare));
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, this);
FUNCTION_TEST_PARAM(STRING, compare);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(compare != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(INT, strcmp(strPtr(this), strPtr(compare)));
}
int
strCmpZ(const String *this, const char *compare)
{
return strcmp(strPtr(this), compare);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, this);
FUNCTION_TEST_PARAM(STRINGZ, compare);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(compare != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(INT, strcmp(strPtr(this), compare));
}
/***********************************************************************************************************************************
@ -218,12 +294,16 @@ Duplicate a string from an existing string
String *
strDup(const String *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, this);
FUNCTION_TEST_END();
String *result = NULL;
if (this != NULL)
result = strNew(strPtr(this));
return result;
FUNCTION_TEST_RESULT(STRING, result);
}
/***********************************************************************************************************************************
@ -232,19 +312,35 @@ Does the string end with the specified string?
bool
strEndsWith(const String *this, const String *endsWith)
{
return strEndsWithZ(this, strPtr(endsWith));
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, this);
FUNCTION_TEST_PARAM(STRING, endsWith);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(endsWith != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(BOOL, strEndsWithZ(this, strPtr(endsWith)));
}
bool
strEndsWithZ(const String *this, const char *endsWith)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, this);
FUNCTION_TEST_PARAM(STRINGZ, endsWith);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(endsWith != NULL);
FUNCTION_TEST_END();
bool result = false;
unsigned int endsWithSize = (unsigned int)strlen(endsWith);
if (this->size >= endsWithSize)
result = strcmp(strPtr(this) + (this->size - endsWithSize), endsWith) == 0;
return result;
FUNCTION_TEST_RESULT(BOOL, result);
}
/***********************************************************************************************************************************
@ -256,18 +352,34 @@ would need a call to strlen().
bool
strEq(const String *this, const String *compare)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, this);
FUNCTION_TEST_PARAM(STRING, compare);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(compare != NULL);
FUNCTION_TEST_END();
bool result = false;
if (this->size == compare->size)
result = strcmp(strPtr(this), strPtr(compare)) == 0;
return result;
FUNCTION_TEST_RESULT(BOOL, result);
}
bool
strEqZ(const String *this, const char *compare)
{
return strcmp(strPtr(this), compare) == 0;
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, this);
FUNCTION_TEST_PARAM(STRINGZ, compare);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(compare != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(BOOL, strcmp(strPtr(this), compare) == 0);
}
/***********************************************************************************************************************************
@ -276,10 +388,16 @@ Upper-case the first letter
String *
strFirstUpper(String *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, this);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
if (this->size > 0)
this->buffer[0] = (char)toupper(this->buffer[0]);
return this;
FUNCTION_TEST_RESULT(STRING, this);
}
/***********************************************************************************************************************************
@ -288,10 +406,16 @@ Lower-case the first letter
String *
strFirstLower(String *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, this);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
if (this->size > 0)
this->buffer[0] = (char)tolower(this->buffer[0]);
return this;
FUNCTION_TEST_RESULT(STRING, this);
}
/***********************************************************************************************************************************
@ -300,11 +424,17 @@ Upper-case entire string
String *
strUpper(String *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, this);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
if (this->size > 0)
for (unsigned int idx = 0; idx <= this->size; idx++)
this->buffer[idx] = (char)toupper(this->buffer[idx]);
return this;
FUNCTION_TEST_RESULT(STRING, this);
}
/***********************************************************************************************************************************
@ -313,11 +443,17 @@ Upper-case entire string
String *
strLower(String *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, this);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
if (this->size > 0)
for (unsigned int idx = 0; idx <= this->size; idx++)
this->buffer[idx] = (char)tolower(this->buffer[idx]);
return this;
FUNCTION_TEST_RESULT(STRING, this);
}
/***********************************************************************************************************************************
@ -326,12 +462,19 @@ Return the path part of a string (i.e. everything before the last / or "" if the
String *
strPath(const String *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, this);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
const char *end = this->buffer + this->size;
while (end > this->buffer && *(end - 1) != '/')
end--;
return strNewN(this->buffer, end - this->buffer <= 1 ? (size_t)(end - this->buffer) : (size_t)(end - this->buffer - 1));
FUNCTION_TEST_RESULT(
STRING, strNewN(this->buffer, end - this->buffer <= 1 ? (size_t)(end - this->buffer) : (size_t)(end - this->buffer - 1)));
}
/***********************************************************************************************************************************
@ -340,12 +483,47 @@ Return string ptr
const char *
strPtr(const String *this)
{
const char *result = NULL;
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, this);
FUNCTION_TEST_END();
char *result = NULL;
if (this != NULL)
result = (const char *)this->buffer;
result = this->buffer;
return result;
FUNCTION_TEST_RESULT(CHARP, result);
}
/***********************************************************************************************************************************
Quote a string
***********************************************************************************************************************************/
String *
strQuote(const String *this, const String *quote)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, this);
FUNCTION_TEST_PARAM(STRING, quote);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(quote != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(STRING, strQuoteZ(this, strPtr(quote)));
}
String *
strQuoteZ(const String *this, const char *quote)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, this);
FUNCTION_TEST_PARAM(STRINGZ, quote);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(quote != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(STRING, strNewFmt("%s%s%s", quote, strPtr(this), quote));
}
/***********************************************************************************************************************************
@ -354,7 +532,15 @@ Return a substring given only the start position
String *
strSub(const String *this, size_t start)
{
return strSubN(this, start, this->size - start);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, this);
FUNCTION_TEST_PARAM(SIZE, start);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(start < this->size);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(STRING, strSubN(this, start, this->size - start));
}
/***********************************************************************************************************************************
@ -363,10 +549,17 @@ Return a substring given the start position and size
String *
strSubN(const String *this, size_t start, size_t size)
{
ASSERT(start < this->size);
ASSERT(start + size <= this->size);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, this);
FUNCTION_TEST_PARAM(SIZE, start);
FUNCTION_TEST_PARAM(SIZE, size);
return strNewN(this->buffer + start, size);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(start < this->size);
FUNCTION_TEST_ASSERT(start + size <= this->size);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(STRING, strNewN(this->buffer + start, size));
}
/***********************************************************************************************************************************
@ -375,7 +568,13 @@ Return string size
size_t
strSize(const String *this)
{
return this->size;
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, this);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(SIZE, this->size);
}
/***********************************************************************************************************************************
@ -384,6 +583,12 @@ Trim whitespace from the beginnning and end of a string
String *
strTrim(String *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, this);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
// Nothing to trim if size is zero
if (this->size > 0)
{
@ -420,7 +625,7 @@ strTrim(String *this)
}
}
return this;
FUNCTION_TEST_RESULT(STRING, this);
}
/***********************************************************************************************************************************
@ -429,16 +634,23 @@ Return the index to the location of the the first occurrence of a character with
int
strChr(const String *this, char chr)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, this);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
int result = -1;
if (this->size > 0)
{
const char *ptr = strchr(this->buffer, chr);
if (ptr != NULL)
result = (int)(ptr - this->buffer);
result = (int)(ptr - this->buffer);
}
return result;
FUNCTION_TEST_RESULT(INT, result);
}
/***********************************************************************************************************************************
@ -447,9 +659,12 @@ Truncate the end of a string from the index provided to the current end (e.g. 12
String *
strTrunc(String *this, int idx)
{
// If the index position is outside the array boundaries then error
if (idx < 0 || (size_t)idx > this->size)
THROW_FMT(AssertError, "index passed is outside the string boundaries");
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, this);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(idx >= 0 && (size_t)idx <= this->size);
FUNCTION_TEST_END();
if (this->size > 0)
{
@ -465,7 +680,31 @@ strTrunc(String *this, int idx)
MEM_CONTEXT_END();
}
return this;
FUNCTION_TEST_RESULT(STRING, this);
}
/***********************************************************************************************************************************
Convert to a zero-terminated string for logging
***********************************************************************************************************************************/
size_t
strToLog(const String *this, char *buffer, size_t bufferSize)
{
size_t result = 0;
MEM_CONTEXT_TEMP_BEGIN()
{
String *string = NULL;
if (this == NULL)
string = strNew("null");
else
string = strNewFmt("{\"%s\"}", strPtr(this));
result = (size_t)snprintf(buffer, bufferSize, "%s", strPtr(string));
}
MEM_CONTEXT_TEMP_END();
return result;
}
/***********************************************************************************************************************************
@ -474,6 +713,10 @@ Free the string
void
strFree(String *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, this);
FUNCTION_TEST_END();
if (this != NULL)
{
MEM_CONTEXT_BEGIN(this->memContext)
@ -483,4 +726,6 @@ strFree(String *this)
}
MEM_CONTEXT_END();
}
FUNCTION_TEST_RESULT_VOID();
}

View File

@ -37,6 +37,8 @@ String *strUpper(String *this);
String *strLower(String *this);
String *strPath(const String *this);
const char *strPtr(const String *this);
String *strQuote(const String *this, const String *quote);
String *strQuoteZ(const String *this, const char *quote);
size_t strSize(const String *this);
String *strSub(const String *this, size_t start);
String *strSubN(const String *this, size_t start, size_t size);
@ -46,4 +48,24 @@ String *strTrunc(String *this, int idx);
void strFree(String *this);
/***********************************************************************************************************************************
Macros for function logging
***********************************************************************************************************************************/
size_t strToLog(const String *this, char *buffer, size_t bufferSize);
#define FUNCTION_DEBUG_CONST_STRING_TYPE \
const String *
#define FUNCTION_DEBUG_CONST_STRING_FORMAT(value, buffer, bufferSize) \
FUNCTION_DEBUG_STRING_FORMAT(value, buffer, bufferSize)
#define FUNCTION_DEBUG_STRING_TYPE \
String *
#define FUNCTION_DEBUG_STRING_FORMAT(value, buffer, bufferSize) \
strToLog(value, buffer, bufferSize)
#define FUNCTION_DEBUG_STRINGP_TYPE \
const String **
#define FUNCTION_DEBUG_STRINGP_FORMAT(value, buffer, bufferSize) \
ptrToLog(value, "String **", buffer, bufferSize)
#endif

View File

@ -2,9 +2,12 @@
String List Handler
***********************************************************************************************************************************/
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "common/assert.h"
#include "common/debug.h"
#include "common/memContext.h"
#include "common/type/list.h"
#include "common/type/stringList.h"
@ -15,7 +18,8 @@ Wrapper for lstNew()
StringList *
strLstNew()
{
return (StringList *)lstNew(sizeof(String *));
FUNCTION_TEST_VOID();
FUNCTION_TEST_RESULT(STRING_LIST, (StringList *)lstNew(sizeof(String *)));
}
/***********************************************************************************************************************************
@ -24,7 +28,14 @@ Internal add -- the string must have been created in the list's mem context befo
static StringList *
strLstAddInternal(StringList *this, String *string)
{
return (StringList *)lstAdd((List *)this, &string);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING_LIST, this);
FUNCTION_TEST_PARAM(STRING, string);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(STRING_LIST, (StringList *)lstAdd((List *)this, &string));
}
/***********************************************************************************************************************************
@ -33,12 +44,28 @@ Split a string into a string list based on a delimiter
StringList *
strLstNewSplit(const String *string, const String *delimiter)
{
return strLstNewSplitZ(string, strPtr(delimiter));
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, string);
FUNCTION_TEST_PARAM(STRING, delimiter);
FUNCTION_TEST_ASSERT(string != NULL);
FUNCTION_TEST_ASSERT(delimiter != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(STRING_LIST, strLstNewSplitZ(string, strPtr(delimiter)));
}
StringList *
strLstNewSplitZ(const String *string, const char *delimiter)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, string);
FUNCTION_TEST_PARAM(STRINGZ, delimiter);
FUNCTION_TEST_ASSERT(string != NULL);
FUNCTION_TEST_ASSERT(delimiter != NULL);
FUNCTION_TEST_END();
// Create the list
StringList *this = strLstNew();
@ -69,7 +96,7 @@ strLstNewSplitZ(const String *string, const char *delimiter)
}
MEM_CONTEXT_END();
return this;
FUNCTION_TEST_RESULT(STRING_LIST, this);
}
/***********************************************************************************************************************************
@ -81,12 +108,30 @@ breaking up test on spaces, for example.
StringList *
strLstNewSplitSize(const String *string, const String *delimiter, size_t size)
{
return strLstNewSplitSizeZ(string, strPtr(delimiter), size);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, string);
FUNCTION_TEST_PARAM(STRING, delimiter);
FUNCTION_TEST_PARAM(SIZE, size);
FUNCTION_TEST_ASSERT(string != NULL);
FUNCTION_TEST_ASSERT(delimiter != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(STRING_LIST, strLstNewSplitSizeZ(string, strPtr(delimiter), size));
}
StringList *
strLstNewSplitSizeZ(const String *string, const char *delimiter, size_t size)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, string);
FUNCTION_TEST_PARAM(STRINGZ, delimiter);
FUNCTION_TEST_PARAM(SIZE, size);
FUNCTION_TEST_ASSERT(string != NULL);
FUNCTION_TEST_ASSERT(delimiter != NULL);
FUNCTION_TEST_END();
// Create the list
StringList *this = strLstNew();
@ -135,7 +180,7 @@ strLstNewSplitSizeZ(const String *string, const char *delimiter, size_t size)
}
MEM_CONTEXT_END();
return this;
FUNCTION_TEST_RESULT(STRING_LIST, this);
}
/***********************************************************************************************************************************
@ -144,6 +189,12 @@ New string list from a variant list -- all variants in the list must be type str
StringList *
strLstNewVarLst(const VariantList *sourceList)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(VARIANT_LIST, sourceList);
FUNCTION_TEST_ASSERT(sourceList != NULL);
FUNCTION_TEST_END();
// Create the list
StringList *this = strLstNew();
@ -155,7 +206,7 @@ strLstNewVarLst(const VariantList *sourceList)
}
MEM_CONTEXT_END();
return this;
FUNCTION_TEST_RESULT(STRING_LIST, this);
}
/***********************************************************************************************************************************
@ -164,6 +215,12 @@ Duplicate a string list
StringList *
strLstDup(const StringList *sourceList)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING_LIST, sourceList);
FUNCTION_TEST_ASSERT(sourceList != NULL);
FUNCTION_TEST_END();
// Create the list
StringList *this = strLstNew();
@ -175,7 +232,7 @@ strLstDup(const StringList *sourceList)
}
MEM_CONTEXT_END();
return this;
FUNCTION_TEST_RESULT(STRING_LIST, this);
}
/***********************************************************************************************************************************
@ -184,6 +241,13 @@ Does the specified string exist in the list?
bool
strLstExists(const StringList *this, const String *string)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING_LIST, this);
FUNCTION_TEST_PARAM(STRING, string);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
bool result = false;
for (unsigned int listIdx = 0; listIdx < strLstSize(this); listIdx++)
@ -195,12 +259,19 @@ strLstExists(const StringList *this, const String *string)
}
}
return result;
FUNCTION_TEST_RESULT(BOOL, result);
}
bool
strLstExistsZ(const StringList *this, const char *cstring)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING_LIST, this);
FUNCTION_TEST_PARAM(STRINGZ, cstring);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
bool result = false;
for (unsigned int listIdx = 0; listIdx < strLstSize(this); listIdx++)
@ -212,7 +283,7 @@ strLstExistsZ(const StringList *this, const char *cstring)
}
}
return result;
FUNCTION_TEST_RESULT(BOOL, result);
}
/***********************************************************************************************************************************
@ -221,6 +292,13 @@ Wrapper for lstAdd()
StringList *
strLstAdd(StringList *this, const String *string)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING_LIST, this);
FUNCTION_TEST_PARAM(STRING, string);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
StringList *result = NULL;
MEM_CONTEXT_BEGIN(lstMemContext((List *)this))
@ -229,7 +307,7 @@ strLstAdd(StringList *this, const String *string)
}
MEM_CONTEXT_END();
return result;
FUNCTION_TEST_RESULT(STRING_LIST, result);
}
/***********************************************************************************************************************************
@ -238,6 +316,13 @@ Add a zero-terminated string to the list
StringList *
strLstAddZ(StringList *this, const char *string)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING_LIST, this);
FUNCTION_TEST_PARAM(STRINGZ, string);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
StringList *result = NULL;
MEM_CONTEXT_BEGIN(lstMemContext((List *)this))
@ -246,7 +331,7 @@ strLstAddZ(StringList *this, const char *string)
}
MEM_CONTEXT_END();
return result;
FUNCTION_TEST_RESULT(STRING_LIST, result);
}
/***********************************************************************************************************************************
@ -255,7 +340,14 @@ Wrapper for lstGet()
String *
strLstGet(const StringList *this, unsigned int listIdx)
{
return *(String **)lstGet((List *)this, listIdx);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING_LIST, this);
FUNCTION_TEST_PARAM(UINT, listIdx);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(STRING, *(String **)lstGet((List *)this, listIdx));
}
/***********************************************************************************************************************************
@ -264,6 +356,33 @@ Join a list of strings into a single string using the specified separator
String *
strLstJoin(const StringList *this, const char *separator)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING_LIST, this);
FUNCTION_TEST_PARAM(STRINGZ, separator);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(separator != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(STRING, strLstJoinQuote(this, separator, ""));
}
/***********************************************************************************************************************************
Join a list of strings into a single string using the specified separator and quote with specified quote character
***********************************************************************************************************************************/
String *
strLstJoinQuote(const StringList *this, const char *separator, const char *quote)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING_LIST, this);
FUNCTION_TEST_PARAM(STRINGZ, separator);
FUNCTION_TEST_PARAM(STRINGZ, quote);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(separator != NULL);
FUNCTION_TEST_ASSERT(quote != NULL);
FUNCTION_TEST_END();
String *join = strNew("");
for (unsigned int listIdx = 0; listIdx < strLstSize(this); listIdx++)
@ -274,10 +393,10 @@ strLstJoin(const StringList *this, const char *separator)
if (strLstGet(this, listIdx) == NULL)
strCat(join, "[NULL]");
else
strCat(join, strPtr(strLstGet(this, listIdx)));
strCatFmt(join, "%s%s%s", quote, strPtr(strLstGet(this, listIdx)), quote);
}
return join;
FUNCTION_TEST_RESULT(STRING, join);
}
/***********************************************************************************************************************************
@ -286,8 +405,16 @@ Move the string list
StringList *
strLstMove(StringList *this, MemContext *parentNew)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING_LIST, this);
FUNCTION_TEST_PARAM(MEM_CONTEXT, parentNew);
FUNCTION_TEST_ASSERT(parentNew != NULL);
FUNCTION_TEST_END();
lstMove((List *)this, parentNew);
return this;
FUNCTION_TEST_RESULT(STRING_LIST, this);
}
/***********************************************************************************************************************************
@ -297,6 +424,12 @@ this array, though it is OK to modify the array itself.
const char **
strLstPtr(const StringList *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING_LIST, this);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
const char **list = memNew(strLstSize(this) * sizeof(char *));
for (unsigned int listIdx = 0; listIdx < strLstSize(this); listIdx++)
@ -307,7 +440,7 @@ strLstPtr(const StringList *this)
list[listIdx] = strPtr(strLstGet(this, listIdx));
}
return list;
FUNCTION_TEST_RESULT(CONST_CHARPP, list);
}
/***********************************************************************************************************************************
@ -316,7 +449,13 @@ Wrapper for lstSize()
unsigned int
strLstSize(const StringList *this)
{
return lstSize((List *)this);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING_LIST, this);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(UINT, lstSize((List *)this));
}
/***********************************************************************************************************************************
@ -325,18 +464,41 @@ Sort strings in alphabetical order
static int
sortAscComparator(const void *item1, const void *item2)
{
return strCmp(*(String **)item1, *(String **)item2);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(VOIDP, item1);
FUNCTION_TEST_PARAM(VOIDP, item2);
FUNCTION_TEST_ASSERT(item1 != NULL);
FUNCTION_TEST_ASSERT(item2 != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(INT, strCmp(*(String **)item1, *(String **)item2));
}
static int
sortDescComparator(const void *item1, const void *item2)
{
return strCmp(*(String **)item2, *(String **)item1);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(VOIDP, item1);
FUNCTION_TEST_PARAM(VOIDP, item2);
FUNCTION_TEST_ASSERT(item1 != NULL);
FUNCTION_TEST_ASSERT(item2 != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(INT, strCmp(*(String **)item2, *(String **)item1));
}
StringList *
strLstSort(StringList *this, SortOrder sortOrder)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING_LIST, this);
FUNCTION_TEST_PARAM(ENUM, sortOrder);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
switch (sortOrder)
{
case sortOrderAsc:
@ -351,7 +513,32 @@ strLstSort(StringList *this, SortOrder sortOrder)
break;
}
}
return this;
FUNCTION_TEST_RESULT(STRING_LIST, this);
}
/***********************************************************************************************************************************
Convert to a zero-terminated string for logging
***********************************************************************************************************************************/
size_t
strLstToLog(const StringList *this, char *buffer, size_t bufferSize)
{
size_t result = 0;
MEM_CONTEXT_TEMP_BEGIN()
{
String *string = NULL;
if (this == NULL)
string = strNew("null");
else
string = strNewFmt("{[%s]}", strPtr(strLstJoinQuote(this, ", ", "\"")));
result = (size_t)snprintf(buffer, bufferSize, "%s", strPtr(string));
}
MEM_CONTEXT_TEMP_END();
return result;
}
/***********************************************************************************************************************************
@ -360,5 +547,11 @@ Wrapper for lstFree()
void
strLstFree(StringList *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING_LIST, this);
FUNCTION_TEST_END();
lstFree((List *)this);
FUNCTION_TEST_RESULT_VOID();
}

View File

@ -39,6 +39,7 @@ bool strLstExists(const StringList *this, const String *string);
bool strLstExistsZ(const StringList *this, const char *cstring);
String *strLstGet(const StringList *this, unsigned int listIdx);
String *strLstJoin(const StringList *this, const char *separator);
String *strLstJoinQuote(const StringList *this, const char *separator, const char *quote);
StringList * strLstMove(StringList *this, MemContext *parentNew);
const char **strLstPtr(const StringList *this);
unsigned int strLstSize(const StringList *this);
@ -46,4 +47,14 @@ StringList *strLstSort(StringList *this, SortOrder sortOrder);
void strLstFree(StringList *this);
/***********************************************************************************************************************************
Macros for function logging
***********************************************************************************************************************************/
size_t strLstToLog(const StringList *this, char *buffer, size_t bufferSize);
#define FUNCTION_DEBUG_STRING_LIST_TYPE \
StringList *
#define FUNCTION_DEBUG_STRING_LIST_FORMAT(value, buffer, bufferSize) \
strLstToLog(value, buffer, bufferSize)
#endif

View File

@ -8,7 +8,9 @@ Variant Data Type
#include <strings.h>
#include "common/assert.h"
#include "common/debug.h"
#include "common/memContext.h"
#include "common/type/convert.h"
#include "common/type/variant.h"
/***********************************************************************************************************************************
@ -40,9 +42,14 @@ New variant of any supported type
static Variant *
varNewInternal(VariantType type, void *data, size_t dataSize)
{
// Make sure there is some data to store
ASSERT_DEBUG(dataSize > 0);
ASSERT_DEBUG(data != NULL);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, type);
FUNCTION_TEST_PARAM(VOIDP, data);
FUNCTION_TEST_PARAM(SIZE, dataSize);
FUNCTION_TEST_ASSERT(data != NULL);
FUNCTION_TEST_ASSERT(dataSize > 0);
FUNCTION_TEST_END();
// Allocate memory for the variant and set the type
Variant *this = memNew(sizeof(Variant) + dataSize);
@ -52,7 +59,7 @@ varNewInternal(VariantType type, void *data, size_t dataSize)
// Copy data
memcpy((unsigned char *)this + sizeof(Variant), data, dataSize);
return this;
FUNCTION_TEST_RESULT(VARIANT, this);
}
/***********************************************************************************************************************************
@ -61,7 +68,13 @@ Get a pointer to the data stored in the variant. This hides the complicated poi
static void *
varData(const Variant *this)
{
return (void *)((unsigned char *)this + sizeof(Variant));
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(VARIANT, this);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(VOIDP, (void *)((unsigned char *)this + sizeof(Variant)));
}
/***********************************************************************************************************************************
@ -70,6 +83,10 @@ Duplicate a variant
Variant *
varDup(const Variant *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(VARIANT, this);
FUNCTION_TEST_END();
Variant *result = NULL;
if (this != NULL)
@ -121,7 +138,7 @@ varDup(const Variant *this)
}
}
return result;
FUNCTION_TEST_RESULT(VARIANT, result);
}
/***********************************************************************************************************************************
@ -130,6 +147,11 @@ Test if variants are equal
bool
varEq(const Variant *this1, const Variant *this2)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(VARIANT, this1);
FUNCTION_TEST_PARAM(VARIANT, this2);
FUNCTION_TEST_END();
bool result = false;
// Test if both variants are non-null
@ -180,7 +202,7 @@ varEq(const Variant *this1, const Variant *this2)
else
result = this1 == NULL && this2 == NULL;
return result;
FUNCTION_TEST_RESULT(BOOL, result);
}
/***********************************************************************************************************************************
@ -189,7 +211,13 @@ Get variant type
VariantType
varType(const Variant *this)
{
return this->type;
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(VARIANT, this);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(ENUM, this->type);
}
/***********************************************************************************************************************************
@ -198,7 +226,11 @@ New bool variant
Variant *
varNewBool(bool data)
{
return varNewInternal(varTypeBool, (void *)&data, sizeof(data));
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(BOOL, data);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(VARIANT, varNewInternal(varTypeBool, (void *)&data, sizeof(data)));
}
/***********************************************************************************************************************************
@ -207,12 +239,15 @@ Return bool
bool
varBool(const Variant *this)
{
// Only valid for int
if (this->type != varTypeBool)
THROW(AssertError, "variant type is not bool");
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(VARIANT, this);
// Get the int
return *((bool *)varData(this));
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
ASSERT(this->type == varTypeBool);
FUNCTION_TEST_RESULT(BOOL, *((bool *)varData(this)));
}
/***********************************************************************************************************************************
@ -221,6 +256,12 @@ Return bool regardless of variant type
bool
varBoolForce(const Variant *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(VARIANT, this);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
bool result = false;
switch (this->type)
@ -268,7 +309,7 @@ varBoolForce(const Variant *this)
THROW_FMT(FormatError, "unable to force %s to %s", variantTypeName[this->type], variantTypeName[varTypeBool]);
}
return result;
FUNCTION_TEST_RESULT(BOOL, result);
}
/***********************************************************************************************************************************
@ -277,7 +318,11 @@ New double variant
Variant *
varNewDbl(double data)
{
return varNewInternal(varTypeDouble, (unsigned char *)&data, sizeof(data));
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(DOUBLE, data);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(VARIANT, varNewInternal(varTypeDouble, (unsigned char *)&data, sizeof(data)));
}
/***********************************************************************************************************************************
@ -286,12 +331,15 @@ Return double
double
varDbl(const Variant *this)
{
// Only valid for double
if (this->type != varTypeDouble)
THROW(AssertError, "variant type is not double");
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(VARIANT, this);
// Get the int
return *((double *)varData(this));
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
ASSERT(this->type == varTypeDouble);
FUNCTION_TEST_RESULT(DOUBLE, *((double *)varData(this)));
}
/***********************************************************************************************************************************
@ -300,6 +348,12 @@ Return double regardless of variant type
double
varDblForce(const Variant *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(VARIANT, this);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
double result = 0;
switch (this->type)
@ -330,15 +384,7 @@ varDblForce(const Variant *this)
case varTypeString:
{
sscanf(strPtr(varStr(this)), "%lf", &result);
if (result == 0 && strcmp(strPtr(varStr(this)), "0") != 0)
{
THROW_FMT(
FormatError, "unable to force %s '%s' to %s", variantTypeName[this->type], strPtr(varStr(this)),
variantTypeName[varTypeDouble]);
}
result = cvtZToDouble(strPtr(varStr(this)));
break;
}
@ -346,7 +392,7 @@ varDblForce(const Variant *this)
THROW_FMT(FormatError, "unable to force %s to %s", variantTypeName[this->type], variantTypeName[varTypeDouble]);
}
return result;
FUNCTION_TEST_RESULT(DOUBLE, result);
}
/***********************************************************************************************************************************
@ -355,7 +401,11 @@ New int variant
Variant *
varNewInt(int data)
{
return varNewInternal(varTypeInt, (void *)&data, sizeof(data));
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(INT, data);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(VARIANT, varNewInternal(varTypeInt, (void *)&data, sizeof(data)));
}
/***********************************************************************************************************************************
@ -364,12 +414,15 @@ Return int
int
varInt(const Variant *this)
{
// Only valid for int
if (this->type != varTypeInt)
THROW(AssertError, "variant type is not int");
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(VARIANT, this);
// Get the int
return *((int *)varData(this));
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
ASSERT(this->type == varTypeInt);
FUNCTION_TEST_RESULT(INT, *((int *)varData(this)));
}
/***********************************************************************************************************************************
@ -378,6 +431,12 @@ Return int regardless of variant type
int
varIntForce(const Variant *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(VARIANT, this);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
int result = 0;
switch (this->type)
@ -409,11 +468,7 @@ varIntForce(const Variant *this)
case varTypeString:
{
result = atoi(strPtr(varStr(this)));
if (result == 0 && strcmp(strPtr(varStr(this)), "0") != 0)
THROW_FMT(FormatError, "unable to convert str '%s' to int", strPtr(varStr(this)));
result = cvtZToInt(strPtr(varStr(this)));
break;
}
@ -421,7 +476,7 @@ varIntForce(const Variant *this)
THROW_FMT(FormatError, "unable to force %s to %s", variantTypeName[this->type], variantTypeName[varTypeInt]);
}
return result;
FUNCTION_TEST_RESULT(INT, result);
}
/***********************************************************************************************************************************
@ -430,7 +485,11 @@ New int64 variant
Variant *
varNewInt64(int64_t data)
{
return varNewInternal(varTypeInt64, (void *)&data, sizeof(data));
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(INT64, data);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(VARIANT, varNewInternal(varTypeInt64, (void *)&data, sizeof(data)));
}
/***********************************************************************************************************************************
@ -439,12 +498,15 @@ Return int64
int64_t
varInt64(const Variant *this)
{
// Only valid for int
if (this->type != varTypeInt64)
THROW_FMT(AssertError, "variant type is not %s", variantTypeName[varTypeInt64]);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(VARIANT, this);
// Get the int
return *((int64_t *)varData(this));
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
ASSERT(this->type == varTypeInt64);
FUNCTION_TEST_RESULT(INT64, *((int64_t *)varData(this)));
}
/***********************************************************************************************************************************
@ -453,6 +515,12 @@ Return int64 regardless of variant type
int64_t
varInt64Force(const Variant *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(VARIANT, this);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
int64_t result = 0;
switch (this->type)
@ -477,16 +545,7 @@ varInt64Force(const Variant *this)
case varTypeString:
{
result = atoll(strPtr(varStr(this)));
char buffer[32];
snprintf(buffer, sizeof(buffer), "%" PRId64, result);
if (strcmp(strPtr(varStr(this)), buffer) != 0)
THROW_FMT(
FormatError, "unable to convert %s '%s' to %s", variantTypeName[varTypeString], strPtr(varStr(this)),
variantTypeName[varTypeInt64]);
result = cvtZToInt64(strPtr(varStr(this)));
break;
}
@ -494,7 +553,7 @@ varInt64Force(const Variant *this)
THROW_FMT(FormatError, "unable to force %s to %s", variantTypeName[this->type], variantTypeName[varTypeInt64]);
}
return result;
FUNCTION_TEST_RESULT(INT64, result);
}
/***********************************************************************************************************************************
@ -503,9 +562,12 @@ New key/value variant
Variant *
varNewKv()
{
// Create the variant
FUNCTION_TEST_VOID();
// Create a new kv for the variant
KeyValue *data = kvNew();
return varNewInternal(varTypeKeyValue, (void *)&data, sizeof(data));
FUNCTION_TEST_RESULT(VARIANT, varNewInternal(varTypeKeyValue, (void *)&data, sizeof(data)));
}
/***********************************************************************************************************************************
@ -514,19 +576,19 @@ Return key/value
KeyValue *
varKv(const Variant *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(VARIANT, this);
FUNCTION_TEST_END();
KeyValue *result = NULL;
if (this != NULL)
{
// Only valid for key/value
if (this->type != varTypeKeyValue)
THROW(AssertError, "variant type is not 'KeyValue'");
// Get the string
ASSERT(this->type == varTypeKeyValue);
result = *((KeyValue **)varData(this));
}
return result;
FUNCTION_TEST_RESULT(KEY_VALUE, result);
}
/***********************************************************************************************************************************
@ -535,13 +597,16 @@ New string variant
Variant *
varNewStr(const String *data)
{
// Make sure the string is not NULL
if (data == NULL)
THROW(AssertError, "string variant cannot be NULL");
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, data);
// Create the variant
FUNCTION_TEST_ASSERT(data != NULL);
FUNCTION_TEST_END();
// Create a copy of the string for the variant
String *dataCopy = strDup(data);
return varNewInternal(varTypeString, (void *)&dataCopy, sizeof(dataCopy));
FUNCTION_TEST_RESULT(VARIANT, varNewInternal(varTypeString, (void *)&dataCopy, sizeof(dataCopy)));
}
/***********************************************************************************************************************************
@ -550,13 +615,16 @@ New string variant from a zero-terminated string
Variant *
varNewStrZ(const char *data)
{
// Make sure the string is not NULL
if (data == NULL)
THROW(AssertError, "zero-terminated string cannot be NULL");
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRINGZ, data);
// Create the variant
FUNCTION_TEST_ASSERT(data != NULL);
FUNCTION_TEST_END();
// Create a string for the variant
String *dataCopy = strNew(data);
return varNewInternal(varTypeString, (void *)&dataCopy, sizeof(dataCopy));
FUNCTION_TEST_RESULT(VARIANT, varNewInternal(varTypeString, (void *)&dataCopy, sizeof(dataCopy)));
}
/***********************************************************************************************************************************
@ -565,19 +633,19 @@ Return string
String *
varStr(const Variant *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(VARIANT, this);
FUNCTION_TEST_END();
String *result = NULL;
if (this != NULL)
{
// Only valid for strings
if (this->type != varTypeString)
THROW(AssertError, "variant type is not string");
// Get the string
ASSERT(this->type == varTypeString);
result = *((String **)varData(this));
}
return result;
FUNCTION_TEST_RESULT(STRING, result);
}
/***********************************************************************************************************************************
@ -586,60 +654,51 @@ Return string regardless of variant type
String *
varStrForce(const Variant *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(VARIANT, this);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
String *result = NULL;
switch (varType(this))
{
case varTypeBool:
{
if (varBool(this))
result = strNew("true");
else
result = strNew("false");
char working[6];
cvtBoolToZ(varBool(this), working, sizeof(working));
result = strNew(working);
break;
}
case varTypeDouble:
{
// Convert to a string
String *working = strNewFmt("%f", varDbl(this));
char working[64];
// Any formatted double should be at least 8 characters, i.e. 0.000000
ASSERT_DEBUG(strSize(working) >= 8);
// Any formatted double should have a decimal point
ASSERT_DEBUG(strchr(strPtr(working), '.') != NULL);
// Strip off any final 0s and the decimal point if there are no non-zero digits after it
const char *begin = strPtr(working);
const char *end = begin + strSize(working) - 1;
while (*end == '0' || *end == '.')
{
// It should not be possible to go past the beginning because format "%f" will always write a decimal point
ASSERT_DEBUG(end > begin);
end--;
if (*(end + 1) == '.')
break;
}
result = strNewN(begin, (size_t)(end - begin + 1));
strFree(working);
cvtDoubleToZ(varDbl(this), working, sizeof(working));
result = strNew(working);
break;
}
case varTypeInt:
{
result = strNewFmt("%d", varInt(this));
char working[64];
cvtIntToZ(varInt(this), working, sizeof(working));
result = strNew(working);
break;
}
case varTypeInt64:
{
result = strNewFmt("%" PRId64, varInt64(this));
char working[64];
cvtInt64ToZ(varInt64(this), working, sizeof(working));
result = strNew(working);
break;
}
@ -654,7 +713,7 @@ varStrForce(const Variant *this)
THROW_FMT(FormatError, "unable to force %s to %s", variantTypeName[this->type], variantTypeName[varTypeString]);
}
return result;
FUNCTION_TEST_RESULT(STRING, result);
}
/***********************************************************************************************************************************
@ -663,20 +722,16 @@ New variant list variant
Variant *
varNewVarLst(const VariantList *data)
{
// Create the variant
VariantList *dataCopy = varLstDup(data);
return varNewInternal(varTypeVariantList, (void *)&dataCopy, sizeof(dataCopy));
}
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(VARIANT_LIST, data);
/***********************************************************************************************************************************
New empty variant list variant
***********************************************************************************************************************************/
Variant *
varNewVarLstEmpty()
{
// Create the variant
VariantList *data = varLstNew();
return varNewInternal(varTypeVariantList, (void *)&data, sizeof(data));
FUNCTION_TEST_ASSERT(data != NULL);
FUNCTION_TEST_END();
// Copy variant list for the variant
VariantList *dataCopy = varLstDup(data);
FUNCTION_TEST_RESULT(VARIANT, varNewInternal(varTypeVariantList, (void *)&dataCopy, sizeof(dataCopy)));
}
/***********************************************************************************************************************************
@ -685,18 +740,77 @@ Return key/value
VariantList *
varVarLst(const Variant *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(VARIANT, this);
FUNCTION_TEST_END();
VariantList *result = NULL;
if (this != NULL)
{
// Only valid for key/value
if (this->type != varTypeVariantList)
THROW_FMT(AssertError, "variant type is not '%s'", variantTypeName[varTypeVariantList]);
// Get the string
ASSERT(this->type == varTypeVariantList);
result = *((VariantList **)varData(this));
}
FUNCTION_TEST_RESULT(VARIANT_LIST, result);
}
/***********************************************************************************************************************************
Convert variant to a zero-terminated string for logging
***********************************************************************************************************************************/
size_t
varToLog(const Variant *this, char *buffer, size_t bufferSize)
{
size_t result = 0;
MEM_CONTEXT_TEMP_BEGIN()
{
String *string = NULL;
if (this == NULL)
{
string = strNew("null");
result = (size_t)snprintf(buffer, bufferSize, "%s", strPtr(string));
}
else
{
switch (varType(this))
{
case varTypeString:
{
String *temp = varStrForce(this);
string = strNewFmt("\"%s\"", strPtr(temp));
strFree(temp);
break;
}
case varTypeKeyValue:
{
string = strNew("KeyValue");
break;
}
case varTypeVariantList:
{
string = strNew("VariantList");
break;
}
case varTypeBool:
case varTypeDouble:
case varTypeInt:
case varTypeInt64:
{
string = varStrForce(this);
break;
}
}
result = (size_t)snprintf(buffer, bufferSize, "{%s}", strPtr(string));
}
}
MEM_CONTEXT_TEMP_END();
return result;
}
@ -706,6 +820,10 @@ Free variant
void
varFree(Variant *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(VARIANT, this);
FUNCTION_TEST_END();
if (this != NULL)
{
MEM_CONTEXT_BEGIN(this->memContext)
@ -742,4 +860,6 @@ varFree(Variant *this)
}
MEM_CONTEXT_END();
}
FUNCTION_TEST_RESULT_VOID();
}

View File

@ -57,7 +57,6 @@ String *varStr(const Variant *this);
String *varStrForce(const Variant *this);
Variant *varNewVarLst(const VariantList *data);
Variant *varNewVarLstEmpty();
VariantList *varVarLst(const Variant *this);
Variant *varDup(const Variant *this);
@ -66,4 +65,19 @@ VariantType varType(const Variant *this);
void varFree(Variant *this);
/***********************************************************************************************************************************
Macros for function logging
***********************************************************************************************************************************/
size_t varToLog(const Variant *this, char *buffer, size_t bufferSize);
#define FUNCTION_DEBUG_CONST_VARIANT_TYPE \
const FUNCTION_DEBUG_VARIANT_TYPE
#define FUNCTION_DEBUG_CONST_VARIANT_FORMAT(value, buffer, bufferSize) \
FUNCTION_DEBUG_VARIANT_FORMAT(value, buffer, bufferSize)
#define FUNCTION_DEBUG_VARIANT_TYPE \
Variant *
#define FUNCTION_DEBUG_VARIANT_FORMAT(value, buffer, bufferSize) \
varToLog(value, buffer, bufferSize)
#endif

View File

@ -5,6 +5,7 @@ Variant List Handler
#include <stdlib.h>
#include <string.h>
#include "common/debug.h"
#include "common/memContext.h"
#include "common/type/list.h"
#include "common/type/variantList.h"
@ -15,7 +16,8 @@ Wrapper for lstNew()
VariantList *
varLstNew()
{
return (VariantList *)lstNew(sizeof(Variant *));
FUNCTION_TEST_VOID();
FUNCTION_TEST_RESULT(VARIANT_LIST, (VariantList *)lstNew(sizeof(Variant *)));
}
/***********************************************************************************************************************************
@ -24,6 +26,10 @@ Create a variant list from a string list
VariantList *
varLstNewStrLst(const StringList *stringList)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING_LIST, stringList);
FUNCTION_TEST_END();
VariantList *result = NULL;
if (stringList != NULL)
@ -34,7 +40,7 @@ varLstNewStrLst(const StringList *stringList)
varLstAdd(result, varNewStr(strLstGet(stringList, listIdx)));
}
return result;
FUNCTION_TEST_RESULT(VARIANT_LIST, result);
}
/***********************************************************************************************************************************
@ -43,6 +49,10 @@ Duplicate a variant list
VariantList *
varLstDup(const VariantList *source)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(VARIANT_LIST, source);
FUNCTION_TEST_END();
VariantList *result = NULL;
if (source != NULL)
@ -53,7 +63,7 @@ varLstDup(const VariantList *source)
varLstAdd(result, varDup(varLstGet(source, listIdx)));
}
return result;
FUNCTION_TEST_RESULT(VARIANT_LIST, result);
}
/***********************************************************************************************************************************
@ -62,7 +72,14 @@ Wrapper for lstAdd()
VariantList *
varLstAdd(VariantList *this, Variant *data)
{
return (VariantList *)lstAdd((List *)this, &data);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(VARIANT_LIST, this);
FUNCTION_TEST_PARAM(VARIANT, data);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(VARIANT_LIST, (VariantList *)lstAdd((List *)this, &data));
}
/***********************************************************************************************************************************
@ -71,7 +88,14 @@ Wrapper for lstGet()
Variant *
varLstGet(const VariantList *this, unsigned int listIdx)
{
return *(Variant **)lstGet((List *)this, listIdx);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(VARIANT_LIST, this);
FUNCTION_TEST_PARAM(UINT, listIdx);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(VARIANT, *(Variant **)lstGet((List *)this, listIdx));
}
/***********************************************************************************************************************************
@ -80,7 +104,13 @@ Wrapper for lstSize()
unsigned int
varLstSize(const VariantList *this)
{
return lstSize((List *)this);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(VARIANT_LIST, this);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(UINT, lstSize((List *)this));
}
/***********************************************************************************************************************************
@ -89,5 +119,11 @@ Wrapper for lstFree()
void
varLstFree(VariantList *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(VARIANT_LIST, this);
FUNCTION_TEST_END();
lstFree((List *)this);
FUNCTION_TEST_RESULT_VOID();
}

View File

@ -23,4 +23,12 @@ Variant *varLstGet(const VariantList *this, unsigned int listIdx);
unsigned int varLstSize(const VariantList *this);
void varLstFree(VariantList *this);
/***********************************************************************************************************************************
Macros for function logging
***********************************************************************************************************************************/
#define FUNCTION_DEBUG_VARIANT_LIST_TYPE \
VariantList *
#define FUNCTION_DEBUG_VARIANT_LIST_FORMAT(value, buffer, bufferSize) \
objToLog(value, "VariantList", buffer, bufferSize)
#endif

View File

@ -1,6 +1,7 @@
/***********************************************************************************************************************************
Wait Handler
***********************************************************************************************************************************/
#include "common/debug.h"
#include "common/memContext.h"
#include "common/time.h"
#include "common/wait.h"
@ -23,9 +24,11 @@ New wait handler
Wait *
waitNew(double waitTime)
{
// Make sure wait time is valid
if (waitTime < 0.1 || waitTime > 999999.0)
THROW(AssertError, "waitTime must be >= 0.1 and <= 999999.0");
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(DOUBLE, waitTime);
FUNCTION_DEBUG_ASSERT(waitTime >= 0.1 && waitTime <= 999999.0);
FUNCTION_DEBUG_END();
// Allocate wait object
Wait *this = NULL;
@ -51,7 +54,7 @@ waitNew(double waitTime)
}
MEM_CONTEXT_NEW_END();
return this;
FUNCTION_DEBUG_RESULT(WAIT, this);
}
/***********************************************************************************************************************************
@ -60,6 +63,12 @@ Wait and return whether the caller has more time left
bool
waitMore(Wait *this)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(WAIT, this);
FUNCTION_DEBUG_ASSERT(this != NULL);
FUNCTION_DEBUG_END();
bool result = false;
// If sleep is 0 then the wait time has already ended
@ -93,7 +102,7 @@ waitMore(Wait *this)
result = true;
}
return result;
FUNCTION_DEBUG_RESULT(BOOL, result);
}
/***********************************************************************************************************************************
@ -102,6 +111,12 @@ Free the wait
void
waitFree(Wait *this)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(WAIT, this);
FUNCTION_DEBUG_END();
if (this != NULL)
memContextFree(this->memContext);
FUNCTION_DEBUG_RESULT_VOID();
}

View File

@ -16,4 +16,12 @@ Wait *waitNew(double waitTime);
bool waitMore(Wait *this);
void waitFree(Wait *this);
/***********************************************************************************************************************************
Macros for function logging
***********************************************************************************************************************************/
#define FUNCTION_DEBUG_WAIT_TYPE \
Wait *
#define FUNCTION_DEBUG_WAIT_FORMAT(value, buffer, bufferSize) \
objToLog(value, "Wait", buffer, bufferSize)
#endif

View File

@ -4,6 +4,7 @@ Command and Option Configuration
#include <string.h>
#include "common/assert.h"
#include "common/debug.h"
#include "common/error.h"
#include "common/memContext.h"
#include "config/config.h"
@ -71,39 +72,32 @@ Include the automatically generated configuration data
***********************************************************************************************************************************/
#include "config/config.auto.c"
/***********************************************************************************************************************************
Debug Asserts
***********************************************************************************************************************************/
// The command must be set
#define ASSERT_DEBUG_COMMAND_SET() \
ASSERT_DEBUG(cfgCommand() != cfgCmdNone)
/***********************************************************************************************************************************
Store the config memory context
***********************************************************************************************************************************/
MemContext *configMemContext = NULL;
static MemContext *configMemContext = NULL;
/***********************************************************************************************************************************
Store the current command
This is generally set by the command parser but can also be set by during execute to change commands, i.e. backup -> expire.
***********************************************************************************************************************************/
ConfigCommand command = cfgCmdNone;
static ConfigCommand command = cfgCmdNone;
/***********************************************************************************************************************************
Store the location of the executable
***********************************************************************************************************************************/
String *exe = NULL;
static String *exe = NULL;
/***********************************************************************************************************************************
Was help requested for the command?
***********************************************************************************************************************************/
bool help = false;
static bool help = false;
/***********************************************************************************************************************************
Store the list of parameters passed to the command
***********************************************************************************************************************************/
StringList *paramList = NULL;
static StringList *paramList = NULL;
/***********************************************************************************************************************************
Map options names and indexes to option definitions.
@ -127,6 +121,8 @@ Initialize or reinitialize the configuration data
void
cfgInit()
{
FUNCTION_TEST_VOID();
// Reset configuration
command = cfgCmdNone;
exe = NULL;
@ -151,34 +147,32 @@ cfgInit()
MEM_CONTEXT_NEW_END();
}
MEM_CONTEXT_END();
FUNCTION_TEST_RESULT_VOID();
}
/***********************************************************************************************************************************
Get the current command
Get/set the current command
***********************************************************************************************************************************/
ConfigCommand
cfgCommand()
{
return command;
FUNCTION_TEST_VOID();
FUNCTION_TEST_RESULT(ENUM, command);
}
/***********************************************************************************************************************************
Set the current command
***********************************************************************************************************************************/
void
cfgCommandSet(ConfigCommand commandParam)
{
command = commandParam;
}
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, commandParam);
/***********************************************************************************************************************************
Ensure that command id is valid
***********************************************************************************************************************************/
void
cfgCommandCheck(ConfigCommand commandId)
{
if (commandId >= CFG_COMMAND_TOTAL)
THROW_FMT(AssertError, "command id %u invalid - must be >= 0 and < %d", commandId, CFG_COMMAND_TOTAL);
FUNCTION_TEST_ASSERT(commandParam <= cfgCmdNone);
FUNCTION_TEST_END();
command = commandParam;
FUNCTION_TEST_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -187,13 +181,20 @@ Was help requested?
bool
cfgCommandHelp()
{
return help;
FUNCTION_TEST_VOID();
FUNCTION_TEST_RESULT(BOOL, help);
}
void
cfgCommandHelpSet(bool helpParam)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(BOOL, helpParam);
FUNCTION_TEST_END();
help = helpParam;
FUNCTION_TEST_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -205,16 +206,27 @@ be modified to do the mapping.
ConfigDefineCommand
cfgCommandDefIdFromId(ConfigCommand commandId)
{
cfgCommandCheck(commandId);
return (ConfigDefineCommand)commandId;
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, commandId);
FUNCTION_TEST_ASSERT(commandId < cfgCmdNone);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(ENUM, (ConfigDefineCommand)commandId);
}
/***********************************************************************************************************************************
Get command id by name
***********************************************************************************************************************************/
int
ConfigCommand
cfgCommandId(const char *commandName)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRINGZ, commandName);
FUNCTION_TEST_ASSERT(commandName != NULL);
FUNCTION_TEST_END();
ConfigCommand commandId;
for (commandId = 0; commandId < cfgCmdNone; commandId++)
@ -224,7 +236,7 @@ cfgCommandId(const char *commandName)
if (commandId == cfgCmdNone)
THROW_FMT(AssertError, "invalid command '%s'", commandName);
return commandId;
FUNCTION_TEST_RESULT(ENUM, commandId);
}
/***********************************************************************************************************************************
@ -233,8 +245,13 @@ Get command name by id
const char *
cfgCommandName(ConfigCommand commandId)
{
cfgCommandCheck(commandId);
return configCommandData[commandId].name;
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, commandId);
FUNCTION_TEST_ASSERT(commandId < cfgCmdNone);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(STRINGZ, configCommandData[commandId].name);
}
/***********************************************************************************************************************************
@ -243,6 +260,8 @@ Command parameters, if any
const StringList *
cfgCommandParam()
{
FUNCTION_TEST_VOID();
if (paramList == NULL)
{
MEM_CONTEXT_BEGIN(configMemContext)
@ -252,17 +271,25 @@ cfgCommandParam()
MEM_CONTEXT_END();
}
return paramList;
FUNCTION_TEST_RESULT(STRING_LIST, paramList);
}
void
cfgCommandParamSet(const StringList *param)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING_LIST, param);
FUNCTION_TEST_ASSERT(param != NULL);
FUNCTION_TEST_END();
MEM_CONTEXT_BEGIN(configMemContext)
{
paramList = strLstDup(param);
}
MEM_CONTEXT_END();
FUNCTION_TEST_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -271,17 +298,26 @@ Command parameters, if any
const String *
cfgExe()
{
return exe;
FUNCTION_TEST_VOID();
FUNCTION_TEST_RESULT(STRING, exe);
}
void
cfgExeSet(const String *exeParam)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, exeParam);
FUNCTION_TEST_ASSERT(exeParam != NULL);
FUNCTION_TEST_END();
MEM_CONTEXT_BEGIN(configMemContext)
{
exe = strDup(exeParam);
}
MEM_CONTEXT_END();
FUNCTION_TEST_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -290,8 +326,11 @@ Does this command require an immediate lock?
bool
cfgLockRequired()
{
ASSERT_DEBUG_COMMAND_SET();
return configCommandData[cfgCommand()].lockRequired;
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_ASSERT(command != cfgCmdNone);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(BOOL, configCommandData[cfgCommand()].lockRequired);
}
/***********************************************************************************************************************************
@ -300,8 +339,11 @@ Get the lock type required for this command
LockType
cfgLockType()
{
ASSERT_DEBUG_COMMAND_SET();
return (LockType)configCommandData[cfgCommand()].lockType;
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_ASSERT(command != cfgCmdNone);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(ENUM, (LockType)configCommandData[cfgCommand()].lockType);
}
/***********************************************************************************************************************************
@ -310,8 +352,11 @@ Does this command log to a file?
bool
cfgLogFile()
{
ASSERT_DEBUG_COMMAND_SET();
return configCommandData[cfgCommand()].logFile;
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_ASSERT(command != cfgCmdNone);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(BOOL, configCommandData[cfgCommand()].logFile);
}
/***********************************************************************************************************************************
@ -320,8 +365,11 @@ Get default log level -- used for log messages that are common to all commands
LogLevel
cfgLogLevelDefault()
{
ASSERT_DEBUG_COMMAND_SET();
return (LogLevel)configCommandData[cfgCommand()].logLevelDefault;
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_ASSERT(command != cfgCmdNone);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(ENUM, (LogLevel)configCommandData[cfgCommand()].logLevelDefault);
}
/***********************************************************************************************************************************
@ -330,18 +378,11 @@ Get max stderr log level -- used to suppress error output for higher log levels,
LogLevel
cfgLogLevelStdErrMax()
{
ASSERT_DEBUG_COMMAND_SET();
return (LogLevel)configCommandData[cfgCommand()].logLevelStdErrMax;
}
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_ASSERT(command != cfgCmdNone);
FUNCTION_TEST_END();
/***********************************************************************************************************************************
Ensure that option id is valid
***********************************************************************************************************************************/
void
cfgOptionCheck(ConfigOption optionId)
{
if (optionId >= CFG_OPTION_TOTAL)
THROW_FMT(AssertError, "option id %u invalid - must be >= 0 and < %d", optionId, CFG_OPTION_TOTAL);
FUNCTION_TEST_RESULT(ENUM, (LogLevel)configCommandData[cfgCommand()].logLevelStdErrMax);
}
/***********************************************************************************************************************************
@ -350,8 +391,13 @@ Get the option define for this option
ConfigDefineOption
cfgOptionDefIdFromId(ConfigOption optionId)
{
cfgOptionCheck(optionId);
return configOptionData[optionId].defineId;
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, optionId);
FUNCTION_TEST_ASSERT(optionId < CFG_OPTION_TOTAL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(ENUM, configOptionData[optionId].defineId);
}
/***********************************************************************************************************************************
@ -360,7 +406,11 @@ Get/set option default
const Variant *
cfgOptionDefault(ConfigOption optionId)
{
cfgOptionCheck(optionId);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, optionId);
FUNCTION_TEST_ASSERT(optionId < CFG_OPTION_TOTAL);
FUNCTION_TEST_END();
if (configOptionValue[optionId].defaultValue == NULL)
{
@ -410,12 +460,19 @@ cfgOptionDefault(ConfigOption optionId)
}
}
return configOptionValue[optionId].defaultValue;
FUNCTION_TEST_RESULT(VARIANT, configOptionValue[optionId].defaultValue);
}
void
cfgOptionDefaultSet(ConfigOption optionId, const Variant *defaultValue)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, optionId);
FUNCTION_TEST_PARAM(VARIANT, defaultValue);
FUNCTION_TEST_ASSERT(optionId < CFG_OPTION_TOTAL);
FUNCTION_TEST_END();
MEM_CONTEXT_BEGIN(configMemContext)
{
if (configOptionValue[optionId].defaultValue != NULL)
@ -432,6 +489,8 @@ cfgOptionDefaultSet(ConfigOption optionId, const Variant *defaultValue)
}
}
MEM_CONTEXT_END();
FUNCTION_TEST_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -440,8 +499,13 @@ Get index for option
unsigned int
cfgOptionIndex(ConfigOption optionId)
{
cfgOptionCheck(optionId);
return configOptionData[optionId].index;
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, optionId);
FUNCTION_TEST_ASSERT(optionId < CFG_OPTION_TOTAL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(UINT, configOptionData[optionId].index);
}
/***********************************************************************************************************************************
@ -450,11 +514,19 @@ Get option id by name
int
cfgOptionId(const char *optionName)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRINGZ, optionName);
FUNCTION_TEST_ASSERT(optionName != NULL);
FUNCTION_TEST_END();
int result = -1;
for (ConfigOption optionId = 0; optionId < CFG_OPTION_TOTAL; optionId++)
if (strcmp(optionName, configOptionData[optionId].name) == 0)
return optionId;
result = optionId;
return -1;
FUNCTION_TEST_RESULT(INT, result);
}
/***********************************************************************************************************************************
@ -463,8 +535,13 @@ Get total indexed values for option
unsigned int
cfgOptionIndexTotal(ConfigOption optionId)
{
cfgOptionCheck(optionId);
return cfgDefOptionIndexTotal(configOptionData[optionId].defineId);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, optionId);
FUNCTION_TEST_ASSERT(optionId < CFG_OPTION_TOTAL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(UINT, cfgDefOptionIndexTotal(configOptionData[optionId].defineId));
}
/***********************************************************************************************************************************
@ -473,19 +550,26 @@ Get the id for this option define
ConfigOption
cfgOptionIdFromDefId(ConfigDefineOption optionDefId, unsigned int index)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, optionDefId);
FUNCTION_TEST_PARAM(UINT, index);
FUNCTION_TEST_ASSERT(optionDefId < cfgDefOptionTotal());
FUNCTION_TEST_ASSERT(index < cfgDefOptionIndexTotal(optionDefId));
FUNCTION_TEST_END();
// Search for the option
ConfigOption optionId;
for (optionId = 0; optionId < CFG_OPTION_TOTAL; optionId++)
for (optionId = 0; optionId < CFG_OPTION_TOTAL; optionId++) // {uncoverable - only a bug in code gen lets this loop end}
if (configOptionData[optionId].defineId == optionDefId)
break;
// Error when not found
if (optionId == CFG_OPTION_TOTAL)
cfgDefOptionCheck(optionDefId);
// If the mapping is not found then there is a bug in the code generator
ASSERT_DEBUG(optionId != CFG_OPTION_TOTAL);
// Return with original index
return optionId + index;
FUNCTION_TEST_RESULT(ENUM, optionId + index);
}
/***********************************************************************************************************************************
@ -494,8 +578,13 @@ Get option name by id
const char *
cfgOptionName(ConfigOption optionId)
{
cfgOptionCheck(optionId);
return configOptionData[optionId].name;
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, optionId);
FUNCTION_TEST_ASSERT(optionId < CFG_OPTION_TOTAL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(STRINGZ, configOptionData[optionId].name);
}
/***********************************************************************************************************************************
@ -504,15 +593,28 @@ Was the option negated?
bool
cfgOptionNegate(ConfigOption optionId)
{
cfgOptionCheck(optionId);
return configOptionValue[optionId].negate;
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, optionId);
FUNCTION_TEST_ASSERT(optionId < CFG_OPTION_TOTAL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(BOOL, configOptionValue[optionId].negate);
}
void
cfgOptionNegateSet(ConfigOption optionId, bool negate)
{
cfgOptionCheck(optionId);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, optionId);
FUNCTION_TEST_PARAM(BOOL, negate);
FUNCTION_TEST_ASSERT(optionId < CFG_OPTION_TOTAL);
FUNCTION_TEST_END();
configOptionValue[optionId].negate = negate;
FUNCTION_TEST_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -521,15 +623,28 @@ Was the option reset?
bool
cfgOptionReset(ConfigOption optionId)
{
cfgOptionCheck(optionId);
return configOptionValue[optionId].reset;
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, optionId);
FUNCTION_TEST_ASSERT(optionId < CFG_OPTION_TOTAL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(BOOL, configOptionValue[optionId].reset);
}
void
cfgOptionResetSet(ConfigOption optionId, bool reset)
{
cfgOptionCheck(optionId);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, optionId);
FUNCTION_TEST_PARAM(BOOL, reset);
FUNCTION_TEST_ASSERT(optionId < CFG_OPTION_TOTAL);
FUNCTION_TEST_END();
configOptionValue[optionId].reset = reset;
FUNCTION_TEST_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -538,69 +653,90 @@ Get and set config options
const Variant *
cfgOption(ConfigOption optionId)
{
cfgOptionCheck(optionId);
return configOptionValue[optionId].value;
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, optionId);
FUNCTION_TEST_ASSERT(optionId < CFG_OPTION_TOTAL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(VARIANT, configOptionValue[optionId].value);
}
bool
cfgOptionBool(ConfigOption optionId)
{
cfgOptionCheck(optionId);
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(ENUM, optionId);
if (varType(configOptionValue[optionId].value) != varTypeBool)
THROW_FMT(AssertError, "option '%s' is not type 'bool'", cfgOptionName(optionId));
FUNCTION_DEBUG_ASSERT(optionId < CFG_OPTION_TOTAL);
FUNCTION_DEBUG_ASSERT(varType(configOptionValue[optionId].value) == varTypeBool);
FUNCTION_DEBUG_END();
return varBool(configOptionValue[optionId].value);
FUNCTION_DEBUG_RESULT(BOOL, varBool(configOptionValue[optionId].value));
}
double
cfgOptionDbl(ConfigOption optionId)
{
cfgOptionCheck(optionId);
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(ENUM, optionId);
if (varType(configOptionValue[optionId].value) != varTypeDouble)
THROW_FMT(AssertError, "option '%s' is not type 'double'", cfgOptionName(optionId));
FUNCTION_DEBUG_ASSERT(optionId < CFG_OPTION_TOTAL);
FUNCTION_DEBUG_ASSERT(varType(configOptionValue[optionId].value) == varTypeDouble);
FUNCTION_DEBUG_END();
return varDbl(configOptionValue[optionId].value);
FUNCTION_DEBUG_RESULT(DOUBLE, varDbl(configOptionValue[optionId].value));
}
int
cfgOptionInt(ConfigOption optionId)
{
cfgOptionCheck(optionId);
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(ENUM, optionId);
if (varType(configOptionValue[optionId].value) != varTypeInt64)
THROW_FMT(AssertError, "option '%s' is not type 'int64'", cfgOptionName(optionId));
FUNCTION_DEBUG_ASSERT(optionId < CFG_OPTION_TOTAL);
FUNCTION_DEBUG_ASSERT(varType(configOptionValue[optionId].value) == varTypeInt64);
FUNCTION_DEBUG_END();
return varIntForce(configOptionValue[optionId].value);
FUNCTION_DEBUG_RESULT(INT, varIntForce(configOptionValue[optionId].value));
}
int64_t
cfgOptionInt64(ConfigOption optionId)
{
cfgOptionCheck(optionId);
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(ENUM, optionId);
if (varType(configOptionValue[optionId].value) != varTypeInt64)
THROW_FMT(AssertError, "option '%s' is not type 'int64'", cfgOptionName(optionId));
FUNCTION_DEBUG_ASSERT(optionId < CFG_OPTION_TOTAL);
FUNCTION_DEBUG_ASSERT(varType(configOptionValue[optionId].value) == varTypeInt64);
FUNCTION_DEBUG_END();
return varInt64(configOptionValue[optionId].value);
FUNCTION_DEBUG_RESULT(INT64, varInt64(configOptionValue[optionId].value));
}
const KeyValue *
cfgOptionKv(ConfigOption optionId)
{
cfgOptionCheck(optionId);
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(ENUM, optionId);
if (varType(configOptionValue[optionId].value) != varTypeKeyValue)
THROW_FMT(AssertError, "option '%s' is not type 'KeyValue'", cfgOptionName(optionId));
FUNCTION_DEBUG_ASSERT(optionId < CFG_OPTION_TOTAL);
FUNCTION_DEBUG_ASSERT(varType(configOptionValue[optionId].value) == varTypeKeyValue);
FUNCTION_DEBUG_END();
return varKv(configOptionValue[optionId].value);
FUNCTION_DEBUG_RESULT(KEY_VALUE, varKv(configOptionValue[optionId].value));
}
const VariantList *
cfgOptionLst(ConfigOption optionId)
{
cfgOptionCheck(optionId);
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(ENUM, optionId);
FUNCTION_DEBUG_ASSERT(optionId < CFG_OPTION_TOTAL);
FUNCTION_DEBUG_ASSERT(
configOptionValue[optionId].value == NULL || varType(configOptionValue[optionId].value) == varTypeVariantList);
FUNCTION_DEBUG_END();
if (configOptionValue[optionId].value == NULL)
{
@ -610,34 +746,39 @@ cfgOptionLst(ConfigOption optionId)
}
MEM_CONTEXT_END();
}
else if (varType(configOptionValue[optionId].value) != varTypeVariantList)
THROW_FMT(AssertError, "option '%s' is not type 'VariantList'", cfgOptionName(optionId));
return varVarLst(configOptionValue[optionId].value);
FUNCTION_DEBUG_RESULT(VARIANT_LIST, varVarLst(configOptionValue[optionId].value));
}
const String *
cfgOptionStr(ConfigOption optionId)
{
cfgOptionCheck(optionId);
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(ENUM, optionId);
FUNCTION_DEBUG_ASSERT(optionId < CFG_OPTION_TOTAL);
FUNCTION_DEBUG_ASSERT(
configOptionValue[optionId].value == NULL || varType(configOptionValue[optionId].value) == varTypeString);
FUNCTION_DEBUG_END();
const String *result = NULL;
if (configOptionValue[optionId].value != NULL)
{
if (varType(configOptionValue[optionId].value) != varTypeString)
THROW_FMT(AssertError, "option '%s' is not type 'String'", cfgOptionName(optionId));
result = varStr(configOptionValue[optionId].value);
}
return result;
FUNCTION_DEBUG_RESULT(CONST_STRING, result);
}
void
cfgOptionSet(ConfigOption optionId, ConfigSource source, const Variant *value)
{
cfgOptionCheck(optionId);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, optionId);
FUNCTION_TEST_PARAM(ENUM, source);
FUNCTION_TEST_PARAM(VARIANT, value);
FUNCTION_TEST_ASSERT(optionId < CFG_OPTION_TOTAL);
FUNCTION_TEST_END();
MEM_CONTEXT_BEGIN(configMemContext)
{
@ -720,6 +861,8 @@ cfgOptionSet(ConfigOption optionId, ConfigSource source, const Variant *value)
varFree(valueOld);
}
MEM_CONTEXT_END();
FUNCTION_TEST_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -728,8 +871,13 @@ How was the option set (default, param, config)?
ConfigSource
cfgOptionSource(ConfigOption optionId)
{
cfgOptionCheck(optionId);
return configOptionValue[optionId].source;
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, optionId);
FUNCTION_TEST_ASSERT(optionId < CFG_OPTION_TOTAL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(ENUM, configOptionValue[optionId].source);
}
/***********************************************************************************************************************************
@ -738,8 +886,13 @@ Is the option valid for the command and set?
bool
cfgOptionTest(ConfigOption optionId)
{
cfgOptionCheck(optionId);
return cfgOptionValid(optionId) && configOptionValue[optionId].value != NULL;
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, optionId);
FUNCTION_TEST_ASSERT(optionId < CFG_OPTION_TOTAL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(BOOL, cfgOptionValid(optionId) && configOptionValue[optionId].value != NULL);
}
/***********************************************************************************************************************************
@ -748,13 +901,26 @@ Is the option valid for this command?
bool
cfgOptionValid(ConfigOption optionId)
{
cfgOptionCheck(optionId);
return configOptionValue[optionId].valid;
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, optionId);
FUNCTION_TEST_ASSERT(optionId < CFG_OPTION_TOTAL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(BOOL, configOptionValue[optionId].valid);
}
void
cfgOptionValidSet(ConfigOption optionId, bool valid)
{
cfgOptionCheck(optionId);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, optionId);
FUNCTION_TEST_PARAM(BOOL, valid);
FUNCTION_TEST_ASSERT(optionId < CFG_OPTION_TOTAL);
FUNCTION_TEST_END();
configOptionValue[optionId].valid = valid;
FUNCTION_TEST_RESULT_VOID();
}

View File

@ -86,7 +86,7 @@ void cfgInit();
ConfigDefineCommand cfgCommandDefIdFromId(ConfigCommand commandId);
bool cfgCommandHelp();
void cfgCommandHelpSet(bool helpParam);
int cfgCommandId(const char *commandName);
ConfigCommand cfgCommandId(const char *commandName);
void cfgCommandParamSet(const StringList *param);
void cfgCommandSet(ConfigCommand commandParam);

View File

@ -6,6 +6,7 @@ Command and Option Configuration Definition
#include <string.h>
#include "common/assert.h"
#include "common/debug.h"
#include "common/error.h"
#include "config/define.h"
@ -180,6 +181,21 @@ cfgDefDataFind(
ConfigDefineDataType typeFind, ConfigDefineCommand commandDefId, const void **dataList, bool *dataDefFound, int *dataDef,
const void ***dataDefList, unsigned int *dataDefListSize)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, typeFind);
FUNCTION_TEST_PARAM(ENUM, commandDefId);
FUNCTION_TEST_PARAM(VOIDPP, dataList);
FUNCTION_TEST_PARAM(BOOLP, dataDefFound);
FUNCTION_TEST_PARAM(INTP, dataDef);
FUNCTION_TEST_PARAM(VOIDPP, dataDefList);
FUNCTION_TEST_PARAM(VOIDPP, dataDefListSize);
FUNCTION_TEST_ASSERT(dataDefFound != NULL);
FUNCTION_TEST_ASSERT(dataDef != NULL);
FUNCTION_TEST_ASSERT(dataDefList != NULL);
FUNCTION_TEST_ASSERT(dataDefListSize != NULL);
FUNCTION_TEST_END();
*dataDefFound = false;
// Only proceed if there is data
@ -227,6 +243,8 @@ cfgDefDataFind(
}
while(type != configDefDataTypeEnd);
}
FUNCTION_TEST_RESULT_VOID();
}
#define CONFIG_DEFINE_DATA_FIND(commandDefId, optionDefId, type) \
@ -244,37 +262,15 @@ Command and option define totals
unsigned int
cfgDefCommandTotal()
{
return sizeof(configDefineCommandData) / sizeof(ConfigDefineCommandData);
FUNCTION_TEST_VOID();
FUNCTION_TEST_RESULT(UINT, sizeof(configDefineCommandData) / sizeof(ConfigDefineCommandData));
}
unsigned int
cfgDefOptionTotal()
{
return sizeof(configDefineOptionData) / sizeof(ConfigDefineOptionData);
}
/***********************************************************************************************************************************
Check that command and option ids are valid
***********************************************************************************************************************************/
void
cfgDefCommandCheck(ConfigDefineCommand commandDefId)
{
if (commandDefId >= cfgDefCommandTotal())
THROW_FMT(AssertError, "command def id %u invalid - must be >= 0 and < %u", commandDefId, cfgDefCommandTotal());
}
void
cfgDefOptionCheck(ConfigDefineOption optionDefId)
{
if (optionDefId >= cfgDefOptionTotal())
THROW_FMT(AssertError, "option def id %u invalid - must be >= 0 and < %u", optionDefId, cfgDefOptionTotal());
}
static void
cfgDefCommandOptionCheck(ConfigDefineCommand commandDefId, ConfigDefineOption optionDefId)
{
cfgDefCommandCheck(commandDefId);
cfgDefOptionCheck(optionDefId);
FUNCTION_TEST_VOID();
FUNCTION_TEST_RESULT(UINT, sizeof(configDefineOptionData) / sizeof(ConfigDefineOptionData));
}
/***********************************************************************************************************************************
@ -283,8 +279,13 @@ Command help description
const char *
cfgDefCommandHelpDescription(ConfigDefineCommand commandDefId)
{
cfgDefCommandCheck(commandDefId);
return configDefineCommandData[commandDefId].helpDescription;
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, commandDefId);
FUNCTION_TEST_ASSERT(commandDefId < cfgDefCommandTotal());
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(STRINGZ, configDefineCommandData[commandDefId].helpDescription);
}
/***********************************************************************************************************************************
@ -293,8 +294,13 @@ Command help summary
const char *
cfgDefCommandHelpSummary(ConfigDefineCommand commandDefId)
{
cfgDefCommandCheck(commandDefId);
return configDefineCommandData[commandDefId].helpSummary;
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, commandDefId);
FUNCTION_TEST_ASSERT(commandDefId < cfgDefCommandTotal());
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(STRINGZ, configDefineCommandData[commandDefId].helpSummary);
}
/***********************************************************************************************************************************
@ -303,47 +309,76 @@ Option allow lists
bool
cfgDefOptionAllowList(ConfigDefineCommand commandDefId, ConfigDefineOption optionDefId)
{
cfgDefCommandOptionCheck(commandDefId, optionDefId);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, commandDefId);
FUNCTION_TEST_PARAM(ENUM, optionDefId);
FUNCTION_TEST_ASSERT(commandDefId < cfgDefCommandTotal());
FUNCTION_TEST_ASSERT(optionDefId < cfgDefOptionTotal());
FUNCTION_TEST_END();
CONFIG_DEFINE_DATA_FIND(commandDefId, optionDefId, configDefDataTypeAllowList);
return dataDefFound;
FUNCTION_TEST_RESULT(BOOL, dataDefFound);
}
const char *
cfgDefOptionAllowListValue(ConfigDefineCommand commandDefId, ConfigDefineOption optionDefId, unsigned int valueId)
{
cfgDefCommandOptionCheck(commandDefId, optionDefId);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, commandDefId);
FUNCTION_TEST_PARAM(ENUM, optionDefId);
FUNCTION_TEST_PARAM(UINT, valueId);
FUNCTION_TEST_ASSERT(commandDefId < cfgDefCommandTotal());
FUNCTION_TEST_ASSERT(optionDefId < cfgDefOptionTotal());
FUNCTION_TEST_ASSERT(valueId < cfgDefOptionAllowListValueTotal(commandDefId, optionDefId));
FUNCTION_TEST_END();
CONFIG_DEFINE_DATA_FIND(commandDefId, optionDefId, configDefDataTypeAllowList);
if (valueId >= dataDefListSize)
THROW_FMT(AssertError, "value id %u invalid - must be >= 0 and < %u", valueId, dataDefListSize);
return (char *)dataDefList[valueId];
FUNCTION_TEST_RESULT(STRINGZ, (char *)dataDefList[valueId]);
}
unsigned int
cfgDefOptionAllowListValueTotal(ConfigDefineCommand commandDefId, ConfigDefineOption optionDefId)
{
cfgDefCommandOptionCheck(commandDefId, optionDefId);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, commandDefId);
FUNCTION_TEST_PARAM(ENUM, optionDefId);
FUNCTION_TEST_ASSERT(commandDefId < cfgDefCommandTotal());
FUNCTION_TEST_ASSERT(optionDefId < cfgDefOptionTotal());
FUNCTION_TEST_END();
CONFIG_DEFINE_DATA_FIND(commandDefId, optionDefId, configDefDataTypeAllowList);
return dataDefListSize;
FUNCTION_TEST_RESULT(UINT, dataDefListSize);
}
// Check if the value matches a value in the allow list
bool
cfgDefOptionAllowListValueValid(ConfigDefineCommand commandDefId, ConfigDefineOption optionDefId, const char *value)
{
ASSERT_DEBUG(value != NULL);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, commandDefId);
FUNCTION_TEST_PARAM(ENUM, optionDefId);
FUNCTION_TEST_PARAM(STRINGZ, value);
FUNCTION_TEST_ASSERT(commandDefId < cfgDefCommandTotal());
FUNCTION_TEST_ASSERT(optionDefId < cfgDefOptionTotal());
FUNCTION_TEST_ASSERT(value != NULL);
FUNCTION_TEST_END();
bool result = false;
for (unsigned int valueIdx = 0; valueIdx < cfgDefOptionAllowListValueTotal(commandDefId, optionDefId); valueIdx++)
{
if (strcmp(value, cfgDefOptionAllowListValue(commandDefId, optionDefId, valueIdx)) == 0)
return true;
result = true;
}
return false;
FUNCTION_TEST_RESULT(BOOL, result);
}
/***********************************************************************************************************************************
@ -352,31 +387,51 @@ Allow range
bool
cfgDefOptionAllowRange(ConfigDefineCommand commandDefId, ConfigDefineOption optionDefId)
{
cfgDefCommandOptionCheck(commandDefId, optionDefId);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, commandDefId);
FUNCTION_TEST_PARAM(ENUM, optionDefId);
FUNCTION_TEST_ASSERT(commandDefId < cfgDefCommandTotal());
FUNCTION_TEST_ASSERT(optionDefId < cfgDefOptionTotal());
FUNCTION_TEST_END();
CONFIG_DEFINE_DATA_FIND(commandDefId, optionDefId, configDefDataTypeAllowRange);
return dataDefFound;
FUNCTION_TEST_RESULT(BOOL, dataDefFound);
}
double
cfgDefOptionAllowRangeMax(ConfigDefineCommand commandDefId, ConfigDefineOption optionDefId)
{
cfgDefCommandOptionCheck(commandDefId, optionDefId);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, commandDefId);
FUNCTION_TEST_PARAM(ENUM, optionDefId);
FUNCTION_TEST_ASSERT(commandDefId < cfgDefCommandTotal());
FUNCTION_TEST_ASSERT(optionDefId < cfgDefOptionTotal());
FUNCTION_TEST_END();
CONFIG_DEFINE_DATA_FIND(commandDefId, optionDefId, configDefDataTypeAllowRange);
return ((double)(((int64_t)(intptr_t)dataDefList[2]) + (((int64_t)(intptr_t)dataDefList[3]) * 1000000000L))) / 100;
FUNCTION_TEST_RESULT(
DOUBLE, ((double)(((int64_t)(intptr_t)dataDefList[2]) + (((int64_t)(intptr_t)dataDefList[3]) * 1000000000L))) / 100);
}
double
cfgDefOptionAllowRangeMin(ConfigDefineCommand commandDefId, ConfigDefineOption optionDefId)
{
cfgDefCommandOptionCheck(commandDefId, optionDefId);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, commandDefId);
FUNCTION_TEST_PARAM(ENUM, optionDefId);
FUNCTION_TEST_ASSERT(commandDefId < cfgDefCommandTotal());
FUNCTION_TEST_ASSERT(optionDefId < cfgDefOptionTotal());
FUNCTION_TEST_END();
CONFIG_DEFINE_DATA_FIND(commandDefId, optionDefId, configDefDataTypeAllowRange);
return ((double)(((int64_t)(intptr_t)dataDefList[0]) + (((int64_t)(intptr_t)dataDefList[1]) * 1000000000L))) / 100;
FUNCTION_TEST_RESULT(
DOUBLE, ((double)(((int64_t)(intptr_t)dataDefList[0]) + (((int64_t)(intptr_t)dataDefList[1]) * 1000000000L))) / 100);
}
/***********************************************************************************************************************************
@ -385,14 +440,22 @@ Default value for the option
const char *
cfgDefOptionDefault(ConfigDefineCommand commandDefId, ConfigDefineOption optionDefId)
{
cfgDefCommandOptionCheck(commandDefId, optionDefId);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, commandDefId);
FUNCTION_TEST_PARAM(ENUM, optionDefId);
FUNCTION_TEST_ASSERT(commandDefId < cfgDefCommandTotal());
FUNCTION_TEST_ASSERT(optionDefId < cfgDefOptionTotal());
FUNCTION_TEST_END();
CONFIG_DEFINE_DATA_FIND(commandDefId, optionDefId, configDefDataTypeDefault);
if (dataDefFound)
return (char *)dataDefList[0];
char *result = NULL;
return NULL;
if (dataDefFound)
result = (char *)dataDefList[0];
FUNCTION_TEST_RESULT(STRINGZ, result);
}
/***********************************************************************************************************************************
@ -401,57 +464,92 @@ Dependencies and depend lists
bool
cfgDefOptionDepend(ConfigDefineCommand commandDefId, ConfigDefineOption optionDefId)
{
cfgDefCommandOptionCheck(commandDefId, optionDefId);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, commandDefId);
FUNCTION_TEST_PARAM(ENUM, optionDefId);
FUNCTION_TEST_ASSERT(commandDefId < cfgDefCommandTotal());
FUNCTION_TEST_ASSERT(optionDefId < cfgDefOptionTotal());
FUNCTION_TEST_END();
CONFIG_DEFINE_DATA_FIND(commandDefId, optionDefId, configDefDataTypeDepend);
return dataDefFound;
FUNCTION_TEST_RESULT(BOOL, dataDefFound);
}
ConfigDefineOption
cfgDefOptionDependOption(ConfigDefineCommand commandDefId, ConfigDefineOption optionDefId)
{
cfgDefCommandOptionCheck(commandDefId, optionDefId);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, commandDefId);
FUNCTION_TEST_PARAM(ENUM, optionDefId);
FUNCTION_TEST_ASSERT(commandDefId < cfgDefCommandTotal());
FUNCTION_TEST_ASSERT(optionDefId < cfgDefOptionTotal());
FUNCTION_TEST_END();
CONFIG_DEFINE_DATA_FIND(commandDefId, optionDefId, configDefDataTypeDepend);
return (ConfigDefineOption)dataDef;
FUNCTION_TEST_RESULT(ENUM, (ConfigDefineOption)dataDef);
}
const char *
cfgDefOptionDependValue(ConfigDefineCommand commandDefId, ConfigDefineOption optionDefId, unsigned int valueId)
{
cfgDefCommandOptionCheck(commandDefId, optionDefId);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, commandDefId);
FUNCTION_TEST_PARAM(ENUM, optionDefId);
FUNCTION_TEST_PARAM(UINT, valueId);
FUNCTION_TEST_ASSERT(commandDefId < cfgDefCommandTotal());
FUNCTION_TEST_ASSERT(optionDefId < cfgDefOptionTotal());
FUNCTION_TEST_ASSERT(valueId < cfgDefOptionDependValueTotal(commandDefId, optionDefId));
FUNCTION_TEST_END();
CONFIG_DEFINE_DATA_FIND(commandDefId, optionDefId, configDefDataTypeDepend);
if (valueId >= dataDefListSize)
THROW_FMT(AssertError, "value id %u invalid - must be >= 0 and < %u", valueId, dataDefListSize);
return (char *)dataDefList[valueId];
FUNCTION_TEST_RESULT(STRINGZ, (char *)dataDefList[valueId]);
}
unsigned int
cfgDefOptionDependValueTotal(ConfigDefineCommand commandDefId, ConfigDefineOption optionDefId)
{
cfgDefCommandOptionCheck(commandDefId, optionDefId);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, commandDefId);
FUNCTION_TEST_PARAM(ENUM, optionDefId);
FUNCTION_TEST_ASSERT(commandDefId < cfgDefCommandTotal());
FUNCTION_TEST_ASSERT(optionDefId < cfgDefOptionTotal());
FUNCTION_TEST_END();
CONFIG_DEFINE_DATA_FIND(commandDefId, optionDefId, configDefDataTypeDepend);
return dataDefListSize;
FUNCTION_TEST_RESULT(UINT, dataDefListSize);
}
// Check if the value matches a value in the allow list
bool
cfgDefOptionDependValueValid(ConfigDefineCommand commandDefId, ConfigDefineOption optionDefId, const char *value)
{
ASSERT_DEBUG(value != NULL);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, commandDefId);
FUNCTION_TEST_PARAM(ENUM, optionDefId);
FUNCTION_TEST_PARAM(STRINGZ, value);
FUNCTION_TEST_ASSERT(commandDefId < cfgDefCommandTotal());
FUNCTION_TEST_ASSERT(optionDefId < cfgDefOptionTotal());
FUNCTION_TEST_ASSERT(value != NULL);
FUNCTION_TEST_END();
bool result = false;
for (unsigned int valueIdx = 0; valueIdx < cfgDefOptionDependValueTotal(commandDefId, optionDefId); valueIdx++)
{
if (strcmp(value, cfgDefOptionDependValue(commandDefId, optionDefId, valueIdx)) == 0)
return true;
result = true;
}
return false;
FUNCTION_TEST_RESULT(BOOL, result);
}
/***********************************************************************************************************************************
@ -460,14 +558,22 @@ Option help description
const char *
cfgDefOptionHelpDescription(ConfigDefineCommand commandDefId, ConfigDefineOption optionDefId)
{
cfgDefCommandOptionCheck(commandDefId, optionDefId);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, commandDefId);
FUNCTION_TEST_PARAM(ENUM, optionDefId);
FUNCTION_TEST_ASSERT(commandDefId < cfgDefCommandTotal());
FUNCTION_TEST_ASSERT(optionDefId < cfgDefOptionTotal());
FUNCTION_TEST_END();
CONFIG_DEFINE_DATA_FIND(commandDefId, optionDefId, configDefDataTypeHelpDescription);
if (dataDefFound)
return (char *)dataDefList[0];
const char *result = configDefineOptionData[optionDefId].helpDescription;
return configDefineOptionData[optionDefId].helpDescription;
if (dataDefFound)
result = (char *)dataDefList[0];
FUNCTION_TEST_RESULT(STRINGZ, result);
}
/***********************************************************************************************************************************
@ -476,34 +582,45 @@ Option help name alt
bool
cfgDefOptionHelpNameAlt(ConfigDefineOption optionDefId)
{
cfgDefOptionCheck(optionDefId);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, optionDefId);
FUNCTION_TEST_ASSERT(optionDefId < cfgDefOptionTotal());
FUNCTION_TEST_END();
CONFIG_DEFINE_DATA_FIND(-1, optionDefId, configDefDataTypeHelpNameAlt);
return dataDefFound;
FUNCTION_TEST_RESULT(BOOL, dataDefFound);
}
const char *
cfgDefOptionHelpNameAltValue(ConfigDefineOption optionDefId, unsigned int valueId)
{
cfgDefOptionCheck(optionDefId);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, optionDefId);
FUNCTION_TEST_PARAM(UINT, valueId);
FUNCTION_TEST_ASSERT(optionDefId < cfgDefOptionTotal());
FUNCTION_TEST_ASSERT(valueId < cfgDefOptionHelpNameAltValueTotal(optionDefId));
FUNCTION_TEST_END();
CONFIG_DEFINE_DATA_FIND(-1, optionDefId, configDefDataTypeHelpNameAlt);
if (valueId >= dataDefListSize)
THROW_FMT(AssertError, "value id %u invalid - must be >= 0 and < %u", valueId, dataDefListSize);
return (char *)dataDefList[valueId];
FUNCTION_TEST_RESULT(STRINGZ, (char *)dataDefList[valueId]);
}
unsigned int
cfgDefOptionHelpNameAltValueTotal(ConfigDefineOption optionDefId)
{
cfgDefOptionCheck(optionDefId);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, optionDefId);
FUNCTION_TEST_ASSERT(optionDefId < cfgDefOptionTotal());
FUNCTION_TEST_END();
CONFIG_DEFINE_DATA_FIND(-1, optionDefId, configDefDataTypeHelpNameAlt);
return dataDefListSize;
FUNCTION_TEST_RESULT(UINT, dataDefListSize);
}
/***********************************************************************************************************************************
@ -512,8 +629,13 @@ Option help section
const char *
cfgDefOptionHelpSection(ConfigDefineOption optionDefId)
{
cfgDefOptionCheck(optionDefId);
return configDefineOptionData[optionDefId].helpSection;
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, optionDefId);
FUNCTION_TEST_ASSERT(optionDefId < cfgDefOptionTotal());
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(STRINGZ, configDefineOptionData[optionDefId].helpSection);
}
/***********************************************************************************************************************************
@ -522,14 +644,22 @@ Option help summary
const char *
cfgDefOptionHelpSummary(ConfigDefineCommand commandDefId, ConfigDefineOption optionDefId)
{
cfgDefCommandOptionCheck(commandDefId, optionDefId);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, commandDefId);
FUNCTION_TEST_PARAM(ENUM, optionDefId);
FUNCTION_TEST_ASSERT(commandDefId < cfgDefCommandTotal());
FUNCTION_TEST_ASSERT(optionDefId < cfgDefOptionTotal());
FUNCTION_TEST_END();
CONFIG_DEFINE_DATA_FIND(commandDefId, optionDefId, configDefDataTypeHelpSummary);
if (dataDefFound)
return (char *)dataDefList[0];
const char *result = configDefineOptionData[optionDefId].helpSummary;
return configDefineOptionData[optionDefId].helpSummary;
if (dataDefFound)
result = (char *)dataDefList[0];
FUNCTION_TEST_RESULT(STRINGZ, result);
}
/***********************************************************************************************************************************
@ -538,11 +668,19 @@ Get option id by name
int
cfgDefOptionId(const char *optionName)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRINGZ, optionName);
FUNCTION_TEST_ASSERT(optionName != NULL);
FUNCTION_TEST_END();
int result = -1;
for (ConfigDefineOption optionDefId = 0; optionDefId < cfgDefOptionTotal(); optionDefId++)
if (strcmp(optionName, configDefineOptionData[optionDefId].name) == 0)
return optionDefId;
result = optionDefId;
return -1;
FUNCTION_TEST_RESULT(INT, result);
}
/***********************************************************************************************************************************
@ -551,8 +689,13 @@ Get total indexed values for option
unsigned int
cfgDefOptionIndexTotal(ConfigDefineOption optionDefId)
{
cfgDefOptionCheck(optionDefId);
return configDefineOptionData[optionDefId].indexTotal;
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, optionDefId);
FUNCTION_TEST_ASSERT(optionDefId < cfgDefOptionTotal());
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(UINT, configDefineOptionData[optionDefId].indexTotal);
}
/***********************************************************************************************************************************
@ -561,14 +704,22 @@ Is the option for internal use only?
bool
cfgDefOptionInternal(ConfigDefineCommand commandDefId, ConfigDefineOption optionDefId)
{
cfgDefCommandOptionCheck(commandDefId, optionDefId);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, commandDefId);
FUNCTION_TEST_PARAM(ENUM, optionDefId);
FUNCTION_TEST_ASSERT(commandDefId < cfgDefCommandTotal());
FUNCTION_TEST_ASSERT(optionDefId < cfgDefOptionTotal());
FUNCTION_TEST_END();
CONFIG_DEFINE_DATA_FIND(commandDefId, optionDefId, configDefDataTypeInternal);
if (dataDefFound)
return (bool)dataDef;
bool result = configDefineOptionData[optionDefId].internal;
return configDefineOptionData[optionDefId].internal;
if (dataDefFound)
result = (bool)dataDef;
FUNCTION_TEST_RESULT(BOOL, result);
}
/***********************************************************************************************************************************
@ -577,8 +728,13 @@ Name of the option
const char *
cfgDefOptionName(ConfigDefineOption optionDefId)
{
cfgDefOptionCheck(optionDefId);
return configDefineOptionData[optionDefId].name;
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, optionDefId);
FUNCTION_TEST_ASSERT(optionDefId < cfgDefOptionTotal());
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(STRINGZ, configDefineOptionData[optionDefId].name);
}
/***********************************************************************************************************************************
@ -587,14 +743,20 @@ Option prefix for indexed options
const char *
cfgDefOptionPrefix(ConfigDefineOption optionDefId)
{
cfgDefOptionCheck(optionDefId);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, optionDefId);
FUNCTION_TEST_ASSERT(optionDefId < cfgDefOptionTotal());
FUNCTION_TEST_END();
CONFIG_DEFINE_DATA_FIND(-1, optionDefId, configDefDataTypePrefix);
if (dataDefFound)
return (char *)dataDefList[0];
char *result = NULL;
return NULL;
if (dataDefFound)
result = (char *)dataDefList[0];
FUNCTION_TEST_RESULT(STRINGZ, result);
}
/***********************************************************************************************************************************
@ -603,8 +765,13 @@ Does the option need to be protected from showing up in logs, command lines, etc
bool
cfgDefOptionSecure(ConfigDefineOption optionDefId)
{
cfgDefOptionCheck(optionDefId);
return configDefineOptionData[optionDefId].secure;
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, optionDefId);
FUNCTION_TEST_ASSERT(optionDefId < cfgDefOptionTotal());
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(BOOL, configDefineOptionData[optionDefId].secure);
}
/***********************************************************************************************************************************
@ -613,14 +780,22 @@ Is the option required
bool
cfgDefOptionRequired(ConfigDefineCommand commandDefId, ConfigDefineOption optionDefId)
{
cfgDefCommandOptionCheck(commandDefId, optionDefId);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, commandDefId);
FUNCTION_TEST_PARAM(ENUM, optionDefId);
FUNCTION_TEST_ASSERT(commandDefId < cfgDefCommandTotal());
FUNCTION_TEST_ASSERT(optionDefId < cfgDefOptionTotal());
FUNCTION_TEST_END();
CONFIG_DEFINE_DATA_FIND(commandDefId, optionDefId, configDefDataTypeRequired);
if (dataDefFound)
return (bool)dataDef;
bool result = configDefineOptionData[optionDefId].required;
return configDefineOptionData[optionDefId].required;
if (dataDefFound)
result = (bool)dataDef;
FUNCTION_TEST_RESULT(BOOL, result);
}
/***********************************************************************************************************************************
@ -629,8 +804,13 @@ Get option section
ConfigDefSection
cfgDefOptionSection(ConfigDefineOption optionDefId)
{
cfgDefOptionCheck(optionDefId);
return configDefineOptionData[optionDefId].section;
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, optionDefId);
FUNCTION_TEST_ASSERT(optionDefId < cfgDefOptionTotal());
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(ENUM, configDefineOptionData[optionDefId].section);
}
/***********************************************************************************************************************************
@ -639,8 +819,13 @@ Get option data type
int
cfgDefOptionType(ConfigDefineOption optionDefId)
{
cfgDefOptionCheck(optionDefId);
return configDefineOptionData[optionDefId].type;
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, optionDefId);
FUNCTION_TEST_ASSERT(optionDefId < cfgDefOptionTotal());
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(INT, configDefineOptionData[optionDefId].type);
}
/***********************************************************************************************************************************
@ -649,6 +834,13 @@ Is the option valid for the command?
bool
cfgDefOptionValid(ConfigDefineCommand commandDefId, ConfigDefineOption optionDefId)
{
cfgDefCommandOptionCheck(commandDefId, optionDefId);
return configDefineOptionData[optionDefId].commandValid & (1 << commandDefId);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, commandDefId);
FUNCTION_TEST_PARAM(ENUM, optionDefId);
FUNCTION_TEST_ASSERT(commandDefId < cfgDefCommandTotal());
FUNCTION_TEST_ASSERT(optionDefId < cfgDefOptionTotal());
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(BOOL, configDefineOptionData[optionDefId].commandValid & (1 << commandDefId));
}

View File

@ -6,6 +6,7 @@ Configuration Load
#include "command/command.h"
#include "common/memContext.h"
#include "common/debug.h"
#include "common/lock.h"
#include "common/log.h"
#include "config/config.h"
@ -18,6 +19,8 @@ Load log settings
void
cfgLoadLogSetting()
{
FUNCTION_DEBUG_VOID(logLevelTrace);
// Initialize logging
LogLevel logLevelConsole = logLevelOff;
LogLevel logLevelStdErr = logLevelOff;
@ -43,6 +46,8 @@ cfgLoadLogSetting()
logTimestamp = cfgOptionBool(cfgOptLogTimestamp);
logInit(logLevelConsole, logLevelStdErr, logLevelFile, logTimestamp);
FUNCTION_DEBUG_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -51,6 +56,8 @@ Update options that have complex rules
void
cfgLoadUpdateOption()
{
FUNCTION_DEBUG_VOID(logLevelTrace);
// Set default for repo-host-cmd
if (cfgOptionTest(cfgOptRepoHost) && cfgOptionSource(cfgOptRepoHostCmd) == cfgSourceDefault)
cfgOptionDefaultSet(cfgOptRepoHostCmd, varNewStr(cfgExe()));
@ -186,6 +193,8 @@ cfgLoadUpdateOption()
}
}
}
FUNCTION_DEBUG_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -194,6 +203,11 @@ Load the configuration
void
cfgLoad(unsigned int argListSize, const char *argList[])
{
FUNCTION_DEBUG_BEGIN(logLevelDebug);
FUNCTION_DEBUG_PARAM(UINT, argListSize);
FUNCTION_DEBUG_PARAM(CHARPY, argList);
FUNCTION_DEBUG_END();
MEM_CONTEXT_TEMP_BEGIN()
{
// Parse config from command line and config file
@ -209,12 +223,8 @@ cfgLoad(unsigned int argListSize, const char *argList[])
// If a command is set
if (cfgCommand() != cfgCmdNone)
{
// Acquire a lock if required
if (cfgLockRequired())
lockAcquire(cfgOptionStr(cfgOptLockPath), cfgOptionStr(cfgOptStanza), cfgLockType(), 0, true);
// Open the log file if this command logs to a file
if (cfgLogFile())
if (cfgLogFile() && !cfgCommandHelp())
{
logFileSet(
strPtr(strNewFmt("%s/%s-%s.log", strPtr(cfgOptionStr(cfgOptLogPath)), strPtr(cfgOptionStr(cfgOptStanza)),
@ -224,9 +234,15 @@ cfgLoad(unsigned int argListSize, const char *argList[])
// Begin the command
cmdBegin(true);
// Open the log file if this command logs to a file
if (cfgLockRequired() && !cfgCommandHelp())
lockAcquire(cfgOptionStr(cfgOptLockPath), cfgOptionStr(cfgOptStanza), cfgLockType(), 0, true);
// Update options that have complex rules
cfgLoadUpdateOption();
}
}
MEM_CONTEXT_TEMP_END();
FUNCTION_DEBUG_RESULT_VOID();
}

View File

@ -6,6 +6,7 @@ Command and Option Parse
#include <strings.h>
#include "common/assert.h"
#include "common/debug.h"
#include "common/error.h"
#include "common/ini.h"
#include "common/log.h"
@ -86,6 +87,13 @@ Convert the value passed into bytes and update valueDbl for range checking
void
convertToByte(String **value, double *valueDbl)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(STRINGP, value);
FUNCTION_DEBUG_PARAM(DOUBLEP, valueDbl);
FUNCTION_DEBUG_ASSERT(valueDbl != NULL);
FUNCTION_DEBUG_END();
// Make a copy of the value so it is not updated until we know the conversion will succeed
String *result = strLower(strDup(*value));
@ -161,6 +169,8 @@ convertToByte(String **value, double *valueDbl)
}
else
THROW_FMT(FormatError, "value '%s' is not valid", strPtr(*value));
FUNCTION_DEBUG_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -198,6 +208,18 @@ cfgFileLoad( // NOTE: Pas
const String *optConfigIncludePathDefault, // Current default for --config-include-path option
const String *origConfigDefault) // Original --config option default (/etc/pgbackrest.conf)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM_PTR("ParseOption *", optionList);
FUNCTION_DEBUG_PARAM(STRING, optConfigDefault);
FUNCTION_DEBUG_PARAM(STRING, optConfigIncludePathDefault);
FUNCTION_DEBUG_PARAM(STRING, origConfigDefault);
FUNCTION_TEST_ASSERT(optionList != NULL);
FUNCTION_TEST_ASSERT(optConfigDefault != NULL);
FUNCTION_TEST_ASSERT(optConfigIncludePathDefault != NULL);
FUNCTION_TEST_ASSERT(origConfigDefault != NULL);
FUNCTION_DEBUG_END();
bool loadConfig = true;
bool loadConfigInclude = true;
@ -324,7 +346,7 @@ cfgFileLoad( // NOTE: Pas
}
}
return result;
FUNCTION_DEBUG_RESULT(STRING, result);
}
/***********************************************************************************************************************************
@ -336,6 +358,11 @@ logic to this critical path code.
void
configParse(unsigned int argListSize, const char *argList[])
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(UINT, argListSize);
FUNCTION_DEBUG_PARAM(CHARPY, argList);
FUNCTION_DEBUG_END();
// Initialize configuration
cfgInit();
@ -406,17 +433,11 @@ configParse(unsigned int argListSize, const char *argList[])
// If the option is unknown then error
case '?':
{
THROW_FMT(OptionInvalidError, "invalid option '%s'", argList[optind - 1]);
break;
}
// If the option is missing an argument then error
case ':':
{
THROW_FMT(OptionInvalidError, "option '%s' requires argument", argList[optind - 1]);
break;
}
// Parse valid option
default:
@ -964,4 +985,6 @@ configParse(unsigned int argListSize, const char *argList[])
}
}
MEM_CONTEXT_TEMP_END();
FUNCTION_DEBUG_RESULT_VOID();
}

View File

@ -8,6 +8,7 @@ Main
#include "command/archive/push/push.h"
#include "command/help/help.h"
#include "command/command.h"
#include "common/debug.h"
#include "common/error.h"
#include "common/exit.h"
#include "config/config.h"
@ -18,6 +19,15 @@ Main
int
main(int argListSize, const char *argList[])
{
#ifdef WITH_BACKTRACE
stackTraceInit(argList[0]);
#endif
FUNCTION_DEBUG_BEGIN(logLevelDebug);
FUNCTION_DEBUG_PARAM(INT, argListSize);
FUNCTION_DEBUG_PARAM(CHARPY, argList);
FUNCTION_DEBUG_END();
volatile bool result = 0;
volatile bool error = false;
@ -88,5 +98,5 @@ main(int argListSize, const char *argList[])
}
TRY_END();
return exitSafe(result, error, 0);
FUNCTION_DEBUG_RESULT(INT, exitSafe(result, error, 0));
}

View File

@ -1,6 +1,7 @@
/***********************************************************************************************************************************
Perl Configuration
***********************************************************************************************************************************/
#include "common/debug.h"
#include "common/memContext.h"
#include "config/config.h"
@ -10,6 +11,8 @@ Build JSON output from options
String *
perlOptionJson()
{
FUNCTION_TEST_VOID();
String *result = strNew("{");
MEM_CONTEXT_TEMP_BEGIN()
@ -128,5 +131,5 @@ perlOptionJson()
}
MEM_CONTEXT_TEMP_END();
return result;
FUNCTION_TEST_RESULT(STRING, result);
}

View File

@ -8,6 +8,7 @@ Execute Perl for Legacy Functionality
#include <unistd.h>
#include "version.h"
#include "common/debug.h"
#include "common/error.h"
#include "common/memContext.h"
#include "config/config.h"
@ -56,6 +57,8 @@ Build list of parameters to use for perl main
String *
perlMain()
{
FUNCTION_TEST_VOID();
// Add command arguments to pass to main
String *commandParam = strNew("");
@ -66,22 +69,23 @@ perlMain()
String *mainCall = strNewFmt(
"($result, $message) = " PGBACKREST_MAIN "('%s'%s)", cfgCommandName(cfgCommand()), strPtr(commandParam));
return mainCall;
FUNCTION_TEST_RESULT(STRING, mainCall);
}
/***********************************************************************************************************************************
Init the dynaloader so other C modules can be loaded
There are no FUNCTION_TEST* calls because this is a callback from Perl and it doesn't seem wise to mix our stack stuff up in it.
***********************************************************************************************************************************/
EXTERN_C void boot_DynaLoader (pTHX_ CV* cv);
static void xs_init(pTHX)
{
const char *file = __FILE__;
dXSUB_SYS;
PERL_UNUSED_CONTEXT;
/* DynaLoader is a special case */
newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, __FILE__);
}
/***********************************************************************************************************************************
@ -90,7 +94,13 @@ Evaluate a perl statement
static void
perlEval(const String *statement)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, statement);
FUNCTION_TEST_END();
eval_pv(strPtr(statement), TRUE);
FUNCTION_TEST_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -99,6 +109,8 @@ Initialize Perl
static void
perlInit()
{
FUNCTION_TEST_VOID();
if (!my_perl)
{
// Initialize Perl with dummy args and environment
@ -123,6 +135,8 @@ perlInit()
// Set config data -- this is done separately to avoid it being included in stack traces
perlEval(strNewFmt(PGBACKREST_MAIN "ConfigSet('%s', '%s')", strPtr(cfgExe()), strPtr(perlOptionJson())));
}
FUNCTION_TEST_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -131,6 +145,8 @@ Execute main function in Perl
int
perlExec()
{
FUNCTION_DEBUG_VOID(logLevelDebug);
// Initialize Perl
perlInit();
@ -144,7 +160,7 @@ perlExec()
if (code >= errorTypeCode(&AssertError)) // {uncovered - success tested in integration}
THROW_CODE(code, strlen(message) == 0 ? PERL_EMBED_ERROR : message); // {+uncovered}
return code; // {+uncovered}
FUNCTION_DEBUG_RESULT(INT, code); // {+uncovered}
}
/***********************************************************************************************************************************
@ -155,6 +171,12 @@ Don't bother freeing Perl itself since we are about to exit.
void
perlFree(int result)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(INT, result);
FUNCTION_TEST_END();
if (my_perl != NULL)
perlEval(strNewFmt(PGBACKREST_MAIN "Cleanup(%d)", result));
FUNCTION_TEST_RESULT_VOID();
}

View File

@ -1,6 +1,7 @@
/***********************************************************************************************************************************
PostgreSQL Info
***********************************************************************************************************************************/
#include "common/debug.h"
#include "common/memContext.h"
#include "postgres/info.h"
#include "postgres/type.h"
@ -13,6 +14,11 @@ Map control/catalog version to PostgreSQL version
static uint
pgVersionMap(uint32_t controlVersion, uint32_t catalogVersion)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(UINT32, controlVersion);
FUNCTION_TEST_PARAM(UINT32, catalogVersion);
FUNCTION_TEST_END();
uint result = 0;
if (controlVersion == 1002 && catalogVersion == 201707211)
@ -44,7 +50,7 @@ pgVersionMap(uint32_t controlVersion, uint32_t catalogVersion)
controlVersion, catalogVersion);
}
return result;
FUNCTION_TEST_RESULT(UINT, result);
}
/***********************************************************************************************************************************
@ -53,6 +59,12 @@ Get info from pg_control
PgControlInfo
pgControlInfo(const String *pgPath)
{
FUNCTION_DEBUG_BEGIN(logLevelDebug);
FUNCTION_DEBUG_PARAM(STRING, pgPath);
FUNCTION_TEST_ASSERT(pgPath != NULL);
FUNCTION_DEBUG_END();
PgControlInfo result = {0};
MEM_CONTEXT_TEMP_BEGIN()
@ -73,5 +85,5 @@ pgControlInfo(const String *pgPath)
}
MEM_CONTEXT_TEMP_END();
return result;
FUNCTION_DEBUG_RESULT(PG_CONTROL_INFO, result);
}

View File

@ -25,4 +25,12 @@ Functions
***********************************************************************************************************************************/
PgControlInfo pgControlInfo(const String *pgPath);
/***********************************************************************************************************************************
Macros for function logging
***********************************************************************************************************************************/
#define FUNCTION_DEBUG_PG_CONTROL_INFO_TYPE \
PgControlInfo
#define FUNCTION_DEBUG_PG_CONTROL_INFO_FORMAT(value, buffer, bufferSize) \
objToLog(&value, "PgControlInfo", buffer, bufferSize)
#endif

View File

@ -65,6 +65,7 @@ minimize register spilling. For less sophisticated compilers it might be benefic
#include <string.h>
#include "common/assert.h"
#include "common/debug.h"
#include "common/error.h"
#include "postgres/pageChecksum.h"
#include "postgres/type.h"
@ -134,10 +135,15 @@ do { \
} while (0)
static uint32_t
pageChecksumBlock(const unsigned char *page, uint32_t pageSize)
pageChecksumBlock(const unsigned char *page, unsigned int pageSize)
{
ASSERT_DEBUG(page != NULL);
ASSERT_DEBUG(pageSize == PG_PAGE_SIZE);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(UCHARP, page);
FUNCTION_TEST_PARAM(UINT, pageSize);
FUNCTION_TEST_ASSERT(page != NULL);
FUNCTION_TEST_ASSERT(pageSize == PG_PAGE_SIZE);
FUNCTION_TEST_END();
uint32_t sums[N_SUMS];
uint32_t (*dataArray)[N_SUMS] = (uint32_t (*)[N_SUMS])page;
@ -161,7 +167,7 @@ pageChecksumBlock(const unsigned char *page, uint32_t pageSize)
for (i = 0; i < N_SUMS; i++)
result ^= sums[i];
return result;
FUNCTION_TEST_RESULT(UINT32, result);
}
/***********************************************************************************************************************************
@ -173,7 +179,14 @@ The checksum includes the block number (to detect the case where a page is someh
uint16_t
pageChecksum(const unsigned char *page, unsigned int blockNo, unsigned int pageSize)
{
ASSERT_DEBUG(page != NULL);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(UCHARP, page);
FUNCTION_TEST_PARAM(UINT, blockNo);
FUNCTION_TEST_PARAM(UINT, pageSize);
FUNCTION_TEST_ASSERT(page != NULL);
FUNCTION_TEST_ASSERT(pageSize == PG_PAGE_SIZE);
FUNCTION_TEST_END();
// Save pd_checksum and temporarily set it to zero, so that the checksum calculation isn't affected by the old checksum stored
// on the page. Restore it after, because actually updating the checksum is NOT part of the API of this function.
@ -188,7 +201,7 @@ pageChecksum(const unsigned char *page, unsigned int blockNo, unsigned int pageS
checksum ^= blockNo;
// Reduce to a uint16 with an offset of one. That avoids checksums of zero, which seems like a good idea.
return (uint16_t)((checksum % 65535) + 1);
FUNCTION_TEST_RESULT(UINT16, (uint16_t)(checksum % 65535 + 1));
}
/***********************************************************************************************************************************
@ -198,15 +211,25 @@ bool
pageChecksumTest(
const unsigned char *page, unsigned int blockNo, unsigned int pageSize, uint32_t ignoreWalId, uint32_t ignoreWalOffset)
{
ASSERT_DEBUG(page != NULL);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(UCHARP, page);
FUNCTION_TEST_PARAM(UINT, blockNo);
FUNCTION_TEST_PARAM(UINT, pageSize);
FUNCTION_TEST_PARAM(UINT32, ignoreWalId);
FUNCTION_TEST_PARAM(UINT32, ignoreWalOffset);
return
FUNCTION_TEST_ASSERT(page != NULL);
FUNCTION_TEST_ASSERT(pageSize == PG_PAGE_SIZE);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(
BOOL,
// This is a new page so don't test checksum
((PageHeader)page)->pd_upper == 0 ||
// LSN is after the backup started so checksum is not tested because pages may be torn
(((PageHeader)page)->pd_lsn.walid >= ignoreWalId && ((PageHeader)page)->pd_lsn.xrecoff >= ignoreWalOffset) ||
// Checksum is valid
((PageHeader)page)->pd_checksum == pageChecksum(page, blockNo, pageSize);
((PageHeader)page)->pd_checksum == pageChecksum(page, blockNo, pageSize));
}
/***********************************************************************************************************************************
@ -217,13 +240,21 @@ pageChecksumBufferTest(
const unsigned char *pageBuffer, unsigned int pageBufferSize, unsigned int blockNoBegin, unsigned int pageSize,
uint32_t ignoreWalId, uint32_t ignoreWalOffset)
{
ASSERT_DEBUG(pageBuffer != NULL);
ASSERT_DEBUG(pageBufferSize > 0);
ASSERT_DEBUG(pageSize == PG_PAGE_SIZE);
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(UCHARP, pageBuffer);
FUNCTION_DEBUG_PARAM(UINT, pageBufferSize);
FUNCTION_DEBUG_PARAM(UINT, blockNoBegin);
FUNCTION_DEBUG_PARAM(UINT, pageSize);
FUNCTION_DEBUG_PARAM(UINT32, ignoreWalId);
FUNCTION_DEBUG_PARAM(UINT32, ignoreWalOffset);
// If the buffer does not represent an even number of pages then error
if (pageBufferSize % pageSize != 0)
THROW_FMT(AssertError, "buffer size %u, page size %u are not divisible", pageBufferSize, pageSize);
FUNCTION_TEST_ASSERT(pageBuffer != NULL);
FUNCTION_DEBUG_ASSERT(pageBufferSize > 0);
FUNCTION_DEBUG_ASSERT(pageSize == PG_PAGE_SIZE);
FUNCTION_DEBUG_ASSERT(pageBufferSize % pageSize == 0);
FUNCTION_DEBUG_END();
bool result = true;
// Loop through all pages in the buffer
for (unsigned int pageIdx = 0; pageIdx < pageBufferSize / pageSize; pageIdx++)
@ -232,9 +263,11 @@ pageChecksumBufferTest(
// Return false if the checksums do not match
if (!pageChecksumTest(page, blockNoBegin + pageIdx, pageSize, ignoreWalId, ignoreWalOffset))
return false;
{
result = false;
break;
}
}
// All checksums match
return true;
FUNCTION_DEBUG_RESULT(BOOL, result);
}

View File

@ -13,6 +13,7 @@ Storage Driver Posix
#include <sys/stat.h>
#include <unistd.h>
#include "common/debug.h"
#include "common/memContext.h"
#include "common/regExp.h"
#include "storage/driver/posix/driver.h"
@ -25,6 +26,12 @@ Does a file/path exist?
bool
storageDriverPosixExists(const String *path)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(STRING, path);
FUNCTION_DEBUG_ASSERT(path != NULL);
FUNCTION_DEBUG_END();
bool result = false;
// Attempt to stat the file to determine if it exists
@ -40,7 +47,7 @@ storageDriverPosixExists(const String *path)
else
result = !S_ISDIR(statFile.st_mode);
return result;
FUNCTION_DEBUG_RESULT(BOOL, result);
}
/***********************************************************************************************************************************
@ -49,6 +56,13 @@ File/path info
StorageInfo
storageDriverPosixInfo(const String *file, bool ignoreMissing)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(STRING, file);
FUNCTION_DEBUG_PARAM(BOOL, ignoreMissing);
FUNCTION_DEBUG_ASSERT(file != NULL);
FUNCTION_DEBUG_END();
StorageInfo result = {0};
// Attempt to stat the file
@ -79,7 +93,7 @@ storageDriverPosixInfo(const String *file, bool ignoreMissing)
result.mode = statFile.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
}
return result;
FUNCTION_DEBUG_RESULT(STORAGE_INFO, result);
}
/***********************************************************************************************************************************
@ -88,6 +102,14 @@ Get a list of files from a directory
StringList *
storageDriverPosixList(const String *path, bool errorOnMissing, const String *expression)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(STRING, path);
FUNCTION_DEBUG_PARAM(BOOL, errorOnMissing);
FUNCTION_DEBUG_PARAM(STRING, expression);
FUNCTION_DEBUG_ASSERT(path != NULL);
FUNCTION_DEBUG_END();
StringList *result = NULL;
DIR *dir = NULL;
@ -141,7 +163,7 @@ storageDriverPosixList(const String *path, bool errorOnMissing, const String *ex
}
TRY_END();
return result;
FUNCTION_DEBUG_RESULT(STRING_LIST, result);
}
/***********************************************************************************************************************************
@ -150,6 +172,14 @@ Move a file
bool
storageDriverPosixMove(StorageFileReadPosix *source, StorageFileWritePosix *destination)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(STORAGE_FILE_READ_POSIX, source);
FUNCTION_DEBUG_PARAM(STORAGE_FILE_WRITE_POSIX, destination);
FUNCTION_TEST_ASSERT(source != NULL);
FUNCTION_TEST_ASSERT(destination != NULL);
FUNCTION_DEBUG_END();
bool result = true;
MEM_CONTEXT_TEMP_BEGIN()
@ -199,7 +229,7 @@ storageDriverPosixMove(StorageFileReadPosix *source, StorageFileWritePosix *dest
}
MEM_CONTEXT_TEMP_END();
return result;
FUNCTION_DEBUG_RESULT(BOOL, result);
}
/***********************************************************************************************************************************
@ -208,6 +238,15 @@ Create a path
void
storageDriverPosixPathCreate(const String *path, bool errorOnExists, bool noParentCreate, mode_t mode)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(STRING, path);
FUNCTION_DEBUG_PARAM(BOOL, errorOnExists);
FUNCTION_DEBUG_PARAM(BOOL, noParentCreate);
FUNCTION_DEBUG_PARAM(MODE, mode);
FUNCTION_DEBUG_ASSERT(path != NULL);
FUNCTION_DEBUG_END();
// Attempt to create the directory
if (mkdir(strPtr(path), mode) == -1)
{
@ -221,6 +260,8 @@ storageDriverPosixPathCreate(const String *path, bool errorOnExists, bool noPare
else if (errno != EEXIST || errorOnExists)
THROW_SYS_ERROR_FMT(PathCreateError, "unable to create path '%s'", strPtr(path));
}
FUNCTION_DEBUG_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -229,6 +270,14 @@ Remove a path
void
storageDriverPosixPathRemove(const String *path, bool errorOnMissing, bool recurse)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(STRING, path);
FUNCTION_DEBUG_PARAM(BOOL, errorOnMissing);
FUNCTION_DEBUG_PARAM(BOOL, recurse);
FUNCTION_DEBUG_ASSERT(path != NULL);
FUNCTION_DEBUG_END();
MEM_CONTEXT_TEMP_BEGIN()
{
// Recurse if requested
@ -267,6 +316,8 @@ storageDriverPosixPathRemove(const String *path, bool errorOnMissing, bool recur
}
}
MEM_CONTEXT_TEMP_END();
FUNCTION_DEBUG_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -275,6 +326,13 @@ Sync a path
void
storageDriverPosixPathSync(const String *path, bool ignoreMissing)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(STRING, path);
FUNCTION_DEBUG_PARAM(BOOL, ignoreMissing);
FUNCTION_DEBUG_ASSERT(path != NULL);
FUNCTION_DEBUG_END();
// Open directory and handle errors
int handle = storageFilePosixOpen(path, O_RDONLY, 0, ignoreMissing, &PathOpenError, "sync");
@ -287,6 +345,8 @@ storageDriverPosixPathSync(const String *path, bool ignoreMissing)
// Close the directory
storageFilePosixClose(handle, path, &PathCloseError);
}
FUNCTION_DEBUG_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -295,10 +355,19 @@ Remove a file
void
storageDriverPosixRemove(const String *file, bool errorOnMissing)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(STRING, file);
FUNCTION_DEBUG_PARAM(BOOL, errorOnMissing);
FUNCTION_DEBUG_ASSERT(file != NULL);
FUNCTION_DEBUG_END();
// Attempt to unlink the file
if (unlink(strPtr(file)) == -1)
{
if (errorOnMissing || errno != ENOENT)
THROW_SYS_ERROR_FMT(FileRemoveError, "unable to remove '%s'", strPtr(file));
}
FUNCTION_DEBUG_RESULT_VOID();
}

View File

@ -10,6 +10,7 @@ Storage File Routines For Posix
#include <unistd.h>
#include "common/assert.h"
#include "common/debug.h"
#include "storage/driver/posix/driverFile.h"
/***********************************************************************************************************************************
@ -21,6 +22,19 @@ int
storageFilePosixOpen(
const String *name, int flags, mode_t mode, bool ignoreMissing, const ErrorType *errorType, const char *purpose)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, name);
FUNCTION_TEST_PARAM(INT, flags);
FUNCTION_TEST_PARAM(MODE, mode);
FUNCTION_TEST_PARAM(BOOL, ignoreMissing);
FUNCTION_TEST_PARAM(ERROR_TYPE, errorType);
FUNCTION_TEST_PARAM(STRINGZ, purpose);
FUNCTION_TEST_ASSERT(name != NULL);
FUNCTION_TEST_ASSERT(errorType != NULL);
FUNCTION_TEST_ASSERT(purpose != NULL);
FUNCTION_TEST_END();
int result = -1;
result = open(strPtr(name), flags, mode);
@ -31,7 +45,7 @@ storageFilePosixOpen(
THROWP_SYS_ERROR_FMT(errorType, "unable to open '%s' for %s", strPtr(name), purpose);
}
return result;
FUNCTION_TEST_RESULT(INT, result);
}
/***********************************************************************************************************************************
@ -40,6 +54,17 @@ Sync a file/directory handle
void
storageFilePosixSync(int handle, const String *name, const ErrorType *errorType, bool closeOnError)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(INT, handle);
FUNCTION_TEST_PARAM(STRING, name);
FUNCTION_TEST_PARAM(ERROR_TYPE, errorType);
FUNCTION_TEST_PARAM(BOOL, closeOnError);
FUNCTION_TEST_ASSERT(handle != -1);
FUNCTION_TEST_ASSERT(name != NULL);
FUNCTION_TEST_ASSERT(errorType != NULL);
FUNCTION_TEST_END();
if (fsync(handle) == -1)
{
int errNo = errno;
@ -50,6 +75,8 @@ storageFilePosixSync(int handle, const String *name, const ErrorType *errorType,
THROWP_SYS_ERROR_CODE_FMT(errNo, errorType, "unable to sync '%s'", strPtr(name));
}
FUNCTION_TEST_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -58,6 +85,18 @@ Close a file/directory handle
void
storageFilePosixClose(int handle, const String *name, const ErrorType *errorType)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(INT, handle);
FUNCTION_TEST_PARAM(STRING, name);
FUNCTION_TEST_PARAM(ERROR_TYPE, errorType);
FUNCTION_TEST_ASSERT(handle != -1);
FUNCTION_TEST_ASSERT(name != NULL);
FUNCTION_TEST_ASSERT(errorType != NULL);
FUNCTION_TEST_END();
if (close(handle) == -1)
THROWP_SYS_ERROR_FMT(errorType, "unable to close '%s'", strPtr(name));
FUNCTION_TEST_RESULT_VOID();
}

View File

@ -5,6 +5,7 @@ Storage File Read Driver For Posix
#include <unistd.h>
#include "common/assert.h"
#include "common/debug.h"
#include "common/memContext.h"
#include "storage/driver/posix/driverFile.h"
#include "storage/driver/posix/driverRead.h"
@ -31,10 +32,16 @@ Create a new file
StorageFileReadPosix *
storageFileReadPosixNew(const String *name, bool ignoreMissing, size_t bufferSize)
{
StorageFileReadPosix *this = NULL;
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(STRING, name);
FUNCTION_DEBUG_PARAM(BOOL, ignoreMissing);
FUNCTION_DEBUG_PARAM(BOOL, bufferSize);
ASSERT_DEBUG(name != NULL);
ASSERT_DEBUG(bufferSize > 0);
FUNCTION_TEST_ASSERT(name != NULL);
FUNCTION_TEST_ASSERT(bufferSize > 0);
FUNCTION_DEBUG_END();
StorageFileReadPosix *this = NULL;
// Create the file object
MEM_CONTEXT_NEW_BEGIN("StorageFileReadPosix")
@ -49,7 +56,7 @@ storageFileReadPosixNew(const String *name, bool ignoreMissing, size_t bufferSiz
}
MEM_CONTEXT_NEW_END();
return this;
FUNCTION_DEBUG_RESULT(STORAGE_FILE_READ_POSIX, this);
}
/***********************************************************************************************************************************
@ -58,10 +65,14 @@ Open the file
bool
storageFileReadPosixOpen(StorageFileReadPosix *this)
{
bool result = false;
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(STORAGE_FILE_READ_POSIX, this);
ASSERT_DEBUG(this != NULL);
ASSERT_DEBUG(this->handle == -1);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(this->handle == -1);
FUNCTION_DEBUG_END();
bool result = false;
// Open the file and handle errors
this->handle = storageFilePosixOpen(this->name, O_RDONLY, 0, this->ignoreMissing, &FileOpenError, "read");
@ -73,7 +84,7 @@ storageFileReadPosixOpen(StorageFileReadPosix *this)
result = true;
}
return result;
FUNCTION_DEBUG_RESULT(BOOL, result);
}
/***********************************************************************************************************************************
@ -82,6 +93,13 @@ Read from a file
Buffer *
storageFileReadPosix(StorageFileReadPosix *this)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(STORAGE_FILE_READ_POSIX, this);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(this->handle != -1);
FUNCTION_DEBUG_END();
Buffer *result = NULL;
ASSERT_DEBUG(this != NULL);
@ -112,7 +130,7 @@ storageFileReadPosix(StorageFileReadPosix *this)
}
}
return result;
FUNCTION_DEBUG_RESULT(BUFFER, result);
}
/***********************************************************************************************************************************
@ -121,7 +139,11 @@ Close the file
void
storageFileReadPosixClose(StorageFileReadPosix *this)
{
ASSERT_DEBUG(this != NULL);
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(STORAGE_FILE_READ_POSIX, this);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_DEBUG_END();
// Close if the file has not already been closed
if (this->handle != -1)
@ -131,6 +153,8 @@ storageFileReadPosixClose(StorageFileReadPosix *this)
this->handle = -1;
}
FUNCTION_DEBUG_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -139,9 +163,13 @@ Should a missing file be ignored?
bool
storageFileReadPosixIgnoreMissing(StorageFileReadPosix *this)
{
ASSERT_DEBUG(this != NULL);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STORAGE_FILE_READ_POSIX, this);
return this->ignoreMissing;
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(BOOL, this->ignoreMissing);
}
/***********************************************************************************************************************************
@ -150,9 +178,13 @@ File name
const String *
storageFileReadPosixName(StorageFileReadPosix *this)
{
ASSERT_DEBUG(this != NULL);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STORAGE_FILE_READ_POSIX, this);
return this->name;
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(CONST_STRING, this->name);
}
/***********************************************************************************************************************************
@ -161,9 +193,13 @@ File size
size_t
storageFileReadPosixSize(StorageFileReadPosix *this)
{
ASSERT_DEBUG(this != NULL);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STORAGE_FILE_READ_POSIX, this);
return this->size;
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(SIZE, this->size);
}
/***********************************************************************************************************************************
@ -172,9 +208,15 @@ Free the file
void
storageFileReadPosixFree(StorageFileReadPosix *this)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(STORAGE_FILE_READ_POSIX, this);
FUNCTION_DEBUG_END();
if (this != NULL)
{
storageFileReadPosixClose(this);
memContextFree(this->memContext);
}
FUNCTION_DEBUG_RESULT_VOID();
}

View File

@ -36,4 +36,12 @@ Destructor
***********************************************************************************************************************************/
void storageFileReadPosixFree(StorageFileReadPosix *this);
/***********************************************************************************************************************************
Macros for function logging
***********************************************************************************************************************************/
#define FUNCTION_DEBUG_STORAGE_FILE_READ_POSIX_TYPE \
StorageFileReadPosix *
#define FUNCTION_DEBUG_STORAGE_FILE_READ_POSIX_FORMAT(value, buffer, bufferSize) \
objToLog(value, "StorageFileReadPosix", buffer, bufferSize)
#endif

View File

@ -6,6 +6,7 @@ Storage File Write Driver For Posix
#include <unistd.h>
#include "common/assert.h"
#include "common/debug.h"
#include "common/memContext.h"
#include "storage/driver/posix/driverFile.h"
#include "storage/driver/posix/driverWrite.h"
@ -48,6 +49,18 @@ StorageFileWritePosix *
storageFileWritePosixNew(
const String *name, mode_t modeFile, mode_t modePath, bool noCreatePath, bool noSyncFile, bool noSyncPath, bool noAtomic)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(STRING, name);
FUNCTION_DEBUG_PARAM(MODE, modeFile);
FUNCTION_DEBUG_PARAM(MODE, modePath);
FUNCTION_DEBUG_PARAM(BOOL, noCreatePath);
FUNCTION_DEBUG_PARAM(BOOL, noSyncFile);
FUNCTION_DEBUG_PARAM(BOOL, noSyncPath);
FUNCTION_DEBUG_PARAM(BOOL, noAtomic);
FUNCTION_TEST_ASSERT(name != NULL);
FUNCTION_DEBUG_END();
StorageFileWritePosix *this = NULL;
ASSERT_DEBUG(name != NULL);
@ -71,7 +84,7 @@ storageFileWritePosixNew(
}
MEM_CONTEXT_NEW_END();
return this;
FUNCTION_DEBUG_RESULT(STORAGE_FILE_WRITE_POSIX, this);
}
/***********************************************************************************************************************************
@ -80,8 +93,12 @@ Open the file
void
storageFileWritePosixOpen(StorageFileWritePosix *this)
{
ASSERT_DEBUG(this != NULL);
ASSERT_DEBUG(this->handle == -1);
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(STORAGE_FILE_WRITE_POSIX, this);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(this->handle == -1);
FUNCTION_DEBUG_END();
// Open the file and handle errors
this->handle = storageFilePosixOpen(
@ -100,6 +117,8 @@ storageFileWritePosixOpen(StorageFileWritePosix *this)
// On success set free callback to ensure file handle is freed
else
memContextCallback(this->memContext, (MemContextCallback)storageFileWritePosixFree, this);
FUNCTION_DEBUG_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -108,13 +127,20 @@ Write to a file
void
storageFileWritePosix(StorageFileWritePosix *this, const Buffer *buffer)
{
ASSERT_DEBUG(this != NULL);
ASSERT_DEBUG(buffer != NULL);
ASSERT_DEBUG(this->handle != -1);
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(STORAGE_FILE_WRITE_POSIX, this);
FUNCTION_DEBUG_PARAM(BUFFER, buffer);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_ASSERT(buffer != NULL);
FUNCTION_TEST_ASSERT(this->handle != -1);
FUNCTION_DEBUG_END();
// Write the data
if (write(this->handle, bufPtr(buffer), bufSize(buffer)) != (ssize_t)bufSize(buffer))
THROW_SYS_ERROR_FMT(FileWriteError, "unable to write '%s'", strPtr(this->name));
FUNCTION_DEBUG_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -123,7 +149,11 @@ Close the file
void
storageFileWritePosixClose(StorageFileWritePosix *this)
{
ASSERT_DEBUG(this != NULL);
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(STORAGE_FILE_WRITE_POSIX, this);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_DEBUG_END();
// Close if the file has not already been closed
if (this->handle != -1)
@ -149,6 +179,8 @@ storageFileWritePosixClose(StorageFileWritePosix *this)
// This marks the file as closed
this->handle = -1;
}
FUNCTION_DEBUG_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -159,9 +191,13 @@ For the posix driver this means writing to a temp file first and then renaming o
bool
storageFileWritePosixAtomic(StorageFileWritePosix *this)
{
ASSERT_DEBUG(this != NULL);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STORAGE_FILE_WRITE_POSIX, this);
return !this->noAtomic;
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(BOOL, !this->noAtomic);
}
/***********************************************************************************************************************************
@ -170,9 +206,13 @@ Will the path be created for the file if it does not exist?
bool
storageFileWritePosixCreatePath(StorageFileWritePosix *this)
{
ASSERT_DEBUG(this != NULL);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STORAGE_FILE_WRITE_POSIX, this);
return !this->noCreatePath;
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(BOOL, !this->noCreatePath);
}
/***********************************************************************************************************************************
@ -181,9 +221,13 @@ Mode for the file to be created
mode_t
storageFileWritePosixModeFile(StorageFileWritePosix *this)
{
ASSERT_DEBUG(this != NULL);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STORAGE_FILE_WRITE_POSIX, this);
return this->modeFile;
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(MODE, this->modeFile);
}
/***********************************************************************************************************************************
@ -192,9 +236,13 @@ Mode for any paths that are created while writing the file
mode_t
storageFileWritePosixModePath(StorageFileWritePosix *this)
{
ASSERT_DEBUG(this != NULL);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STORAGE_FILE_WRITE_POSIX, this);
return this->modePath;
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(MODE, this->modePath);
}
/***********************************************************************************************************************************
@ -203,9 +251,13 @@ File name
const String *
storageFileWritePosixName(StorageFileWritePosix *this)
{
ASSERT_DEBUG(this != NULL);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STORAGE_FILE_WRITE_POSIX, this);
return this->name;
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(CONST_STRING, this->name);
}
/***********************************************************************************************************************************
@ -214,9 +266,13 @@ File path
const String *
storageFileWritePosixPath(StorageFileWritePosix *this)
{
ASSERT_DEBUG(this != NULL);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STORAGE_FILE_WRITE_POSIX, this);
return this->path;
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(CONST_STRING, this->path);
}
/***********************************************************************************************************************************
@ -225,9 +281,13 @@ Will the file be synced after it is closed?
bool
storageFileWritePosixSyncFile(StorageFileWritePosix *this)
{
ASSERT_DEBUG(this != NULL);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STORAGE_FILE_WRITE_POSIX, this);
return !this->noSyncFile;
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(BOOL, !this->noSyncFile);
}
/***********************************************************************************************************************************
@ -236,9 +296,13 @@ Will the directory be synced to disk after the write is completed?
bool
storageFileWritePosixSyncPath(StorageFileWritePosix *this)
{
ASSERT_DEBUG(this != NULL);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STORAGE_FILE_WRITE_POSIX, this);
return !this->noSyncPath;
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(BOOL, !this->noSyncPath);
}
/***********************************************************************************************************************************
@ -247,9 +311,15 @@ Free the file
void
storageFileWritePosixFree(StorageFileWritePosix *this)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(STORAGE_FILE_WRITE_POSIX, this);
FUNCTION_DEBUG_END();
if (this != NULL)
{
storageFileWritePosixClose(this);
memContextFree(this->memContext);
}
FUNCTION_DEBUG_RESULT_VOID();
}

View File

@ -44,4 +44,12 @@ Destructor
***********************************************************************************************************************************/
void storageFileWritePosixFree(StorageFileWritePosix *this);
/***********************************************************************************************************************************
Macros for function logging
***********************************************************************************************************************************/
#define FUNCTION_DEBUG_STORAGE_FILE_WRITE_POSIX_TYPE \
StorageFileWritePosix *
#define FUNCTION_DEBUG_STORAGE_FILE_WRITE_POSIX_FORMAT(value, buffer, bufferSize) \
objToLog(value, "StorageFileWritePosix", buffer, bufferSize)
#endif

View File

@ -2,6 +2,7 @@
Storage File Read
***********************************************************************************************************************************/
#include "common/assert.h"
#include "common/debug.h"
#include "common/memContext.h"
#include "storage/fileRead.h"
@ -20,9 +21,16 @@ Create a new storage file
StorageFileRead *
storageFileReadNew(const String *name, bool ignoreMissing, size_t bufferSize)
{
StorageFileRead *this = NULL;
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(STRING, name);
FUNCTION_DEBUG_PARAM(BOOL, ignoreMissing);
FUNCTION_DEBUG_PARAM(BOOL, bufferSize);
ASSERT_DEBUG(name != NULL);
FUNCTION_TEST_ASSERT(name != NULL);
FUNCTION_TEST_ASSERT(bufferSize > 0);
FUNCTION_DEBUG_END();
StorageFileRead *this = NULL;
MEM_CONTEXT_NEW_BEGIN("StorageFileRead")
{
@ -34,7 +42,7 @@ storageFileReadNew(const String *name, bool ignoreMissing, size_t bufferSize)
}
MEM_CONTEXT_NEW_END();
return this;
FUNCTION_DEBUG_RESULT(STORAGE_FILE_READ, this);
}
/***********************************************************************************************************************************
@ -43,9 +51,13 @@ Open the file
bool
storageFileReadOpen(StorageFileRead *this)
{
ASSERT_DEBUG(this != NULL);
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(STORAGE_FILE_READ, this);
return storageFileReadPosixOpen(this->fileDriver);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_DEBUG_END();
FUNCTION_DEBUG_RESULT(BOOL, storageFileReadPosixOpen(this->fileDriver));
}
/***********************************************************************************************************************************
@ -54,9 +66,13 @@ Read data from the file
Buffer *
storageFileRead(StorageFileRead *this)
{
ASSERT_DEBUG(this != NULL);
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(STORAGE_FILE_READ, this);
return storageFileReadPosix(this->fileDriver);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_DEBUG_END();
FUNCTION_DEBUG_RESULT(BUFFER, storageFileReadPosix(this->fileDriver));
}
/***********************************************************************************************************************************
@ -65,10 +81,17 @@ Move the file object to a new context
StorageFileRead *
storageFileReadMove(StorageFileRead *this, MemContext *parentNew)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STORAGE_FILE_READ, this);
FUNCTION_TEST_PARAM(MEM_CONTEXT, parentNew);
FUNCTION_TEST_ASSERT(parentNew != NULL);
FUNCTION_TEST_END();
if (this != NULL)
memContextMove(this->memContext, parentNew);
return this;
FUNCTION_TEST_RESULT(STORAGE_FILE_READ, this);
}
/***********************************************************************************************************************************
@ -77,9 +100,15 @@ Close the file
void
storageFileReadClose(StorageFileRead *this)
{
ASSERT_DEBUG(this != NULL);
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(STORAGE_FILE_READ, this);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_DEBUG_END();
storageFileReadPosixClose(this->fileDriver);
FUNCTION_DEBUG_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -88,9 +117,13 @@ Get file driver
StorageFileReadPosix *
storageFileReadFileDriver(const StorageFileRead *this)
{
ASSERT_DEBUG(this != NULL);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STORAGE_FILE_READ, this);
return this->fileDriver;
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(STORAGE_FILE_READ_POSIX, this->fileDriver);
}
/***********************************************************************************************************************************
@ -99,9 +132,13 @@ Should a missing file be ignored?
bool
storageFileReadIgnoreMissing(const StorageFileRead *this)
{
ASSERT_DEBUG(this != NULL);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STORAGE_FILE_READ, this);
return storageFileReadPosixIgnoreMissing(this->fileDriver);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(BOOL, storageFileReadPosixIgnoreMissing(this->fileDriver));
}
/***********************************************************************************************************************************
@ -110,9 +147,13 @@ Get file name
const String *
storageFileReadName(const StorageFileRead *this)
{
ASSERT_DEBUG(this != NULL);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STORAGE_FILE_READ, this);
return storageFileReadPosixName(this->fileDriver);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(CONST_STRING, storageFileReadPosixName(this->fileDriver));
}
/***********************************************************************************************************************************
@ -121,9 +162,13 @@ Get file size
size_t
storageFileReadSize(const StorageFileRead *this)
{
ASSERT_DEBUG(this != NULL);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STORAGE_FILE_READ, this);
return storageFileReadPosixSize(this->fileDriver);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(SIZE, storageFileReadPosixSize(this->fileDriver));
}
/***********************************************************************************************************************************
@ -132,6 +177,12 @@ Free the file
void
storageFileReadFree(StorageFileRead *this)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(STORAGE_FILE_READ, this);
FUNCTION_DEBUG_END();
if (this != NULL)
memContextFree(this->memContext);
FUNCTION_DEBUG_RESULT_VOID();
}

View File

@ -40,4 +40,12 @@ Destructor
***********************************************************************************************************************************/
void storageFileReadFree(StorageFileRead *this);
/***********************************************************************************************************************************
Macros for function logging
***********************************************************************************************************************************/
#define FUNCTION_DEBUG_STORAGE_FILE_READ_TYPE \
StorageFileRead *
#define FUNCTION_DEBUG_STORAGE_FILE_READ_FORMAT(value, buffer, bufferSize) \
objToLog(value, "StorageFileRead", buffer, bufferSize)
#endif

View File

@ -2,6 +2,7 @@
Storage File Write
***********************************************************************************************************************************/
#include "common/assert.h"
#include "common/debug.h"
#include "common/memContext.h"
#include "storage/fileWrite.h"
@ -24,6 +25,18 @@ StorageFileWrite *
storageFileWriteNew(
const String *name, mode_t modeFile, mode_t modePath, bool noCreatePath, bool noSyncFile, bool noSyncPath, bool noAtomic)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(STRING, name);
FUNCTION_DEBUG_PARAM(MODE, modeFile);
FUNCTION_DEBUG_PARAM(MODE, modePath);
FUNCTION_DEBUG_PARAM(BOOL, noCreatePath);
FUNCTION_DEBUG_PARAM(BOOL, noSyncFile);
FUNCTION_DEBUG_PARAM(BOOL, noSyncPath);
FUNCTION_DEBUG_PARAM(BOOL, noAtomic);
FUNCTION_TEST_ASSERT(name != NULL);
FUNCTION_DEBUG_END();
StorageFileWrite *this = NULL;
ASSERT_DEBUG(name != NULL);
@ -39,7 +52,7 @@ storageFileWriteNew(
}
MEM_CONTEXT_NEW_END();
return this;
FUNCTION_DEBUG_RESULT(STORAGE_FILE_WRITE, this);
}
/***********************************************************************************************************************************
@ -48,10 +61,16 @@ Open the file
void
storageFileWriteOpen(StorageFileWrite *this)
{
ASSERT_DEBUG(this != NULL);
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(STORAGE_FILE_WRITE, this);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_DEBUG_END();
// Open the file
storageFileWritePosixOpen(this->fileDriver);
FUNCTION_DEBUG_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -60,11 +79,18 @@ Write to a file
void
storageFileWrite(StorageFileWrite *this, const Buffer *buffer)
{
ASSERT_DEBUG(this != NULL);
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(STORAGE_FILE_WRITE, this);
FUNCTION_DEBUG_PARAM(BUFFER, buffer);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_DEBUG_END();
// Only write if there is data to write
if (buffer != NULL && bufSize(buffer) > 0)
storageFileWritePosix(this->fileDriver, buffer);
FUNCTION_DEBUG_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -73,10 +99,17 @@ Move the file object to a new context
StorageFileWrite *
storageFileWriteMove(StorageFileWrite *this, MemContext *parentNew)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STORAGE_FILE_WRITE, this);
FUNCTION_TEST_PARAM(MEM_CONTEXT, parentNew);
FUNCTION_TEST_ASSERT(parentNew != NULL);
FUNCTION_TEST_END();
if (this != NULL)
memContextMove(this->memContext, parentNew);
return this;
FUNCTION_TEST_RESULT(STORAGE_FILE_WRITE, this);
}
/***********************************************************************************************************************************
@ -85,9 +118,15 @@ Close the file
void
storageFileWriteClose(StorageFileWrite *this)
{
ASSERT_DEBUG(this != NULL);
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(STORAGE_FILE_WRITE, this);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_DEBUG_END();
storageFileWritePosixClose(this->fileDriver);
FUNCTION_DEBUG_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -98,9 +137,13 @@ Atomic writes means the file will be complete or be missing. Filesystems have d
bool
storageFileWriteAtomic(const StorageFileWrite *this)
{
ASSERT_DEBUG(this != NULL);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STORAGE_FILE_WRITE, this);
return storageFileWritePosixAtomic(this->fileDriver);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(BOOL, storageFileWritePosixAtomic(this->fileDriver));
}
/***********************************************************************************************************************************
@ -109,9 +152,13 @@ Will the path be created if required?
bool
storageFileWriteCreatePath(const StorageFileWrite *this)
{
ASSERT_DEBUG(this != NULL);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STORAGE_FILE_WRITE, this);
return storageFileWritePosixCreatePath(this->fileDriver);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(BOOL, storageFileWritePosixCreatePath(this->fileDriver));
}
/***********************************************************************************************************************************
@ -120,9 +167,13 @@ Get file driver
StorageFileWritePosix *
storageFileWriteFileDriver(const StorageFileWrite *this)
{
ASSERT_DEBUG(this != NULL);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STORAGE_FILE_WRITE, this);
return this->fileDriver;
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(STORAGE_FILE_WRITE_POSIX, this->fileDriver);
}
/***********************************************************************************************************************************
@ -131,9 +182,13 @@ Get file mode
mode_t
storageFileWriteModeFile(const StorageFileWrite *this)
{
ASSERT_DEBUG(this != NULL);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STORAGE_FILE_WRITE, this);
return storageFileWritePosixModeFile(this->fileDriver);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(MODE, storageFileWritePosixModeFile(this->fileDriver));
}
/***********************************************************************************************************************************
@ -142,9 +197,13 @@ Get path mode
mode_t
storageFileWriteModePath(const StorageFileWrite *this)
{
ASSERT_DEBUG(this != NULL);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STORAGE_FILE_WRITE, this);
return storageFileWritePosixModePath(this->fileDriver);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(MODE, storageFileWritePosixModePath(this->fileDriver));
}
/***********************************************************************************************************************************
@ -153,9 +212,13 @@ Get file name
const String *
storageFileWriteName(const StorageFileWrite *this)
{
ASSERT_DEBUG(this != NULL);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STORAGE_FILE_WRITE, this);
return storageFileWritePosixName(this->fileDriver);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(CONST_STRING, storageFileWritePosixName(this->fileDriver));
}
/***********************************************************************************************************************************
@ -164,9 +227,13 @@ Get file path
const String *
storageFileWritePath(const StorageFileWrite *this)
{
ASSERT_DEBUG(this != NULL);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STORAGE_FILE_WRITE, this);
return storageFileWritePosixPath(this->fileDriver);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(CONST_STRING, storageFileWritePosixPath(this->fileDriver));
}
/***********************************************************************************************************************************
@ -175,9 +242,13 @@ Will the file be synced after it is closed?
bool
storageFileWriteSyncFile(const StorageFileWrite *this)
{
ASSERT_DEBUG(this != NULL);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STORAGE_FILE_WRITE, this);
return storageFileWritePosixSyncFile(this->fileDriver);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(BOOL, storageFileWritePosixSyncFile(this->fileDriver));
}
/***********************************************************************************************************************************
@ -186,9 +257,13 @@ Will the path be synced after the file is closed?
bool
storageFileWriteSyncPath(const StorageFileWrite *this)
{
ASSERT_DEBUG(this != NULL);
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STORAGE_FILE_WRITE, this);
return storageFileWritePosixSyncPath(this->fileDriver);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(BOOL, storageFileWritePosixSyncPath(this->fileDriver));
}
/***********************************************************************************************************************************
@ -197,6 +272,12 @@ Free the file
void
storageFileWriteFree(const StorageFileWrite *this)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(STORAGE_FILE_WRITE, this);
FUNCTION_DEBUG_END();
if (this != NULL)
memContextFree(this->memContext);
FUNCTION_DEBUG_RESULT_VOID();
}

View File

@ -54,4 +54,12 @@ Destructor
***********************************************************************************************************************************/
void storageFileWriteFree(const StorageFileWrite *this);
/***********************************************************************************************************************************
Macros for function logging
***********************************************************************************************************************************/
#define FUNCTION_DEBUG_STORAGE_FILE_WRITE_TYPE \
StorageFileWrite *
#define FUNCTION_DEBUG_STORAGE_FILE_WRITE_FORMAT(value, buffer, bufferSize) \
objToLog(value, "StorageFileWrite", buffer, bufferSize)
#endif

View File

@ -3,6 +3,7 @@ Storage Helper
***********************************************************************************************************************************/
#include <string.h>
#include "common/debug.h"
#include "common/memContext.h"
#include "config/config.h"
#include "storage/helper.h"
@ -30,6 +31,8 @@ Create the storage helper memory context
static void
storageHelperInit()
{
FUNCTION_TEST_VOID();
if (memContextStorageHelper == NULL)
{
MEM_CONTEXT_BEGIN(memContextTop())
@ -38,6 +41,8 @@ storageHelperInit()
}
MEM_CONTEXT_END();
}
FUNCTION_TEST_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -46,10 +51,12 @@ Get a local storage object
const Storage *
storageLocal()
{
storageHelperInit();
FUNCTION_TEST_VOID();
if (storageLocalData == NULL)
{
storageHelperInit();
MEM_CONTEXT_BEGIN(memContextStorageHelper)
{
storageLocalData = storageNewNP(strNew("/"));
@ -57,7 +64,7 @@ storageLocal()
MEM_CONTEXT_END();
}
return storageLocalData;
FUNCTION_TEST_RESULT(STORAGE, storageLocalData);
}
/***********************************************************************************************************************************
@ -68,10 +75,12 @@ This should be used very sparingly. If writes are not needed then always use st
const Storage *
storageLocalWrite()
{
storageHelperInit();
FUNCTION_TEST_VOID();
if (storageLocalWriteData == NULL)
{
storageHelperInit();
MEM_CONTEXT_BEGIN(memContextStorageHelper)
{
storageLocalWriteData = storageNewP(strNew("/"), .write = true);
@ -79,7 +88,7 @@ storageLocalWrite()
MEM_CONTEXT_END();
}
return storageLocalWriteData;
FUNCTION_TEST_RESULT(STORAGE, storageLocalWriteData);
}
/***********************************************************************************************************************************
@ -88,6 +97,13 @@ Get a spool storage object
String *
storageSpoolPathExpression(const String *expression, const String *path)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, expression);
FUNCTION_TEST_PARAM(STRING, path);
FUNCTION_TEST_ASSERT(expression != NULL);
FUNCTION_TEST_END();
String *result = NULL;
if (strcmp(strPtr(expression), STORAGE_SPOOL_ARCHIVE_IN) == 0)
@ -107,7 +123,7 @@ storageSpoolPathExpression(const String *expression, const String *path)
else
THROW_FMT(AssertError, "invalid expression '%s'", strPtr(expression));
return result;
FUNCTION_TEST_RESULT(STRING, result);
}
/***********************************************************************************************************************************
@ -116,10 +132,12 @@ Get a spool storage object
const Storage *
storageSpool()
{
storageHelperInit();
FUNCTION_TEST_VOID();
if (storageSpoolData == NULL)
{
storageHelperInit();
MEM_CONTEXT_BEGIN(memContextStorageHelper)
{
storageSpoolStanza = strDup(cfgOptionStr(cfgOptStanza));
@ -130,5 +148,5 @@ storageSpool()
MEM_CONTEXT_END();
}
return storageSpoolData;
FUNCTION_TEST_RESULT(STORAGE, storageSpoolData);
}

View File

@ -27,4 +27,12 @@ typedef struct StorageInfo
mode_t mode; // Mode of path/file/link
} StorageInfo;
/***********************************************************************************************************************************
Macros for function logging
***********************************************************************************************************************************/
#define FUNCTION_DEBUG_STORAGE_INFO_TYPE \
StorageInfo
#define FUNCTION_DEBUG_STORAGE_INFO_FORMAT(value, buffer, bufferSize) \
objToLog(&value, "StorageInfo", buffer, bufferSize)
#endif

View File

@ -1,9 +1,11 @@
/***********************************************************************************************************************************
Storage Manager
***********************************************************************************************************************************/
#include <stdio.h>
#include <string.h>
#include "common/assert.h"
#include "common/debug.h"
#include "common/memContext.h"
#include "common/wait.h"
#include "storage/driver/posix/driver.h"
@ -23,24 +25,24 @@ struct Storage
StoragePathExpressionCallback pathExpressionFunction;
};
/***********************************************************************************************************************************
Debug Asserts
***********************************************************************************************************************************/
// Check that commands that write are not allowed unless the storage is writable
#define ASSERT_STORAGE_ALLOWS_WRITE() \
ASSERT(this->write == true)
/***********************************************************************************************************************************
New storage object
***********************************************************************************************************************************/
Storage *
storageNew(const String *path, StorageNewParam param)
{
Storage *this = NULL;
FUNCTION_DEBUG_BEGIN(logLevelDebug);
FUNCTION_DEBUG_PARAM(STRING, path);
FUNCTION_DEBUG_PARAM(MODE, param.modeFile);
FUNCTION_DEBUG_PARAM(MODE, param.modePath);
FUNCTION_DEBUG_PARAM(SIZE, param.bufferSize);
FUNCTION_DEBUG_PARAM(BOOL, param.write);
FUNCTION_DEBUG_PARAM(FUNCTIONP, param.pathExpressionFunction);
// Path is required
if (path == NULL)
THROW(AssertError, "storage base path cannot be null");
FUNCTION_DEBUG_ASSERT(path != NULL);
FUNCTION_DEBUG_END();
Storage *this = NULL;
// Create the storage
MEM_CONTEXT_NEW_BEGIN("Storage")
@ -56,7 +58,7 @@ storageNew(const String *path, StorageNewParam param)
}
MEM_CONTEXT_NEW_END();
return this;
FUNCTION_DEBUG_RESULT(STORAGE, this);
}
/***********************************************************************************************************************************
@ -65,6 +67,14 @@ Copy a file
bool
storageCopy(StorageFileRead *source, StorageFileWrite *destination)
{
FUNCTION_DEBUG_BEGIN(logLevelDebug);
FUNCTION_DEBUG_PARAM(STORAGE_FILE_READ, source);
FUNCTION_DEBUG_PARAM(STORAGE_FILE_WRITE, destination);
FUNCTION_TEST_ASSERT(source != NULL);
FUNCTION_TEST_ASSERT(destination != NULL);
FUNCTION_DEBUG_END();
bool result = false;
MEM_CONTEXT_TEMP_BEGIN()
@ -95,7 +105,7 @@ storageCopy(StorageFileRead *source, StorageFileWrite *destination)
}
MEM_CONTEXT_TEMP_END();
return result;
FUNCTION_DEBUG_RESULT(BOOL, result);
}
/***********************************************************************************************************************************
@ -104,10 +114,16 @@ Does a file/path exist?
bool
storageExists(const Storage *this, const String *pathExp, StorageExistsParam param)
{
bool result = false;
FUNCTION_DEBUG_BEGIN(logLevelDebug);
FUNCTION_DEBUG_PARAM(STORAGE, this);
FUNCTION_DEBUG_PARAM(STRING, pathExp);
FUNCTION_DEBUG_PARAM(DOUBLE, param.timeout);
// Timeout can't be negative
ASSERT_DEBUG(param.timeout >= 0);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_DEBUG_ASSERT(param.timeout >= 0);
FUNCTION_DEBUG_END();
bool result = false;
MEM_CONTEXT_TEMP_BEGIN()
{
@ -127,7 +143,7 @@ storageExists(const Storage *this, const String *pathExp, StorageExistsParam par
}
MEM_CONTEXT_TEMP_END();
return result;
FUNCTION_DEBUG_RESULT(BOOL, result);
}
/***********************************************************************************************************************************
@ -136,9 +152,13 @@ Read from storage into a buffer
Buffer *
storageGet(StorageFileRead *file)
{
Buffer *result = NULL;
FUNCTION_DEBUG_BEGIN(logLevelDebug);
FUNCTION_DEBUG_PARAM(STORAGE_FILE_READ, file);
ASSERT_DEBUG(file != NULL);
FUNCTION_TEST_ASSERT(file != NULL);
FUNCTION_DEBUG_END();
Buffer *result = NULL;
// If the file exists
if (storageFileReadOpen(file))
@ -166,7 +186,7 @@ storageGet(StorageFileRead *file)
storageFileReadClose(file);
}
return result;
FUNCTION_DEBUG_RESULT(BUFFER, result);
}
/***********************************************************************************************************************************
@ -175,6 +195,14 @@ File/path info
StorageInfo
storageInfo(const Storage *this, const String *fileExp, StorageInfoParam param)
{
FUNCTION_DEBUG_BEGIN(logLevelDebug);
FUNCTION_DEBUG_PARAM(STORAGE, this);
FUNCTION_DEBUG_PARAM(STRING, fileExp);
FUNCTION_DEBUG_PARAM(BOOL, param.ignoreMissing);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_DEBUG_END();
StorageInfo result = {0};
MEM_CONTEXT_TEMP_BEGIN()
@ -187,7 +215,7 @@ storageInfo(const Storage *this, const String *fileExp, StorageInfoParam param)
}
MEM_CONTEXT_TEMP_END();
return result;
FUNCTION_DEBUG_RESULT(STORAGE_INFO, result);
}
/***********************************************************************************************************************************
@ -196,6 +224,15 @@ Get a list of files from a directory
StringList *
storageList(const Storage *this, const String *pathExp, StorageListParam param)
{
FUNCTION_DEBUG_BEGIN(logLevelDebug);
FUNCTION_DEBUG_PARAM(STORAGE, this);
FUNCTION_DEBUG_PARAM(STRING, pathExp);
FUNCTION_DEBUG_PARAM(BOOL, param.errorOnMissing);
FUNCTION_DEBUG_PARAM(STRING, param.expression);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_DEBUG_END();
StringList *result = NULL;
MEM_CONTEXT_TEMP_BEGIN()
@ -208,7 +245,7 @@ storageList(const Storage *this, const String *pathExp, StorageListParam param)
}
MEM_CONTEXT_TEMP_END();
return result;
FUNCTION_DEBUG_RESULT(STRING_LIST, result);
}
/***********************************************************************************************************************************
@ -217,7 +254,14 @@ Move a file
void
storageMove(StorageFileRead *source, StorageFileWrite *destination)
{
ASSERT_DEBUG(!storageFileReadIgnoreMissing(source));
FUNCTION_DEBUG_BEGIN(logLevelDebug);
FUNCTION_DEBUG_PARAM(STORAGE_FILE_READ, source);
FUNCTION_DEBUG_PARAM(STORAGE_FILE_WRITE, destination);
FUNCTION_TEST_ASSERT(source != NULL);
FUNCTION_TEST_ASSERT(destination != NULL);
FUNCTION_DEBUG_ASSERT(!storageFileReadIgnoreMissing(source));
FUNCTION_DEBUG_END();
MEM_CONTEXT_TEMP_BEGIN()
{
@ -237,6 +281,8 @@ storageMove(StorageFileRead *source, StorageFileWrite *destination)
}
}
MEM_CONTEXT_TEMP_END();
FUNCTION_DEBUG_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -245,6 +291,14 @@ Open a file for reading
StorageFileRead *
storageNewRead(const Storage *this, const String *fileExp, StorageNewReadParam param)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(STORAGE, this);
FUNCTION_DEBUG_PARAM(STRING, fileExp);
FUNCTION_DEBUG_PARAM(BOOL, param.ignoreMissing);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_DEBUG_END();
StorageFileRead *result = NULL;
MEM_CONTEXT_NEW_BEGIN("StorageFileRead")
@ -256,7 +310,7 @@ storageNewRead(const Storage *this, const String *fileExp, StorageNewReadParam p
}
MEM_CONTEXT_NEW_END();
return result;
FUNCTION_DEBUG_RESULT(STORAGE_FILE_READ, result);
}
/***********************************************************************************************************************************
@ -265,9 +319,21 @@ Open a file for writing
StorageFileWrite *
storageNewWrite(const Storage *this, const String *fileExp, StorageNewWriteParam param)
{
StorageFileWrite *result = NULL;
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(STORAGE, this);
FUNCTION_DEBUG_PARAM(STRING, fileExp);
FUNCTION_DEBUG_PARAM(MODE, param.modeFile);
FUNCTION_DEBUG_PARAM(MODE, param.modePath);
FUNCTION_DEBUG_PARAM(BOOL, param.noCreatePath);
FUNCTION_DEBUG_PARAM(BOOL, param.noSyncFile);
FUNCTION_DEBUG_PARAM(BOOL, param.noSyncPath);
FUNCTION_DEBUG_PARAM(BOOL, param.noAtomic);
ASSERT_STORAGE_ALLOWS_WRITE();
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_DEBUG_ASSERT(this->write);
FUNCTION_DEBUG_END();
StorageFileWrite *result = NULL;
MEM_CONTEXT_TEMP_BEGIN()
{
@ -283,7 +349,7 @@ storageNewWrite(const Storage *this, const String *fileExp, StorageNewWriteParam
}
MEM_CONTEXT_TEMP_END();
return result;
FUNCTION_DEBUG_RESULT(STORAGE_FILE_WRITE, result);
}
/***********************************************************************************************************************************
@ -292,6 +358,13 @@ Get the absolute path in the storage
String *
storagePath(const Storage *this, const String *pathExp)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STORAGE, this);
FUNCTION_TEST_PARAM(STRING, pathExp);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
String *result = NULL;
// If there there is no path expression then return the base storage path
@ -378,7 +451,7 @@ storagePath(const Storage *this, const String *pathExp)
}
}
return result;
FUNCTION_TEST_RESULT(STRING, result);
}
/***********************************************************************************************************************************
@ -387,11 +460,21 @@ Create a path
void
storagePathCreate(const Storage *this, const String *pathExp, StoragePathCreateParam param)
{
ASSERT_STORAGE_ALLOWS_WRITE();
FUNCTION_DEBUG_BEGIN(logLevelDebug);
FUNCTION_DEBUG_PARAM(STORAGE, this);
FUNCTION_DEBUG_PARAM(STRING, pathExp);
FUNCTION_DEBUG_PARAM(BOOL, param.errorOnExists);
FUNCTION_DEBUG_PARAM(BOOL, param.noParentCreate);
FUNCTION_DEBUG_PARAM(MODE, param.mode);
// It doesn't make sense to combine these parameters because if we are creating missing parent paths why error when they exist?
// If this somehow wasn't caught in testing, the worst case is that the path would not be created and an error would be thrown.
ASSERT_DEBUG(!(param.noParentCreate && param.errorOnExists));
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_DEBUG_ASSERT(this->write);
// It doesn't make sense to combine these parameters because if we are creating missing parent paths why error when they
// exist? If this somehow wasn't caught in testing, the worst case is that the path would not be created and an error would
// be thrown.
FUNCTION_TEST_ASSERT(!(param.noParentCreate && param.errorOnExists));
FUNCTION_DEBUG_END();
MEM_CONTEXT_TEMP_BEGIN()
{
@ -403,6 +486,8 @@ storagePathCreate(const Storage *this, const String *pathExp, StoragePathCreateP
path, param.errorOnExists, param.noParentCreate, param.mode != 0 ? param.mode : this->modePath);
}
MEM_CONTEXT_TEMP_END();
FUNCTION_DEBUG_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -411,7 +496,15 @@ Remove a path
void
storagePathRemove(const Storage *this, const String *pathExp, StoragePathRemoveParam param)
{
ASSERT_STORAGE_ALLOWS_WRITE();
FUNCTION_DEBUG_BEGIN(logLevelDebug);
FUNCTION_DEBUG_PARAM(STORAGE, this);
FUNCTION_DEBUG_PARAM(STRING, pathExp);
FUNCTION_DEBUG_PARAM(BOOL, param.errorOnMissing);
FUNCTION_DEBUG_PARAM(BOOL, param.recurse);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_DEBUG_ASSERT(this->write);
FUNCTION_DEBUG_END();
MEM_CONTEXT_TEMP_BEGIN()
{
@ -422,6 +515,8 @@ storagePathRemove(const Storage *this, const String *pathExp, StoragePathRemoveP
storageDriverPosixPathRemove(path, param.errorOnMissing, param.recurse);
}
MEM_CONTEXT_TEMP_END();
FUNCTION_DEBUG_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -429,7 +524,14 @@ Sync a path
***********************************************************************************************************************************/
void storagePathSync(const Storage *this, const String *pathExp, StoragePathSyncParam param)
{
ASSERT_STORAGE_ALLOWS_WRITE();
FUNCTION_DEBUG_BEGIN(logLevelDebug);
FUNCTION_DEBUG_PARAM(STORAGE, this);
FUNCTION_DEBUG_PARAM(STRING, pathExp);
FUNCTION_DEBUG_PARAM(BOOL, param.ignoreMissing);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_DEBUG_ASSERT(this->write);
FUNCTION_DEBUG_END();
MEM_CONTEXT_TEMP_BEGIN()
{
@ -440,6 +542,8 @@ void storagePathSync(const Storage *this, const String *pathExp, StoragePathSync
storageDriverPosixPathSync(path, param.ignoreMissing);
}
MEM_CONTEXT_TEMP_END();
FUNCTION_DEBUG_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -448,9 +552,18 @@ Write a buffer to storage
void
storagePut(StorageFileWrite *file, const Buffer *buffer)
{
FUNCTION_DEBUG_BEGIN(logLevelDebug);
FUNCTION_DEBUG_PARAM(STORAGE_FILE_WRITE, file);
FUNCTION_DEBUG_PARAM(BUFFER, buffer);
FUNCTION_DEBUG_ASSERT(file != NULL);
FUNCTION_DEBUG_END();
storageFileWriteOpen(file);
storageFileWrite(file, buffer);
storageFileWriteClose(file);
FUNCTION_DEBUG_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -459,7 +572,14 @@ Remove a file
void
storageRemove(const Storage *this, const String *fileExp, StorageRemoveParam param)
{
ASSERT_STORAGE_ALLOWS_WRITE();
FUNCTION_DEBUG_BEGIN(logLevelDebug);
FUNCTION_DEBUG_PARAM(STORAGE, this);
FUNCTION_DEBUG_PARAM(STRING, fileExp);
FUNCTION_DEBUG_PARAM(BOOL, param.errorOnMissing);
FUNCTION_DEBUG_ASSERT(this != NULL);
FUNCTION_DEBUG_ASSERT(this->write);
FUNCTION_DEBUG_END();
MEM_CONTEXT_TEMP_BEGIN()
{
@ -470,6 +590,32 @@ storageRemove(const Storage *this, const String *fileExp, StorageRemoveParam par
storageDriverPosixRemove(file, param.errorOnMissing);
}
MEM_CONTEXT_TEMP_END();
FUNCTION_DEBUG_RESULT_VOID();
}
/***********************************************************************************************************************************
Convert to a zero-terminated string for logging
***********************************************************************************************************************************/
size_t
storageToLog(const Storage *this, char *buffer, size_t bufferSize)
{
size_t result = 0;
MEM_CONTEXT_TEMP_BEGIN()
{
String *string = NULL;
if (this == NULL)
string = strNew("null");
else
string = strNewFmt("{path: %s, write: %s}", strPtr(strQuoteZ(this->path, "\"")), this->write ? "true" : "false");
result = (size_t)snprintf(buffer, bufferSize, "%s", strPtr(string));
}
MEM_CONTEXT_TEMP_END();
return result;
}
/***********************************************************************************************************************************
@ -478,6 +624,12 @@ Free storage
void
storageFree(const Storage *this)
{
FUNCTION_DEBUG_BEGIN(logLevelDebug);
FUNCTION_DEBUG_PARAM(STORAGE, this);
FUNCTION_DEBUG_END();
if (this != NULL)
memContextFree(this->memContext);
FUNCTION_DEBUG_RESULT_VOID();
}

View File

@ -247,4 +247,14 @@ storageFree
void storageFree(const Storage *this);
/***********************************************************************************************************************************
Macros for function logging
***********************************************************************************************************************************/
size_t storageToLog(const Storage *this, char *buffer, size_t bufferSize);
#define FUNCTION_DEBUG_STORAGE_TYPE \
Storage *
#define FUNCTION_DEBUG_STORAGE_FORMAT(value, buffer, bufferSize) \
(size_t)storageToLog(value, buffer, bufferSize)
#endif

5
test/Vagrantfile vendored
View File

@ -43,9 +43,8 @@ Vagrant.configure(2) do |config|
# Set time sync settings so builds don't fail with clock drift errors
#---------------------------------------------------------------------------------------------------------------------------
echo 'Time Sync Settings' && date
/etc/init.d/virtualbox-guest-utils stop
/usr/sbin/VBoxService --timesync-set-on-restore 1 --timesync-interval 5000 --timesync-set-threshold 1
/etc/init.d/virtualbox-guest-utils start
sudo /etc/init.d/virtualbox-guest-utils stop
sudo /usr/sbin/VBoxService --timesync-set-on-restore 1 --timesync-interval 5000 --timesync-set-threshold 1
#---------------------------------------------------------------------------------------------------------------------------
echo 'Install Perl Modules' && date

View File

@ -33,18 +33,10 @@ unit:
- name: common
test:
# ----------------------------------------------------------------------------------------------------------------------------
- name: time
total: 2
define: -DNO_ERROR -DNO_LOG
coverage:
common/time: full
# ----------------------------------------------------------------------------------------------------------------------------
- name: error
total: 8
define: -DNO_ERROR -DNO_LOG
define: -DNO_ERROR -DNO_LOG -DNO_STACK_TRACE -DNO_MEM_CONTEXT
coverage:
common/error: full
@ -53,7 +45,7 @@ unit:
# ----------------------------------------------------------------------------------------------------------------------------
- name: assert-on
total: 2
define: -DNO_LOG
define: -DNO_LOG -DNO_STACK_TRACE -DNO_MEM_CONTEXT
coverage:
common/assert: noCode
@ -61,19 +53,19 @@ unit:
# ----------------------------------------------------------------------------------------------------------------------------
- name: assert-off
total: 2
define: -DNDEBUG -DNO_LOG
define: -DNDEBUG -DNO_LOG -DNO_STACK_TRACE -DNO_MEM_CONTEXT
debugUnitSuppress: true
coverage:
common/assert: noCode
# ----------------------------------------------------------------------------------------------------------------------------
- name: fork
total: 1
define: -DNO_LOG
- name: stack-trace
total: 4
define: -DNO_LOG -DNO_STACK_TRACE -DNO_MEM_CONTEXT
coverage:
common/fork: full
common/stackTrace: full
# ----------------------------------------------------------------------------------------------------------------------------
- name: mem-context
@ -83,20 +75,36 @@ unit:
coverage:
common/memContext: full
# ----------------------------------------------------------------------------------------------------------------------------
- name: time
total: 2
define: -DNO_ERROR -DNO_LOG
coverage:
common/time: full
# ----------------------------------------------------------------------------------------------------------------------------
- name: fork
total: 1
define: -DNO_LOG
coverage:
common/fork: full
# ----------------------------------------------------------------------------------------------------------------------------
- name: log
total: 5
define: -DNO_LOG
define: -DIN_LOG
coverage:
common/log: full
# ----------------------------------------------------------------------------------------------------------------------------
- name: debug-on
total: 2
total: 4
coverage:
common/debug: noCode
common/debug: full
# ----------------------------------------------------------------------------------------------------------------------------
- name: debug-off
@ -105,7 +113,7 @@ unit:
debugUnitSuppress: true
coverage:
common/debug: noCode
common/debug: full
# ----------------------------------------------------------------------------------------------------------------------------
- name: lock
@ -135,6 +143,13 @@ unit:
coverage:
common/wait: full
# ----------------------------------------------------------------------------------------------------------------------------
- name: type-convert
total: 8
coverage:
common/type/convert: full
# ----------------------------------------------------------------------------------------------------------------------------
- name: type-list
total: 3
@ -144,14 +159,14 @@ unit:
# ----------------------------------------------------------------------------------------------------------------------------
- name: type-string
total: 11
total: 13
coverage:
common/type/string: full
# ----------------------------------------------------------------------------------------------------------------------------
- name: type-string-list
total: 8
total: 9
coverage:
common/type/stringList: full
@ -165,7 +180,7 @@ unit:
# ----------------------------------------------------------------------------------------------------------------------------
- name: type-variant
total: 7
total: 8
coverage:
common/type/variant: full

View File

@ -83,8 +83,12 @@ full backup - create pg_stat link, pg_clog dir (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --no-online --manifest-save-threshold=3 --buffer-size=16384 --checksum-page --process-max=1 --repo1-type=cifs --type=full --stanza=db backup
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: backup command begin [BACKREST-VERSION]: --buffer-size=16384 --checksum-page --no-compress --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --no-log-timestamp --manifest-save-threshold=3 --no-online --pg1-path=[TEST_PATH]/db-master/db/base --process-max=1 --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --repo1-type=cifs --stanza=db --start-fast --type=full
P00 DEBUG: common/lock::lockAcquire: (lockPath: {"[TEST_PATH]/db-master/lock"}, stanza: {"db"}, lockType: 1, lockTimeout: 0, failOnNoLock: true)
P00 DEBUG: common/lock::lockAcquire: => true
P00 WARN: option repo1-retention-full is not set, the repository may run out of space
HINT: to retain full backups indefinitely (without warning), set option 'repo1-retention-full' to the maximum.
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [hash], lBufferMax = 16384, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = [TEST_PATH]/db-master/repo, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathExists(): strPathExp =
@ -292,8 +296,10 @@ P00 DEBUG: Storage::Local->openWrite(): bAtomic = <false>, bPathCreate = <f
P00 DEBUG: Storage::Local->pathSync(): strPathExp = [TEST_PATH]/db-master/repo/backup/db
P00 DEBUG: Storage::Local->openWrite(): bAtomic = <false>, bPathCreate = <false>, lTimestamp = [undef], rhyFilter = [undef], strCipherPass = [undef], strGroup = [undef], strMode = <0640>, strUser = [undef], xFileExp = [TEST_PATH]/db-master/repo/backup/db/backup.info.copy
P00 DEBUG: Storage::Local->pathSync(): strPathExp = [TEST_PATH]/db-master/repo/backup/db
P00 DEBUG: perl/exec::perlExec: => 0
P00 INFO: backup command end: completed successfully
P00 INFO: expire command begin
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Storage::Local->pathExists(): strPathExp =
P00 DEBUG: Storage::Local->pathExists=>: bExists = true
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 0770, strPathExp = [TEST_PATH]/db-master/log
@ -324,10 +330,16 @@ P00 DEBUG: Storage::Local->list=>: stryFileList = ([BACKUP-FULL-1])
P00 DEBUG: Backup::Info->current(): strBackup = [BACKUP-FULL-1]
P00 DEBUG: Backup::Info->current=>: bTest = true
P00 INFO: option 'repo1-retention-archive' is not set - archive logs will not be expired
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => true
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: expire command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
+ supplemental file: [TEST_PATH]/db-master/pgbackrest.conf
----------------------------------------------------------
@ -466,27 +478,39 @@ full backup - invalid cmd line (db-master host)
------------------------------------------------------------------------------------------------------------------------------------
STDERR:
ERROR: [037]: backup command requires option: pg1-path
HINT: does this stanza exist?
HINT: does this stanza exist?
stop all stanzas (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --force stop
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stop command begin [BACKREST-VERSION]: --config=[TEST_PATH]/db-master/pgbackrest.conf --force --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --no-log-timestamp --repo1-path=[TEST_PATH]/db-master/repo
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = [undef], oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 770, strPathExp = [TEST_PATH]/db-master/lock
P00 INFO: sent term signal to process [PROCESS-ID]
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => false
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: stop command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
full backup - abort backup - local (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --no-online --type=full --stanza=db backup --test --test-delay=5 --test-point=backup-start=y
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: backup command begin [BACKREST-VERSION]: --no-compress --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --no-log-timestamp --no-online --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --stanza=db --start-fast --test --test-delay=5 --test-point=backup-start=y --type=full
P00 DEBUG: common/lock::lockAcquire: (lockPath: {"[TEST_PATH]/db-master/lock"}, stanza: {"db"}, lockType: 1, lockTimeout: 0, failOnNoLock: true)
P00 DEBUG: common/lock::lockAcquire: => true
P00 WARN: option repo1-retention-full is not set, the repository may run out of space
HINT: to retain full backups indefinitely (without warning), set option 'repo1-retention-full' to the maximum.
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [hash], lBufferMax = 4194304, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = [TEST_PATH]/db-master/repo, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathExists(): strPathExp =
@ -563,8 +587,12 @@ full backup - global stop (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --no-online --type=full --stanza=db backup
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: backup command begin [BACKREST-VERSION]: --no-compress --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --no-log-timestamp --no-online --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --stanza=db --start-fast --type=full
P00 DEBUG: common/lock::lockAcquire: (lockPath: {"[TEST_PATH]/db-master/lock"}, stanza: {"db"}, lockType: 1, lockTimeout: 0, failOnNoLock: true)
P00 DEBUG: common/lock::lockAcquire: => true
P00 WARN: option repo1-retention-full is not set, the repository may run out of space
HINT: to retain full backups indefinitely (without warning), set option 'repo1-retention-full' to the maximum.
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [hash], lBufferMax = 4194304, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = [TEST_PATH]/db-master/repo, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathExists(): strPathExp =
@ -574,42 +602,67 @@ P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBu
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 0770, strPathExp = [TEST_PATH]/db-master/log
P00 DEBUG: Common::Lock::lockStopTest(): bStanzaStopRequired = <false>
P00 ERROR: [062]: stop file exists for all stanzas
P00 DEBUG: common/exit::exitSafe: (result: 0, error: true, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => true
P00 DEBUG: Main::mainCleanup(): iExitCode = 62
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = false, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: backup command end: aborted with exception [062]
P00 DEBUG: common/exit::exitSafe: => 62
P00 DEBUG: main::main: => 62
stop db stanza (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db stop
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stop command begin [BACKREST-VERSION]: --config=[TEST_PATH]/db-master/pgbackrest.conf --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --no-log-timestamp --repo1-path=[TEST_PATH]/db-master/repo --stanza=db
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = [undef], oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 770, strPathExp = [TEST_PATH]/db-master/lock
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => false
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: stop command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
stop db stanza (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db stop
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stop command begin [BACKREST-VERSION]: --config=[TEST_PATH]/db-master/pgbackrest.conf --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --no-log-timestamp --repo1-path=[TEST_PATH]/db-master/repo --stanza=db
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = [undef], oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 770, strPathExp = [TEST_PATH]/db-master/lock
P00 WARN: stop file already exists for stanza db
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => false
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: stop command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
full backup - stanza stop (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --no-online --type=full --stanza=db backup
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: backup command begin [BACKREST-VERSION]: --no-compress --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --no-log-timestamp --no-online --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --stanza=db --start-fast --type=full
P00 DEBUG: common/lock::lockAcquire: (lockPath: {"[TEST_PATH]/db-master/lock"}, stanza: {"db"}, lockType: 1, lockTimeout: 0, failOnNoLock: true)
P00 DEBUG: common/lock::lockAcquire: => true
P00 WARN: option repo1-retention-full is not set, the repository may run out of space
HINT: to retain full backups indefinitely (without warning), set option 'repo1-retention-full' to the maximum.
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [hash], lBufferMax = 4194304, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = [TEST_PATH]/db-master/repo, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathExists(): strPathExp =
@ -619,45 +672,78 @@ P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBu
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 0770, strPathExp = [TEST_PATH]/db-master/log
P00 DEBUG: Common::Lock::lockStopTest(): bStanzaStopRequired = <false>
P00 ERROR: [062]: stop file exists for stanza db
P00 DEBUG: common/exit::exitSafe: (result: 0, error: true, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => true
P00 DEBUG: Main::mainCleanup(): iExitCode = 62
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = false, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: backup command end: aborted with exception [062]
P00 DEBUG: common/exit::exitSafe: => 62
P00 DEBUG: main::main: => 62
start db stanza (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db start
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: start command begin [BACKREST-VERSION]: --config=[TEST_PATH]/db-master/pgbackrest.conf --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --no-log-timestamp --repo1-path=[TEST_PATH]/db-master/repo --stanza=db
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => false
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: start command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
start all stanzas (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf start
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: start command begin [BACKREST-VERSION]: --config=[TEST_PATH]/db-master/pgbackrest.conf --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --no-log-timestamp --repo1-path=[TEST_PATH]/db-master/repo
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => false
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: start command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
start all stanzas (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf start
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: start command begin [BACKREST-VERSION]: --config=[TEST_PATH]/db-master/pgbackrest.conf --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --no-log-timestamp --repo1-path=[TEST_PATH]/db-master/repo
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 WARN: stop file does not exist
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => false
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: start command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
full backup - resume (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --no-online --force --checksum-page --type=full --stanza=db backup --test --test-delay=0.2 --test-point=backup-resume=y
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: backup command begin [BACKREST-VERSION]: --checksum-page --no-compress --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --force --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --no-log-timestamp --no-online --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --stanza=db --start-fast --test --test-delay=0.2 --test-point=backup-resume=y --type=full
P00 DEBUG: common/lock::lockAcquire: (lockPath: {"[TEST_PATH]/db-master/lock"}, stanza: {"db"}, lockType: 1, lockTimeout: 0, failOnNoLock: true)
P00 DEBUG: common/lock::lockAcquire: => true
P00 WARN: option repo1-retention-full is not set, the repository may run out of space
HINT: to retain full backups indefinitely (without warning), set option 'repo1-retention-full' to the maximum.
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [hash], lBufferMax = 4194304, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = [TEST_PATH]/db-master/repo, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathExists(): strPathExp =
@ -861,8 +947,10 @@ P00 DEBUG: Storage::Local->pathSync(): strPathExp = [TEST_PATH]/db-master/r
P00 DEBUG: Storage::Local->openWrite(): bAtomic = <false>, bPathCreate = <false>, lTimestamp = [undef], rhyFilter = [undef], strCipherPass = [undef], strGroup = [undef], strMode = <0640>, strUser = [undef], xFileExp = [TEST_PATH]/db-master/repo/backup/db/backup.info.copy
P00 DEBUG: Storage::Local->pathSync(): strPathExp = [TEST_PATH]/db-master/repo/backup/db
P00 DEBUG: Storage::Local->pathSync(): strPathExp = <REPO:BACKUP>
P00 DEBUG: perl/exec::perlExec: => 0
P00 INFO: backup command end: completed successfully
P00 INFO: expire command begin
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Storage::Local->pathExists(): strPathExp =
P00 DEBUG: Storage::Local->pathExists=>: bExists = true
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 0770, strPathExp = [TEST_PATH]/db-master/log
@ -893,10 +981,16 @@ P00 DEBUG: Storage::Local->list=>: stryFileList = ([BACKUP-FULL-2])
P00 DEBUG: Backup::Info->current(): strBackup = [BACKUP-FULL-2]
P00 DEBUG: Backup::Info->current=>: bTest = true
P00 INFO: option 'repo1-retention-archive' is not set - archive logs will not be expired
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => true
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: expire command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
+ supplemental file: [TEST_PATH]/db-master/pgbackrest.conf
----------------------------------------------------------
@ -1043,6 +1137,8 @@ restore delta, backup '[BACKUP-FULL-2]' - add and delete files (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --delta --set=[BACKUP-FULL-2] --link-all --stanza=db restore
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: restore command begin [BACKREST-VERSION]: --no-compress --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --delta --link-all --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --no-log-timestamp --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --set=[BACKUP-FULL-2] --stanza=db
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [hash], lBufferMax = 4194304, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = [TEST_PATH]/db-master/repo, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathExists(): strPathExp =
@ -1338,10 +1434,16 @@ P00 DEBUG: Storage::Local->pathSync(): strPathExp = [TEST_PATH]/db-master/d
P00 DEBUG: Storage::Local->remove(): bIgnoreMissing = <true>, bRecurse = <false>, xstryPathFileExp = [TEST_PATH]/db-master/db/base/backup.manifest
P00 DEBUG: Storage::Local->remove=>: bRemoved = true
P00 DEBUG: Storage::Local->pathSync(): strPathExp = [TEST_PATH]/db-master/db/base
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => false
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: restore command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
+ supplemental file: [TEST_PATH]/db-master/db/base/recovery.conf
----------------------------------------------------------------
@ -1725,8 +1827,12 @@ incr backup - add tablespace 1 (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --no-online --test --stanza=db backup
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: backup command begin [BACKREST-VERSION]: --no-compress --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --no-log-timestamp --no-online --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --stanza=db --start-fast --test
P00 DEBUG: common/lock::lockAcquire: (lockPath: {"[TEST_PATH]/db-master/lock"}, stanza: {"db"}, lockType: 1, lockTimeout: 0, failOnNoLock: true)
P00 DEBUG: common/lock::lockAcquire: => true
P00 WARN: option repo1-retention-full is not set, the repository may run out of space
HINT: to retain full backups indefinitely (without warning), set option 'repo1-retention-full' to the maximum.
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [hash], lBufferMax = 4194304, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = [TEST_PATH]/db-master/repo, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathExists(): strPathExp =
@ -1907,8 +2013,10 @@ P00 DEBUG: Storage::Local->pathSync(): strPathExp = [TEST_PATH]/db-master/r
P00 DEBUG: Storage::Local->openWrite(): bAtomic = <false>, bPathCreate = <false>, lTimestamp = [undef], rhyFilter = [undef], strCipherPass = [undef], strGroup = [undef], strMode = <0640>, strUser = [undef], xFileExp = [TEST_PATH]/db-master/repo/backup/db/backup.info.copy
P00 DEBUG: Storage::Local->pathSync(): strPathExp = [TEST_PATH]/db-master/repo/backup/db
P00 DEBUG: Storage::Local->pathSync(): strPathExp = <REPO:BACKUP>
P00 DEBUG: perl/exec::perlExec: => 0
P00 INFO: backup command end: completed successfully
P00 INFO: expire command begin
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Storage::Local->pathExists(): strPathExp =
P00 DEBUG: Storage::Local->pathExists=>: bExists = true
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 0770, strPathExp = [TEST_PATH]/db-master/log
@ -1947,10 +2055,16 @@ P00 DEBUG: Backup::Info->current=>: bTest = true
P00 DEBUG: Backup::Info->current(): strBackup = [BACKUP-FULL-2]
P00 DEBUG: Backup::Info->current=>: bTest = true
P00 INFO: option 'repo1-retention-archive' is not set - archive logs will not be expired
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => true
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: expire command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
+ supplemental file: [TEST_PATH]/db-master/pgbackrest.conf
----------------------------------------------------------
@ -2091,8 +2205,12 @@ incr backup - resume and add tablespace 2 (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --no-online --process-max=1 --stanza=db backup --test --test-delay=0.2 --test-point=backup-resume=y
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: backup command begin [BACKREST-VERSION]: --no-compress --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --no-log-timestamp --no-online --pg1-path=[TEST_PATH]/db-master/db/base --process-max=1 --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --stanza=db --start-fast --test --test-delay=0.2 --test-point=backup-resume=y
P00 DEBUG: common/lock::lockAcquire: (lockPath: {"[TEST_PATH]/db-master/lock"}, stanza: {"db"}, lockType: 1, lockTimeout: 0, failOnNoLock: true)
P00 DEBUG: common/lock::lockAcquire: => true
P00 WARN: option repo1-retention-full is not set, the repository may run out of space
HINT: to retain full backups indefinitely (without warning), set option 'repo1-retention-full' to the maximum.
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [hash], lBufferMax = 4194304, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = [TEST_PATH]/db-master/repo, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathExists(): strPathExp =
@ -2317,8 +2435,10 @@ P00 DEBUG: Storage::Local->pathSync(): strPathExp = [TEST_PATH]/db-master/r
P00 DEBUG: Storage::Local->openWrite(): bAtomic = <false>, bPathCreate = <false>, lTimestamp = [undef], rhyFilter = [undef], strCipherPass = [undef], strGroup = [undef], strMode = <0640>, strUser = [undef], xFileExp = [TEST_PATH]/db-master/repo/backup/db/backup.info.copy
P00 DEBUG: Storage::Local->pathSync(): strPathExp = [TEST_PATH]/db-master/repo/backup/db
P00 DEBUG: Storage::Local->pathSync(): strPathExp = <REPO:BACKUP>
P00 DEBUG: perl/exec::perlExec: => 0
P00 INFO: backup command end: completed successfully
P00 INFO: expire command begin
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Storage::Local->pathExists(): strPathExp =
P00 DEBUG: Storage::Local->pathExists=>: bExists = true
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 0770, strPathExp = [TEST_PATH]/db-master/log
@ -2357,10 +2477,16 @@ P00 DEBUG: Backup::Info->current=>: bTest = true
P00 DEBUG: Backup::Info->current(): strBackup = [BACKUP-FULL-2]
P00 DEBUG: Backup::Info->current=>: bTest = true
P00 INFO: option 'repo1-retention-archive' is not set - archive logs will not be expired
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => true
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: expire command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
+ supplemental file: [TEST_PATH]/db-master/pgbackrest.conf
----------------------------------------------------------
@ -2848,6 +2974,8 @@ restore, backup '[BACKUP-DIFF-2]', remap - remap all paths (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --set=[BACKUP-DIFF-2] --stanza=db restore
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: restore command begin [BACKREST-VERSION]: --no-compress --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --no-log-timestamp --pg1-path=[TEST_PATH]/db-master/db/base-2 --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --set=[BACKUP-DIFF-2] --stanza=db --tablespace-map=1=[TEST_PATH]/db-master/db/tablespace/ts1-2 --tablespace-map=2=[TEST_PATH]/db-master/db/tablespace/ts2-2
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [hash], lBufferMax = 4194304, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = [TEST_PATH]/db-master/repo, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathExists(): strPathExp =
@ -3143,10 +3271,16 @@ P00 DEBUG: Storage::Local->pathSync(): strPathExp = [TEST_PATH]/db-master/d
P00 DEBUG: Storage::Local->remove(): bIgnoreMissing = <true>, bRecurse = <false>, xstryPathFileExp = [TEST_PATH]/db-master/db/base-2/backup.manifest
P00 DEBUG: Storage::Local->remove=>: bRemoved = true
P00 DEBUG: Storage::Local->pathSync(): strPathExp = [TEST_PATH]/db-master/db/base-2
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => false
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: restore command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
+ supplemental file: [TEST_PATH]/db-master/db/base-2/recovery.conf
------------------------------------------------------------------

View File

@ -71,8 +71,12 @@ full backup - create pg_stat link, pg_clog dir (backup host)
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --no-online --manifest-save-threshold=3 --protocol-timeout=2 --db-timeout=1 --cmd-ssh=/usr/bin/ssh --pg1-port=9999 --pg1-socket-path =/test_socket_path --buffer-size=16384 --checksum-page --process-max=1 --repo1-type=cifs --type=full --stanza=db backup
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: backup command begin [BACKREST-VERSION]: --buffer-size=16384 --checksum-page --cmd-ssh=/usr/bin/ssh --no-compress --compress-level=3 --compress-level-network=1 --config=[TEST_PATH]/backup/pgbackrest.conf --db-timeout=1 --lock-path=[TEST_PATH]/backup/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/backup/log --no-log-timestamp --manifest-save-threshold=3 --no-online --pg1-host=db-master --pg1-host-cmd=[BACKREST-BIN] --pg1-host-config=[TEST_PATH]/db-master/pgbackrest.conf --pg1-host-user=[USER-1] --pg1-path=[TEST_PATH]/db-master/db/base --pg1-port=9999 --pg1-socket-path==/test_socket_path --process-max=1 --protocol-timeout=2 --repo1-path=[TEST_PATH]/backup/repo --repo1-type=cifs --stanza=db --start-fast --type=full
P00 DEBUG: common/lock::lockAcquire: (lockPath: {"[TEST_PATH]/backup/lock"}, stanza: {"db"}, lockType: 1, lockTimeout: 0, failOnNoLock: true)
P00 DEBUG: common/lock::lockAcquire: => true
P00 WARN: option repo1-retention-full is not set, the repository may run out of space
HINT: to retain full backups indefinitely (without warning), set option 'repo1-retention-full' to the maximum.
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [hash], lBufferMax = 16384, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = [TEST_PATH]/backup/repo, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathExists(): strPathExp =
@ -284,8 +288,10 @@ P00 DEBUG: Storage::Local->openWrite(): bAtomic = <false>, bPathCreate = <f
P00 DEBUG: Storage::Local->pathSync(): strPathExp = [TEST_PATH]/backup/repo/backup/db
P00 DEBUG: Storage::Local->openWrite(): bAtomic = <false>, bPathCreate = <false>, lTimestamp = [undef], rhyFilter = [undef], strCipherPass = [undef], strGroup = [undef], strMode = <0640>, strUser = [undef], xFileExp = [TEST_PATH]/backup/repo/backup/db/backup.info.copy
P00 DEBUG: Storage::Local->pathSync(): strPathExp = [TEST_PATH]/backup/repo/backup/db
P00 DEBUG: perl/exec::perlExec: => 0
P00 INFO: backup command end: completed successfully
P00 INFO: expire command begin
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Storage::Local->pathExists(): strPathExp =
P00 DEBUG: Storage::Local->pathExists=>: bExists = true
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 0770, strPathExp = [TEST_PATH]/backup/log
@ -316,10 +322,16 @@ P00 DEBUG: Storage::Local->list=>: stryFileList = ([BACKUP-FULL-1])
P00 DEBUG: Backup::Info->current(): strBackup = [BACKUP-FULL-1]
P00 DEBUG: Backup::Info->current=>: bTest = true
P00 INFO: option 'repo1-retention-archive' is not set - archive logs will not be expired
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => true
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: expire command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
+ supplemental file: [TEST_PATH]/db-master/pgbackrest.conf
----------------------------------------------------------
@ -482,21 +494,33 @@ stop all stanzas (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --force stop
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stop command begin [BACKREST-VERSION]: --config=[TEST_PATH]/db-master/pgbackrest.conf --force --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --no-log-timestamp --repo1-host=backup --repo1-host-cmd=[BACKREST-BIN] --repo1-host-config=[TEST_PATH]/backup/pgbackrest.conf --repo1-host-user=[USER-2]
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = [undef], oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 770, strPathExp = [TEST_PATH]/db-master/lock
P00 INFO: sent term signal to process [PROCESS-ID]
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => false
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: stop command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
full backup - abort backup - local (backup host)
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --no-online --type=full --stanza=db backup --test --test-delay=5 --test-point=backup-start=y
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: backup command begin [BACKREST-VERSION]: --no-compress --compress-level=3 --compress-level-network=1 --config=[TEST_PATH]/backup/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/backup/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/backup/log --no-log-timestamp --no-online --pg1-host=db-master --pg1-host-cmd=[BACKREST-BIN] --pg1-host-config=[TEST_PATH]/db-master/pgbackrest.conf --pg1-host-user=[USER-1] --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/backup/repo --stanza=db --start-fast --test --test-delay=5 --test-point=backup-start=y --type=full
P00 DEBUG: common/lock::lockAcquire: (lockPath: {"[TEST_PATH]/backup/lock"}, stanza: {"db"}, lockType: 1, lockTimeout: 0, failOnNoLock: true)
P00 DEBUG: common/lock::lockAcquire: => true
P00 WARN: option repo1-retention-full is not set, the repository may run out of space
HINT: to retain full backups indefinitely (without warning), set option 'repo1-retention-full' to the maximum.
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [hash], lBufferMax = 4194304, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = [TEST_PATH]/backup/repo, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathExists(): strPathExp =
@ -589,18 +613,27 @@ P00 TEST: PgBaCkReStTeSt-BACKUP-START-PgBaCkReStTeSt
P00 DEBUG: Protocol::Helper::protocolGet(): bCache = <true>, iProcessIdx = [undef], iRemoteIdx = 1, strBackRestBin = [undef], strCommand = <backup>, strRemoteType = db
P00 DEBUG: Protocol::Helper::protocolGet: found cached protocol
P00 ERROR: [063]: remote process on 'db-master' terminated unexpectedly [063]
P00 DEBUG: common/exit::exitSafe: (result: 0, error: true, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => true
P00 DEBUG: Main::mainCleanup(): iExitCode = 63
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = false, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy: found cached protocol: iRemoteIdx = 1, strRemoteType = db
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: backup command end: terminated on signal from child process
P00 DEBUG: common/exit::exitSafe: => 63
P00 DEBUG: main::main: => 63
full backup - global stop (backup host)
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --no-online --type=full --stanza=db backup
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: backup command begin [BACKREST-VERSION]: --no-compress --compress-level=3 --compress-level-network=1 --config=[TEST_PATH]/backup/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/backup/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/backup/log --no-log-timestamp --no-online --pg1-host=db-master --pg1-host-cmd=[BACKREST-BIN] --pg1-host-config=[TEST_PATH]/db-master/pgbackrest.conf --pg1-host-user=[USER-1] --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/backup/repo --stanza=db --start-fast --type=full
P00 DEBUG: common/lock::lockAcquire: (lockPath: {"[TEST_PATH]/backup/lock"}, stanza: {"db"}, lockType: 1, lockTimeout: 0, failOnNoLock: true)
P00 DEBUG: common/lock::lockAcquire: => true
P00 WARN: option repo1-retention-full is not set, the repository may run out of space
HINT: to retain full backups indefinitely (without warning), set option 'repo1-retention-full' to the maximum.
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [hash], lBufferMax = 4194304, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = [TEST_PATH]/backup/repo, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathExists(): strPathExp =
@ -642,42 +675,67 @@ P00 DEBUG: Protocol::Remote::Master->new(): iBufferMax = 4194304, iCompress
P00 DEBUG: Protocol::Command::Master->new(): iBufferMax = 4194304, iCompressLevel = 3, iCompressLevelNetwork = 1, iProtocolTimeout = 60, strCommand = ssh -o LogLevel=error -o Compression=no -o PasswordAuthentication=no [USER-1]@db-master '[BACKREST-BIN] --buffer-size=4194304 --command=backup --compress-level=3 --compress-level-network=1 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/backup/repo --stanza=db --type=db remote', strId = remote process on 'db-master', strName = remote
P00 ERROR: [062]: raised from remote process on 'db-master': stop file exists for all stanzas
P00 DEBUG: Protocol::Command::Master->close=>: iExitStatus = 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: true, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => true
P00 DEBUG: Main::mainCleanup(): iExitCode = 62
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = false, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: backup command end: aborted with exception [062]
P00 DEBUG: common/exit::exitSafe: => 62
P00 DEBUG: main::main: => 62
stop db stanza (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db stop
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stop command begin [BACKREST-VERSION]: --config=[TEST_PATH]/db-master/pgbackrest.conf --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --no-log-timestamp --repo1-host=backup --repo1-host-cmd=[BACKREST-BIN] --repo1-host-config=[TEST_PATH]/backup/pgbackrest.conf --repo1-host-user=[USER-2] --stanza=db
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = [undef], oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 770, strPathExp = [TEST_PATH]/db-master/lock
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => false
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: stop command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
stop db stanza (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db stop
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stop command begin [BACKREST-VERSION]: --config=[TEST_PATH]/db-master/pgbackrest.conf --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --no-log-timestamp --repo1-host=backup --repo1-host-cmd=[BACKREST-BIN] --repo1-host-config=[TEST_PATH]/backup/pgbackrest.conf --repo1-host-user=[USER-2] --stanza=db
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = [undef], oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 770, strPathExp = [TEST_PATH]/db-master/lock
P00 WARN: stop file already exists for stanza db
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => false
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: stop command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
full backup - stanza stop (backup host)
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --no-online --type=full --stanza=db backup
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: backup command begin [BACKREST-VERSION]: --no-compress --compress-level=3 --compress-level-network=1 --config=[TEST_PATH]/backup/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/backup/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/backup/log --no-log-timestamp --no-online --pg1-host=db-master --pg1-host-cmd=[BACKREST-BIN] --pg1-host-config=[TEST_PATH]/db-master/pgbackrest.conf --pg1-host-user=[USER-1] --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/backup/repo --stanza=db --start-fast --type=full
P00 DEBUG: common/lock::lockAcquire: (lockPath: {"[TEST_PATH]/backup/lock"}, stanza: {"db"}, lockType: 1, lockTimeout: 0, failOnNoLock: true)
P00 DEBUG: common/lock::lockAcquire: => true
P00 WARN: option repo1-retention-full is not set, the repository may run out of space
HINT: to retain full backups indefinitely (without warning), set option 'repo1-retention-full' to the maximum.
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [hash], lBufferMax = 4194304, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = [TEST_PATH]/backup/repo, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathExists(): strPathExp =
@ -719,58 +777,99 @@ P00 DEBUG: Protocol::Remote::Master->new(): iBufferMax = 4194304, iCompress
P00 DEBUG: Protocol::Command::Master->new(): iBufferMax = 4194304, iCompressLevel = 3, iCompressLevelNetwork = 1, iProtocolTimeout = 60, strCommand = ssh -o LogLevel=error -o Compression=no -o PasswordAuthentication=no [USER-1]@db-master '[BACKREST-BIN] --buffer-size=4194304 --command=backup --compress-level=3 --compress-level-network=1 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/backup/repo --stanza=db --type=db remote', strId = remote process on 'db-master', strName = remote
P00 ERROR: [062]: raised from remote process on 'db-master': stop file exists for stanza db
P00 DEBUG: Protocol::Command::Master->close=>: iExitStatus = 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: true, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => true
P00 DEBUG: Main::mainCleanup(): iExitCode = 62
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = false, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: backup command end: aborted with exception [062]
P00 DEBUG: common/exit::exitSafe: => 62
P00 DEBUG: main::main: => 62
start db stanza (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db start
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: start command begin [BACKREST-VERSION]: --config=[TEST_PATH]/db-master/pgbackrest.conf --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --no-log-timestamp --repo1-host=backup --repo1-host-cmd=[BACKREST-BIN] --repo1-host-config=[TEST_PATH]/backup/pgbackrest.conf --repo1-host-user=[USER-2] --stanza=db
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => false
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: start command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
start all stanzas (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf start
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: start command begin [BACKREST-VERSION]: --config=[TEST_PATH]/db-master/pgbackrest.conf --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --no-log-timestamp --repo1-host=backup --repo1-host-cmd=[BACKREST-BIN] --repo1-host-config=[TEST_PATH]/backup/pgbackrest.conf --repo1-host-user=[USER-2]
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => false
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: start command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
start all stanzas (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf start
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: start command begin [BACKREST-VERSION]: --config=[TEST_PATH]/db-master/pgbackrest.conf --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --no-log-timestamp --repo1-host=backup --repo1-host-cmd=[BACKREST-BIN] --repo1-host-config=[TEST_PATH]/backup/pgbackrest.conf --repo1-host-user=[USER-2]
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 WARN: stop file does not exist
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => false
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: start command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
stop all stanzas (backup host)
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --force stop
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stop command begin [BACKREST-VERSION]: --config=[TEST_PATH]/backup/pgbackrest.conf --force --lock-path=[TEST_PATH]/backup/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/backup/log --no-log-timestamp --repo1-path=[TEST_PATH]/backup/repo
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = [undef], oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 770, strPathExp = [TEST_PATH]/backup/lock
P00 INFO: sent term signal to process [PROCESS-ID]
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => false
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: stop command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
full backup - abort backup - remote (backup host)
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --no-online --type=full --stanza=db backup --test --test-delay=5 --test-point=backup-start=y
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: backup command begin [BACKREST-VERSION]: --no-compress --compress-level=3 --compress-level-network=1 --config=[TEST_PATH]/backup/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/backup/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/backup/log --no-log-timestamp --no-online --pg1-host=db-master --pg1-host-cmd=[BACKREST-BIN] --pg1-host-config=[TEST_PATH]/db-master/pgbackrest.conf --pg1-host-user=[USER-1] --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/backup/repo --stanza=db --start-fast --test --test-delay=5 --test-point=backup-start=y --type=full
P00 DEBUG: common/lock::lockAcquire: (lockPath: {"[TEST_PATH]/backup/lock"}, stanza: {"db"}, lockType: 1, lockTimeout: 0, failOnNoLock: true)
P00 DEBUG: common/lock::lockAcquire: => true
P00 WARN: option repo1-retention-full is not set, the repository may run out of space
HINT: to retain full backups indefinitely (without warning), set option 'repo1-retention-full' to the maximum.
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [hash], lBufferMax = 4194304, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = [TEST_PATH]/backup/repo, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathExists(): strPathExp =
@ -871,8 +970,12 @@ full backup - global stop (backup host)
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --no-online --type=full --stanza=db backup
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: backup command begin [BACKREST-VERSION]: --no-compress --compress-level=3 --compress-level-network=1 --config=[TEST_PATH]/backup/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/backup/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/backup/log --no-log-timestamp --no-online --pg1-host=db-master --pg1-host-cmd=[BACKREST-BIN] --pg1-host-config=[TEST_PATH]/db-master/pgbackrest.conf --pg1-host-user=[USER-1] --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/backup/repo --stanza=db --start-fast --type=full
P00 DEBUG: common/lock::lockAcquire: (lockPath: {"[TEST_PATH]/backup/lock"}, stanza: {"db"}, lockType: 1, lockTimeout: 0, failOnNoLock: true)
P00 DEBUG: common/lock::lockAcquire: => true
P00 WARN: option repo1-retention-full is not set, the repository may run out of space
HINT: to retain full backups indefinitely (without warning), set option 'repo1-retention-full' to the maximum.
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [hash], lBufferMax = 4194304, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = [TEST_PATH]/backup/repo, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathExists(): strPathExp =
@ -882,26 +985,43 @@ P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBu
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 0770, strPathExp = [TEST_PATH]/backup/log
P00 DEBUG: Common::Lock::lockStopTest(): bStanzaStopRequired = <false>
P00 ERROR: [062]: stop file exists for all stanzas
P00 DEBUG: common/exit::exitSafe: (result: 0, error: true, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => true
P00 DEBUG: Main::mainCleanup(): iExitCode = 62
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = false, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: backup command end: aborted with exception [062]
P00 DEBUG: common/exit::exitSafe: => 62
P00 DEBUG: main::main: => 62
start all stanzas (backup host)
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf start
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: start command begin [BACKREST-VERSION]: --config=[TEST_PATH]/backup/pgbackrest.conf --lock-path=[TEST_PATH]/backup/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/backup/log --no-log-timestamp --repo1-path=[TEST_PATH]/backup/repo
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => false
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: start command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
full backup - resume (backup host)
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --no-online --force --checksum-page --type=full --stanza=db backup --test --test-delay=0.2 --test-point=backup-resume=y
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: backup command begin [BACKREST-VERSION]: --checksum-page --no-compress --compress-level=3 --compress-level-network=1 --config=[TEST_PATH]/backup/pgbackrest.conf --db-timeout=45 --force --lock-path=[TEST_PATH]/backup/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/backup/log --no-log-timestamp --no-online --pg1-host=db-master --pg1-host-cmd=[BACKREST-BIN] --pg1-host-config=[TEST_PATH]/db-master/pgbackrest.conf --pg1-host-user=[USER-1] --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/backup/repo --stanza=db --start-fast --test --test-delay=0.2 --test-point=backup-resume=y --type=full
P00 DEBUG: common/lock::lockAcquire: (lockPath: {"[TEST_PATH]/backup/lock"}, stanza: {"db"}, lockType: 1, lockTimeout: 0, failOnNoLock: true)
P00 DEBUG: common/lock::lockAcquire: => true
P00 WARN: option repo1-retention-full is not set, the repository may run out of space
HINT: to retain full backups indefinitely (without warning), set option 'repo1-retention-full' to the maximum.
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [hash], lBufferMax = 4194304, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = [TEST_PATH]/backup/repo, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathExists(): strPathExp =
@ -1102,8 +1222,10 @@ P00 DEBUG: Storage::Local->pathSync(): strPathExp = [TEST_PATH]/backup/repo
P00 DEBUG: Storage::Local->openWrite(): bAtomic = <false>, bPathCreate = <false>, lTimestamp = [undef], rhyFilter = [undef], strCipherPass = [undef], strGroup = [undef], strMode = <0640>, strUser = [undef], xFileExp = [TEST_PATH]/backup/repo/backup/db/backup.info.copy
P00 DEBUG: Storage::Local->pathSync(): strPathExp = [TEST_PATH]/backup/repo/backup/db
P00 DEBUG: Storage::Local->pathSync(): strPathExp = <REPO:BACKUP>
P00 DEBUG: perl/exec::perlExec: => 0
P00 INFO: backup command end: completed successfully
P00 INFO: expire command begin
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Storage::Local->pathExists(): strPathExp =
P00 DEBUG: Storage::Local->pathExists=>: bExists = true
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 0770, strPathExp = [TEST_PATH]/backup/log
@ -1134,10 +1256,16 @@ P00 DEBUG: Storage::Local->list=>: stryFileList = ([BACKUP-FULL-2])
P00 DEBUG: Backup::Info->current(): strBackup = [BACKUP-FULL-2]
P00 DEBUG: Backup::Info->current=>: bTest = true
P00 INFO: option 'repo1-retention-archive' is not set - archive logs will not be expired
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => true
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: expire command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
+ supplemental file: [TEST_PATH]/db-master/pgbackrest.conf
----------------------------------------------------------
@ -1304,6 +1432,8 @@ restore delta, backup '[BACKUP-FULL-2]' - add and delete files (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --delta --set=[BACKUP-FULL-2] --link-all --cmd-ssh=/usr/bin/ssh --stanza=db restore
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: restore command begin [BACKREST-VERSION]: --cmd-ssh=/usr/bin/ssh --no-compress --compress-level=3 --compress-level-network=1 --config=[TEST_PATH]/db-master/pgbackrest.conf --delta --link-all --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --no-log-timestamp --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-host=backup --repo1-host-cmd=[BACKREST-BIN] --repo1-host-config=[TEST_PATH]/backup/pgbackrest.conf --repo1-host-user=[USER-2] --set=[BACKUP-FULL-2] --stanza=db
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = 4194304, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 0770, strPathExp = [TEST_PATH]/db-master/log
@ -1539,12 +1669,18 @@ P00 DEBUG: Storage::Local->pathSync(): strPathExp = [TEST_PATH]/db-master/d
P00 DEBUG: Storage::Local->remove(): bIgnoreMissing = <true>, bRecurse = <false>, xstryPathFileExp = [TEST_PATH]/db-master/db/base/backup.manifest
P00 DEBUG: Storage::Local->remove=>: bRemoved = true
P00 DEBUG: Storage::Local->pathSync(): strPathExp = [TEST_PATH]/db-master/db/base
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => false
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy: found cached protocol: iRemoteIdx = 1, strRemoteType = backup
P00 DEBUG: Protocol::Command::Master->close=>: iExitStatus = 0
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: restore command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
+ supplemental file: [TEST_PATH]/db-master/db/base/recovery.conf
----------------------------------------------------------------
@ -1757,8 +1893,12 @@ incr backup - add tablespace 1 (backup host)
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --no-online --test --stanza=db backup
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: backup command begin [BACKREST-VERSION]: --no-compress --compress-level=3 --compress-level-network=1 --config=[TEST_PATH]/backup/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/backup/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/backup/log --no-log-timestamp --no-online --pg1-host=db-master --pg1-host-cmd=[BACKREST-BIN] --pg1-host-config=[TEST_PATH]/db-master/pgbackrest.conf --pg1-host-user=[USER-1] --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/backup/repo --stanza=db --start-fast --test
P00 DEBUG: common/lock::lockAcquire: (lockPath: {"[TEST_PATH]/backup/lock"}, stanza: {"db"}, lockType: 1, lockTimeout: 0, failOnNoLock: true)
P00 DEBUG: common/lock::lockAcquire: => true
P00 WARN: option repo1-retention-full is not set, the repository may run out of space
HINT: to retain full backups indefinitely (without warning), set option 'repo1-retention-full' to the maximum.
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [hash], lBufferMax = 4194304, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = [TEST_PATH]/backup/repo, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathExists(): strPathExp =
@ -1936,8 +2076,10 @@ P00 DEBUG: Storage::Local->pathSync(): strPathExp = [TEST_PATH]/backup/repo
P00 DEBUG: Storage::Local->openWrite(): bAtomic = <false>, bPathCreate = <false>, lTimestamp = [undef], rhyFilter = [undef], strCipherPass = [undef], strGroup = [undef], strMode = <0640>, strUser = [undef], xFileExp = [TEST_PATH]/backup/repo/backup/db/backup.info.copy
P00 DEBUG: Storage::Local->pathSync(): strPathExp = [TEST_PATH]/backup/repo/backup/db
P00 DEBUG: Storage::Local->pathSync(): strPathExp = <REPO:BACKUP>
P00 DEBUG: perl/exec::perlExec: => 0
P00 INFO: backup command end: completed successfully
P00 INFO: expire command begin
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Storage::Local->pathExists(): strPathExp =
P00 DEBUG: Storage::Local->pathExists=>: bExists = true
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 0770, strPathExp = [TEST_PATH]/backup/log
@ -1976,10 +2118,16 @@ P00 DEBUG: Backup::Info->current=>: bTest = true
P00 DEBUG: Backup::Info->current(): strBackup = [BACKUP-FULL-2]
P00 DEBUG: Backup::Info->current=>: bTest = true
P00 INFO: option 'repo1-retention-archive' is not set - archive logs will not be expired
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => true
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: expire command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
+ supplemental file: [TEST_PATH]/db-master/pgbackrest.conf
----------------------------------------------------------
@ -2140,8 +2288,12 @@ incr backup - resume and add tablespace 2 (backup host)
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --no-online --process-max=1 --stanza=db backup --test --test-delay=0.2 --test-point=backup-resume=y
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: backup command begin [BACKREST-VERSION]: --no-compress --compress-level=3 --compress-level-network=1 --config=[TEST_PATH]/backup/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/backup/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/backup/log --no-log-timestamp --no-online --pg1-host=db-master --pg1-host-cmd=[BACKREST-BIN] --pg1-host-config=[TEST_PATH]/db-master/pgbackrest.conf --pg1-host-user=[USER-1] --pg1-path=[TEST_PATH]/db-master/db/base --process-max=1 --protocol-timeout=60 --repo1-path=[TEST_PATH]/backup/repo --stanza=db --start-fast --test --test-delay=0.2 --test-point=backup-resume=y
P00 DEBUG: common/lock::lockAcquire: (lockPath: {"[TEST_PATH]/backup/lock"}, stanza: {"db"}, lockType: 1, lockTimeout: 0, failOnNoLock: true)
P00 DEBUG: common/lock::lockAcquire: => true
P00 WARN: option repo1-retention-full is not set, the repository may run out of space
HINT: to retain full backups indefinitely (without warning), set option 'repo1-retention-full' to the maximum.
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [hash], lBufferMax = 4194304, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = [TEST_PATH]/backup/repo, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathExists(): strPathExp =
@ -2363,8 +2515,10 @@ P00 DEBUG: Storage::Local->pathSync(): strPathExp = [TEST_PATH]/backup/repo
P00 DEBUG: Storage::Local->openWrite(): bAtomic = <false>, bPathCreate = <false>, lTimestamp = [undef], rhyFilter = [undef], strCipherPass = [undef], strGroup = [undef], strMode = <0640>, strUser = [undef], xFileExp = [TEST_PATH]/backup/repo/backup/db/backup.info.copy
P00 DEBUG: Storage::Local->pathSync(): strPathExp = [TEST_PATH]/backup/repo/backup/db
P00 DEBUG: Storage::Local->pathSync(): strPathExp = <REPO:BACKUP>
P00 DEBUG: perl/exec::perlExec: => 0
P00 INFO: backup command end: completed successfully
P00 INFO: expire command begin
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Storage::Local->pathExists(): strPathExp =
P00 DEBUG: Storage::Local->pathExists=>: bExists = true
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 0770, strPathExp = [TEST_PATH]/backup/log
@ -2403,10 +2557,16 @@ P00 DEBUG: Backup::Info->current=>: bTest = true
P00 DEBUG: Backup::Info->current(): strBackup = [BACKUP-FULL-2]
P00 DEBUG: Backup::Info->current=>: bTest = true
P00 INFO: option 'repo1-retention-archive' is not set - archive logs will not be expired
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => true
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: expire command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
+ supplemental file: [TEST_PATH]/db-master/pgbackrest.conf
----------------------------------------------------------

View File

@ -68,6 +68,8 @@ db-version="9.4"
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-push --log-level-console=debug [TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000001
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: archive-push command begin [BACKREST-VERSION]: [[TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000001] --no-compress --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --no-log-timestamp --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-cipher-pass=<redacted> --repo1-cipher-type=aes-256-cbc --repo1-path=[TEST_PATH]/db-master/repo --stanza=db
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Archive::Push::Push->process(): strWalPathFile = [TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000001
P00 DEBUG: Common::Lock::lockStopTest(): bStanzaStopRequired = <false>
P00 DEBUG: Common::Lock::lockStopTest=>: bStopExists = false
@ -105,14 +107,23 @@ P00 DEBUG: Storage::Local->openWrite(): bAtomic = true, bPathCreate = true,
P00 DEBUG: Storage::Base->copy(): xDestinationFile = [object], xSourceFile = [object]
P00 DEBUG: Archive::Push::File::archivePushFile=>: strWarning = [undef]
P00 INFO: pushed WAL segment 000000010000000100000001
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => false
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: archive-push command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get --log-level-console=debug 000000010000000100000001 [TEST_PATH]/db-master/db/base/pg_xlog/RECOVERYXLOG
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: archive-get command begin [BACKREST-VERSION]: [000000010000000100000001, [TEST_PATH]/db-master/db/base/pg_xlog/RECOVERYXLOG] --no-compress --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --no-log-timestamp --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-cipher-pass=<redacted> --repo1-cipher-type=aes-256-cbc --repo1-path=[TEST_PATH]/db-master/repo --stanza=db
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: command/archive/get/get::cmdArchiveGet: (void)
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Archive::Get::Get->process(): rstryCommandArg = (000000010000000100000001, [TEST_PATH]/db-master/db/base/pg_xlog/RECOVERYXLOG)
P00 DEBUG: Archive::Get::File::archiveGetFile(): bAtomic = false, strDestinationFile = [TEST_PATH]/db-master/db/base/pg_xlog/RECOVERYXLOG, strSourceArchive = 000000010000000100000001
P00 DEBUG: Common::Lock::lockStopTest(): bStanzaStopRequired = <false>
@ -149,10 +160,17 @@ P00 DEBUG: Storage::Local->openWrite(): bAtomic = false, bPathCreate = <fal
P00 DEBUG: Storage::Base->copy(): xDestinationFile = [object], xSourceFile = [object]
P00 DEBUG: Archive::Get::File::archiveGetFile=>: iResult = 0
P00 INFO: got WAL segment 000000010000000100000001
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: command/archive/get/get::cmdArchiveGet: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => false
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: archive-get command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-push --compress --archive-async --process-max=2 [TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000002
------------------------------------------------------------------------------------------------------------------------------------

View File

@ -60,6 +60,8 @@ db-version="9.4"
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-push --cmd-ssh=/usr/bin/ssh --log-level-console=debug [TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000001
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: archive-push command begin [BACKREST-VERSION]: [[TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000001] --cmd-ssh=/usr/bin/ssh --no-compress --compress-level=3 --compress-level-network=1 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --no-log-timestamp --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-host=backup --repo1-host-cmd=[BACKREST-BIN] --repo1-host-config=[TEST_PATH]/backup/pgbackrest.conf --repo1-host-user=[USER-1] --stanza=db
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Archive::Push::Push->process(): strWalPathFile = [TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000001
P00 DEBUG: Common::Lock::lockStopTest(): bStanzaStopRequired = <false>
P00 DEBUG: Common::Lock::lockStopTest=>: bStopExists = false
@ -87,16 +89,25 @@ P00 DEBUG: Protocol::Storage::Remote->openWrite(): rhParam = [hash], strFil
P00 DEBUG: Storage::Base->copy(): xDestinationFile = [object], xSourceFile = [object]
P00 DEBUG: Archive::Push::File::archivePushFile=>: strWarning = [undef]
P00 INFO: pushed WAL segment 000000010000000100000001
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => false
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy: found cached protocol: iRemoteIdx = 1, strRemoteType = backup
P00 DEBUG: Protocol::Command::Master->close=>: iExitStatus = 0
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: archive-push command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get --log-level-console=debug 000000010000000100000001 [TEST_PATH]/db-master/db/base/pg_xlog/RECOVERYXLOG
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: archive-get command begin [BACKREST-VERSION]: [000000010000000100000001, [TEST_PATH]/db-master/db/base/pg_xlog/RECOVERYXLOG] --no-compress --compress-level=3 --compress-level-network=1 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --no-log-timestamp --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-host=backup --repo1-host-cmd=[BACKREST-BIN] --repo1-host-config=[TEST_PATH]/backup/pgbackrest.conf --repo1-host-user=[USER-1] --stanza=db
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: command/archive/get/get::cmdArchiveGet: (void)
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Archive::Get::Get->process(): rstryCommandArg = (000000010000000100000001, [TEST_PATH]/db-master/db/base/pg_xlog/RECOVERYXLOG)
P00 DEBUG: Archive::Get::File::archiveGetFile(): bAtomic = false, strDestinationFile = [TEST_PATH]/db-master/db/base/pg_xlog/RECOVERYXLOG, strSourceArchive = 000000010000000100000001
P00 DEBUG: Common::Lock::lockStopTest(): bStanzaStopRequired = <false>
@ -124,12 +135,19 @@ P00 DEBUG: Storage::Local->openWrite(): bAtomic = false, bPathCreate = <fal
P00 DEBUG: Storage::Base->copy(): xDestinationFile = [object], xSourceFile = [object]
P00 DEBUG: Archive::Get::File::archiveGetFile=>: iResult = 0
P00 INFO: got WAL segment 000000010000000100000001
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: command/archive/get/get::cmdArchiveGet: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => false
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy: found cached protocol: iRemoteIdx = 1, strRemoteType = backup
P00 DEBUG: Protocol::Command::Master->close=>: iExitStatus = 0
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: archive-get command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-push --compress --archive-async --process-max=2 [TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000002
------------------------------------------------------------------------------------------------------------------------------------

View File

@ -178,6 +178,8 @@ db-version="9.3"
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-push [TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000001
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: archive-push command begin [BACKREST-VERSION]: [[TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000001] --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --no-log-timestamp --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --stanza=db
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Archive::Push::Push->process(): strWalPathFile = [TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000001
P00 DEBUG: Common::Lock::lockStopTest(): bStanzaStopRequired = <false>
P00 DEBUG: Common::Lock::lockStopTest=>: bStopExists = false
@ -215,10 +217,16 @@ P00 DEBUG: Storage::Local->openWrite(): bAtomic = true, bPathCreate = true,
P00 DEBUG: Storage::Base->copy(): xDestinationFile = [object], xSourceFile = [object]
P00 DEBUG: Archive::Push::File::archivePushFile=>: strWarning = [undef]
P00 INFO: pushed WAL segment 000000010000000100000001
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => false
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: archive-push command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
stanza-create db - fail on archive info file missing from non-empty dir (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db --log-level-console=detail --no-online stanza-create
@ -425,6 +433,8 @@ db-version="9.3"
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-push [TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000002
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: archive-push command begin [BACKREST-VERSION]: [[TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000002] --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --no-log-timestamp --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --stanza=db
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Archive::Push::Push->process(): strWalPathFile = [TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000002
P00 DEBUG: Common::Lock::lockStopTest(): bStanzaStopRequired = <false>
P00 DEBUG: Common::Lock::lockStopTest=>: bStopExists = false
@ -462,10 +472,16 @@ P00 DEBUG: Storage::Local->openWrite(): bAtomic = true, bPathCreate = true,
P00 DEBUG: Storage::Base->copy(): xDestinationFile = [object], xSourceFile = [object]
P00 DEBUG: Archive::Push::File::archivePushFile=>: strWarning = [undef]
P00 INFO: pushed WAL segment 000000010000000100000002
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => false
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: archive-push command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --log-level-console=warn --archive-push-queue-max=33554432 --stanza=db archive-push [TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000001
------------------------------------------------------------------------------------------------------------------------------------
@ -516,6 +532,9 @@ db-version="9.4"
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get 000000010000000100000002 [TEST_PATH]/db-master/db/base/pg_xlog/RECOVERYXLOG
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: archive-get command begin [BACKREST-VERSION]: [000000010000000100000002, [TEST_PATH]/db-master/db/base/pg_xlog/RECOVERYXLOG] --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --no-log-timestamp --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --stanza=db
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: command/archive/get/get::cmdArchiveGet: (void)
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Archive::Get::Get->process(): rstryCommandArg = (000000010000000100000002, [TEST_PATH]/db-master/db/base/pg_xlog/RECOVERYXLOG)
P00 DEBUG: Archive::Get::File::archiveGetFile(): bAtomic = false, strDestinationFile = [TEST_PATH]/db-master/db/base/pg_xlog/RECOVERYXLOG, strSourceArchive = 000000010000000100000002
P00 DEBUG: Common::Lock::lockStopTest(): bStanzaStopRequired = <false>
@ -552,10 +571,17 @@ P00 DEBUG: Storage::Local->openWrite(): bAtomic = false, bPathCreate = <fal
P00 DEBUG: Storage::Base->copy(): xDestinationFile = [object], xSourceFile = [object]
P00 DEBUG: Archive::Get::File::archiveGetFile=>: iResult = 0
P00 INFO: got WAL segment 000000010000000100000002
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: command/archive/get/get::cmdArchiveGet: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => false
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: archive-get command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --log-level-console=warn --archive-push-queue-max=33554432 --stanza=db archive-push [TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000001
------------------------------------------------------------------------------------------------------------------------------------
@ -958,13 +984,21 @@ stop db stanza (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db stop
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stop command begin [BACKREST-VERSION]: --config=[TEST_PATH]/db-master/pgbackrest.conf --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --no-log-timestamp --repo1-path=[TEST_PATH]/db-master/repo --stanza=db
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = [undef], oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 770, strPathExp = [TEST_PATH]/db-master/lock
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => false
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: stop command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
stanza-delete db - successfully delete the stanza (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db --log-level-console=detail stanza-delete

View File

@ -202,6 +202,8 @@ db-version="9.3"
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-push [TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000001
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: archive-push command begin [BACKREST-VERSION]: [[TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000001] --compress-level=3 --compress-level-network=1 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --no-log-timestamp --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-host=backup --repo1-host-cmd=[BACKREST-BIN] --repo1-host-config=[TEST_PATH]/backup/pgbackrest.conf --repo1-host-user=[USER-2] --stanza=db
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Archive::Push::Push->process(): strWalPathFile = [TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000001
P00 DEBUG: Common::Lock::lockStopTest(): bStanzaStopRequired = <false>
P00 DEBUG: Common::Lock::lockStopTest=>: bStopExists = false
@ -229,12 +231,18 @@ P00 DEBUG: Protocol::Storage::Remote->openWrite(): rhParam = [hash], strFil
P00 DEBUG: Storage::Base->copy(): xDestinationFile = [object], xSourceFile = [object]
P00 DEBUG: Archive::Push::File::archivePushFile=>: strWarning = [undef]
P00 INFO: pushed WAL segment 000000010000000100000001
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => false
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy: found cached protocol: iRemoteIdx = 1, strRemoteType = backup
P00 DEBUG: Protocol::Command::Master->close=>: iExitStatus = 0
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: archive-push command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
stanza-create db - gunzip fail on forced stanza-create (backup host)
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --stanza=db --log-level-console=detail --no-online --force stanza-create
@ -293,6 +301,8 @@ db-version="9.3"
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-push [TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000002
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: archive-push command begin [BACKREST-VERSION]: [[TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000002] --compress-level=3 --compress-level-network=1 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --no-log-timestamp --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-host=backup --repo1-host-cmd=[BACKREST-BIN] --repo1-host-config=[TEST_PATH]/backup/pgbackrest.conf --repo1-host-user=[USER-2] --stanza=db
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Archive::Push::Push->process(): strWalPathFile = [TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000002
P00 DEBUG: Common::Lock::lockStopTest(): bStanzaStopRequired = <false>
P00 DEBUG: Common::Lock::lockStopTest=>: bStopExists = false
@ -320,12 +330,18 @@ P00 DEBUG: Protocol::Storage::Remote->openWrite(): rhParam = [hash], strFil
P00 DEBUG: Storage::Base->copy(): xDestinationFile = [object], xSourceFile = [object]
P00 DEBUG: Archive::Push::File::archivePushFile=>: strWarning = [undef]
P00 INFO: pushed WAL segment 000000010000000100000002
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => false
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy: found cached protocol: iRemoteIdx = 1, strRemoteType = backup
P00 DEBUG: Protocol::Command::Master->close=>: iExitStatus = 0
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: archive-push command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --log-level-console=warn --archive-push-queue-max=33554432 --stanza=db archive-push [TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000001
------------------------------------------------------------------------------------------------------------------------------------
@ -382,6 +398,9 @@ db-version="9.4"
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get 000000010000000100000002 [TEST_PATH]/db-master/db/base/pg_xlog/RECOVERYXLOG
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: archive-get command begin [BACKREST-VERSION]: [000000010000000100000002, [TEST_PATH]/db-master/db/base/pg_xlog/RECOVERYXLOG] --compress-level=3 --compress-level-network=1 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --no-log-timestamp --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-host=backup --repo1-host-cmd=[BACKREST-BIN] --repo1-host-config=[TEST_PATH]/backup/pgbackrest.conf --repo1-host-user=[USER-2] --stanza=db
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: command/archive/get/get::cmdArchiveGet: (void)
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Archive::Get::Get->process(): rstryCommandArg = (000000010000000100000002, [TEST_PATH]/db-master/db/base/pg_xlog/RECOVERYXLOG)
P00 DEBUG: Archive::Get::File::archiveGetFile(): bAtomic = false, strDestinationFile = [TEST_PATH]/db-master/db/base/pg_xlog/RECOVERYXLOG, strSourceArchive = 000000010000000100000002
P00 DEBUG: Common::Lock::lockStopTest(): bStanzaStopRequired = <false>
@ -409,12 +428,19 @@ P00 DEBUG: Storage::Local->openWrite(): bAtomic = false, bPathCreate = <fal
P00 DEBUG: Storage::Base->copy(): xDestinationFile = [object], xSourceFile = [object]
P00 DEBUG: Archive::Get::File::archiveGetFile=>: iResult = 0
P00 INFO: got WAL segment 000000010000000100000002
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: command/archive/get/get::cmdArchiveGet: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => false
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy: found cached protocol: iRemoteIdx = 1, strRemoteType = backup
P00 DEBUG: Protocol::Command::Master->close=>: iExitStatus = 0
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: archive-get command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --log-level-console=warn --archive-push-queue-max=33554432 --stanza=db archive-push [TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000001
------------------------------------------------------------------------------------------------------------------------------------
@ -792,13 +818,21 @@ stop db stanza (backup host)
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --stanza=db stop
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stop command begin [BACKREST-VERSION]: --config=[TEST_PATH]/backup/pgbackrest.conf --lock-path=[TEST_PATH]/backup/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/backup/log --no-log-timestamp --pg1-host=db-master --pg1-host-cmd=[BACKREST-BIN] --pg1-host-config=[TEST_PATH]/db-master/pgbackrest.conf --pg1-host-user=[USER-1] --repo1-cipher-pass=<redacted> --repo1-cipher-type=aes-256-cbc --repo1-path=[TEST_PATH]/backup/repo --stanza=db
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = [undef], oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 770, strPathExp = [TEST_PATH]/backup/lock
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => false
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: stop command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
stanza-delete db - successfully delete the stanza (backup host)
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --stanza=db --log-level-console=detail stanza-delete

View File

@ -178,6 +178,8 @@ db-version="9.3"
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-push [TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000001
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: archive-push command begin [BACKREST-VERSION]: [[TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000001] --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --no-log-timestamp --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=/ --repo1-s3-bucket=pgbackrest-dev --repo1-s3-endpoint=s3.amazonaws.com --repo1-s3-key=<redacted> --repo1-s3-key-secret=<redacted> --repo1-s3-region=us-east-1 --no-repo1-s3-verify-ssl --repo1-type=s3 --stanza=db
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Archive::Push::Push->process(): strWalPathFile = [TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000001
P00 DEBUG: Common::Lock::lockStopTest(): bStanzaStopRequired = <false>
P00 DEBUG: Common::Lock::lockStopTest=>: bStopExists = false
@ -215,10 +217,16 @@ P00 DEBUG: Storage::Local->openWrite(): bAtomic = true, bPathCreate = true,
P00 DEBUG: Storage::Base->copy(): xDestinationFile = [object], xSourceFile = [object]
P00 DEBUG: Archive::Push::File::archivePushFile=>: strWarning = [undef]
P00 INFO: pushed WAL segment 000000010000000100000001
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => false
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: archive-push command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
stanza-create db - fail on archive info file missing from non-empty dir (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db --log-level-console=detail --no-online stanza-create
@ -400,6 +408,8 @@ db-version="9.3"
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-push [TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000002
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: archive-push command begin [BACKREST-VERSION]: [[TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000002] --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --no-log-timestamp --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=/ --repo1-s3-bucket=pgbackrest-dev --repo1-s3-endpoint=s3.amazonaws.com --repo1-s3-key=<redacted> --repo1-s3-key-secret=<redacted> --repo1-s3-region=us-east-1 --no-repo1-s3-verify-ssl --repo1-type=s3 --stanza=db
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Archive::Push::Push->process(): strWalPathFile = [TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000002
P00 DEBUG: Common::Lock::lockStopTest(): bStanzaStopRequired = <false>
P00 DEBUG: Common::Lock::lockStopTest=>: bStopExists = false
@ -437,10 +447,16 @@ P00 DEBUG: Storage::Local->openWrite(): bAtomic = true, bPathCreate = true,
P00 DEBUG: Storage::Base->copy(): xDestinationFile = [object], xSourceFile = [object]
P00 DEBUG: Archive::Push::File::archivePushFile=>: strWarning = [undef]
P00 INFO: pushed WAL segment 000000010000000100000002
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => false
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: archive-push command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --log-level-console=warn --archive-push-queue-max=33554432 --stanza=db archive-push [TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000001
------------------------------------------------------------------------------------------------------------------------------------
@ -491,6 +507,9 @@ db-version="9.4"
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get 000000010000000100000002 [TEST_PATH]/db-master/db/base/pg_xlog/RECOVERYXLOG
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: archive-get command begin [BACKREST-VERSION]: [000000010000000100000002, [TEST_PATH]/db-master/db/base/pg_xlog/RECOVERYXLOG] --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --no-log-timestamp --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=/ --repo1-s3-bucket=pgbackrest-dev --repo1-s3-endpoint=s3.amazonaws.com --repo1-s3-key=<redacted> --repo1-s3-key-secret=<redacted> --repo1-s3-region=us-east-1 --no-repo1-s3-verify-ssl --repo1-type=s3 --stanza=db
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: command/archive/get/get::cmdArchiveGet: (void)
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Archive::Get::Get->process(): rstryCommandArg = (000000010000000100000002, [TEST_PATH]/db-master/db/base/pg_xlog/RECOVERYXLOG)
P00 DEBUG: Archive::Get::File::archiveGetFile(): bAtomic = false, strDestinationFile = [TEST_PATH]/db-master/db/base/pg_xlog/RECOVERYXLOG, strSourceArchive = 000000010000000100000002
P00 DEBUG: Common::Lock::lockStopTest(): bStanzaStopRequired = <false>
@ -527,10 +546,17 @@ P00 DEBUG: Storage::Local->openWrite(): bAtomic = false, bPathCreate = <fal
P00 DEBUG: Storage::Base->copy(): xDestinationFile = [object], xSourceFile = [object]
P00 DEBUG: Archive::Get::File::archiveGetFile=>: iResult = 0
P00 INFO: got WAL segment 000000010000000100000002
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: command/archive/get/get::cmdArchiveGet: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => false
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: archive-get command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --log-level-console=warn --archive-push-queue-max=33554432 --stanza=db archive-push [TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000001
------------------------------------------------------------------------------------------------------------------------------------
@ -945,13 +971,21 @@ stop db stanza (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db stop
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stop command begin [BACKREST-VERSION]: --config=[TEST_PATH]/db-master/pgbackrest.conf --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --no-log-timestamp --repo1-path=/ --repo1-s3-bucket=pgbackrest-dev --repo1-s3-endpoint=s3.amazonaws.com --repo1-s3-key=<redacted> --repo1-s3-key-secret=<redacted> --repo1-s3-region=us-east-1 --no-repo1-s3-verify-ssl --repo1-type=s3 --stanza=db
P00 DEBUG: config/load::cfgLoad: => void
P00 DEBUG: perl/exec::perlExec: (void)
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = [undef], oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 770, strPathExp = [TEST_PATH]/db-master/lock
P00 DEBUG: perl/exec::perlExec: => 0
P00 DEBUG: common/exit::exitSafe: (result: 0, error: false, signalType: 0)
P00 DEBUG: common/lock::lockRelease: (failOnNoLock: false)
P00 DEBUG: common/lock::lockRelease: => false
P00 DEBUG: Main::mainCleanup(): iExitCode = 0
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy=>: iExitStatus = 0
P00 INFO: stop command end: completed successfully
P00 DEBUG: common/exit::exitSafe: => 0
P00 DEBUG: main::main: => 0
stanza-delete db - successfully delete the stanza (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db --log-level-console=detail stanza-delete

View File

@ -69,6 +69,7 @@ sub new
$self->{bValgrindUnit},
$self->{bCoverageUnit},
$self->{bOptimize},
$self->{bBackTrace},
$self->{bProfile},
$self->{bDebug},
) =
@ -94,6 +95,7 @@ sub new
{name => 'bValgrindUnit'},
{name => 'bCoverageUnit'},
{name => 'bOptimize'},
{name => 'bBackTrace'},
{name => 'bProfile'},
{name => 'bDebug'},
);
@ -360,8 +362,10 @@ sub run
" -Wformat=2 -Wformat-nonliteral \\\n" .
" `perl -MExtUtils::Embed -e ccopts`\n" .
"LDFLAGS=-lcrypto" . (vmCoverage($self->{oTest}->{&TEST_VM}) && $self->{bCoverageUnit} ? " -lgcov" : '') .
(vmWithBackTrace($self->{oTest}->{&TEST_VM}) && $self->{bBackTrace} ? ' -lbacktrace' : '') .
" `perl -MExtUtils::Embed -e ldopts`\n" .
'TESTFLAGS=' . ($self->{oTest}->{&TEST_DEBUG_UNIT_SUPPRESS} ? '' : "-DDEBUG_UNIT") .
(vmWithBackTrace($self->{oTest}->{&TEST_VM}) && $self->{bBackTrace} ? ' -DWITH_BACKTRACE' : '') .
($self->{oTest}->{&TEST_CDEF} ? " $self->{oTest}->{&TEST_CDEF}" : '') .
($self->{bDebug} ? '' : " -DNDEBUG") .
"\n" .

View File

@ -1,6 +1,7 @@
/***********************************************************************************************************************************
Harness for Loading Test Configurations
***********************************************************************************************************************************/
#include "common/harnessDebug.h"
#include "common/logTest.h"
#include "config/load.h"
@ -15,7 +16,14 @@ log files, acquire locks, etc.
void
harnessCfgLoad(unsigned int argListSize, const char *argList[])
{
FUNCTION_HARNESS_BEGIN();
FUNCTION_HARNESS_PARAM(UINT, argListSize);
FUNCTION_HARNESS_PARAM(CHARPY, argList);
FUNCTION_HARNESS_END();
configParse(argListSize, argList);
logInit(logLevelInfo, logLevelOff, logLevelDebug, false);
cfgLoadUpdateOption();
FUNCTION_HARNESS_RESULT_VOID();
}

View File

@ -0,0 +1,58 @@
/***********************************************************************************************************************************
C Debug Harness
***********************************************************************************************************************************/
#ifndef TEST_COMMON_HARNESS_DEBUG_H
#define TEST_COMMON_HARNESS_DEBUG_H
#ifdef NO_STACK_TRACE
#define FUNCTION_HARNESS_INIT(exe)
#define FUNCTION_HARNESS_BEGIN()
#define FUNCTION_HARNESS_PARAM(typeMacroPrefix, param)
#define FUNCTION_HARNESS_END()
#define FUNCTION_HARNESS_VOID()
#define FUNCTION_HARNESS_ASSERT(condition)
#define FUNCTION_HARNESS_RESULT(typeMacroPrefix, result) \
return result
#define FUNCTION_HARNESS_RESULT_VOID();
#else
#include "common/debug.h"
#ifdef WITH_BACKTRACE
#define FUNCTION_HARNESS_INIT(exe) \
stackTraceInit(exe)
#else
#define FUNCTION_HARNESS_INIT(exe)
#endif
#define FUNCTION_HARNESS_BEGIN() \
STACK_TRACE_PUSH(logLevelDebug); \
stackTraceParamLog()
#define FUNCTION_HARNESS_PARAM(typeMacroPrefix, param) \
FUNCTION_DEBUG_PARAM(typeMacroPrefix, param)
#define FUNCTION_HARNESS_END()
#define FUNCTION_HARNESS_VOID() \
FUNCTION_HARNESS_BEGIN(); \
FUNCTION_HARNESS_END()
#define FUNCTION_HARNESS_ASSERT(condition) \
do \
{ \
if (!(condition)) \
THROW_FMT(AssertError, "function harness assertion '%s' failed", #condition); \
} \
while (0)
#define FUNCTION_HARNESS_RESULT(typeMacroPrefix, result) \
STACK_TRACE_POP(); \
return result \
#define FUNCTION_HARNESS_RESULT_VOID() \
STACK_TRACE_POP();
#endif
#endif

View File

@ -5,6 +5,7 @@ C Test Harness
#include <stdlib.h>
#include <string.h>
#include "common/harnessDebug.h"
#include "common/harnessTest.h"
#include "common/logTest.h"
@ -21,21 +22,55 @@ static int testRun = 0;
static int testTotal = 0;
static bool testFirst = true;
static const char *testExeData = NULL;
static const char *testPathData = NULL;
/***********************************************************************************************************************************
Get and set the test exe
***********************************************************************************************************************************/
const char *
testExe()
{
FUNCTION_HARNESS_VOID();
FUNCTION_HARNESS_RESULT(STRINGZ, testExeData);
}
void
testExeSet(const char *testExe)
{
FUNCTION_HARNESS_BEGIN();
FUNCTION_HARNESS_PARAM(STRINGZ, testExe);
FUNCTION_HARNESS_ASSERT(testExe != NULL);
FUNCTION_HARNESS_END();
testExeData = testExe;
FUNCTION_HARNESS_RESULT_VOID();
}
/***********************************************************************************************************************************
Get and set the test path, i.e., the path where this test should write its files
***********************************************************************************************************************************/
const char *
testPath()
{
return testPathData;
FUNCTION_HARNESS_VOID();
FUNCTION_HARNESS_RESULT(STRINGZ, testPathData);
}
void
testPathSet(const char *testPathParam)
testPathSet(const char *testPath)
{
testPathData = testPathParam;
FUNCTION_HARNESS_BEGIN();
FUNCTION_HARNESS_PARAM(STRINGZ, testPath);
FUNCTION_HARNESS_ASSERT(testPath != NULL);
FUNCTION_HARNESS_END();
testPathData = testPath;
FUNCTION_HARNESS_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -44,6 +79,11 @@ testAdd - add a new test
void
testAdd(int run, bool selected)
{
FUNCTION_HARNESS_BEGIN();
FUNCTION_HARNESS_PARAM(INT, run);
FUNCTION_HARNESS_PARAM(BOOL, selected);
FUNCTION_HARNESS_END();
if (run != testTotal + 1)
{
fprintf(stderr, "ERROR: test run %d is not in order\n", run);
@ -53,6 +93,8 @@ testAdd(int run, bool selected)
testList[testTotal].selected = selected;
testTotal++;
FUNCTION_HARNESS_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -61,14 +103,23 @@ testBegin - should this test run?
bool
testBegin(const char *name)
{
FUNCTION_HARNESS_BEGIN();
FUNCTION_HARNESS_PARAM(STRINGZ, name);
FUNCTION_HARNESS_ASSERT(name != NULL);
FUNCTION_HARNESS_END();
bool result = false;
testRun++;
if (testList[testRun - 1].selected)
{
#ifndef NO_LOG
#ifndef IN_LOG
// Make sure there is nothing untested left in the log
if (!testFirst)
testLogFinal();
#endif
#endif
// No longer the first test
testFirst = false;
@ -80,14 +131,16 @@ testBegin(const char *name)
fflush(stdout);
#ifndef NO_LOG
#ifndef IN_LOG
// Initialize logging
testLogInit();
#endif
#endif
return true;
result = true;
}
return false;
FUNCTION_HARNESS_RESULT(BOOL, result);
}
/***********************************************************************************************************************************
@ -96,9 +149,13 @@ testComplete - make sure all expected tests ran
void
testComplete()
{
FUNCTION_HARNESS_VOID();
#ifndef NO_LOG
#ifndef IN_LOG
// Make sure there is nothing untested left in the log
testLogFinal();
#endif
#endif
// Check that all tests ran
@ -108,4 +165,6 @@ testComplete()
fflush(stderr);
exit(255);
}
FUNCTION_HARNESS_RESULT_VOID();
}

View File

@ -16,8 +16,11 @@ void testAdd(int run, bool selected);
bool testBegin(const char *name);
void testComplete();
const char *testExe();
void testExeSet(const char *testExe);
const char *testPath();
void testPathSet(const char *testPathParam);
void testPathSet(const char *testPath);
/***********************************************************************************************************************************
Convert a macro to a string -- handy for testing debug macros
@ -53,8 +56,8 @@ Test that an expected error is actually thrown and error when it isn't
\
if (strcmp(errorMessage(), errorMessageExpected) != 0 || errorType() != &errorTypeExpected) \
THROW_FMT( \
AssertError, "expected error %s, '%s' but got %s, '%s'", errorTypeName(&errorTypeExpected), errorMessageExpected, \
errorName(), errorMessage()); \
AssertError, "EXECTED %s: %s\n\nBUT GOT %s: %s\n\nTHROWN AT:\n%s", errorTypeName(&errorTypeExpected), \
errorMessageExpected, errorName(), errorMessage(), errorStackTrace()); \
} \
TRY_END(); \
\
@ -153,8 +156,8 @@ parameters.
{ \
/* No errors were expected so error */ \
THROW_FMT( \
AssertError, "statement '%s' threw error %s, '%s' but result <%s> expected", \
#statement, errorName(), errorMessage(), TEST_RESULT_resultExpectedStr); \
AssertError, "STATEMENT: %s\n\nTHREW %s: %s\n\nTHROWN AT:\n%s\n\nBUT EXPECTED RESULT:\n%s", \
#statement, errorName(), errorMessage(), errorStackTrace(), TEST_RESULT_resultExpectedStr); \
} \
TRY_END(); \
\

View File

@ -3,11 +3,14 @@ Log Test Harness
***********************************************************************************************************************************/
#include <fcntl.h>
#include <unistd.h>
#include "common/harnessTest.h"
#include <regex.h>
#include <stdio.h>
#include <string.h>
#include "common/log.h"
#include "storage/helper.h"
#include "common/harnessDebug.h"
#include "common/harnessTest.h"
#ifndef NO_LOG
@ -19,8 +22,35 @@ static bool harnessLogInit = false;
/***********************************************************************************************************************************
Name of file where logs are stored for testing
***********************************************************************************************************************************/
String *stdoutFile = NULL;
String *stderrFile = NULL;
static char stdoutFile[1024];
static char stderrFile[1024];
/***********************************************************************************************************************************
Buffer where log results are loaded for comparison purposes
***********************************************************************************************************************************/
char harnessLogBuffer[256 * 1024];
/***********************************************************************************************************************************
Open a log file -- centralized here for error handling
***********************************************************************************************************************************/
static int
harnessLogOpen(const char *logFile, int flags, int mode)
{
FUNCTION_HARNESS_BEGIN();
FUNCTION_HARNESS_PARAM(STRINGZ, logFile);
FUNCTION_HARNESS_PARAM(INT, flags);
FUNCTION_HARNESS_PARAM(INT, mode);
FUNCTION_HARNESS_ASSERT(logFile != NULL);
FUNCTION_HARNESS_END();
int result = open(logFile, flags, mode);
if (result == -1)
THROW_SYS_ERROR_FMT(FileOpenError, "unable to open log file '%s'", logFile);
FUNCTION_HARNESS_RESULT(INT, result);
}
/***********************************************************************************************************************************
Initialize log for testing
@ -28,18 +58,61 @@ Initialize log for testing
void
testLogInit()
{
FUNCTION_HARNESS_VOID();
if (!harnessLogInit)
{
logInit(logLevelInfo, logLevelOff, logLevelOff, false);
stdoutFile = strNewFmt("%s/stdout.log", testPath());
logHandleStdOut = open(strPtr(stdoutFile), O_WRONLY | O_CREAT | O_TRUNC, 0640);
snprintf(stdoutFile, sizeof(stdoutFile), "%s/stdout.log", testPath());
logHandleStdOut = harnessLogOpen(stdoutFile, O_WRONLY | O_CREAT | O_TRUNC, 0640);
stderrFile = strNewFmt("%s/stderr.log", testPath());
logHandleStdErr = open(strPtr(stderrFile), O_WRONLY | O_CREAT | O_TRUNC, 0640);
snprintf(stderrFile, sizeof(stderrFile), "%s/stderr.log", testPath());
logHandleStdErr = harnessLogOpen(stderrFile, O_WRONLY | O_CREAT | O_TRUNC, 0640);
harnessLogInit = true;
}
FUNCTION_HARNESS_RESULT_VOID();
}
/***********************************************************************************************************************************
Load log result from file into the log buffer
***********************************************************************************************************************************/
void
harnessLogLoad(const char *logFile)
{
FUNCTION_HARNESS_BEGIN();
FUNCTION_HARNESS_PARAM(STRINGZ, logFile);
FUNCTION_HARNESS_ASSERT(logFile != NULL);
FUNCTION_HARNESS_END();
harnessLogBuffer[0] = 0;
int handle = harnessLogOpen(logFile, O_RDONLY, 0);
size_t totalBytes = 0;
ssize_t actualBytes = 0;
do
{
actualBytes = read(handle, harnessLogBuffer, sizeof(harnessLogBuffer) - totalBytes);
if (actualBytes == -1)
THROW_SYS_ERROR_FMT(FileOpenError, "unable to read log file '%s'", logFile);
totalBytes += (size_t)actualBytes;
}
while (actualBytes != 0);
if (close(handle) == -1)
THROW_SYS_ERROR_FMT(FileOpenError, "unable to close log file '%s'", logFile);
// Remove final linefeed
harnessLogBuffer[totalBytes - 1] = 0;
FUNCTION_HARNESS_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -50,13 +123,67 @@ After the comparison the log is cleared so the next result can be compared.
void
testLogResult(const char *expected)
{
String *actual = strTrim(strNewBuf(storageGetNP(storageNewReadNP(storageLocal(), stdoutFile))));
FUNCTION_HARNESS_BEGIN();
FUNCTION_HARNESS_PARAM(STRINGZ, expected);
if (!strEqZ(actual, expected))
THROW_FMT(AssertError, "\n\nexpected log:\n\n%s\n\nbut actual log was:\n\n%s\n\n", expected, strPtr(actual));
FUNCTION_HARNESS_ASSERT(expected != NULL);
FUNCTION_HARNESS_END();
harnessLogLoad(stdoutFile);
if (strcmp(harnessLogBuffer, expected) != 0)
THROW_FMT(AssertError, "\n\nexpected log:\n\n%s\n\nbut actual log was:\n\n%s\n\n", expected, harnessLogBuffer);
close(logHandleStdOut);
logHandleStdOut = open(strPtr(stdoutFile), O_WRONLY | O_CREAT | O_TRUNC, 0640);
logHandleStdOut = harnessLogOpen(stdoutFile, O_WRONLY | O_CREAT | O_TRUNC, 0640);
FUNCTION_HARNESS_RESULT_VOID();
}
/***********************************************************************************************************************************
Compare log to a regexp
After the comparison the log is cleared so the next result can be compared.
***********************************************************************************************************************************/
void
testLogResultRegExp(const char *expression)
{
FUNCTION_HARNESS_BEGIN();
FUNCTION_HARNESS_PARAM(STRINGZ, expression);
FUNCTION_HARNESS_ASSERT(expression != NULL);
FUNCTION_HARNESS_END();
regex_t regExp;
TRY_BEGIN()
{
harnessLogLoad(stdoutFile);
// Compile the regexp and process errors
int result = 0;
if ((result = regcomp(&regExp, expression, REG_NOSUB | REG_EXTENDED)) != 0)
{
char buffer[4096];
regerror(result, NULL, buffer, sizeof(buffer));
THROW(FormatError, buffer);
}
// Do the match
if (regexec(&regExp, harnessLogBuffer, 0, NULL, 0) != 0)
THROW_FMT(AssertError, "\n\nexpected log regexp:\n\n%s\n\nbut actual log was:\n\n%s\n\n", expression, harnessLogBuffer);
close(logHandleStdOut);
logHandleStdOut = harnessLogOpen(stdoutFile, O_WRONLY | O_CREAT | O_TRUNC, 0640);
}
FINALLY()
{
regfree(&regExp);
}
TRY_END();
FUNCTION_HARNESS_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -67,13 +194,21 @@ After the comparison the log is cleared so the next result can be compared.
void
testLogErrResult(const char *expected)
{
String *actual = strTrim(strNewBuf(storageGetNP(storageNewReadNP(storageLocal(), stderrFile))));
FUNCTION_HARNESS_BEGIN();
FUNCTION_HARNESS_PARAM(STRINGZ, expected);
if (!strEqZ(actual, expected))
THROW_FMT(AssertError, "\n\nexpected error log:\n\n%s\n\nbut actual error log was:\n\n%s\n\n", expected, strPtr(actual));
FUNCTION_HARNESS_ASSERT(expected != NULL);
FUNCTION_HARNESS_END();
harnessLogLoad(stderrFile);
if (strcmp(harnessLogBuffer, expected) != 0)
THROW_FMT(AssertError, "\n\nexpected error log:\n\n%s\n\nbut actual error log was:\n\n%s\n\n", expected, harnessLogBuffer);
close(logHandleStdErr);
logHandleStdErr = open(strPtr(stderrFile), O_WRONLY | O_CREAT | O_TRUNC, 0640);
logHandleStdErr = harnessLogOpen(stderrFile, O_WRONLY | O_CREAT | O_TRUNC, 0640);
FUNCTION_HARNESS_RESULT_VOID();
}
/***********************************************************************************************************************************
@ -82,15 +217,19 @@ Make sure nothing is left in the log after all tests have completed
void
testLogFinal()
{
String *actual = strTrim(strNewBuf(storageGetNP(storageNewReadNP(storageLocal(), stdoutFile))));
FUNCTION_HARNESS_VOID();
if (!strEqZ(actual, ""))
THROW_FMT(AssertError, "\n\nexpected log to be empty but actual log was:\n\n%s\n\n", strPtr(actual));
harnessLogLoad(stdoutFile);
actual = strTrim(strNewBuf(storageGetNP(storageNewReadNP(storageLocal(), stderrFile))));
if (strcmp(harnessLogBuffer, "") != 0)
THROW_FMT(AssertError, "\n\nexpected log to be empty but actual log was:\n\n%s\n\n", harnessLogBuffer);
if (!strEqZ(actual, ""))
THROW_FMT(AssertError, "\n\nexpected error log to be empty but actual error log was:\n\n%s\n\n", strPtr(actual));
harnessLogLoad(stderrFile);
if (strcmp(harnessLogBuffer, "") != 0)
THROW_FMT(AssertError, "\n\nexpected error log to be empty but actual error log was:\n\n%s\n\n", harnessLogBuffer);
FUNCTION_HARNESS_RESULT_VOID();
}
#endif

View File

@ -7,11 +7,10 @@ Log Test Harness
/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/
#ifndef NO_LOG
void testLogInit();
void testLogResult(const char *expected);
void testLogResultRegExp(const char *expression);
void testLogErrResult(const char *expected);
void testLogFinal();
#endif
#endif

View File

@ -11,6 +11,8 @@ Test Run
void
testRun()
{
FUNCTION_HARNESS_VOID();
// *****************************************************************************************************************************
if (testBegin("archiveAsyncStatus()"))
{
@ -53,7 +55,7 @@ testRun()
storagePutNP(
storageNewWriteNP(storageSpool(), strNewFmt(STORAGE_SPOOL_ARCHIVE_OUT "/%s.ok", strPtr(segment))),
bufNewStr(strNew(BOGUS_STR "\nmessage")));
TEST_ERROR(archiveAsyncStatus(archiveModePush, segment, false), FormatError, "unable to convert str 'BOGUS' to int");
TEST_ERROR(archiveAsyncStatus(archiveModePush, segment, false), FormatError, "unable to convert string 'BOGUS' to int");
storagePutNP(storageNewWriteNP(storageSpool(), strNewFmt(STORAGE_SPOOL_ARCHIVE_OUT "/%s.ok", strPtr(segment))), NULL);
TEST_RESULT_BOOL(archiveAsyncStatus(archiveModePush, segment, false), true, "ok file");
@ -143,4 +145,6 @@ testRun()
"000000070000000700000FFE|000000070000000700000FFF|000000070000000800000000|000000070000000800000001",
"get range >= 11/1MB");
}
FUNCTION_HARNESS_RESULT_VOID();
}

View File

@ -13,6 +13,8 @@ Test Run
void
testRun()
{
FUNCTION_HARNESS_VOID();
Storage *storageTest = storageNewP(strNew(testPath()), .write = true);
// *****************************************************************************************************************************
@ -48,12 +50,15 @@ testRun()
"000000010000000100000001|000000010000000100000002|000000010000000100000003", "empty queue");
// -------------------------------------------------------------------------------------------------------------------------
Buffer *walSegmentBuffer = bufNew(walSegmentSize);
memset(bufPtr(walSegmentBuffer), 0, walSegmentSize);
storagePutNP(
storageNewWriteNP(
storageSpool(), strNew(STORAGE_SPOOL_ARCHIVE_IN "/0000000100000001000000FE")), bufNew(walSegmentSize));
storageSpool(), strNew(STORAGE_SPOOL_ARCHIVE_IN "/0000000100000001000000FE")), walSegmentBuffer);
storagePutNP(
storageNewWriteNP(
storageSpool(), strNew(STORAGE_SPOOL_ARCHIVE_IN "/0000000100000001000000FF")), bufNew(walSegmentSize));
storageSpool(), strNew(STORAGE_SPOOL_ARCHIVE_IN "/0000000100000001000000FF")), walSegmentBuffer);
TEST_RESULT_STR(
strPtr(strLstJoin(queueNeed(strNew("0000000100000001000000FE"), false, queueSize, walSegmentSize, PG_VERSION_92), "|")),
@ -67,13 +72,13 @@ testRun()
walSegmentSize = 1024 * 1024;
queueSize = walSegmentSize * 5;
storagePutNP(storageNewWriteNP(storageSpool(), strNew(STORAGE_SPOOL_ARCHIVE_IN "/junk")), bufNew(16));
storagePutNP(storageNewWriteNP(storageSpool(), strNew(STORAGE_SPOOL_ARCHIVE_IN "/junk")), bufNewStr(strNew("JUNK")));
storagePutNP(
storageNewWriteNP(
storageSpool(), strNew(STORAGE_SPOOL_ARCHIVE_IN "/000000010000000A00000FFE")), bufNew(walSegmentSize));
storageSpool(), strNew(STORAGE_SPOOL_ARCHIVE_IN "/000000010000000A00000FFE")), walSegmentBuffer);
storagePutNP(
storageNewWriteNP(
storageSpool(), strNew(STORAGE_SPOOL_ARCHIVE_IN "/000000010000000A00000FFF")), bufNew(walSegmentSize));
storageSpool(), strNew(STORAGE_SPOOL_ARCHIVE_IN "/000000010000000A00000FFF")), walSegmentBuffer);
TEST_RESULT_STR(
strPtr(strLstJoin(queueNeed(strNew("000000010000000A00000FFD"), true, queueSize, walSegmentSize, PG_VERSION_11), "|")),
@ -106,7 +111,7 @@ testRun()
strLstAdd(argListTemp, walSegment);
harnessCfgLoad(strLstSize(argListTemp), strLstPtr(argListTemp));
TEST_ERROR(cmdArchiveGet(), ParamRequiredError, "Path to copy WAL segment required");
TEST_ERROR(cmdArchiveGet(), ParamRequiredError, "path to copy WAL segment required");
// -------------------------------------------------------------------------------------------------------------------------
String *controlFile = strNew("db/" PG_PATH_GLOBAL "/" PG_FILE_PGCONTROL);
@ -240,6 +245,8 @@ testRun()
strLstAddZ(argList, BOGUS_STR);
harnessCfgLoad(strLstSize(argList), strLstPtr(argList));
TEST_ERROR(cmdArchiveGet(), ParamRequiredError, "extra parameters found");
TEST_ERROR(cmdArchiveGet(), ParamInvalidError, "extra parameters found");
}
FUNCTION_HARNESS_RESULT_VOID();
}

View File

@ -9,6 +9,8 @@ Test Run
void
testRun()
{
FUNCTION_HARNESS_VOID();
// Create default storage object for testing
Storage *storageTest = storageNewP(strNew(testPath()), .write = true);
@ -83,4 +85,6 @@ testRun()
cmdArchivePush(), ArchiveTimeoutError,
"unable to push WAL segment '000000010000000100000001' asynchronously after 1 second(s)");
}
FUNCTION_HARNESS_RESULT_VOID();
}

View File

@ -21,6 +21,8 @@ Test Run
void
testRun()
{
FUNCTION_HARNESS_VOID();
// -----------------------------------------------------------------------------------------------------------------------------
if (testBegin("blockCipherNew() and blockCipherFree()"))
{
@ -30,9 +32,6 @@ testRun()
cipherBlockNew(
cipherModeEncrypt, BOGUS_STR, (unsigned char *)TEST_PASS, TEST_PASS_SIZE, NULL), AssertError,
"unable to load cipher 'BOGUS'");
TEST_ERROR(
cipherBlockNew(cipherModeEncrypt, NULL, (unsigned char *)TEST_PASS, TEST_PASS_SIZE, NULL), AssertError,
"unable to load cipher '(null)'");
TEST_ERROR(
cipherBlockNew(
cipherModeEncrypt, TEST_CIPHER, (unsigned char *)TEST_PASS, TEST_PASS_SIZE, BOGUS_STR), AssertError,
@ -159,7 +158,7 @@ testRun()
// -------------------------------------------------------------------------------------------------------------------------
blockEncrypt = cipherBlockNew(cipherModeEncrypt, TEST_CIPHER, (unsigned char *)TEST_PASS, TEST_PASS_SIZE, NULL);
TEST_RESULT_INT(cipherBlockProcess(blockEncrypt, NULL, 0, encryptBuffer), 16, "process header");
TEST_RESULT_INT(cipherBlockProcess(blockEncrypt, decryptBuffer, 0, encryptBuffer), 16, "process header");
TEST_RESULT_INT(cipherBlockFlush(blockEncrypt, encryptBuffer + 16), 16, "flush remaining bytes");
cipherBlockFree(blockEncrypt);
@ -200,7 +199,7 @@ testRun()
// -------------------------------------------------------------------------------------------------------------------------
blockDecrypt = cipherBlockNew(cipherModeDecrypt, TEST_CIPHER, (unsigned char *)TEST_PASS, TEST_PASS_SIZE, NULL);
TEST_RESULT_INT(cipherBlockProcess(blockDecrypt, NULL, 0, decryptBuffer), 0, "no header processed");
TEST_RESULT_INT(cipherBlockProcess(blockDecrypt, encryptBuffer, 0, decryptBuffer), 0, "no header processed");
TEST_ERROR(cipherBlockFlush(blockDecrypt, decryptBuffer), CipherError, "cipher header missing");
cipherBlockFree(blockDecrypt);
@ -217,5 +216,5 @@ testRun()
cipherBlockFree(blockDecrypt);
}
cipherFree();
FUNCTION_HARNESS_RESULT_VOID();
}

View File

@ -8,6 +8,8 @@ Test Run
void
testRun()
{
FUNCTION_HARNESS_VOID();
// -----------------------------------------------------------------------------------------------------------------------------
if (testBegin("randomBytes()"))
{
@ -24,9 +26,11 @@ testRun()
int nonZeroTotal = 0;
for (unsigned int charIdx = 0; charIdx < bufferSize; charIdx++)
if (buffer[charIdx] != 0)
if (buffer[charIdx] != 0) // {uncovered - ok if there are no zeros}
nonZeroTotal++;
TEST_RESULT_INT_NE(nonZeroTotal, 0, "check that there are non-zero values in the buffer");
}
FUNCTION_HARNESS_RESULT_VOID();
}

Some files were not shown because too many files have changed in this diff Show More