You've already forked pgbackrest
mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2026-05-22 10:15:16 +02:00
Add execOne() to simplify exec for build, documentation, and testing.
The core Exec object is efficient but geared toward the specific needs of core and not ease-of-use as required for build, documentation, and testing. execOne() works similarly to system() except that it automatically redirects stderr to stdout and captures the output.
This commit is contained in:
+4
-4
@@ -406,10 +406,10 @@ unit:
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------------------------------
|
||||
- name: exec
|
||||
total: 1
|
||||
total: 2
|
||||
|
||||
coverage:
|
||||
- common/exec
|
||||
- build/common/exec
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------------------------------
|
||||
- name: ini
|
||||
@@ -483,7 +483,7 @@ unit:
|
||||
- protocol/server
|
||||
|
||||
include:
|
||||
- common/exec
|
||||
- build/common/exec
|
||||
|
||||
# ********************************************************************************************************************************
|
||||
- name: config
|
||||
@@ -700,7 +700,7 @@ unit:
|
||||
test:
|
||||
# ----------------------------------------------------------------------------------------------------------------------------
|
||||
- name: test
|
||||
total: 3
|
||||
total: 2
|
||||
|
||||
coverage:
|
||||
- test/command/test/build
|
||||
|
||||
@@ -5,43 +5,13 @@ Test Command
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "build/common/exec.h"
|
||||
#include "command/test/build.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/log.h"
|
||||
#include "config/config.h"
|
||||
#include "storage/posix/storage.h"
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
static const String *cmdTestExecLog;
|
||||
|
||||
static void
|
||||
cmdTestExec(const String *const command)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(STRING, command);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
ASSERT(cmdTestExecLog != NULL);
|
||||
ASSERT(command != NULL);
|
||||
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
LOG_DETAIL_FMT("exec: %s", strZ(command));
|
||||
|
||||
if (system(zNewFmt("%s > %s 2>&1", strZ(command), strZ(cmdTestExecLog))) != 0)
|
||||
{
|
||||
const Buffer *const buffer = storageGetP(storageNewReadP(storagePosixNewP(FSLASH_STR), cmdTestExecLog));
|
||||
|
||||
THROW_FMT(
|
||||
ExecuteError, "unable to execute: %s > %s 2>&1:\n%s", strZ(command), strZ(cmdTestExecLog),
|
||||
zNewFmt("\n%s", strZ(strTrim(strNewBuf(buffer)))));
|
||||
}
|
||||
}
|
||||
MEM_CONTEXT_TEMP_END();
|
||||
|
||||
FUNCTION_LOG_RETURN_VOID();
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
static void
|
||||
cmdTestPathCreate(const Storage *const storage, const String *const path)
|
||||
@@ -55,17 +25,19 @@ cmdTestPathCreate(const Storage *const storage, const String *const path)
|
||||
|
||||
ASSERT(storage != NULL);
|
||||
|
||||
const String *const rmCommand = strNewFmt("rm -rf '%s'/*", strZ(storagePathP(storage, path)));
|
||||
|
||||
TRY_BEGIN()
|
||||
{
|
||||
storagePathRemoveP(storage, path, .recurse = true);
|
||||
execOneP(rmCommand);
|
||||
}
|
||||
CATCH_ANY()
|
||||
{
|
||||
// Reset permissions
|
||||
cmdTestExec(strNewFmt("chmod -R 777 %s", strZ(storagePathP(storage, path))));
|
||||
execOneP(strNewFmt("chmod -R 777 '%s'", strZ(storagePathP(storage, path))));
|
||||
|
||||
// Try to remove again
|
||||
storagePathRemoveP(storage, path, .recurse = true);
|
||||
execOneP(rmCommand);
|
||||
}
|
||||
TRY_END();
|
||||
|
||||
@@ -100,9 +72,6 @@ cmdTest(
|
||||
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
// Log file name
|
||||
cmdTestExecLog = strNewFmt("%s/exec-%u.log", strZ(pathTest), vmId);
|
||||
|
||||
// Find test
|
||||
ASSERT(moduleName != NULL);
|
||||
|
||||
@@ -144,9 +113,9 @@ cmdTest(
|
||||
{
|
||||
LOG_DETAIL("meson setup");
|
||||
|
||||
cmdTestExec(
|
||||
execOneP(
|
||||
strNewFmt(
|
||||
"meson setup -Dwerror=true -Dfatal-errors=true %s %s %s", strZ(mesonSetup), strZ(pathUnitBuild),
|
||||
"meson setup -Dwerror=true -Dfatal-errors=true %s '%s' '%s'", strZ(mesonSetup), strZ(pathUnitBuild),
|
||||
strZ(pathUnit)));
|
||||
}
|
||||
// Else reconfigure
|
||||
@@ -154,7 +123,7 @@ cmdTest(
|
||||
{
|
||||
LOG_DETAIL("meson configure");
|
||||
|
||||
cmdTestExec(strNewFmt("meson configure %s %s", strZ(mesonSetup), strZ(pathUnitBuild)));
|
||||
execOneP(strNewFmt("meson configure %s '%s'", strZ(mesonSetup), strZ(pathUnitBuild)));
|
||||
}
|
||||
|
||||
// Remove old coverage data. Note that coverage can be in different paths depending on the meson version.
|
||||
@@ -175,7 +144,7 @@ cmdTest(
|
||||
storageRemoveP(storageUnitBuild, STRDEF("gmon.out"));
|
||||
|
||||
// Ninja build
|
||||
cmdTestExec(strNewFmt("ninja -C %s", strZ(pathUnitBuild)));
|
||||
execOneP(strNewFmt("ninja -C '%s'", strZ(pathUnitBuild)));
|
||||
buildRetry = false;
|
||||
}
|
||||
CATCH_ANY()
|
||||
|
||||
@@ -26,6 +26,7 @@ subdir('command/help')
|
||||
# test target
|
||||
####################################################################################################################################
|
||||
src_test = [
|
||||
'../../src/build/common/exec.c',
|
||||
'../../src/build/common/render.c',
|
||||
'../../src/build/common/string.c',
|
||||
'../../src/build/common/yaml.c',
|
||||
@@ -34,6 +35,7 @@ src_test = [
|
||||
'../../src/command/help/help.c',
|
||||
'../../src/common/compress/bz2/common.c',
|
||||
'../../src/common/compress/bz2/decompress.c',
|
||||
'../../src/common/fork.c',
|
||||
'../../src/common/ini.c',
|
||||
'../../src/common/io/fd.c',
|
||||
'../../src/common/io/fdRead.c',
|
||||
|
||||
@@ -108,5 +108,43 @@ testRun(void)
|
||||
TEST_RESULT_VOID(execFree(exec), "sleep exited as expected");
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************************
|
||||
if (testBegin("execOne()"))
|
||||
{
|
||||
Exec *exec = NULL;
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("exec without output");
|
||||
|
||||
TEST_RESULT_STR_Z(execOneP(STRDEF("ls " TEST_PATH)), "", "exec ls");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("touch file");
|
||||
|
||||
TEST_RESULT_STR_Z(execOneP(STRDEF("touch " TEST_PATH "/file")), "", "exec touch");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("exec with custom shell and output");
|
||||
|
||||
TEST_RESULT_STR_Z(execOneP(STRDEF("ls " TEST_PATH), .shell = STRDEF("sh -c")), "file\n", "exec ls");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("exec exits from signal");
|
||||
|
||||
TEST_ASSIGN(exec, execNew(STRDEF("cat"), NULL, STRDEF("cat"), 1000), "new cat exec");
|
||||
TEST_RESULT_VOID(execOpen(exec), "open cat exec");
|
||||
kill(exec->processId, SIGKILL);
|
||||
|
||||
TEST_ERROR(execProcess(exec), ExecuteError, "cat terminated unexpectedly on signal 9");
|
||||
TEST_RESULT_VOID(execFree(exec), "free exec");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("exec exits with error");
|
||||
|
||||
TEST_ERROR(
|
||||
execOneP(STRDEF("cat missing.txt")), UnknownError,
|
||||
"cat missing.txt terminated unexpectedly [1]: cat: missing.txt: No such file or directory");
|
||||
}
|
||||
|
||||
FUNCTION_HARNESS_RETURN_VOID();
|
||||
}
|
||||
|
||||
@@ -299,7 +299,7 @@ testRun(void)
|
||||
OBJ_NEW_BASE_BEGIN(Exec, .childQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1)
|
||||
{
|
||||
protocolHelperClient.exec = OBJ_NEW_ALLOC();
|
||||
*protocolHelperClient.exec = (Exec){.name = strNewZ("test"), .command = strNewZ("test"), .processId = INT_MAX};
|
||||
*protocolHelperClient.exec = (Exec){.pub = {.command = strNewZ("test")}, .name = strNewZ("test"), .processId = INT_MAX};
|
||||
memContextCallbackSet(memContextCurrent(), execFreeResource, protocolHelperClient.exec);
|
||||
}
|
||||
OBJ_NEW_END();
|
||||
|
||||
@@ -66,28 +66,6 @@ testRun(void)
|
||||
TEST_RESULT_STR_Z(cmdBldPathRelative(STRDEF("/tmp"), STRDEF("/tmp/sub")), "sub", "base is sub of compare");
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************************
|
||||
if (testBegin("cmdTestExec()"))
|
||||
{
|
||||
cmdTestExecLog = STRDEF(TEST_PATH "/error.log");
|
||||
bool error = false;
|
||||
|
||||
// The error will vary by OS so just make sure an error was thrown
|
||||
TRY_BEGIN()
|
||||
{
|
||||
cmdTestExec(STRDEF("/bogus/bogus"));
|
||||
}
|
||||
CATCH(ExecuteError)
|
||||
{
|
||||
error = true;
|
||||
}
|
||||
TRY_END();
|
||||
|
||||
TEST_RESULT_BOOL(error, true, "an error should be thrown");
|
||||
|
||||
cmdTestExecLog = NULL;
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************************
|
||||
if (testBegin("TestDef and TestBuild"))
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user