You've already forked pgbackrest
mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-08-10 22:21:39 +02:00
Move config parsing out of Perl tests.
cfgParseTest() is provided in the C library for parsing configs in unit tests.
This commit is contained in:
@@ -99,8 +99,11 @@ sub configLoad
|
||||
|
||||
eval
|
||||
{
|
||||
$rhOption = (JSON::PP->new()->allow_nonref())->decode($strConfigJson);
|
||||
return true;
|
||||
# Hacky fix for backslashes that need to be escaped
|
||||
$strConfigJson =~ s/\\/\\\\/g;
|
||||
|
||||
$rhOption = (JSON::PP->new()->allow_nonref())->decode($strConfigJson);
|
||||
return true;
|
||||
}
|
||||
or do
|
||||
{
|
||||
@@ -171,28 +174,6 @@ sub configLoad
|
||||
umask(0000);
|
||||
}
|
||||
|
||||
# Set pg-host-cmd and repo-host-cmd to defaults if they are not set. The command depends on the currently running exe so can't
|
||||
# be calculated correctly in the C Library -- perhaps in the future this value will be passed in or set some other way
|
||||
# ??? THIS IS IMPLEMENTED IN C AND SHOULD BE REMOVED FROM HERE WITHOUT DUPLICATING TEST CODE
|
||||
if (cfgOptionValid(CFGOPT_REPO_HOST_CMD) && cfgOptionTest(CFGOPT_REPO_HOST) && !cfgOptionTest(CFGOPT_REPO_HOST_CMD))
|
||||
{
|
||||
cfgOptionSet(CFGOPT_REPO_HOST_CMD, backrestBin());
|
||||
$oOption{cfgOptionName(CFGOPT_REPO_HOST_CMD)}{source} = CFGDEF_SOURCE_DEFAULT;
|
||||
}
|
||||
|
||||
if (cfgOptionValid(CFGOPT_PG_HOST_CMD))
|
||||
{
|
||||
for (my $iOptionIdx = 1; $iOptionIdx <= cfgOptionIndexTotal(CFGOPT_PG_HOST); $iOptionIdx++)
|
||||
{
|
||||
if (cfgOptionTest(cfgOptionIdFromIndex(CFGOPT_PG_HOST, $iOptionIdx)) &&
|
||||
!cfgOptionTest(cfgOptionIdFromIndex(CFGOPT_PG_HOST_CMD, $iOptionIdx)))
|
||||
{
|
||||
cfgOptionSet(cfgOptionIdFromIndex(CFGOPT_PG_HOST_CMD, $iOptionIdx), backrestBin());
|
||||
$oOption{cfgOptionIdFromIndex(CFGOPT_PG_HOST_CMD, $iOptionIdx)}{source} = CFGDEF_SOURCE_DEFAULT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Protocol timeout should be greater than db timeout
|
||||
if (cfgOptionTest(CFGOPT_DB_TIMEOUT) && cfgOptionTest(CFGOPT_PROTOCOL_TIMEOUT) &&
|
||||
cfgOption(CFGOPT_PROTOCOL_TIMEOUT) <= cfgOption(CFGOPT_DB_TIMEOUT))
|
||||
|
@@ -45,6 +45,8 @@ These includes are from the src directory. There is no Perl-specific code in th
|
||||
#include "common/error.h"
|
||||
#include "config/config.h"
|
||||
#include "config/define.h"
|
||||
#include "config/load.h"
|
||||
#include "perl/exec.h"
|
||||
#include "postgres/pageChecksum.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
@@ -97,5 +99,6 @@ INCLUDE: xs/cipher/block.xs
|
||||
INCLUDE: xs/cipher/random.xs
|
||||
INCLUDE: xs/common/encode.xs
|
||||
INCLUDE: xs/config/config.xs
|
||||
INCLUDE: xs/config/configTest.xs
|
||||
INCLUDE: xs/config/define.xs
|
||||
INCLUDE: xs/postgres/pageChecksum.xs
|
||||
|
@@ -81,7 +81,11 @@ my @stryCFile =
|
||||
'common/encode/base64.c',
|
||||
'common/error.c',
|
||||
'common/errorType.c',
|
||||
'common/ini.c',
|
||||
'common/log.c',
|
||||
'common/memContext.c',
|
||||
'common/regExp.c',
|
||||
'common/time.c',
|
||||
'common/type/buffer.c',
|
||||
'common/type/keyValue.c',
|
||||
'common/type/list.c',
|
||||
@@ -91,7 +95,12 @@ my @stryCFile =
|
||||
'common/type/variantList.c',
|
||||
'config/config.c',
|
||||
'config/define.c',
|
||||
'config/load.c',
|
||||
'config/parse.c',
|
||||
'perl/exec.c',
|
||||
'postgres/pageChecksum.c',
|
||||
'storage/helper.c',
|
||||
'storage/storage.c',
|
||||
);
|
||||
|
||||
# Add ../src for files that are outside libc
|
||||
|
@@ -74,23 +74,8 @@ my $rhExport =
|
||||
{
|
||||
&BLD_EXPORTTYPE_SUB => [qw(
|
||||
cfgCommandId
|
||||
cfgDefOptionAllowList
|
||||
cfgDefOptionAllowListValue
|
||||
cfgDefOptionAllowListValueTotal
|
||||
cfgDefOptionAllowListValueValid
|
||||
cfgDefOptionAllowRange
|
||||
cfgDefOptionAllowRangeMax
|
||||
cfgDefOptionAllowRangeMin
|
||||
cfgDefOptionDefault
|
||||
cfgDefOptionDepend
|
||||
cfgDefOptionDependOption
|
||||
cfgDefOptionDependValue
|
||||
cfgDefOptionDependValueTotal
|
||||
cfgDefOptionDependValueValid
|
||||
cfgDefOptionNegate
|
||||
cfgDefOptionPrefix
|
||||
cfgDefOptionRequired
|
||||
cfgDefOptionSection
|
||||
cfgDefOptionSecure
|
||||
cfgDefOptionType
|
||||
cfgDefOptionValid
|
||||
@@ -128,6 +113,13 @@ my $rhExport =
|
||||
randomBytes
|
||||
)],
|
||||
},
|
||||
|
||||
'test' =>
|
||||
{
|
||||
&BLD_EXPORTTYPE_SUB => [qw(
|
||||
cfgParseTest
|
||||
)],
|
||||
},
|
||||
};
|
||||
|
||||
####################################################################################################################################
|
||||
|
@@ -214,23 +214,8 @@ sub libcAutoExportTag
|
||||
'CFGDEF_TYPE_LIST',
|
||||
'CFGDEF_TYPE_STRING',
|
||||
'cfgCommandId',
|
||||
'cfgDefOptionAllowList',
|
||||
'cfgDefOptionAllowListValue',
|
||||
'cfgDefOptionAllowListValueTotal',
|
||||
'cfgDefOptionAllowListValueValid',
|
||||
'cfgDefOptionAllowRange',
|
||||
'cfgDefOptionAllowRangeMax',
|
||||
'cfgDefOptionAllowRangeMin',
|
||||
'cfgDefOptionDefault',
|
||||
'cfgDefOptionDepend',
|
||||
'cfgDefOptionDependOption',
|
||||
'cfgDefOptionDependValue',
|
||||
'cfgDefOptionDependValueTotal',
|
||||
'cfgDefOptionDependValueValid',
|
||||
'cfgDefOptionNegate',
|
||||
'cfgDefOptionPrefix',
|
||||
'cfgDefOptionRequired',
|
||||
'cfgDefOptionSection',
|
||||
'cfgDefOptionSecure',
|
||||
'cfgDefOptionType',
|
||||
'cfgDefOptionValid',
|
||||
@@ -255,6 +240,11 @@ sub libcAutoExportTag
|
||||
[
|
||||
'randomBytes',
|
||||
],
|
||||
|
||||
test =>
|
||||
[
|
||||
'cfgParseTest',
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
|
34
libc/xs/config/configTest.xs
Normal file
34
libc/xs/config/configTest.xs
Normal file
@@ -0,0 +1,34 @@
|
||||
# ----------------------------------------------------------------------------------------------------------------------------------
|
||||
# Config Test Perl Exports
|
||||
# ----------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
MODULE = pgBackRest::LibC PACKAGE = pgBackRest::LibC
|
||||
|
||||
####################################################################################################################################
|
||||
# Parse command line and return a JSON object with results
|
||||
####################################################################################################################################
|
||||
SV *
|
||||
cfgParseTest(backrestBin, parseParam)
|
||||
const char *backrestBin
|
||||
const char *parseParam
|
||||
CODE:
|
||||
RETVAL = NULL;
|
||||
|
||||
ERROR_XS_BEGIN()
|
||||
{
|
||||
// This should run in a temp context but for some reason getopt_long gets upset when if gets called again after the previous
|
||||
// arg list being freed. So, this is a memory leak but it is only used for testing, not production.
|
||||
StringList *paramList = strLstNewSplitZ(strCat(strNew("pgbackrest|"), parseParam), "|");
|
||||
cfgLoadParam(strLstSize(paramList), strLstPtr(paramList), strNew(backrestBin));
|
||||
|
||||
String *result = perlOptionJson();
|
||||
|
||||
RETVAL = newSV(strSize(result));
|
||||
SvPOK_only(RETVAL);
|
||||
|
||||
strcpy(SvPV_nolen(RETVAL), strPtr(result));
|
||||
SvCUR_set(RETVAL, strSize(result));
|
||||
}
|
||||
ERROR_XS_END()
|
||||
OUTPUT:
|
||||
RETVAL
|
@@ -32,113 +32,6 @@ CODE:
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
bool
|
||||
cfgDefOptionAllowList(commandId, optionId)
|
||||
U32 commandId
|
||||
U32 optionId
|
||||
CODE:
|
||||
RETVAL = false;
|
||||
|
||||
ERROR_XS_BEGIN()
|
||||
{
|
||||
RETVAL = cfgDefOptionAllowList(cfgCommandDefIdFromId(commandId), cfgOptionDefIdFromId(optionId));
|
||||
}
|
||||
ERROR_XS_END();
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
const char *
|
||||
cfgDefOptionAllowListValue(commandId, optionId, valueId)
|
||||
U32 commandId
|
||||
U32 optionId
|
||||
U32 valueId
|
||||
CODE:
|
||||
RETVAL = NULL;
|
||||
|
||||
ERROR_XS_BEGIN()
|
||||
{
|
||||
RETVAL = cfgDefOptionAllowListValue(cfgCommandDefIdFromId(commandId), cfgOptionDefIdFromId(optionId), valueId);
|
||||
}
|
||||
ERROR_XS_END();
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
I32
|
||||
cfgDefOptionAllowListValueTotal(commandId, optionId)
|
||||
U32 commandId
|
||||
U32 optionId
|
||||
CODE:
|
||||
RETVAL = 0;
|
||||
|
||||
ERROR_XS_BEGIN()
|
||||
{
|
||||
RETVAL = cfgDefOptionAllowListValueTotal(cfgCommandDefIdFromId(commandId), cfgOptionDefIdFromId(optionId));
|
||||
}
|
||||
ERROR_XS_END();
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
bool
|
||||
cfgDefOptionAllowListValueValid(commandId, optionId, value);
|
||||
U32 commandId
|
||||
U32 optionId
|
||||
const char *value
|
||||
CODE:
|
||||
RETVAL = false;
|
||||
|
||||
ERROR_XS_BEGIN()
|
||||
{
|
||||
RETVAL = cfgDefOptionAllowListValueValid(cfgCommandDefIdFromId(commandId), cfgOptionDefIdFromId(optionId), value);
|
||||
}
|
||||
ERROR_XS_END();
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
bool
|
||||
cfgDefOptionAllowRange(commandId, optionId)
|
||||
U32 commandId
|
||||
U32 optionId
|
||||
CODE:
|
||||
RETVAL = false;
|
||||
|
||||
ERROR_XS_BEGIN()
|
||||
{
|
||||
RETVAL = cfgDefOptionAllowRange(cfgCommandDefIdFromId(commandId), cfgOptionDefIdFromId(optionId));
|
||||
}
|
||||
ERROR_XS_END();
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
double
|
||||
cfgDefOptionAllowRangeMax(commandId, optionId)
|
||||
U32 commandId
|
||||
U32 optionId
|
||||
CODE:
|
||||
RETVAL = 0;
|
||||
|
||||
ERROR_XS_BEGIN()
|
||||
{
|
||||
RETVAL = cfgDefOptionAllowRangeMax(cfgCommandDefIdFromId(commandId), cfgOptionDefIdFromId(optionId));
|
||||
}
|
||||
ERROR_XS_END();
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
double
|
||||
cfgDefOptionAllowRangeMin(commandId, optionId)
|
||||
U32 commandId
|
||||
U32 optionId
|
||||
CODE:
|
||||
RETVAL = 0;
|
||||
|
||||
ERROR_XS_BEGIN()
|
||||
{
|
||||
RETVAL = cfgDefOptionAllowRangeMin(cfgCommandDefIdFromId(commandId), cfgOptionDefIdFromId(optionId));
|
||||
}
|
||||
ERROR_XS_END();
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
const char *
|
||||
cfgDefOptionDefault(commandId, optionId)
|
||||
U32 commandId
|
||||
@@ -154,98 +47,6 @@ CODE:
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
bool
|
||||
cfgDefOptionDepend(commandId, optionId);
|
||||
U32 commandId
|
||||
U32 optionId
|
||||
CODE:
|
||||
RETVAL = false;
|
||||
|
||||
ERROR_XS_BEGIN()
|
||||
{
|
||||
RETVAL = cfgDefOptionDepend(cfgCommandDefIdFromId(commandId), cfgOptionDefIdFromId(optionId));
|
||||
}
|
||||
ERROR_XS_END();
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
I32
|
||||
cfgDefOptionDependOption(commandId, optionId)
|
||||
U32 commandId
|
||||
U32 optionId
|
||||
CODE:
|
||||
RETVAL = 0;
|
||||
|
||||
ERROR_XS_BEGIN()
|
||||
{
|
||||
RETVAL = cfgOptionIdFromDefId(
|
||||
cfgDefOptionDependOption(
|
||||
cfgCommandDefIdFromId(commandId), cfgOptionDefIdFromId(optionId)), cfgOptionIndex(optionId));
|
||||
}
|
||||
ERROR_XS_END();
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
const char *
|
||||
cfgDefOptionDependValue(commandId, optionId, valueId)
|
||||
U32 commandId
|
||||
U32 optionId
|
||||
U32 valueId
|
||||
CODE:
|
||||
RETVAL = NULL;
|
||||
|
||||
ERROR_XS_BEGIN()
|
||||
{
|
||||
RETVAL = cfgDefOptionDependValue(cfgCommandDefIdFromId(commandId), cfgOptionDefIdFromId(optionId), valueId);
|
||||
}
|
||||
ERROR_XS_END();
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
I32
|
||||
cfgDefOptionDependValueTotal(commandId, optionId)
|
||||
U32 commandId
|
||||
U32 optionId
|
||||
CODE:
|
||||
RETVAL = 0;
|
||||
|
||||
ERROR_XS_BEGIN()
|
||||
{
|
||||
RETVAL = cfgDefOptionDependValueTotal(cfgCommandDefIdFromId(commandId), cfgOptionDefIdFromId(optionId));
|
||||
}
|
||||
ERROR_XS_END();
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
bool
|
||||
cfgDefOptionDependValueValid(commandId, optionId, value)
|
||||
U32 commandId
|
||||
U32 optionId
|
||||
const char *value
|
||||
CODE:
|
||||
RETVAL = false;
|
||||
|
||||
ERROR_XS_BEGIN()
|
||||
{
|
||||
RETVAL = cfgDefOptionDependValueValid(cfgCommandDefIdFromId(commandId), cfgOptionDefIdFromId(optionId), value);
|
||||
}
|
||||
ERROR_XS_END();
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
bool cfgDefOptionNegate(optionId)
|
||||
U32 optionId
|
||||
CODE:
|
||||
RETVAL = false;
|
||||
|
||||
ERROR_XS_BEGIN()
|
||||
{
|
||||
RETVAL = cfgDefOptionNegate(cfgOptionDefIdFromId(optionId));
|
||||
}
|
||||
ERROR_XS_END();
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
const char *
|
||||
cfgDefOptionPrefix(optionId)
|
||||
U32 optionId
|
||||
@@ -260,52 +61,6 @@ CODE:
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
bool
|
||||
cfgDefOptionRequired(commandId, optionId)
|
||||
U32 commandId
|
||||
U32 optionId
|
||||
CODE:
|
||||
RETVAL = false;
|
||||
|
||||
ERROR_XS_BEGIN()
|
||||
{
|
||||
// Only the first indexed option is ever required
|
||||
if (cfgOptionIndex(optionId) == 0)
|
||||
{
|
||||
RETVAL = cfgDefOptionRequired(cfgCommandDefIdFromId(commandId), cfgOptionDefIdFromId(optionId));
|
||||
}
|
||||
}
|
||||
ERROR_XS_END();
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
const char *
|
||||
cfgDefOptionSection(optionId)
|
||||
U32 optionId
|
||||
CODE:
|
||||
RETVAL = NULL;
|
||||
|
||||
ERROR_XS_BEGIN()
|
||||
{
|
||||
switch (cfgDefOptionSection(cfgOptionDefIdFromId(optionId)))
|
||||
{
|
||||
case cfgDefSectionGlobal:
|
||||
RETVAL = "global";
|
||||
break;
|
||||
|
||||
case cfgDefSectionStanza:
|
||||
RETVAL = "stanza";
|
||||
break;
|
||||
|
||||
default:
|
||||
RETVAL = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ERROR_XS_END();
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
bool
|
||||
cfgDefOptionSecure(optionId)
|
||||
U32 optionId
|
||||
|
@@ -6,6 +6,7 @@ Configuration Load
|
||||
#include "common/memContext.h"
|
||||
#include "common/log.h"
|
||||
#include "config/config.h"
|
||||
#include "config/load.h"
|
||||
#include "config/parse.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
@@ -13,6 +14,12 @@ Load the configuration
|
||||
***********************************************************************************************************************************/
|
||||
void
|
||||
cfgLoad(int argListSize, const char *argList[])
|
||||
{
|
||||
cfgLoadParam(argListSize, argList, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
cfgLoadParam(int argListSize, const char *argList[], String *exe)
|
||||
{
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
@@ -38,6 +45,10 @@ cfgLoad(int argListSize, const char *argList[])
|
||||
logInit(logLevelConsole, logLevelStdErr, logTimestamp);
|
||||
}
|
||||
|
||||
// If an exe was passed in the use that
|
||||
if (exe != NULL)
|
||||
cfgExeSet(exe);
|
||||
|
||||
// Set default for repo-host-cmd
|
||||
if (cfgOptionValid(cfgOptRepoHost) && cfgOption(cfgOptRepoHost) != NULL &&
|
||||
cfgOptionSource(cfgOptRepoHostCmd) == cfgSourceDefault)
|
||||
|
@@ -8,5 +8,6 @@ Configuration Load
|
||||
Functions
|
||||
***********************************************************************************************************************************/
|
||||
void cfgLoad(int argListSize, const char *argList[]);
|
||||
void cfgLoadParam(int argListSize, const char *argList[], String *exe);
|
||||
|
||||
#endif
|
||||
|
220
src/perl/exec.c
220
src/perl/exec.c
@@ -24,6 +24,121 @@ Constants used to build perl options
|
||||
#define PGBACKREST_MODULE PGBACKREST_NAME "::Main"
|
||||
#define PGBACKREST_MAIN PGBACKREST_MODULE "::main"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Build JSON output from options
|
||||
***********************************************************************************************************************************/
|
||||
String *
|
||||
perlOptionJson()
|
||||
{
|
||||
String *result = strNew("{");
|
||||
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
for (ConfigOption optionId = 0; optionId < CFG_OPTION_TOTAL; optionId++)
|
||||
{
|
||||
// Skip the option if it is not valid
|
||||
if (!cfgOptionValid(optionId))
|
||||
continue;
|
||||
|
||||
// Output option
|
||||
if (strSize(result) != 1)
|
||||
strCat(result, ",");
|
||||
|
||||
strCatFmt(result, "\"%s\":{", cfgOptionName(optionId));
|
||||
|
||||
// Output source unless it is default
|
||||
if (cfgOptionSource(optionId) != cfgSourceDefault)
|
||||
{
|
||||
strCat(result, "\"source\":\"");
|
||||
|
||||
if (cfgOptionSource(optionId) == cfgSourceParam)
|
||||
strCat(result, "param");
|
||||
else
|
||||
strCat(result, "config");
|
||||
|
||||
strCat(result, "\"");
|
||||
}
|
||||
|
||||
// If option was negated
|
||||
if (cfgOptionNegate(optionId))
|
||||
strCatFmt(result, ",\"negate\":%s", strPtr(varStrForce(varNewBool(true))));
|
||||
// Else not negated and has a value
|
||||
else if (cfgOption(optionId) != NULL)
|
||||
{
|
||||
if (cfgOptionSource(optionId) != cfgSourceDefault)
|
||||
strCat(result, ",");
|
||||
|
||||
strCat(result, "\"value\":");
|
||||
|
||||
switch (cfgDefOptionType(cfgOptionDefIdFromId(optionId)))
|
||||
{
|
||||
case cfgDefOptTypeBoolean:
|
||||
case cfgDefOptTypeFloat:
|
||||
case cfgDefOptTypeInteger:
|
||||
{
|
||||
strCat(result, strPtr(varStrForce(cfgOption(optionId))));
|
||||
break;
|
||||
}
|
||||
|
||||
case cfgDefOptTypeString:
|
||||
{
|
||||
strCatFmt(result, "\"%s\"", strPtr(cfgOptionStr(optionId)));
|
||||
break;
|
||||
}
|
||||
|
||||
case cfgDefOptTypeHash:
|
||||
{
|
||||
const KeyValue *valueKv = cfgOptionKv(optionId);
|
||||
const VariantList *keyList = kvKeyList(valueKv);
|
||||
|
||||
strCat(result, "{");
|
||||
|
||||
for (unsigned int listIdx = 0; listIdx < varLstSize(keyList); listIdx++)
|
||||
{
|
||||
if (listIdx != 0)
|
||||
strCat(result, ",");
|
||||
|
||||
strCatFmt(
|
||||
result, "\"%s\":\"%s\"", strPtr(varStr(varLstGet(keyList, listIdx))),
|
||||
strPtr(varStr(kvGet(valueKv, varLstGet(keyList, listIdx)))));
|
||||
}
|
||||
|
||||
strCat(result, "}");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case cfgDefOptTypeList:
|
||||
{
|
||||
StringList *valueList = strLstNewVarLst(cfgOptionLst(optionId));
|
||||
|
||||
strCat(result, "{");
|
||||
|
||||
for (unsigned int listIdx = 0; listIdx < strLstSize(valueList); listIdx++)
|
||||
{
|
||||
if (listIdx != 0)
|
||||
strCat(result, ",");
|
||||
|
||||
strCatFmt(result, "\"%s\":true", strPtr(strLstGet(valueList, listIdx)));
|
||||
}
|
||||
|
||||
strCat(result, "}");
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
strCat(result, "}");
|
||||
}
|
||||
|
||||
strCat(result, "}");
|
||||
}
|
||||
MEM_CONTEXT_TEMP_END();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Build list of perl options to use for exec
|
||||
***********************************************************************************************************************************/
|
||||
@@ -43,109 +158,6 @@ perlCommand()
|
||||
strLstAdd(perlArgList, strNew(PERL_EXE));
|
||||
}
|
||||
|
||||
// Construct option list to pass to main
|
||||
String *configJson = strNew("{");
|
||||
|
||||
for (ConfigOption optionId = 0; optionId < CFG_OPTION_TOTAL; optionId++)
|
||||
{
|
||||
// Skip the option if it is not valid
|
||||
if (!cfgOptionValid(optionId))
|
||||
continue;
|
||||
|
||||
// Output option
|
||||
if (strSize(configJson) != 1)
|
||||
strCat(configJson, ",");
|
||||
|
||||
strCatFmt(configJson, "\"%s\":{", cfgOptionName(optionId));
|
||||
|
||||
// Output source unless it is default
|
||||
if (cfgOptionSource(optionId) != cfgSourceDefault)
|
||||
{
|
||||
strCat(configJson, "\"source\":\"");
|
||||
|
||||
if (cfgOptionSource(optionId) == cfgSourceParam)
|
||||
strCat(configJson, "param");
|
||||
else
|
||||
strCat(configJson, "config");
|
||||
|
||||
strCat(configJson, "\"");
|
||||
}
|
||||
|
||||
// If option was negated
|
||||
if (cfgOptionNegate(optionId))
|
||||
strCatFmt(configJson, ",\"negate\":%s", strPtr(varStrForce(varNewBool(true))));
|
||||
// Else not negated and has a value
|
||||
else if (cfgOption(optionId) != NULL)
|
||||
{
|
||||
if (cfgOptionSource(optionId) != cfgSourceDefault)
|
||||
strCat(configJson, ",");
|
||||
|
||||
strCat(configJson, "\"value\":");
|
||||
|
||||
switch (cfgDefOptionType(cfgOptionDefIdFromId(optionId)))
|
||||
{
|
||||
case cfgDefOptTypeBoolean:
|
||||
case cfgDefOptTypeFloat:
|
||||
case cfgDefOptTypeInteger:
|
||||
{
|
||||
strCat(configJson, strPtr(varStrForce(cfgOption(optionId))));
|
||||
break;
|
||||
}
|
||||
|
||||
case cfgDefOptTypeString:
|
||||
{
|
||||
strCatFmt(configJson, "\"%s\"", strPtr(cfgOptionStr(optionId)));
|
||||
break;
|
||||
}
|
||||
|
||||
case cfgDefOptTypeHash:
|
||||
{
|
||||
const KeyValue *valueKv = cfgOptionKv(optionId);
|
||||
const VariantList *keyList = kvKeyList(valueKv);
|
||||
|
||||
strCat(configJson, "{");
|
||||
|
||||
for (unsigned int listIdx = 0; listIdx < varLstSize(keyList); listIdx++)
|
||||
{
|
||||
if (listIdx != 0)
|
||||
strCat(configJson, ",");
|
||||
|
||||
strCatFmt(
|
||||
configJson, "\"%s\":\"%s\"", strPtr(varStr(varLstGet(keyList, listIdx))),
|
||||
strPtr(varStr(kvGet(valueKv, varLstGet(keyList, listIdx)))));
|
||||
}
|
||||
|
||||
strCat(configJson, "}");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case cfgDefOptTypeList:
|
||||
{
|
||||
StringList *valueList = strLstNewVarLst(cfgOptionLst(optionId));
|
||||
|
||||
strCat(configJson, "{");
|
||||
|
||||
for (unsigned int listIdx = 0; listIdx < strLstSize(valueList); listIdx++)
|
||||
{
|
||||
if (listIdx != 0)
|
||||
strCat(configJson, ",");
|
||||
|
||||
strCatFmt(configJson, "\"%s\":true", strPtr(strLstGet(valueList, listIdx)));
|
||||
}
|
||||
|
||||
strCat(configJson, "}");
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
strCat(configJson, "}");
|
||||
}
|
||||
|
||||
strCat(configJson, "}");
|
||||
|
||||
// Add command arguments to pass to main
|
||||
String *commandParam = strNew("");
|
||||
|
||||
@@ -161,7 +173,7 @@ perlCommand()
|
||||
|
||||
// Construct Perl main call
|
||||
String *mainCall = strNewFmt(
|
||||
PGBACKREST_MAIN "('%s','%s','%s'%s)", strPtr(cfgExe()), cfgCommandName(cfgCommand()), strPtr(configJson),
|
||||
PGBACKREST_MAIN "('%s','%s','%s'%s)", strPtr(cfgExe()), cfgCommandName(cfgCommand()), strPtr(perlOptionJson()),
|
||||
strPtr(commandParam));
|
||||
|
||||
// End arg list for perl exec
|
||||
|
@@ -9,6 +9,7 @@ Execute Perl for Legacy Functionality
|
||||
/***********************************************************************************************************************************
|
||||
Functions
|
||||
***********************************************************************************************************************************/
|
||||
String *perlOptionJson();
|
||||
StringList *perlCommand();
|
||||
void perlExec(StringList *perlArgList);
|
||||
|
||||
|
@@ -211,9 +211,8 @@ sub run
|
||||
$strCommand =
|
||||
($self->{oTest}->{&TEST_CONTAINER} ? 'docker exec -i -u ' . TEST_USER . " ${strImage} " : '') .
|
||||
testRunExe(
|
||||
vmCoverage($self->{oTest}->{&TEST_VM}), undef, abs_path($0),
|
||||
dirname($self->{strCoveragePath}), $self->{strBackRestBase}, $self->{oTest}->{&TEST_MODULE},
|
||||
$self->{oTest}->{&TEST_NAME}, defined($self->{oTest}->{&TEST_RUN}) ? $self->{oTest}->{&TEST_RUN} : 'all') .
|
||||
vmCoverage($self->{oTest}->{&TEST_VM}), undef, abs_path($0), dirname($self->{strCoveragePath}),
|
||||
$self->{strBackRestBase}, $self->{oTest}->{&TEST_MODULE}, $self->{oTest}->{&TEST_NAME}) .
|
||||
" --test-path=${strVmTestPath}" .
|
||||
" --vm=$self->{oTest}->{&TEST_VM}" .
|
||||
" --vm-id=$self->{iVmIdx}" .
|
||||
|
@@ -157,6 +157,13 @@ sub process
|
||||
# Initialize test storage
|
||||
$oStorage = new pgBackRest::Storage::Local($self->testPath(), new pgBackRest::Storage::Posix::Driver());
|
||||
|
||||
# Generate backrest exe
|
||||
$self->{strBackRestExe} = testRunExe(
|
||||
$self->coverage(), $self->{strBackRestExeC}, $self->{strBackRestExeHelper}, dirname($self->testPath()), $self->basePath(),
|
||||
$self->module(), $self->moduleTest(), true);
|
||||
|
||||
backrestBinSet($self->{strBackRestExe});
|
||||
|
||||
# Init, run, and end the test(s)
|
||||
$self->initModule();
|
||||
$self->run();
|
||||
@@ -236,13 +243,6 @@ sub begin
|
||||
return false;
|
||||
}
|
||||
|
||||
# Generate backrest exe
|
||||
$self->{strBackRestExe} = testRunExe(
|
||||
$self->coverage(), $self->{strBackRestExeC}, $self->{strBackRestExeHelper}, dirname($self->testPath()), $self->basePath(),
|
||||
$self->module(), $self->moduleTest(), $self->runCurrent(), true);
|
||||
|
||||
backrestBinSet($self->{strBackRestExe});
|
||||
|
||||
# Create an ExpectTest object
|
||||
if ($self->doExpect())
|
||||
{
|
||||
@@ -532,7 +532,7 @@ sub testRunGet
|
||||
push @EXPORT, qw(testRunGet);
|
||||
|
||||
####################################################################################################################################
|
||||
# testExe
|
||||
# Generate test executable
|
||||
####################################################################################################################################
|
||||
sub testRunExe
|
||||
{
|
||||
@@ -543,7 +543,6 @@ sub testRunExe
|
||||
my $strBackRestBasePath = shift;
|
||||
my $strModule = shift;
|
||||
my $strTest = shift;
|
||||
my $iRun = shift;
|
||||
my $bLog = shift;
|
||||
|
||||
my $strExe = defined($strExeC) ? $strExeC : undef;
|
||||
|
@@ -17,6 +17,7 @@ use Getopt::Long qw(GetOptions);
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Config::Config;
|
||||
use pgBackRest::LibC qw(:test);
|
||||
use pgBackRest::Version;
|
||||
|
||||
use constant CONFIGENVTEST => 'ConfigEnvTest';
|
||||
@@ -103,333 +104,6 @@ sub commandTestWrite
|
||||
return @szyParam;
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# testOptionValidate
|
||||
#
|
||||
# Make sure the command-line options are valid based on the command.
|
||||
####################################################################################################################################
|
||||
sub testOptionValidate
|
||||
{
|
||||
my $iCommandId = shift;
|
||||
|
||||
# Build hash with all valid command-line options
|
||||
my @stryOptionAllow;
|
||||
|
||||
for (my $iOptionId = 0; $iOptionId < cfgOptionTotal(); $iOptionId++)
|
||||
{
|
||||
my $strOption = cfgOptionName($iOptionId);
|
||||
|
||||
if (cfgDefOptionType($iOptionId) == CFGDEF_TYPE_HASH || cfgDefOptionType($iOptionId) == CFGDEF_TYPE_LIST)
|
||||
{
|
||||
$strOption .= '=s@';
|
||||
}
|
||||
elsif (cfgDefOptionType($iOptionId) != CFGDEF_TYPE_BOOLEAN)
|
||||
{
|
||||
$strOption .= '=s';
|
||||
}
|
||||
|
||||
push(@stryOptionAllow, $strOption);
|
||||
|
||||
# Check if the option can be negated
|
||||
if (cfgDefOptionNegate($iOptionId))
|
||||
{
|
||||
push(@stryOptionAllow, 'no-' . cfgOptionName($iOptionId));
|
||||
}
|
||||
}
|
||||
|
||||
# Get command-line options
|
||||
my $oOptionTest = {};
|
||||
|
||||
# Parse command line options
|
||||
if (!GetOptions($oOptionTest, @stryOptionAllow))
|
||||
{
|
||||
confess &log(ASSERT, "error parsing command line");
|
||||
}
|
||||
|
||||
# Store results of validation
|
||||
my $rhOption = {};
|
||||
|
||||
# Keep track of unresolved dependencies
|
||||
my $bDependUnresolved = true;
|
||||
my %oOptionResolved;
|
||||
|
||||
# Loop through all possible options
|
||||
while ($bDependUnresolved)
|
||||
{
|
||||
# Assume that all dependencies will be resolved in this loop
|
||||
$bDependUnresolved = false;
|
||||
|
||||
for (my $iOptionId = 0; $iOptionId < cfgOptionTotal(); $iOptionId++)
|
||||
{
|
||||
my $strOption = cfgOptionName($iOptionId);
|
||||
|
||||
# Skip the option if it has been resolved in a prior loop
|
||||
if (defined($oOptionResolved{$strOption}))
|
||||
{
|
||||
next;
|
||||
}
|
||||
|
||||
# Determine if an option is valid for a command
|
||||
$rhOption->{$strOption}{valid} = cfgDefOptionValid($iCommandId, $iOptionId);
|
||||
|
||||
if (!$rhOption->{$strOption}{valid})
|
||||
{
|
||||
$oOptionResolved{$strOption} = true;
|
||||
next;
|
||||
}
|
||||
|
||||
# Store the option value
|
||||
my $strValue = $oOptionTest->{$strOption};
|
||||
|
||||
# Check to see if an option can be negated. Make sure that it is not set and negated at the same time.
|
||||
$rhOption->{$strOption}{negate} = false;
|
||||
|
||||
if (cfgDefOptionNegate($iOptionId))
|
||||
{
|
||||
$rhOption->{$strOption}{negate} = defined($$oOptionTest{'no-' . $strOption});
|
||||
|
||||
if ($rhOption->{$strOption}{negate} && defined($strValue))
|
||||
{
|
||||
confess &log(ERROR, "option '${strOption}' cannot be both set and negated", ERROR_OPTION_NEGATE);
|
||||
}
|
||||
|
||||
if ($rhOption->{$strOption}{negate} && cfgDefOptionType($iOptionId) eq CFGDEF_TYPE_BOOLEAN)
|
||||
{
|
||||
$strValue = false;
|
||||
}
|
||||
}
|
||||
|
||||
# Check dependency for the command then for the option
|
||||
my $bDependResolved = true;
|
||||
my $strDependOption;
|
||||
my $strDependValue;
|
||||
my $strDependType;
|
||||
|
||||
if (cfgDefOptionDepend($iCommandId, $iOptionId))
|
||||
{
|
||||
# Check if the depend option has a value
|
||||
my $iDependOptionId = cfgDefOptionDependOption($iCommandId, $iOptionId);
|
||||
$strDependOption = cfgOptionName($iDependOptionId);
|
||||
$strDependValue = $rhOption->{$strDependOption}{value};
|
||||
|
||||
# Make sure the depend option has been resolved, otherwise skip this option for now
|
||||
if (!defined($oOptionResolved{$strDependOption}))
|
||||
{
|
||||
$bDependUnresolved = true;
|
||||
next;
|
||||
}
|
||||
|
||||
if (!defined($strDependValue))
|
||||
{
|
||||
$bDependResolved = false;
|
||||
$strDependType = 'source';
|
||||
}
|
||||
|
||||
# If a depend value exists, make sure the option value matches
|
||||
if ($bDependResolved && cfgDefOptionDependValueTotal($iCommandId, $iOptionId) == 1 &&
|
||||
cfgDefOptionDependValue($iCommandId, $iOptionId, 0) ne $strDependValue)
|
||||
{
|
||||
$bDependResolved = false;
|
||||
$strDependType = 'value';
|
||||
}
|
||||
|
||||
# If a depend list exists, make sure the value is in the list
|
||||
if ($bDependResolved && cfgDefOptionDependValueTotal($iCommandId, $iOptionId) > 1 &&
|
||||
!cfgDefOptionDependValueValid($iCommandId, $iOptionId, $strDependValue))
|
||||
{
|
||||
$bDependResolved = false;
|
||||
$strDependType = 'list';
|
||||
}
|
||||
}
|
||||
|
||||
if (cfgDefOptionDepend($iCommandId, $iOptionId) && !$bDependResolved && defined($strValue))
|
||||
{
|
||||
my $strError = "option '${strOption}' not valid without option ";
|
||||
my $iDependOptionId = cfgOptionId($strDependOption);
|
||||
|
||||
if ($strDependType eq 'source')
|
||||
{
|
||||
confess &log(ERROR, "${strError}'${strDependOption}'", ERROR_OPTION_INVALID);
|
||||
}
|
||||
|
||||
# If a depend value exists, make sure the option value matches
|
||||
if ($strDependType eq 'value')
|
||||
{
|
||||
if (cfgDefOptionType($iDependOptionId) eq CFGDEF_TYPE_BOOLEAN)
|
||||
{
|
||||
$strError .=
|
||||
"'" . (cfgDefOptionDependValue($iCommandId, $iOptionId, 0) ? '' : 'no-') . "${strDependOption}'";
|
||||
}
|
||||
else
|
||||
{
|
||||
$strError .= "'${strDependOption}' = '" . cfgDefOptionDependValue($iCommandId, $iOptionId, 0) . "'";
|
||||
}
|
||||
|
||||
confess &log(ERROR, $strError, ERROR_OPTION_INVALID);
|
||||
}
|
||||
|
||||
$strError .= "'${strDependOption}'";
|
||||
|
||||
# If a depend list exists, make sure the value is in the list
|
||||
if ($strDependType eq 'list')
|
||||
{
|
||||
my @oyValue;
|
||||
|
||||
for (my $iValueId = 0; $iValueId < cfgDefOptionDependValueTotal($iCommandId, $iOptionId); $iValueId++)
|
||||
{
|
||||
push(@oyValue, "'" . cfgDefOptionDependValue($iCommandId, $iOptionId, $iValueId) . "'");
|
||||
}
|
||||
|
||||
$strError .= @oyValue == 1 ? " = $oyValue[0]" : " in (" . join(", ", @oyValue) . ")";
|
||||
confess &log(ERROR, $strError, ERROR_OPTION_INVALID);
|
||||
}
|
||||
}
|
||||
|
||||
# Is the option defined?
|
||||
if (defined($strValue))
|
||||
{
|
||||
# Check that floats and integers are valid
|
||||
if (cfgDefOptionType($iOptionId) eq CFGDEF_TYPE_INTEGER ||
|
||||
cfgDefOptionType($iOptionId) eq CFGDEF_TYPE_FLOAT)
|
||||
{
|
||||
# Test that the string is a valid float or integer by adding 1 to it. It's pretty hokey but it works and it
|
||||
# beats requiring Scalar::Util::Numeric to do it properly.
|
||||
my $bError = false;
|
||||
|
||||
eval
|
||||
{
|
||||
my $strTest = $strValue + 1;
|
||||
return true;
|
||||
}
|
||||
or do
|
||||
{
|
||||
$bError = true;
|
||||
};
|
||||
|
||||
# Check that integers are really integers
|
||||
if (!$bError && cfgDefOptionType($iOptionId) eq CFGDEF_TYPE_INTEGER &&
|
||||
(int($strValue) . 'S') ne ($strValue . 'S'))
|
||||
{
|
||||
$bError = true;
|
||||
}
|
||||
|
||||
# Error if the value did not pass tests
|
||||
!$bError
|
||||
or confess &log(ERROR, "'${strValue}' is not valid for '${strOption}' option", ERROR_OPTION_INVALID_VALUE);
|
||||
}
|
||||
|
||||
# Process an allow list for the command then for the option
|
||||
if (cfgDefOptionAllowList($iCommandId, $iOptionId) &&
|
||||
!cfgDefOptionAllowListValueValid($iCommandId, $iOptionId, $strValue))
|
||||
{
|
||||
confess &log(ERROR, "'${strValue}' is not valid for '${strOption}' option", ERROR_OPTION_INVALID_VALUE);
|
||||
}
|
||||
|
||||
# Process an allow range for the command then for the option
|
||||
if (cfgDefOptionAllowRange($iCommandId, $iOptionId) &&
|
||||
($strValue < cfgDefOptionAllowRangeMin($iCommandId, $iOptionId) ||
|
||||
$strValue > cfgDefOptionAllowRangeMax($iCommandId, $iOptionId)))
|
||||
{
|
||||
confess &log(ERROR, "'${strValue}' is not valid for '${strOption}' option", ERROR_OPTION_INVALID_RANGE);
|
||||
}
|
||||
|
||||
# Set option value
|
||||
if (ref($strValue) eq 'ARRAY' &&
|
||||
(cfgDefOptionType($iOptionId) eq CFGDEF_TYPE_HASH || cfgDefOptionType($iOptionId) eq CFGDEF_TYPE_LIST))
|
||||
{
|
||||
foreach my $strItem (@{$strValue})
|
||||
{
|
||||
my $strKey;
|
||||
my $strValue;
|
||||
|
||||
# If the keys are expected to have values
|
||||
if (cfgDefOptionType($iOptionId) eq CFGDEF_TYPE_HASH)
|
||||
{
|
||||
# Check for = and make sure there is a least one character on each side
|
||||
my $iEqualPos = index($strItem, '=');
|
||||
|
||||
if ($iEqualPos < 1 || length($strItem) <= $iEqualPos + 1)
|
||||
{
|
||||
confess &log(ERROR, "'${strItem}' not valid key/value for '${strOption}' option",
|
||||
ERROR_OPTION_INVALID_PAIR);
|
||||
}
|
||||
|
||||
$strKey = substr($strItem, 0, $iEqualPos);
|
||||
$strValue = substr($strItem, $iEqualPos + 1);
|
||||
}
|
||||
# Else no values are expected so set value to true
|
||||
else
|
||||
{
|
||||
$strKey = $strItem;
|
||||
$strValue = true;
|
||||
}
|
||||
|
||||
# Check that the key has not already been set
|
||||
if (defined($rhOption->{$strOption}{$strKey}{value}))
|
||||
{
|
||||
confess &log(ERROR, "'${$strItem}' already defined for '${strOption}' option",
|
||||
ERROR_OPTION_DUPLICATE_KEY);
|
||||
}
|
||||
|
||||
# Set key/value
|
||||
$rhOption->{$strOption}{value}{$strKey} = $strValue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$rhOption->{$strOption}{value} = $strValue;
|
||||
}
|
||||
|
||||
# If not config sourced then it must be a param
|
||||
if (!defined($rhOption->{$strOption}{source}))
|
||||
{
|
||||
$rhOption->{$strOption}{source} = CFGDEF_SOURCE_PARAM;
|
||||
}
|
||||
}
|
||||
# Else try to set a default
|
||||
elsif ($bDependResolved)
|
||||
{
|
||||
# Source is default for this option
|
||||
$rhOption->{$strOption}{source} = CFGDEF_SOURCE_DEFAULT;
|
||||
|
||||
# Check for default in command then option
|
||||
my $strDefault = cfgDefOptionDefault($iCommandId, $iOptionId);
|
||||
|
||||
# If default is defined
|
||||
if (defined($strDefault))
|
||||
{
|
||||
# Only set default if dependency is resolved
|
||||
$rhOption->{$strOption}{value} = $strDefault if !$rhOption->{$strOption}{negate};
|
||||
}
|
||||
# Else check required
|
||||
elsif (cfgDefOptionRequired($iCommandId, $iOptionId))
|
||||
{
|
||||
confess &log(ERROR,
|
||||
cfgCommandName($iCommandId) . " command requires option: ${strOption}" .
|
||||
ERROR_OPTION_REQUIRED);
|
||||
}
|
||||
}
|
||||
|
||||
$oOptionResolved{$strOption} = true;
|
||||
}
|
||||
}
|
||||
|
||||
# Make sure all options specified on the command line are valid
|
||||
foreach my $strOption (sort(keys(%{$oOptionTest})))
|
||||
{
|
||||
# Strip "no-" off the option
|
||||
$strOption = $strOption =~ /^no\-/ ? substr($strOption, 3) : $strOption;
|
||||
|
||||
if (!$rhOption->{$strOption}{valid})
|
||||
{
|
||||
confess &log(
|
||||
ERROR, "option '${strOption}' not valid for command '" . cfgCommandName($iCommandId) . "'", ERROR_OPTION_COMMAND);
|
||||
}
|
||||
}
|
||||
|
||||
return $rhOption;
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Load the configuration
|
||||
####################################################################################################################################
|
||||
@@ -438,174 +112,11 @@ sub configTestLoad
|
||||
my $self = shift;
|
||||
my $iCommandId = shift;
|
||||
|
||||
@ARGV = $self->commandTestWrite(cfgCommandName($iCommandId), $self->{&CONFIGENVTEST});
|
||||
my @stryArg = $self->commandTestWrite(cfgCommandName($iCommandId), $self->{&CONFIGENVTEST});
|
||||
my $strConfigJson = cfgParseTest(backrestBin(), join('|', @stryArg));
|
||||
$self->testResult(
|
||||
sub {configLoad(
|
||||
false, backrestBin(), cfgCommandName($iCommandId),
|
||||
(JSON::PP->new()->allow_nonref())->encode(testOptionValidate($iCommandId)))},
|
||||
true, 'config load: ' . join(" ", @ARGV));
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# optionTestSetByName - used only by config unit tests, general option set should be done with optionTestSet
|
||||
####################################################################################################################################
|
||||
sub optionTestSetByName
|
||||
{
|
||||
my $self = shift;
|
||||
my $strOption = shift;
|
||||
my $strValue = shift;
|
||||
|
||||
$self->{&CONFIGENVTEST}{option}{$strOption} = $strValue;
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# configTestLoadExpect - used only by config unit tests, for general config load use configTestLoad()
|
||||
####################################################################################################################################
|
||||
sub configTestLoadExpect
|
||||
{
|
||||
my $self = shift;
|
||||
my $strCommand = shift;
|
||||
my $iExpectedError = shift;
|
||||
my $strErrorParam1 = shift;
|
||||
my $strErrorParam2 = shift;
|
||||
my $strErrorParam3 = shift;
|
||||
|
||||
@ARGV = $self->commandTestWrite($strCommand, $self->{&CONFIGENVTEST});
|
||||
$self->configTestClear();
|
||||
&log(INFO, " command line: " . join(" ", @ARGV));
|
||||
|
||||
my $bErrorFound = false;
|
||||
|
||||
eval
|
||||
{
|
||||
configLoad(false);
|
||||
return true;
|
||||
}
|
||||
or do
|
||||
{
|
||||
my $oException = $EVAL_ERROR;
|
||||
|
||||
if (!defined($iExpectedError))
|
||||
{
|
||||
confess $oException;
|
||||
}
|
||||
|
||||
$bErrorFound = true;
|
||||
|
||||
if (isException(\$oException))
|
||||
{
|
||||
if ($oException->code() != $iExpectedError)
|
||||
{
|
||||
confess "expected error ${iExpectedError} from configLoad but got [" . $oException->code() .
|
||||
"] '" . $oException->message() . "'";
|
||||
}
|
||||
|
||||
my $strError;
|
||||
|
||||
if ($iExpectedError == ERROR_OPTION_REQUIRED)
|
||||
{
|
||||
$strError = "${strCommand} command requires option: ${strErrorParam1}" .
|
||||
(defined($strErrorParam2) ? "\nHINT: ${strErrorParam2}" : '');
|
||||
}
|
||||
elsif ($iExpectedError == ERROR_COMMAND_REQUIRED)
|
||||
{
|
||||
$strError = "command must be specified";
|
||||
}
|
||||
elsif ($iExpectedError == ERROR_OPTION_INVALID)
|
||||
{
|
||||
$strError = "option '${strErrorParam1}' not valid without option '${strErrorParam2}'";
|
||||
|
||||
if (defined($strErrorParam3))
|
||||
{
|
||||
$strError .= @{$strErrorParam3} == 1 ? " = '$$strErrorParam3[0]'" :
|
||||
" in ('" . join("', '",@{ $strErrorParam3}) . "')";
|
||||
}
|
||||
}
|
||||
elsif ($iExpectedError == ERROR_OPTION_COMMAND)
|
||||
{
|
||||
$strError = "option '${strErrorParam1}' not valid for command '${strErrorParam2}'";
|
||||
}
|
||||
elsif ($iExpectedError == ERROR_OPTION_INVALID_VALUE)
|
||||
{
|
||||
$strError = "'${strErrorParam1}' is not valid for '${strErrorParam2}' option" .
|
||||
(defined($strErrorParam3) ? "\nHINT: ${strErrorParam3}." : '');
|
||||
}
|
||||
elsif ($iExpectedError == ERROR_OPTION_MULTIPLE_VALUE)
|
||||
{
|
||||
$strError = "option '${strErrorParam1}' cannot be specified multiple times";
|
||||
}
|
||||
elsif ($iExpectedError == ERROR_OPTION_INVALID_RANGE)
|
||||
{
|
||||
$strError = "'${strErrorParam1}' is not valid for '${strErrorParam2}' option";
|
||||
}
|
||||
elsif ($iExpectedError == ERROR_OPTION_INVALID_PAIR)
|
||||
{
|
||||
$strError = "'${strErrorParam1}' not valid key/value for '${strErrorParam2}' option";
|
||||
}
|
||||
elsif ($iExpectedError == ERROR_OPTION_NEGATE)
|
||||
{
|
||||
$strError = "option '${strErrorParam1}' cannot be both set and negated";
|
||||
}
|
||||
elsif ($iExpectedError == ERROR_FILE_INVALID)
|
||||
{
|
||||
$strError = "'${strErrorParam1}' is not a file";
|
||||
}
|
||||
else
|
||||
{
|
||||
confess
|
||||
"must construct message for error ${iExpectedError}, use this as an example: '" . $oException->message() . "'";
|
||||
}
|
||||
|
||||
if ($oException->message() ne $strError)
|
||||
{
|
||||
confess "expected error message \"${strError}\" from configLoad but got \"" . $oException->message() . "\"";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
confess "configLoad should throw pgBackRest::Common::Exception:\n$oException";
|
||||
}
|
||||
};
|
||||
|
||||
if (!$bErrorFound && defined($iExpectedError))
|
||||
{
|
||||
confess "expected error ${iExpectedError} from configLoad but got success";
|
||||
}
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# configTestExpect - used only by config unit tests
|
||||
####################################################################################################################################
|
||||
sub optionTestExpect
|
||||
{
|
||||
my $self = shift;
|
||||
my $iOptionId = shift;
|
||||
my $strExpectedValue = shift;
|
||||
my $strExpectedKey = shift;
|
||||
|
||||
my $strOption = cfgOptionName($iOptionId);
|
||||
|
||||
if (defined($strExpectedValue))
|
||||
{
|
||||
my $strActualValue = cfgOption($iOptionId);
|
||||
|
||||
if (defined($strExpectedKey))
|
||||
{
|
||||
$strActualValue = $$strActualValue{$strExpectedKey};
|
||||
}
|
||||
|
||||
if (!defined($strActualValue))
|
||||
{
|
||||
confess "expected option ${strOption} to have value ${strExpectedValue} but [undef] found instead";
|
||||
}
|
||||
|
||||
$strActualValue eq $strExpectedValue
|
||||
or confess "expected option ${strOption} to have value ${strExpectedValue} but ${strActualValue} found instead";
|
||||
}
|
||||
elsif (cfgOptionTest(cfgOptionId($strOption)))
|
||||
{
|
||||
confess "expected option ${strOption} to be [undef], but " . cfgOption(cfgOptionId($strOption)) . ' found instead';
|
||||
}
|
||||
sub {configLoad(false, backrestBin(), cfgCommandName($iCommandId), $strConfigJson)},
|
||||
true, 'config load: ' . join(" ", @stryArg));
|
||||
}
|
||||
|
||||
1;
|
||||
|
@@ -35,6 +35,7 @@ testRun()
|
||||
|
||||
TEST_RESULT_VOID(cfgLoad(strLstSize(argList), strLstPtr(argList)), "load local config");
|
||||
|
||||
TEST_RESULT_STR(strPtr(cfgExe()), "pgbackrest", "check exe");
|
||||
TEST_RESULT_INT(logLevelStdOut, logLevelOff, "console logging is off");
|
||||
TEST_RESULT_INT(logLevelStdErr, logLevelWarn, "stderr logging is warn");
|
||||
|
||||
@@ -46,8 +47,9 @@ testRun()
|
||||
strLstAdd(argList, strNew("--repo1-path=/path/to/repo"));
|
||||
strLstAdd(argList, strNew("stanza-create"));
|
||||
|
||||
TEST_RESULT_VOID(cfgLoad(strLstSize(argList), strLstPtr(argList)), "load local config");
|
||||
TEST_RESULT_VOID(cfgLoadParam(strLstSize(argList), strLstPtr(argList), strNew("pgbackrest2")), "load local config");
|
||||
|
||||
TEST_RESULT_STR(strPtr(cfgExe()), "pgbackrest2", "check exe");
|
||||
TEST_RESULT_INT(logLevelStdOut, logLevelWarn, "console logging is off");
|
||||
TEST_RESULT_INT(logLevelStdErr, logLevelOff, "stderr logging is off");
|
||||
|
||||
|
Reference in New Issue
Block a user