1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2025-07-03 00:26:59 +02:00
Files
pgbackrest/test/src/module/common/errorTest.c

305 lines
10 KiB
C
Raw Normal View History

/***********************************************************************************************************************************
Test Error Handling
***********************************************************************************************************************************/
#include <assert.h>
#include "common/harnessFork.h"
/***********************************************************************************************************************************
Declare some error locally because real errors won't work for some tests -- they could also break as errors change
***********************************************************************************************************************************/
ERROR_DECLARE(TestParent1Error);
ERROR_DECLARE(TestParent2Error);
ERROR_DECLARE(TestChildError);
ERROR_DEFINE(101, TestParent1Error, TestParent1Error);
ERROR_DEFINE(102, TestParent2Error, TestParent1Error);
ERROR_DEFINE(200, TestChildError, TestParent2Error);
/***********************************************************************************************************************************
testTryRecurse - test to blow up try stack
***********************************************************************************************************************************/
volatile int testTryRecurseTotal = 0;
bool testTryRecurseCatch = false;
bool testTryRecurseFinally = false;
void
testTryRecurse(void)
{
TRY_BEGIN()
{
testTryRecurseTotal++;
assert(errorContext.tryTotal == testTryRecurseTotal + 1);
testTryRecurse();
}
2017-11-13 21:22:13 -05:00
CATCH(MemoryError)
{
testTryRecurseCatch = true; // {uncoverable - catch should never be executed}
}
2017-11-13 21:22:13 -05:00
FINALLY()
{
testTryRecurseFinally = true;
}
TRY_END();
} // {uncoverable - function throws error, never returns}
/***********************************************************************************************************************************
Test Run
***********************************************************************************************************************************/
void
testRun(void)
{
FUNCTION_HARNESS_VOID();
// *****************************************************************************************************************************
if (testBegin("check that try stack is initialized correctly"))
{
assert(errorContext.tryTotal == 0);
}
// *****************************************************************************************************************************
if (testBegin("errorTypeExtends"))
{
assert(errorTypeExtends(&TestParent1Error, &TestParent1Error));
assert(errorTypeExtends(&TestChildError, &TestParent1Error));
assert(errorTypeExtends(&TestChildError, &TestParent2Error));
assert(!errorTypeExtends(&TestChildError, &TestChildError));
}
// *****************************************************************************************************************************
if (testBegin("TRY with no errors"))
{
volatile bool tryDone = false;
bool catchDone = false;
bool finallyDone = false;
TRY_BEGIN()
{
assert(errorContext.tryTotal == 1);
tryDone = true;
}
2017-11-13 21:22:13 -05:00
CATCH_ANY()
{
catchDone = true; // {uncoverable - catch should never be executed}
}
2017-11-13 21:22:13 -05:00
FINALLY()
{
assert(errorContext.tryList[1].state == errorStateFinal);
finallyDone = true;
}
TRY_END();
assert(tryDone);
assert(!catchDone);
assert(finallyDone);
assert(errorContext.tryTotal == 0);
}
// *****************************************************************************************************************************
if (testBegin("TRY with multiple catches"))
{
volatile bool tryDone = false;
volatile bool catchDone = false;
volatile bool finallyDone = false;
assert(errorTryDepth() == 0);
TRY_BEGIN()
{
assert(errorTryDepth() == 1);
TRY_BEGIN()
{
assert(errorTryDepth() == 2);
TRY_BEGIN()
{
assert(errorTryDepth() == 3);
TRY_BEGIN()
{
assert(errorTryDepth() == 4);
tryDone = true;
char bigMessage[sizeof(messageBuffer) * 32];
memset(bigMessage, 'A', sizeof(bigMessage));
THROW(AssertError, bigMessage);
}
TRY_END();
}
2017-11-13 21:22:13 -05:00
CATCH(AssertError)
{
// Finally below should run even though this error has been rethrown
2017-11-13 21:22:13 -05:00
RETHROW();
}
2017-11-13 21:22:13 -05:00
FINALLY()
{
finallyDone = true;
}
TRY_END();
}
2017-11-13 21:22:13 -05:00
CATCH_ANY()
{
2017-11-13 21:22:13 -05:00
RETHROW();
}
TRY_END();
}
2017-11-13 21:22:13 -05:00
CATCH(MemoryError)
{
assert(false); // {uncoverable - catch should never be executed}
}
2017-11-13 21:22:13 -05:00
CATCH(RuntimeError)
{
assert(errorTryDepth() == 1);
assert(errorContext.tryList[1].state == errorStateCatch);
assert(strlen(errorMessage()) == sizeof(messageBuffer) - 1);
catchDone = true;
}
TRY_END();
assert(errorTryDepth() == 0);
assert(tryDone);
assert(catchDone);
assert(finallyDone);
assert(errorContext.tryTotal == 0);
}
// *****************************************************************************************************************************
if (testBegin("too deep recursive TRY_ERROR()"))
{
volatile bool tryDone = false;
bool catchDone = false;
bool finallyDone = false;
TRY_BEGIN()
{
tryDone = true;
testTryRecurse();
}
2017-11-13 21:22:13 -05:00
CATCH(AssertError)
{
assert(errorCode() == AssertError.code);
assert(strcmp(errorFileName(), "test/module/common/errorTest.c") == 0);
assert(strcmp(errorFunctionName(), "testTryRecurse") == 0);
assert(errorFileLine() == 29);
assert(
strcmp(errorStackTrace(),
"test/module/common/errorTest:testTryRecurse:29:(test build required for parameters)") == 0);
assert(strcmp(errorMessage(), "too many nested try blocks") == 0);
assert(strcmp(errorName(), AssertError.name) == 0);
assert(errorType() == &AssertError);
assert(errorTypeCode(errorType()) == AssertError.code);
assert(strcmp(errorTypeName(errorType()), AssertError.name) == 0);
catchDone = true;
}
2017-11-13 21:22:13 -05:00
FINALLY()
{
finallyDone = true;
}
TRY_END();
assert(tryDone);
assert(catchDone);
assert(finallyDone);
assert(errorContext.tryTotal == 0);
// This is only ERROR_TRY_MAX - 1 because one try was used up by the wrapper above the recursive function
assert(testTryRecurseTotal == ERROR_TRY_MAX - 1);
assert(!testTryRecurseCatch);
assert(testTryRecurseFinally);
}
// *****************************************************************************************************************************
if (testBegin("THROW_CODE() and THROW_CODE_FMT()"))
{
TRY_BEGIN()
{
THROW_CODE(25, "message");
}
CATCH_ANY()
{
assert(errorCode() == 25);
assert(strcmp(errorMessage(), "message") == 0);
}
TRY_END();
// -------------------------------------------------------------------------------------------------------------------------
TRY_BEGIN()
{
THROW_CODE_FMT(122, "message %d", 1);
}
CATCH_ANY()
{
assert(errorCode() == 122);
assert(strcmp(errorMessage(), "message 1") == 0);
}
TRY_END();
// -------------------------------------------------------------------------------------------------------------------------
TRY_BEGIN()
{
THROW_CODE(777, "message");
}
CATCH_ANY()
{
assert(errorCode() == UnknownError.code);
assert(strcmp(errorMessage(), "message") == 0);
}
TRY_END();
}
// *****************************************************************************************************************************
if (testBegin("THROW_SYS_ERROR() and THROW_SYS_ERROR_FMT()"))
{
TRY_BEGIN()
{
errno = E2BIG;
THROW_SYS_ERROR(AssertError, "message");
}
CATCH_ANY()
{
printf("%s\n", errorMessage());
assert(errorCode() == AssertError.code);
assert(strcmp(errorMessage(), "message: [7] Argument list too long") == 0);
}
TRY_END();
// -------------------------------------------------------------------------------------------------------------------------
TRY_BEGIN()
{
errno = EIO;
THROW_SYS_ERROR_FMT(AssertError, "message %d", 1);
}
CATCH_ANY()
{
printf("%s\n", errorMessage());
assert(errorCode() == AssertError.code);
assert(strcmp(errorMessage(), "message 1: [5] Input/output error") == 0);
}
TRY_END();
}
// *****************************************************************************************************************************
if (testBegin("Uncaught error"))
{
// Test in a fork so the process does not actually exit
HARNESS_FORK_BEGIN()
{
HARNESS_FORK_CHILD()
{
THROW(TestChildError, "does not get caught!");
}
HARNESS_FORK_CHILD_EXPECTED_EXIT_STATUS_SET(UnhandledError.code);
}
HARNESS_FORK_END();
}
FUNCTION_HARNESS_RESULT_VOID();
}