1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2025-01-30 05:39:12 +02:00

Improve fork harness to allow multiple children and setup pipes automatically.

There was a lot of extra boilerplate involved in setting up pipes so that is now automated.

In some cases testing with multiple children is useful so allow that as well.
This commit is contained in:
David Steele 2019-02-27 18:07:16 +02:00
parent 18b62a4220
commit 4be271ea2a
12 changed files with 231 additions and 171 deletions

View File

@ -115,6 +115,10 @@
<p>Create test matrix for <id>mock/archive</id> and <id>mock/stanza</id> to increase coverage and reduce tests.</p>
</release-item>
<release-item>
<p>Improve fork harness to allow multiple children and setup pipes automatically.</p>
</release-item>
<release-item>
<p>Reduce expect log level in <id>mock/archive</id> and <id>mock/stanza</id> tests.</p>
</release-item>

View File

@ -8,96 +8,197 @@ The general form of the fork harness is:
HARNESS_FORK_BEGIN()
{
// This block is required
HARNESS_FORK_CHILD()
// This block is required and can be repeated up to HARNESS_FORK_CHILD_MAX times.
//
// The first parameter is the expected exit code. If the child block does not have an explicit exit then it will automatically
// exit on 0.
//
// The second paramater specifies whether pipes should be setup between the parent and child processes. These can be accessed
// with the HARNESS_FORK_*() macros;
HARNESS_FORK_CHILD_BEGIN(0, true)
{
// Child test code goes here
}
HARNESS_FORK_CHILD_END();
// This block is optional
HARNESS_FORK_PARENT()
// This block is optional but generally useful
HARNESS_FORK_PARENT_BEGIN()
{
// Parent test code goes here
}
// If the exit result from the child process is expected to be non-zero then that must be set with this optional statement
HARNESS_FORK_CHILD_EXPECTED_EXIT_STATUS_SET(<non-zero exit status>);
HARNESS_FORK_PARENT_END();
}
HARNESS_FORK_END()
If the child process does not explicitly exit in HARNESS_FORK_CHILD() then it will exit with 0 at HARNESS_FORK_END(). This harness
is not intended for long-lived child processes.
If the child process does not explicitly exit in HARNESS_FORK_CHILD_BEGIN/END() then it will exit with 0 at HARNESS_FORK_END().
This harness is not intended for long-lived child processes.
There should not be any code outside the HARNESS_FORK_CHILD() and HARNESS_FORK_PARENT() blocks except the
HARNESS_FORK_CHILD_EXPECTED_EXIT_STATUS_SET() macro unless the code is intended to run in both the child and parent process which is
rare.
There should not be any code outside the HARNESS_FORK_CHILD_BEGIN/END() and HARNESS_FORK_PARENT_BEGIN/END() blocks.
***********************************************************************************************************************************/
#include <sys/wait.h>
#include <unistd.h>
/***********************************************************************************************************************************
HARNESS_FORK_PROCESS_ID()
Return the id of the child process, 0 if in the child process.
Define the max number of child processes allowed
***********************************************************************************************************************************/
#define HARNESS_FORK_PROCESS_ID() \
HARNESS_FORK_processId
#define HARNESS_FORK_CHILD_MAX 4
/***********************************************************************************************************************************
HARNESS_FORK_CHILD_EXPECTED_EXIT_STATUS()
Total number of child processes forked
***********************************************************************************************************************************/
#define HARNESS_FORK_PROCESS_TOTAL() \
HARNESS_FORK_processTotal
/***********************************************************************************************************************************
Return the process index of the child (i.e. the index in the total)
***********************************************************************************************************************************/
#define HARNESS_FORK_PROCESS_IDX() \
HARNESS_FORK_processIdx
/***********************************************************************************************************************************
Return the id of the child process, 0 if in the child process
***********************************************************************************************************************************/
#define HARNESS_FORK_PROCESS_ID(processId) \
HARNESS_FORK_processIdList[processId]
/***********************************************************************************************************************************
Return the pipe for the child process
***********************************************************************************************************************************/
#define HARNESS_FORK_PIPE(processId) \
HARNESS_FORK_pipe[processId]
/***********************************************************************************************************************************
Is the pipe required for this child process?
***********************************************************************************************************************************/
#define HARNESS_FORK_PIPE_REQUIRED(processId) \
HARNESS_FORK_pipeRequired[processId]
/***********************************************************************************************************************************
Get read/write pipe handles
***********************************************************************************************************************************/
#define HARNESS_FORK_CHILD_READ_PROCESS(processId) \
HARNESS_FORK_PIPE(processId)[1][0]
#define HARNESS_FORK_CHILD_READ() \
HARNESS_FORK_CHILD_READ_PROCESS(HARNESS_FORK_PROCESS_IDX())
#define HARNESS_FORK_CHILD_WRITE_PROCESS(processId) \
HARNESS_FORK_PIPE(processId)[0][1]
#define HARNESS_FORK_CHILD_WRITE() \
HARNESS_FORK_CHILD_WRITE_PROCESS(HARNESS_FORK_PROCESS_IDX())
#define HARNESS_FORK_PARENT_READ_PROCESS(processId) \
HARNESS_FORK_PIPE(processId)[0][0]
#define HARNESS_FORK_PARENT_WRITE_PROCESS(processId) \
HARNESS_FORK_PIPE(processId)[1][1]
/***********************************************************************************************************************************
At the end of the HARNESS_FORK block the parent will wait for the child to exit. By default an exit code of 0 is expected but that
can be modified with the _SET macro
can be modified when the child begins.
***********************************************************************************************************************************/
#define HARNESS_FORK_CHILD_EXPECTED_EXIT_STATUS() \
HARNESS_FORK_expectedExitCode
#define HARNESS_FORK_CHILD_EXPECTED_EXIT_STATUS_SET(expectedExitStatus) \
HARNESS_FORK_CHILD_EXPECTED_EXIT_STATUS() = expectedExitStatus;
#define HARNESS_FORK_CHILD_EXPECTED_EXIT_STATUS(processId) \
HARNESS_FORK_expectedExitStatus[processId]
/***********************************************************************************************************************************
HARNESS_FORK_BEGIN()
Performs the fork and stores the process id.
Begin the fork block
***********************************************************************************************************************************/
#define HARNESS_FORK_BEGIN() \
{ \
pid_t HARNESS_FORK_PROCESS_ID() = fork(); \
int HARNESS_FORK_CHILD_EXPECTED_EXIT_STATUS() = 0;
do \
{ \
unsigned int HARNESS_FORK_PROCESS_TOTAL() = 0; \
pid_t HARNESS_FORK_PROCESS_ID(HARNESS_FORK_CHILD_MAX) = {0}; \
int HARNESS_FORK_CHILD_EXPECTED_EXIT_STATUS(HARNESS_FORK_CHILD_MAX) = {0}; \
bool HARNESS_FORK_PIPE_REQUIRED(HARNESS_FORK_CHILD_MAX) = {0}; \
int HARNESS_FORK_PIPE(HARNESS_FORK_CHILD_MAX)[2][2] = {{{0}}};
/***********************************************************************************************************************************
HARNESS_FORK_CHILD()
Is this the child process?
Create a child process
***********************************************************************************************************************************/
#define HARNESS_FORK_CHILD() \
if (HARNESS_FORK_PROCESS_ID() == 0)
#define HARNESS_FORK_CHILD_BEGIN(expectedExitStatus, pipeRequired) \
do \
{ \
HARNESS_FORK_CHILD_EXPECTED_EXIT_STATUS(HARNESS_FORK_PROCESS_TOTAL()) = expectedExitStatus; \
\
if (pipeRequired) \
{ \
HARNESS_FORK_PIPE_REQUIRED(HARNESS_FORK_PROCESS_TOTAL()) = true; \
\
THROW_ON_SYS_ERROR_FMT( \
pipe(HARNESS_FORK_PIPE(HARNESS_FORK_PROCESS_TOTAL())[0]) == -1, KernelError, \
"unable to create read pipe for child process %u", HARNESS_FORK_PROCESS_TOTAL()); \
THROW_ON_SYS_ERROR_FMT( \
pipe(HARNESS_FORK_PIPE(HARNESS_FORK_PROCESS_TOTAL())[1]) == -1, KernelError, \
"unable to create write pipe for child process %u", HARNESS_FORK_PROCESS_TOTAL()); \
} \
\
HARNESS_FORK_PROCESS_ID(HARNESS_FORK_PROCESS_TOTAL()) = fork(); \
\
if (HARNESS_FORK_PROCESS_ID(HARNESS_FORK_PROCESS_TOTAL()) == 0) \
{ \
unsigned int HARNESS_FORK_PROCESS_IDX() = HARNESS_FORK_PROCESS_TOTAL(); \
\
if (pipeRequired) \
{ \
close(HARNESS_FORK_PARENT_READ_PROCESS(HARNESS_FORK_PROCESS_IDX())); \
close(HARNESS_FORK_PARENT_WRITE_PROCESS(HARNESS_FORK_PROCESS_IDX())); \
}
#define HARNESS_FORK_CHILD_END() \
if (HARNESS_FORK_PIPE_REQUIRED(HARNESS_FORK_PROCESS_IDX())) \
{ \
close(HARNESS_FORK_CHILD_READ()); \
close(HARNESS_FORK_CHILD_WRITE()); \
} \
\
exit(0); \
} \
\
HARNESS_FORK_PROCESS_TOTAL()++; \
} \
while (0)
/***********************************************************************************************************************************
HARNESS_FORK_PARENT()
Is this the parent process?
Process in the parent
***********************************************************************************************************************************/
#define HARNESS_FORK_PARENT() \
if (HARNESS_FORK_PROCESS_ID() != 0)
#define HARNESS_FORK_PARENT_BEGIN() \
do \
{ \
for (unsigned int processIdx = 0; processIdx < HARNESS_FORK_PROCESS_TOTAL(); processIdx++) \
{ \
if (HARNESS_FORK_PIPE_REQUIRED(processIdx)) \
{ \
close(HARNESS_FORK_CHILD_READ_PROCESS(processIdx)); \
close(HARNESS_FORK_CHILD_WRITE_PROCESS(processIdx)); \
} \
}
#define HARNESS_FORK_PARENT_END() \
for (unsigned int processIdx = 0; processIdx < HARNESS_FORK_PROCESS_TOTAL(); processIdx++) \
{ \
if (HARNESS_FORK_PIPE_REQUIRED(processIdx)) \
{ \
close(HARNESS_FORK_PARENT_READ_PROCESS(processIdx)); \
close(HARNESS_FORK_PARENT_WRITE_PROCESS(processIdx)); \
} \
} \
} \
while (0)
/***********************************************************************************************************************************
HARNESS_FORK_END()
Finish the fork block by waiting for the child to exit.
End the fork block and check exit status for all child processes
***********************************************************************************************************************************/
#define HARNESS_FORK_END() \
HARNESS_FORK_CHILD() \
exit(0); \
for (unsigned int processIdx = 0; processIdx < HARNESS_FORK_PROCESS_TOTAL(); processIdx++) \
{ \
int processStatus; \
\
HARNESS_FORK_PARENT() \
{ \
int processStatus; \
if (waitpid(HARNESS_FORK_PROCESS_ID(processIdx), &processStatus, 0) != HARNESS_FORK_PROCESS_ID(processIdx)) \
THROW_SYS_ERROR_FMT(AssertError, "unable to find child process %u", processIdx); \
\
if (waitpid(HARNESS_FORK_PROCESS_ID(), &processStatus, 0) != HARNESS_FORK_PROCESS_ID()) \
THROW_SYS_ERROR(AssertError, "unable to find child process"); \
\
if (WEXITSTATUS(processStatus) != HARNESS_FORK_CHILD_EXPECTED_EXIT_STATUS()) \
THROW_FMT(AssertError, "child exited with error %d", WEXITSTATUS(processStatus)); \
if (WEXITSTATUS(processStatus) != HARNESS_FORK_CHILD_EXPECTED_EXIT_STATUS(processIdx)) \
THROW_FMT(AssertError, "child %u exited with error %d", processIdx, WEXITSTATUS(processStatus)); \
} \
} \
}
while (0)

View File

@ -305,10 +305,11 @@ testRun(void)
HARNESS_FORK_BEGIN()
{
HARNESS_FORK_CHILD()
HARNESS_FORK_CHILD_BEGIN(0, false)
{
TEST_ERROR(cmdArchiveGet(), ParamRequiredError, "WAL segment to get required");
}
HARNESS_FORK_CHILD_END();
}
HARNESS_FORK_END();
@ -320,10 +321,11 @@ testRun(void)
HARNESS_FORK_BEGIN()
{
HARNESS_FORK_CHILD()
HARNESS_FORK_CHILD_BEGIN(0, false)
{
TEST_ERROR(cmdArchiveGet(), ParamRequiredError, "path to copy WAL segment required");
}
HARNESS_FORK_CHILD_END();
}
HARNESS_FORK_END();
@ -342,7 +344,7 @@ testRun(void)
// Test this in a fork so we can use different Perl options in later tests
HARNESS_FORK_BEGIN()
{
HARNESS_FORK_CHILD()
HARNESS_FORK_CHILD_BEGIN(0, false)
{
TEST_ERROR_FMT(
cmdArchiveGet(), FileMissingError,
@ -358,6 +360,7 @@ testRun(void)
strPtr(cfgOptionStr(cfgOptRepoPath)), strPtr(cfgOptionStr(cfgOptRepoPath)),
strPtr(cfgOptionStr(cfgOptRepoPath)), strPtr(cfgOptionStr(cfgOptRepoPath)));
}
HARNESS_FORK_CHILD_END();
}
HARNESS_FORK_END();
@ -372,7 +375,7 @@ testRun(void)
// Test this in a fork so we can use different Perl options in later tests
HARNESS_FORK_BEGIN()
{
HARNESS_FORK_CHILD()
HARNESS_FORK_CHILD_BEGIN(0, false)
{
TEST_ERROR_FMT(
cmdArchiveGet(), FileMissingError,
@ -388,6 +391,7 @@ testRun(void)
strPtr(cfgOptionStr(cfgOptRepoPath)), strPtr(cfgOptionStr(cfgOptRepoPath)),
strPtr(cfgOptionStr(cfgOptRepoPath)), strPtr(cfgOptionStr(cfgOptRepoPath)));
}
HARNESS_FORK_CHILD_END();
}
HARNESS_FORK_END();
@ -402,10 +406,11 @@ testRun(void)
HARNESS_FORK_BEGIN()
{
HARNESS_FORK_CHILD()
HARNESS_FORK_CHILD_BEGIN(0, false)
{
TEST_RESULT_INT(cmdArchiveGet(), 1, "timeout getting WAL segment");
}
HARNESS_FORK_CHILD_END();
}
HARNESS_FORK_END();
@ -418,10 +423,11 @@ testRun(void)
HARNESS_FORK_BEGIN()
{
HARNESS_FORK_CHILD()
HARNESS_FORK_CHILD_BEGIN(0, false)
{
TEST_RESULT_INT(cmdArchiveGet(), 1, "successful get of missing WAL");
}
HARNESS_FORK_CHILD_END();
}
HARNESS_FORK_END();
@ -439,10 +445,11 @@ testRun(void)
HARNESS_FORK_BEGIN()
{
HARNESS_FORK_CHILD()
HARNESS_FORK_CHILD_BEGIN(0, false)
{
TEST_RESULT_INT(cmdArchiveGet(), 0, "successful get");
}
HARNESS_FORK_CHILD_END();
}
HARNESS_FORK_END();
@ -470,10 +477,11 @@ testRun(void)
HARNESS_FORK_BEGIN()
{
HARNESS_FORK_CHILD()
HARNESS_FORK_CHILD_BEGIN(0, false)
{
TEST_RESULT_INT(cmdArchiveGet(), 0, "successful get");
}
HARNESS_FORK_CHILD_END();
}
HARNESS_FORK_END();
@ -489,10 +497,11 @@ testRun(void)
HARNESS_FORK_BEGIN()
{
HARNESS_FORK_CHILD()
HARNESS_FORK_CHILD_BEGIN(0, false)
{
TEST_RESULT_INT(cmdArchiveGet(), 1, "timeout waiting for lock");
}
HARNESS_FORK_CHILD_END();
}
HARNESS_FORK_END();

View File

@ -28,11 +28,8 @@ testRun(void)
HARNESS_FORK_BEGIN()
{
HARNESS_FORK_CHILD()
HARNESS_FORK_CHILD_BEGIN(0, true)
{
close(pipeRead[0]);
close(pipeWrite[1]);
StringList *argList = strLstNew();
strLstAddZ(argList, "pgbackrest");
strLstAddZ(argList, "--stanza=test1");
@ -42,29 +39,22 @@ testRun(void)
strLstAddZ(argList, "remote");
harnessCfgLoad(strLstSize(argList), strLstPtr(argList));
cmdRemote(pipeWrite[0], pipeRead[1]);
close(pipeRead[1]);
close(pipeWrite[0]);
cmdRemote(HARNESS_FORK_CHILD_READ(), HARNESS_FORK_CHILD_WRITE());
}
HARNESS_FORK_CHILD_END();
HARNESS_FORK_PARENT()
HARNESS_FORK_PARENT_BEGIN()
{
close(pipeRead[1]);
close(pipeWrite[0]);
IoRead *read = ioHandleReadIo(ioHandleReadNew(strNew("server read"), pipeRead[0], 2000));
IoRead *read = ioHandleReadIo(ioHandleReadNew(strNew("server read"), HARNESS_FORK_PARENT_READ_PROCESS(0), 2000));
ioReadOpen(read);
IoWrite *write = ioHandleWriteIo(ioHandleWriteNew(strNew("server write"), pipeWrite[1]));
IoWrite *write = ioHandleWriteIo(ioHandleWriteNew(strNew("server write"), HARNESS_FORK_PARENT_WRITE_PROCESS(0)));
ioWriteOpen(write);
ProtocolClient *client = protocolClientNew(strNew("test"), PROTOCOL_SERVICE_REMOTE_STR, read, write);
protocolClientNoOp(client);
protocolClientFree(client);
close(pipeRead[0]);
close(pipeWrite[1]);
}
HARNESS_FORK_PARENT_END();
}
HARNESS_FORK_END();
}

View File

@ -290,12 +290,11 @@ testRun(void)
// Test in a fork so the process does not actually exit
HARNESS_FORK_BEGIN()
{
HARNESS_FORK_CHILD()
HARNESS_FORK_CHILD_BEGIN(UnhandledError.code, false)
{
THROW(TestChildError, "does not get caught!");
}
HARNESS_FORK_CHILD_EXPECTED_EXIT_STATUS_SET(UnhandledError.code);
HARNESS_FORK_CHILD_END();
}
HARNESS_FORK_END();
}

View File

@ -29,13 +29,12 @@ testRun(void)
{
HARNESS_FORK_BEGIN()
{
HARNESS_FORK_CHILD()
HARNESS_FORK_CHILD_BEGIN(errorTypeCode(&TermError), false)
{
exitInit();
raise(SIGTERM);
}
HARNESS_FORK_CHILD_EXPECTED_EXIT_STATUS_SET(errorTypeCode(&TermError));
HARNESS_FORK_CHILD_END();
}
HARNESS_FORK_END();
}

View File

@ -18,7 +18,7 @@ testRun(void)
HARNESS_FORK_BEGIN()
{
HARNESS_FORK_CHILD()
HARNESS_FORK_CHILD_BEGIN(0, false)
{
char buffer[1024];
@ -30,6 +30,7 @@ testRun(void)
TEST_RESULT_INT(write(STDOUT_FILENO, buffer, strlen(buffer)), -1, "write to stdout fails");
TEST_RESULT_INT(write(STDERR_FILENO, buffer, strlen(buffer)), -1, "write to stderr fails");
}
HARNESS_FORK_CHILD_END();
}
HARNESS_FORK_END();
}

View File

@ -464,22 +464,18 @@ testRun(void)
{
ioBufferSizeSet(16);
// Create pipe for testing
int pipeTest[2];
THROW_ON_SYS_ERROR(pipe(pipeTest) == -1, KernelError, "unable to create test pipe");
HARNESS_FORK_BEGIN()
{
HARNESS_FORK_CHILD()
HARNESS_FORK_CHILD_BEGIN(0, true)
{
close(pipeTest[0]);
IoHandleWrite *write = NULL;
MEM_CONTEXT_TEMP_BEGIN()
{
TEST_RESULT_VOID(ioHandleWriteMove(NULL, MEM_CONTEXT_OLD()), "move null write");
TEST_ASSIGN(
write, ioHandleWriteMove(ioHandleWriteNew(strNew("write test"), pipeTest[1]), MEM_CONTEXT_OLD()),
write,
ioHandleWriteMove(ioHandleWriteNew(strNew("write test"), HARNESS_FORK_CHILD_WRITE()), MEM_CONTEXT_OLD()),
"move write");
}
MEM_CONTEXT_TEMP_END();
@ -504,20 +500,20 @@ testRun(void)
// Free object
TEST_RESULT_VOID(ioHandleWriteFree(NULL), "free null write");
TEST_RESULT_VOID(ioHandleWriteFree(write), "free write");
close(pipeTest[1]);
}
HARNESS_FORK_CHILD_END();
HARNESS_FORK_PARENT()
HARNESS_FORK_PARENT_BEGIN()
{
close(pipeTest[1]);
IoHandleRead *read = NULL;
MEM_CONTEXT_TEMP_BEGIN()
{
TEST_RESULT_VOID(ioHandleReadMove(NULL, MEM_CONTEXT_OLD()), "move null read");
TEST_ASSIGN(
read, ioHandleReadMove(ioHandleReadNew(strNew("read test"), pipeTest[0], 1000), MEM_CONTEXT_OLD()),
read,
ioHandleReadMove(
ioHandleReadNew(strNew("read test"), HARNESS_FORK_PARENT_READ_PROCESS(0), 1000), MEM_CONTEXT_OLD()),
"move read");
}
MEM_CONTEXT_TEMP_END();
@ -548,9 +544,8 @@ testRun(void)
// Free object
TEST_RESULT_VOID(ioHandleReadFree(NULL), "free null read");
TEST_RESULT_VOID(ioHandleReadFree(read), "free read");
close(pipeTest[0]);
}
HARNESS_FORK_PARENT_END();
}
HARNESS_FORK_END();

View File

@ -82,13 +82,14 @@ testRun(void)
HARNESS_FORK_BEGIN()
{
HARNESS_FORK_CHILD()
HARNESS_FORK_CHILD_BEGIN(0, false)
{
TEST_RESULT_BOOL(lockAcquireFile(backupLock, 0, true), true, "lock on fork");
sleepMSec(500);
}
HARNESS_FORK_CHILD_END();
HARNESS_FORK_PARENT()
HARNESS_FORK_PARENT_BEGIN()
{
sleepMSec(250);
TEST_ERROR(
@ -99,6 +100,7 @@ testRun(void)
"unable to acquire lock on file '%s': Resource temporarily unavailable\n"
"HINT: is another pgBackRest process running?", strPtr(backupLock))));
}
HARNESS_FORK_PARENT_END();
}
HARNESS_FORK_END();
}

View File

@ -20,22 +20,13 @@ testRun(void)
// *****************************************************************************************************************************
if (testBegin("configProtocol() and configProtocolOption()"))
{
// Create pipes for testing. Read/write is from the perspective of the client.
int pipeRead[2];
int pipeWrite[2];
THROW_ON_SYS_ERROR(pipe(pipeRead) == -1, KernelError, "unable to read test pipe");
THROW_ON_SYS_ERROR(pipe(pipeWrite) == -1, KernelError, "unable to write test pipe");
HARNESS_FORK_BEGIN()
{
HARNESS_FORK_CHILD()
HARNESS_FORK_CHILD_BEGIN(0, true)
{
close(pipeRead[0]);
close(pipeWrite[1]);
IoRead *read = ioHandleReadIo(ioHandleReadNew(strNew("client read"), pipeWrite[0], 2000));
IoRead *read = ioHandleReadIo(ioHandleReadNew(strNew("client read"), HARNESS_FORK_CHILD_READ(), 2000));
ioReadOpen(read);
IoWrite *write = ioHandleWriteIo(ioHandleWriteNew(strNew("client write"), pipeRead[1]));
IoWrite *write = ioHandleWriteIo(ioHandleWriteNew(strNew("client write"), HARNESS_FORK_CHILD_WRITE()));
ioWriteOpen(write);
StringList *argList = strLstNew();
@ -49,19 +40,14 @@ testRun(void)
ProtocolServer *server = protocolServerNew(strNew("test"), strNew("config"), read, write);
protocolServerHandlerAdd(server, configProtocol);
protocolServerProcess(server);
close(pipeRead[1]);
close(pipeWrite[0]);
}
HARNESS_FORK_CHILD_END();
HARNESS_FORK_PARENT()
HARNESS_FORK_PARENT_BEGIN()
{
close(pipeRead[1]);
close(pipeWrite[0]);
IoRead *read = ioHandleReadIo(ioHandleReadNew(strNew("server read"), pipeRead[0], 2000));
IoRead *read = ioHandleReadIo(ioHandleReadNew(strNew("server read"), HARNESS_FORK_PARENT_READ_PROCESS(0), 2000));
ioReadOpen(read);
IoWrite *write = ioHandleWriteIo(ioHandleWriteNew(strNew("server write"), pipeWrite[1]));
IoWrite *write = ioHandleWriteIo(ioHandleWriteNew(strNew("server write"), HARNESS_FORK_PARENT_WRITE_PROCESS(0)));
ioWriteOpen(write);
ProtocolClient *client = protocolClientNew(strNew("test"), strNew("config"), read, write);
@ -75,10 +61,8 @@ testRun(void)
"get options");
protocolClientFree(client);
close(pipeRead[0]);
close(pipeWrite[1]);
}
HARNESS_FORK_PARENT_END();
}
HARNESS_FORK_END();
}

View File

@ -137,14 +137,11 @@ testRun(void)
HARNESS_FORK_BEGIN()
{
HARNESS_FORK_CHILD()
HARNESS_FORK_CHILD_BEGIN(0, true)
{
close(pipeRead[0]);
close(pipeWrite[1]);
IoRead *read = ioHandleReadIo(ioHandleReadNew(strNew("server read"), pipeWrite[0], 2000));
IoRead *read = ioHandleReadIo(ioHandleReadNew(strNew("server read"), HARNESS_FORK_CHILD_READ(), 2000));
ioReadOpen(read);
IoWrite *write = ioHandleWriteIo(ioHandleWriteNew(strNew("server write"), pipeRead[1]));
IoWrite *write = ioHandleWriteIo(ioHandleWriteNew(strNew("server write"), HARNESS_FORK_CHILD_WRITE()));
ioWriteOpen(write);
// Various bogus greetings
@ -190,19 +187,14 @@ testRun(void)
// Wait for exit
TEST_RESULT_STR(strPtr(ioReadLine(read)), "{\"cmd\":\"exit\"}", "exit command");
close(pipeRead[1]);
close(pipeWrite[0]);
}
HARNESS_FORK_CHILD_END();
HARNESS_FORK_PARENT()
HARNESS_FORK_PARENT_BEGIN()
{
close(pipeRead[1]);
close(pipeWrite[0]);
IoRead *read = ioHandleReadIo(ioHandleReadNew(strNew("client read"), pipeRead[0], 2000));
IoRead *read = ioHandleReadIo(ioHandleReadNew(strNew("client read"), HARNESS_FORK_PARENT_READ_PROCESS(0), 2000));
ioReadOpen(read);
IoWrite *write = ioHandleWriteIo(ioHandleWriteNew(strNew("client write"), pipeWrite[1]));
IoWrite *write = ioHandleWriteIo(ioHandleWriteNew(strNew("client write"), HARNESS_FORK_PARENT_WRITE_PROCESS(0)));
ioWriteOpen(write);
// Various bogus greetings
@ -259,10 +251,8 @@ testRun(void)
// Free client
TEST_RESULT_VOID(protocolClientFree(client), "free client");
TEST_RESULT_VOID(protocolClientFree(NULL), "free null client");
close(pipeRead[0]);
close(pipeWrite[1]);
}
HARNESS_FORK_PARENT_END();
}
HARNESS_FORK_END();
}
@ -270,22 +260,13 @@ testRun(void)
// *****************************************************************************************************************************
if (testBegin("ProtocolServer"))
{
// Create pipes for testing. Read/write is from the perspective of the client.
int pipeRead[2];
int pipeWrite[2];
THROW_ON_SYS_ERROR(pipe(pipeRead) == -1, KernelError, "unable to read test pipe");
THROW_ON_SYS_ERROR(pipe(pipeWrite) == -1, KernelError, "unable to write test pipe");
HARNESS_FORK_BEGIN()
{
HARNESS_FORK_CHILD()
HARNESS_FORK_CHILD_BEGIN(0, true)
{
close(pipeRead[0]);
close(pipeWrite[1]);
IoRead *read = ioHandleReadIo(ioHandleReadNew(strNew("client read"), pipeWrite[0], 2000));
IoRead *read = ioHandleReadIo(ioHandleReadNew(strNew("client read"), HARNESS_FORK_CHILD_READ(), 2000));
ioReadOpen(read);
IoWrite *write = ioHandleWriteIo(ioHandleWriteNew(strNew("client write"), pipeRead[1]));
IoWrite *write = ioHandleWriteIo(ioHandleWriteNew(strNew("client write"), HARNESS_FORK_CHILD_WRITE()));
ioWriteOpen(write);
// Check greeting
@ -321,19 +302,14 @@ testRun(void)
// Exit
TEST_RESULT_VOID(ioWriteLine(write, strNew("{\"cmd\":\"exit\"}")), "write exit");
TEST_RESULT_VOID(ioWriteFlush(write), "flush exit");
close(pipeRead[1]);
close(pipeWrite[0]);
}
HARNESS_FORK_CHILD_END();
HARNESS_FORK_PARENT()
HARNESS_FORK_PARENT_BEGIN()
{
close(pipeRead[1]);
close(pipeWrite[0]);
IoRead *read = ioHandleReadIo(ioHandleReadNew(strNew("server read"), pipeRead[0], 2000));
IoRead *read = ioHandleReadIo(ioHandleReadNew(strNew("server read"), HARNESS_FORK_PARENT_READ_PROCESS(0), 2000));
ioReadOpen(read);
IoWrite *write = ioHandleWriteIo(ioHandleWriteNew(strNew("server write"), pipeWrite[1]));
IoWrite *write = ioHandleWriteIo(ioHandleWriteNew(strNew("server write"), HARNESS_FORK_PARENT_WRITE_PROCESS(0)));
ioWriteOpen(write);
// Send greeting
@ -360,10 +336,8 @@ testRun(void)
TEST_RESULT_VOID(protocolServerFree(server), "free server");
TEST_RESULT_VOID(protocolServerFree(NULL), "free null server");
close(pipeRead[0]);
close(pipeWrite[1]);
}
HARNESS_FORK_PARENT_END();
}
HARNESS_FORK_END();
}

View File

@ -156,16 +156,18 @@ testRun(void)
// -------------------------------------------------------------------------------------------------------------------------
HARNESS_FORK_BEGIN()
{
HARNESS_FORK_CHILD()
HARNESS_FORK_CHILD_BEGIN(0, false)
{
sleepMSec(250);
TEST_RESULT_INT(system(strPtr(strNewFmt("touch %s", strPtr(fileExists)))), 0, "create exists file");
}
HARNESS_FORK_CHILD_END();
HARNESS_FORK_PARENT()
HARNESS_FORK_PARENT_BEGIN()
{
TEST_RESULT_BOOL(storageExistsP(storageTest, fileExists, .timeout = 1000), true, "file exists after wait");
}
HARNESS_FORK_PARENT_END();
}
HARNESS_FORK_END();