1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2025-07-05 00:28:52 +02:00

Add log module.

This commit is contained in:
David Steele
2018-01-16 13:52:20 -05:00
parent eb452c8add
commit 39cb971afb
17 changed files with 584 additions and 21 deletions

View File

@ -62,7 +62,7 @@
</release-item> </release-item>
<release-item> <release-item>
<p>Add <code>time</code> module.</p> <p>Add <code>log</code> and <code>time</code> modules.</p>
</release-item> </release-item>
<release-item> <release-item>

View File

@ -6,6 +6,7 @@ pgbackrest: \
common/error.o \ common/error.o \
common/errorType.o \ common/errorType.o \
common/ini.o \ common/ini.o \
common/log.o \
common/memContext.o \ common/memContext.o \
common/regExp.o \ common/regExp.o \
common/time.o \ common/time.o \
@ -19,6 +20,7 @@ pgbackrest: \
common/wait.o \ common/wait.o \
config/config.o \ config/config.o \
config/define.o \ config/define.o \
config/load.o \
config/parse.o \ config/parse.o \
perl/exec.o \ perl/exec.o \
storage/helper.o \ storage/helper.o \
@ -28,6 +30,7 @@ pgbackrest: \
common/error.o \ common/error.o \
common/errorType.o \ common/errorType.o \
common/ini.o \ common/ini.o \
common/log.o \
common/memContext.o \ common/memContext.o \
common/regExp.o \ common/regExp.o \
common/time.o \ common/time.o \
@ -41,6 +44,7 @@ pgbackrest: \
common/wait.o \ common/wait.o \
config/config.o \ config/config.o \
config/define.o \ config/define.o \
config/load.o \
config/parse.o \ config/parse.o \
perl/exec.o \ perl/exec.o \
storage/helper.o \ storage/helper.o \

176
src/common/log.c Normal file
View File

@ -0,0 +1,176 @@
/***********************************************************************************************************************************
Log Handler
***********************************************************************************************************************************/
#include <stdarg.h>
#include <string.h>
#include <strings.h>
#include <time.h>
#include <unistd.h>
#include "common/error.h"
#include "common/log.h"
#include "common/time.h"
/***********************************************************************************************************************************
Module variables
***********************************************************************************************************************************/
// Log levels
LogLevel logLevelStdOut = logLevelOff;
LogLevel logLevelStdErr = logLevelWarn;
// Log file handles
int logHandleStdOut = STDOUT_FILENO;
int logHandleStdErr = STDERR_FILENO;
// Is the timestamp printed in the log?
bool logTimestamp = false;
/***********************************************************************************************************************************
Log buffer
***********************************************************************************************************************************/
#define LOG_BUFFER_SIZE 32768
char logBuffer[LOG_BUFFER_SIZE];
char logFormat[LOG_BUFFER_SIZE];
/***********************************************************************************************************************************
Convert log level to string and vice versa
***********************************************************************************************************************************/
#define LOG_LEVEL_TOTAL 9
const char *logLevelList[LOG_LEVEL_TOTAL] =
{
"OFF",
"ASSERT",
"ERROR",
"PROTOCOL",
"WARN",
"INFO",
"DETAIL",
"DEBUG",
"TRACE",
};
LogLevel
logLevelEnum(const char *logLevel)
{
LogLevel result = logLevelOff;
// Search for the log level
for (; result < LOG_LEVEL_TOTAL; result++)
if (strcasecmp(logLevel, logLevelList[result]) == 0)
break;
// If the log level was not found
if (result == LOG_LEVEL_TOTAL)
THROW(AssertError, "log level '%s' not found", logLevel);
return result;
}
const char *
logLevelStr(LogLevel logLevel)
{
if (logLevel >= LOG_LEVEL_TOTAL)
THROW(AssertError, "invalid log level '%d'", logLevel);
return logLevelList[logLevel];
}
/***********************************************************************************************************************************
Initialize the log system
***********************************************************************************************************************************/
void
logInit(LogLevel logLevelStdOutParam, LogLevel logLevelStdErrParam, bool logTimestampParam)
{
logLevelStdOut = logLevelStdOutParam;
logLevelStdErr = logLevelStdErrParam;
logTimestamp = logTimestampParam;
}
/***********************************************************************************************************************************
General log function
***********************************************************************************************************************************/
void
logInternal(LogLevel logLevel, const char *fileName, const char *functionName, int fileLine, int code, const char *format, ...)
{
// Should this entry be logged?
if (logLevel <= logLevelStdOut || logLevel <= logLevelStdErr)
{
int bufferPos = 0;
// Add time
if (logTimestamp && logLevel > logLevelStdErr)
{
TimeUSec logTimeUSec = timeUSec();
time_t logTime = (time_t)(logTimeUSec / USEC_PER_SEC);
bufferPos += strftime(logBuffer + bufferPos, LOG_BUFFER_SIZE - bufferPos, "%Y-%m-%d %H:%M:%S", localtime(&logTime));
bufferPos += snprintf(logBuffer + bufferPos, LOG_BUFFER_SIZE - bufferPos, ".%03d ", (int)(logTimeUSec / 1000 % 1000));
}
// Add process and aligned log level
if (logLevel > logLevelStdErr)
bufferPos += snprintf(logBuffer + bufferPos, LOG_BUFFER_SIZE - bufferPos, "P00 %*s: ", 6, logLevelStr(logLevel));
// Else just the log level with no alignment
else
bufferPos += snprintf(logBuffer + bufferPos, LOG_BUFFER_SIZE - bufferPos, "%s: ", logLevelStr(logLevel));
// Add error code
if (code != 0)
bufferPos += snprintf(logBuffer + bufferPos, LOG_BUFFER_SIZE - bufferPos, "[%03d]: ", code);
// Add debug info
if (logLevelStdOut >= logLevelDebug)
{
bufferPos += snprintf(
logBuffer + bufferPos, LOG_BUFFER_SIZE - bufferPos, "%s:%s():%d: ", fileName, functionName, fileLine);
}
// Format message
va_list argumentList;
va_start(argumentList, format);
if (logLevel <= logLevelStdErr || strchr(format, '\n') == NULL)
bufferPos += 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)
{
strncpy(logBuffer + bufferPos, formatPtr, linefeedPtr - formatPtr + 1);
bufferPos += linefeedPtr - formatPtr + 1;
formatPtr = linefeedPtr + 1;
linefeedPtr = strchr(formatPtr, '\n');
for (int indentIdx = 0; indentIdx < indentSize; indentIdx++)
logBuffer[bufferPos++] = ' ';
}
strcpy(logBuffer + bufferPos, formatPtr);
bufferPos += strlen(formatPtr);
}
va_end(argumentList);
// Add linefeed
logBuffer[bufferPos++] = '\n';
logBuffer[bufferPos] = 0;
// Determine where to log the message based on log-level-stderr
int stream = logHandleStdOut;
if (logLevel <= logLevelStdErr)
stream = logHandleStdErr;
THROW_ON_SYS_ERROR(
write(stream, logBuffer, bufferPos) != bufferPos, FileWriteError, "unable to write log to stdout");
}
}

64
src/common/log.h Normal file
View File

@ -0,0 +1,64 @@
/***********************************************************************************************************************************
Log Handler
***********************************************************************************************************************************/
#ifndef COMMON_LOG_H
#define COMMON_LOG_H
#include "common/type.h"
/***********************************************************************************************************************************
Log types
***********************************************************************************************************************************/
typedef enum
{
logLevelOff,
logLevelAssert,
logLevelError,
logLevelProtocol,
logLevelWarn,
logLevelInfo,
logLevelDetail,
logLevelDebug,
logLevelTrace,
} LogLevel;
/***********************************************************************************************************************************
Expose internal data for debugging/testing
***********************************************************************************************************************************/
#ifndef NDEBUG
extern LogLevel logLevelStdOut;
extern LogLevel logLevelStdErr;
extern int logHandleStdOut;
extern int logHandleStdErr;
extern bool logTimestamp;
#endif
/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/
void logInit(LogLevel logLevelStdOut, LogLevel logLevelStdErr, bool logTimestamp);
LogLevel logLevelEnum(const char *logLevel);
const char *logLevelStr(LogLevel logLevel);
/***********************************************************************************************************************************
Macros
***********************************************************************************************************************************/
#define LOG_ANY(logLevel, code, ...) \
logInternal(logLevel, __FILE__, __func__, __LINE__, code, __VA_ARGS__)
#define LOG_ERROR(code, ...) \
LOG_ANY(logLevelError, code, __VA_ARGS__)
#define LOG_INFO(...) \
LOG_ANY(logLevelInfo, 0, __VA_ARGS__)
#define LOG_WARN(...) \
LOG_ANY(logLevelWarn, 0, __VA_ARGS__)
/***********************************************************************************************************************************
Internal Functions
***********************************************************************************************************************************/
void logInternal(
LogLevel logLevel, const char *fileName, const char *functionName, int fileLine, int code, const char *format, ...);
#endif

39
src/config/load.c Normal file
View File

@ -0,0 +1,39 @@
/***********************************************************************************************************************************
Configuration Load
***********************************************************************************************************************************/
#include <string.h>
#include "common/memContext.h"
#include "common/log.h"
#include "config/config.h"
#include "config/parse.h"
/***********************************************************************************************************************************
Load the configuration
***********************************************************************************************************************************/
void
cfgLoad(int argListSize, const char *argList[])
{
MEM_CONTEXT_TEMP_BEGIN()
{
// Parse config from command line and config file
configParse(argListSize, argList);
// Initialize logging
LogLevel logLevelConsole = logLevelOff;
LogLevel logLevelStdErr = logLevelOff;
bool logTimestamp = true;
if (cfgOptionValid(cfgOptLogLevelConsole))
logLevelConsole = logLevelEnum(strPtr(cfgOptionStr(cfgOptLogLevelConsole)));
if (cfgOptionValid(cfgOptLogLevelStderr))
logLevelStdErr = logLevelEnum(strPtr(cfgOptionStr(cfgOptLogLevelStderr)));
if (cfgOptionValid(cfgOptLogTimestamp))
logTimestamp = cfgOptionBool(cfgOptLogTimestamp);
logInit(logLevelConsole, logLevelStdErr, logTimestamp);
}
MEM_CONTEXT_TEMP_END();
}

12
src/config/load.h Normal file
View File

@ -0,0 +1,12 @@
/***********************************************************************************************************************************
Configuration Load
***********************************************************************************************************************************/
#ifndef CONFIG_LOAD_H
#define CONFIG_LOAD_H
/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/
void cfgLoad(int argListSize, const char *argList[]);
#endif

View File

@ -5,8 +5,9 @@ Main
#include <stdlib.h> #include <stdlib.h>
#include "common/error.h" #include "common/error.h"
#include "common/log.h"
#include "config/config.h" #include "config/config.h"
#include "config/parse.h" #include "config/load.h"
#include "perl/exec.h" #include "perl/exec.h"
#include "version.h" #include "version.h"
@ -14,10 +15,12 @@ int main(int argListSize, const char *argList[])
{ {
TRY_BEGIN() TRY_BEGIN()
{ {
// Parse command line // Load the configuration
configParse(argListSize, argList); // -------------------------------------------------------------------------------------------------------------------------
cfgLoad(argListSize, argList);
// Display version // Display version
// -------------------------------------------------------------------------------------------------------------------------
if (!cfgCommandHelp() && cfgCommand() == cfgCmdVersion) if (!cfgCommandHelp() && cfgCommand() == cfgCmdVersion)
{ {
printf(PGBACKREST_NAME " " PGBACKREST_VERSION "\n"); printf(PGBACKREST_NAME " " PGBACKREST_VERSION "\n");
@ -30,8 +33,7 @@ int main(int argListSize, const char *argList[])
} }
CATCH_ANY() CATCH_ANY()
{ {
fprintf(stderr, "ERROR [%03d]: %s\n", errorCode(), errorMessage()); LOG_ERROR(errorCode(), errorMessage());
fflush(stderr);
exit(errorCode()); exit(errorCode());
} }
TRY_END(); TRY_END();

View File

@ -442,7 +442,7 @@ full backup - invalid cmd line (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --no-online --type=full --stanza=bogus backup > [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --no-online --type=full --stanza=bogus backup
------------------------------------------------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------------------------------------------------
STDERR: STDERR:
ERROR [037]: backup command requires option: db1-path ERROR: [037]: backup command requires option: db1-path
HINT: does this stanza exist? HINT: does this stanza exist?
stop all stanzas (db-master host) stop all stanzas (db-master host)

View File

@ -101,18 +101,28 @@ my $oTestDef =
&TESTDEF_NAME => 'type', &TESTDEF_NAME => 'type',
&TESTDEF_TOTAL => 2, &TESTDEF_TOTAL => 2,
&TESTDEF_C => true, &TESTDEF_C => true,
&TESTDEF_CDEF => '-DNO_ERROR', &TESTDEF_CDEF => '-DNO_ERROR -DNO_LOG',
&TESTDEF_COVERAGE => &TESTDEF_COVERAGE =>
{ {
'common/type' => TESTDEF_COVERAGE_NOCODE, 'common/type' => TESTDEF_COVERAGE_NOCODE,
}, },
}, },
{
&TESTDEF_NAME => 'time',
&TESTDEF_TOTAL => 2,
&TESTDEF_C => true,
&TESTDEF_COVERAGE =>
{
'common/time' => TESTDEF_COVERAGE_FULL,
},
},
{ {
&TESTDEF_NAME => 'error', &TESTDEF_NAME => 'error',
&TESTDEF_TOTAL => 6, &TESTDEF_TOTAL => 6,
&TESTDEF_C => true, &TESTDEF_C => true,
&TESTDEF_CDEF => '-DNO_ERROR', &TESTDEF_CDEF => '-DNO_ERROR -DNO_LOG',
&TESTDEF_COVERAGE => &TESTDEF_COVERAGE =>
{ {
@ -124,7 +134,7 @@ my $oTestDef =
&TESTDEF_NAME => 'mem-context', &TESTDEF_NAME => 'mem-context',
&TESTDEF_TOTAL => 6, &TESTDEF_TOTAL => 6,
&TESTDEF_C => true, &TESTDEF_C => true,
&TESTDEF_CDEF => '-DNO_MEM_CONTEXT', &TESTDEF_CDEF => '-DNO_MEM_CONTEXT -DNO_LOG',
&TESTDEF_COVERAGE => &TESTDEF_COVERAGE =>
{ {
@ -132,13 +142,14 @@ my $oTestDef =
}, },
}, },
{ {
&TESTDEF_NAME => 'time', &TESTDEF_NAME => 'log',
&TESTDEF_TOTAL => 2, &TESTDEF_TOTAL => 3,
&TESTDEF_C => true, &TESTDEF_C => true,
&TESTDEF_CDEF => '-DNO_LOG',
&TESTDEF_COVERAGE => &TESTDEF_COVERAGE =>
{ {
'common/time' => TESTDEF_COVERAGE_FULL, 'common/log' => TESTDEF_COVERAGE_FULL,
}, },
}, },
{ {
@ -433,6 +444,17 @@ my $oTestDef =
'config/parse.auto' => TESTDEF_COVERAGE_NOCODE, 'config/parse.auto' => TESTDEF_COVERAGE_NOCODE,
}, },
}, },
{
&TESTDEF_NAME => 'load',
&TESTDEF_TOTAL => 1,
&TESTDEF_C => true,
&TESTDEF_CDEF => '-DNO_ERROR -DNO_LOG',
&TESTDEF_COVERAGE =>
{
'config/load' => TESTDEF_COVERAGE_FULL,
},
},
{ {
&TESTDEF_NAME => 'unit', &TESTDEF_NAME => 'unit',
&TESTDEF_TOTAL => 1, &TESTDEF_TOTAL => 1,

View File

@ -313,8 +313,9 @@ sub run
' -Werror -Wfatal-errors -Wall -Wextra -Wwrite-strings -Wno-clobbered' . ' -Werror -Wfatal-errors -Wall -Wextra -Wwrite-strings -Wno-clobbered' .
($self->{oTest}->{&TEST_VM} ne VM_CO6 && $self->{oTest}->{&TEST_VM} ne VM_U12 ? ' -Wpedantic' : '') . ($self->{oTest}->{&TEST_VM} ne VM_CO6 && $self->{oTest}->{&TEST_VM} ne VM_U12 ? ' -Wpedantic' : '') .
" -I$self->{strBackRestBase}/src -I$self->{strBackRestBase}/test/src test.c" . " -I$self->{strBackRestBase}/src -I$self->{strBackRestBase}/test/src test.c" .
" $self->{strBackRestBase}/test/src/common/harnessTest.c " . " $self->{strBackRestBase}/test/src/common/harnessTest.c" .
join(' ', @stryCFile) . " -l crypto -o test"; " $self->{strBackRestBase}/test/src/common/logTest.c" .
' ' . join(' ', @stryCFile) . " -l crypto -o test";
executeTest( executeTest(
'docker exec -i -u ' . TEST_USER . " ${strImage} bash -l -c '" . 'docker exec -i -u ' . TEST_USER . " ${strImage} bash -l -c '" .

57
test/src/common/logTest.c Normal file
View File

@ -0,0 +1,57 @@
/***********************************************************************************************************************************
Log Test Harness
***********************************************************************************************************************************/
#include <fcntl.h>
#include <unistd.h>
#include "common/harnessTest.h"
#include "common/log.h"
#include "common/type.h"
#include "storage/helper.h"
/***********************************************************************************************************************************
Name of file where logs are stored for testing
***********************************************************************************************************************************/
String *stdoutFile = NULL;
/***********************************************************************************************************************************
Initialize log for testing
***********************************************************************************************************************************/
void
testLogInit()
{
logInit(logLevelInfo, logLevelOff, false);
stdoutFile = strNewFmt("%s/stdout.log", testPath());
logHandleStdOut = open(strPtr(stdoutFile), O_WRONLY | O_CREAT | O_TRUNC, 0640);
}
/***********************************************************************************************************************************
Compare log to a static string
After the comparison the log is cleared so the next result can be compared.
***********************************************************************************************************************************/
void
testLogResult(const char *expected)
{
String *actual = strTrim(strNewBuf(storageGet(storageLocal(), stdoutFile, false)));
if (!strEqZ(actual, expected))
THROW(AssertError, "\n\nexpected log:\n\n%s\n\nbut actual log was:\n\n%s\n\n", expected, strPtr(actual));
close(logHandleStdOut);
logHandleStdOut = open(strPtr(stdoutFile), O_WRONLY | O_CREAT | O_TRUNC, 0640);
}
/***********************************************************************************************************************************
Make sure nothing is left in the log after all tests have completed
***********************************************************************************************************************************/
void
testLogFinal()
{
String *actual = strTrim(strNewBuf(storageGet(storageLocal(), stdoutFile, false)));
if (!strEqZ(actual, ""))
THROW(AssertError, "\n\nexpected log to be empty but actual log was:\n\n%s\n\n", strPtr(actual));
}

14
test/src/common/logTest.h Normal file
View File

@ -0,0 +1,14 @@
/***********************************************************************************************************************************
Log Test Harness
***********************************************************************************************************************************/
#ifndef TEST_COMMON_LOG_H
#define TEST_COMMON_LOG_H
/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/
void testLogInit();
void testLogResult(const char *expected);
void testLogFinal();
#endif

View File

@ -0,0 +1,95 @@
/***********************************************************************************************************************************
Test Log Handler
***********************************************************************************************************************************/
#include <fcntl.h>
#include <unistd.h>
#include <common/regExp.h>
#include <storage/storage.h>
/***********************************************************************************************************************************
Test Run
***********************************************************************************************************************************/
void testRun()
{
// *****************************************************************************************************************************
if (testBegin("logLevelEnum() and logLevelStr()"))
{
TEST_ERROR(logLevelEnum(BOGUS_STR), AssertError, "log level 'BOGUS' not found");
TEST_RESULT_INT(logLevelEnum("OFF"), logLevelOff, "log level 'OFF' found");
TEST_RESULT_INT(logLevelEnum("info"), logLevelInfo, "log level 'info' found");
TEST_RESULT_INT(logLevelEnum("TRACE"), logLevelTrace, "log level 'TRACE' found");
TEST_ERROR(logLevelStr(999), AssertError, "invalid log level '999'");
TEST_RESULT_STR(logLevelStr(logLevelOff), "OFF", "log level 'OFF' found");
TEST_RESULT_STR(logLevelStr(logLevelInfo), "INFO", "log level 'INFO' found");
TEST_RESULT_STR(logLevelStr(logLevelTrace), "TRACE", "log level 'TRACE' found");
}
// *****************************************************************************************************************************
if (testBegin("logInit()"))
{
TEST_RESULT_INT(logLevelStdOut, logLevelOff, "console logging is off");
TEST_RESULT_INT(logLevelStdErr, logLevelWarn, "stderr logging is warn");
TEST_RESULT_VOID(logInit(logLevelInfo, logLevelError, true), "init logging");
TEST_RESULT_INT(logLevelStdOut, logLevelInfo, "console logging is info");
TEST_RESULT_INT(logLevelStdErr, logLevelError, "stderr logging is error");
}
// *****************************************************************************************************************************
if (testBegin("logInternal()"))
{
TEST_RESULT_VOID(logInit(logLevelWarn, logLevelOff, true), "init logging to warn (timestamp on)");
TEST_RESULT_VOID(logInternal(logLevelWarn, NULL, NULL, 0, 0, "TEST"), "log timestamp");
String *logTime = strNewN(logBuffer, 23);
TEST_RESULT_BOOL(
regExpMatchOne(
strNew("^20[0-9]{2}\\-[0-1][0-9]\\-[0-3][0-9] [0-2][0-9]\\:[0-5][0-9]\\:[0-5][0-9]\\.[0-9]{3}$"), logTime),
true, "check timestamp format: %s", strPtr(logTime));
// Redirect output to files
TEST_RESULT_VOID(logInit(logLevelWarn, logLevelOff, false), "init logging to warn (timestamp off)");
String *stdoutFile = strNewFmt("%s/stdout.log", testPath());
String *stderrFile = strNewFmt("%s/stderr.log", testPath());
logHandleStdOut = open(strPtr(stdoutFile), O_WRONLY | O_CREAT | O_TRUNC, 0640);
logHandleStdErr = open(strPtr(stderrFile), O_WRONLY | O_CREAT | O_TRUNC, 0640);
logBuffer[0] = 0;
TEST_RESULT_VOID(logInternal(logLevelWarn, NULL, NULL, 0, 0, "format %d", 99), "log warn");
TEST_RESULT_STR(logBuffer, "P00 WARN: format 99\n", " check log");
logBuffer[0] = 0;
TEST_RESULT_VOID(logInternal(logLevelError, NULL, NULL, 0, 25, "message"), "log error");
TEST_RESULT_STR(logBuffer, "P00 ERROR: [025]: message\n", " check log");
logBuffer[0] = 0;
TEST_RESULT_VOID(logInternal(logLevelError, NULL, NULL, 0, 25, "message1\nmessage2"), "log error with multiple lines");
TEST_RESULT_STR(logBuffer, "P00 ERROR: [025]: message1\n message2\n", " check log");
TEST_RESULT_VOID(logInit(logLevelDebug, logLevelDebug, false), "init logging to debug");
logBuffer[0] = 0;
TEST_RESULT_VOID(logInternal(logLevelError, "test.c", "test_func", 33, 25, "message"), "log error");
TEST_RESULT_STR(logBuffer, "ERROR: [025]: test.c:test_func():33: message\n", " check log");
// Check stdout
Storage *storage = storageNew(strNew(testPath()), 0750, 65536, NULL);
TEST_RESULT_STR(
strPtr(strNewBuf(storageGet(storage, stdoutFile, false))),
"P00 WARN: format 99\n"
"P00 ERROR: [025]: message\n"
"P00 ERROR: [025]: message1\n"
" message2\n",
"checkout stdout output");
// Check stderr
TEST_RESULT_STR(
strPtr(strNewBuf(storageGet(storage, stderrFile, false))),
"ERROR: [025]: test.c:test_func():33: message\n",
"checkout stderr output");
}
}

View File

@ -0,0 +1,53 @@
/***********************************************************************************************************************************
Test Configuration Load
***********************************************************************************************************************************/
#include "common/log.h"
/***********************************************************************************************************************************
Test run
***********************************************************************************************************************************/
void testRun()
{
// *****************************************************************************************************************************
if (testBegin("cfgLoad()"))
{
StringList *argList = strLstNew();
strLstAdd(argList, strNew("pgbackrest"));
strLstAdd(argList, strNew("archive-get"));
TEST_ERROR(
cfgLoad(strLstSize(argList), strLstPtr(argList)), OptionRequiredError,
"archive-get command requires option: stanza");
// -------------------------------------------------------------------------------------------------------------------------
TEST_RESULT_INT(logLevelStdOut, logLevelOff, "console logging is off");
TEST_RESULT_INT(logLevelStdErr, logLevelWarn, "stderr logging is warn");
argList = strLstNew();
strLstAdd(argList, strNew("pgbackrest"));
strLstAdd(argList, strNew("--host-id=1"));
strLstAdd(argList, strNew("--process=1"));
strLstAdd(argList, strNew("--command=backup"));
strLstAdd(argList, strNew("--stanza=db"));
strLstAdd(argList, strNew("--type=backup"));
strLstAdd(argList, strNew("local"));
TEST_RESULT_VOID(cfgLoad(strLstSize(argList), strLstPtr(argList)), "load local config");
TEST_RESULT_INT(logLevelStdOut, logLevelOff, "console logging is off");
TEST_RESULT_INT(logLevelStdErr, logLevelWarn, "stderr logging is warn");
// -------------------------------------------------------------------------------------------------------------------------
argList = strLstNew();
strLstAdd(argList, strNew("pgbackrest"));
strLstAdd(argList, strNew("--stanza=db"));
strLstAdd(argList, strNew("--db-path=/path/to/db"));
strLstAdd(argList, strNew("--repo-path=/path/to/repo"));
strLstAdd(argList, strNew("stanza-create"));
TEST_RESULT_VOID(cfgLoad(strLstSize(argList), strLstPtr(argList)), "load local config");
TEST_RESULT_INT(logLevelStdOut, logLevelWarn, "console logging is off");
TEST_RESULT_INT(logLevelStdErr, logLevelOff, "stderr logging is off");
}
}

View File

@ -301,6 +301,8 @@ void testRun()
TEST_RESULT_INT(cfgOptionSource(cfgOptOnline), cfgSourceParam, " online is source default"); TEST_RESULT_INT(cfgOptionSource(cfgOptOnline), cfgSourceParam, " online is source default");
TEST_RESULT_BOOL(cfgOptionBool(cfgOptCompress), true, " compress is set"); TEST_RESULT_BOOL(cfgOptionBool(cfgOptCompress), true, " compress is set");
TEST_RESULT_INT(cfgOptionSource(cfgOptCompress), cfgSourceDefault, " compress is source default"); TEST_RESULT_INT(cfgOptionSource(cfgOptCompress), cfgSourceDefault, " compress is source default");
TEST_RESULT_INT(cfgOptionInt(cfgOptBufferSize), 4194304, " buffer-size is set");
TEST_RESULT_INT(cfgOptionSource(cfgOptBufferSize), cfgSourceDefault, " buffer-size is source default");
// ------------------------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------------------------
argList = strLstNew(); argList = strLstNew();

View File

@ -86,7 +86,7 @@ void testRun()
TEST_RESULT_PTR(storageList(storage, strNew(BOGUS_STR), NULL, true), NULL, "ignore missing dir"); TEST_RESULT_PTR(storageList(storage, strNew(BOGUS_STR), NULL, true), NULL, "ignore missing dir");
TEST_RESULT_VOID(storagePut(storage, strNew("aaa.txt"), bufNewStr(strNew("aaa"))), "write aaa.text"); TEST_RESULT_VOID(storagePut(storage, strNew("aaa.txt"), bufNewStr(strNew("aaa"))), "write aaa.text");
TEST_RESULT_STR(strPtr(strLstJoin(storageList(storage, NULL, NULL, false), ", ")), "aaa.txt", "dir list"); TEST_RESULT_STR(strPtr(strLstJoin(storageList(storage, NULL, NULL, false), ", ")), "aaa.txt, stdout.log", "dir list");
TEST_RESULT_VOID(storagePut(storage, strNew("bbb.txt"), bufNewStr(strNew("bbb"))), "write bbb.text"); TEST_RESULT_VOID(storagePut(storage, strNew("bbb.txt"), bufNewStr(strNew("bbb"))), "write bbb.text");
TEST_RESULT_STR(strPtr(strLstJoin(storageList(storage, NULL, strNew("^bbb"), false), ", ")), "bbb.txt", "dir list"); TEST_RESULT_STR(strPtr(strLstJoin(storageList(storage, NULL, strNew("^bbb"), false), ", ")), "bbb.txt", "dir list");

View File

@ -5,7 +5,9 @@ This wrapper runs the the C unit tests.
***********************************************************************************************************************************/ ***********************************************************************************************************************************/
#include <assert.h> #include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/stat.h>
#ifndef NO_ERROR #ifndef NO_ERROR
#include "common/error.h" #include "common/error.h"
@ -13,6 +15,10 @@ This wrapper runs the the C unit tests.
#include "common/harnessTest.h" #include "common/harnessTest.h"
#ifndef NO_LOG
#include "common/logTest.h"
#endif
#ifndef NO_MEM_CONTEXT #ifndef NO_MEM_CONTEXT
#include "common/memContext.h" #include "common/memContext.h"
#endif #endif
@ -36,9 +42,17 @@ main - run the tests
int int
main(void) main(void)
{ {
// Set neutral umask for testing
umask(0000);
// Set globals // Set globals
testPathSet("{[C_TEST_PATH]}"); testPathSet("{[C_TEST_PATH]}");
#ifndef NO_LOG
// Initialize logging
testLogInit();
#endif
// Initialize tests // Initialize tests
// run, selected // run, selected
{[C_TEST_LIST]} {[C_TEST_LIST]}
@ -47,18 +61,26 @@ main(void)
TRY_BEGIN() TRY_BEGIN()
{ {
#endif #endif
// Run the tests // Run the tests
testRun(); testRun();
// End test run and make sure all tests completed #ifndef NO_LOG
testComplete(); // Make sure there is nothing untested left in the log
testLogFinal();
#endif
printf("\nTESTS COMPLETED SUCCESSFULLY\n"); // End test run and make sure all tests completed
testComplete();
printf("\nTESTS COMPLETED SUCCESSFULLY\n");
fflush(stdout);
#ifndef NO_ERROR #ifndef NO_ERROR
} }
CATCH_ANY() CATCH_ANY()
{ {
fprintf(stderr, "TEST FAILED WITH %s, \"%s\" at %s:%d\n", errorName(), errorMessage(), errorFileName(), errorFileLine()); fprintf(stderr, "TEST FAILED WITH %s, \"%s\" at %s:%d\n", errorName(), errorMessage(), errorFileName(), errorFileLine());
fflush(stderr);
exit(errorCode());
} }
#ifndef NO_MEM_CONTEXT #ifndef NO_MEM_CONTEXT
FINALLY() FINALLY()