mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2024-12-12 10:04:14 +02:00
Add experimental unit test harness written in C.
Having the test harness in C will allow us to remove duplicated Perl code and test on systems where Perl support is not present. Custom harnesses and shims are currently not implemented, which means only the following tests in the common module will run: error, stack-trace, type-convert, assert-on, mem-context, time, encode, type-object, type-string, type-list, type-buffer, type-variant, reg-exp, log. The experimental test harness is being committed with partial functionality so it can be used in Windows development. The remaining features will follow as needed.
This commit is contained in:
parent
b7a1b3ec2c
commit
f863fc9888
@ -169,3 +169,4 @@ configuration.set('FN_NO_RETURN', '__attribute__((__noreturn__))', description:
|
||||
# Include subdirs
|
||||
####################################################################################################################################
|
||||
subdir('src')
|
||||
subdir('test/src')
|
||||
|
@ -101,6 +101,38 @@ yamlFree(Yaml *const this)
|
||||
objFree(this);
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Helper macros for iterating sequences and maps
|
||||
***********************************************************************************************************************************/
|
||||
#define YAML_ITER_BEGIN(yamlParam, eventBegin) \
|
||||
do \
|
||||
{ \
|
||||
Yaml *const YAML_ITER_yaml = yaml; \
|
||||
yamlEventNextCheck(YAML_ITER_yaml, eventBegin); \
|
||||
\
|
||||
do \
|
||||
{
|
||||
|
||||
#define YAML_ITER_END(eventEnd) \
|
||||
} \
|
||||
while (yamlEventPeek(YAML_ITER_yaml).type != eventEnd); \
|
||||
\
|
||||
yamlEventNextCheck(YAML_ITER_yaml, eventEnd); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define YAML_SEQ_BEGIN(yaml) \
|
||||
YAML_ITER_BEGIN(yaml, yamlEventTypeSeqBegin)
|
||||
|
||||
#define YAML_SEQ_END() \
|
||||
YAML_ITER_END(yamlEventTypeSeqEnd);
|
||||
|
||||
#define YAML_MAP_BEGIN(yaml) \
|
||||
YAML_ITER_BEGIN(yaml, yamlEventTypeMapBegin)
|
||||
|
||||
#define YAML_MAP_END() \
|
||||
YAML_ITER_END(yamlEventTypeMapEnd);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Macros for function logging
|
||||
***********************************************************************************************************************************/
|
||||
|
@ -15,30 +15,49 @@ int
|
||||
main(int argListSize, const char *argList[])
|
||||
{
|
||||
// Check parameters
|
||||
CHECK(ParamInvalidError, argListSize <= 2, "only one parameter allowed");
|
||||
CHECK(ParamInvalidError, argListSize <= 3, "only two parameters allowed");
|
||||
|
||||
// Initialize logging
|
||||
logInit(logLevelWarn, logLevelError, logLevelOff, false, 0, 1, false);
|
||||
|
||||
// If the path was specified
|
||||
const String *pathRepo;
|
||||
// Get current working dir
|
||||
char currentWorkDir[1024];
|
||||
THROW_ON_SYS_ERROR(getcwd(currentWorkDir, sizeof(currentWorkDir)) == NULL, FormatError, "unable to get cwd");
|
||||
|
||||
// If the repo path was specified
|
||||
const String *pathRepo = strPath(STR(currentWorkDir));
|
||||
String *const pathOut = strCatZ(strNew(), currentWorkDir);
|
||||
|
||||
if (argListSize >= 2)
|
||||
{
|
||||
pathRepo = strPath(STR(argList[1]));
|
||||
}
|
||||
// Else use current working directory
|
||||
else
|
||||
{
|
||||
char currentWorkDir[1024];
|
||||
THROW_ON_SYS_ERROR(getcwd(currentWorkDir, sizeof(currentWorkDir)) == NULL, FormatError, "unable to get cwd");
|
||||
const String *const pathArg = STR(argList[1]);
|
||||
|
||||
pathRepo = strPath(STR(currentWorkDir));
|
||||
if (strBeginsWith(pathArg, FSLASH_STR))
|
||||
pathRepo = strPath(pathArg);
|
||||
else
|
||||
{
|
||||
pathRepo = strPathAbsolute(pathArg, STR(currentWorkDir));
|
||||
strCatZ(pathOut, "/src");
|
||||
}
|
||||
}
|
||||
|
||||
// If the build path was specified
|
||||
const String *pathBuild = pathRepo;
|
||||
|
||||
if (argListSize >= 3)
|
||||
{
|
||||
const String *const pathArg = STR(argList[2]);
|
||||
|
||||
if (strBeginsWith(pathArg, FSLASH_STR))
|
||||
pathBuild = strPath(pathArg);
|
||||
else
|
||||
pathBuild = strPathAbsolute(pathArg, STR(currentWorkDir));
|
||||
}
|
||||
|
||||
// Render config
|
||||
const Storage *const storageRepo = storagePosixNewP(pathRepo, .write = true);
|
||||
bldCfgRender(storageRepo, bldCfgParse(storageRepo), true);
|
||||
const Storage *const storageRepo = storagePosixNewP(pathRepo);
|
||||
const Storage *const storageBuild = storagePosixNewP(pathBuild, .write = true);
|
||||
bldCfgRender(storageBuild, bldCfgParse(storageRepo), true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ int
|
||||
main(int argListSize, const char *argList[])
|
||||
{
|
||||
// Check parameters
|
||||
CHECK(ParamInvalidError, argListSize <= 2, "only one parameter allowed");
|
||||
CHECK(ParamInvalidError, argListSize <= 3, "only two parameters allowed");
|
||||
|
||||
// Initialize logging
|
||||
logInit(logLevelWarn, logLevelError, logLevelOff, false, 0, 1, false);
|
||||
@ -27,7 +27,7 @@ main(int argListSize, const char *argList[])
|
||||
|
||||
// Get repo path (cwd if it was not passed)
|
||||
const String *pathRepo = strPath(STR(currentWorkDir));
|
||||
String *const pathOut = strCatZ(strNew(), currentWorkDir);
|
||||
String *pathBuild = strCatZ(strNew(), currentWorkDir);
|
||||
|
||||
if (argListSize >= 2)
|
||||
{
|
||||
@ -38,13 +38,24 @@ main(int argListSize, const char *argList[])
|
||||
else
|
||||
{
|
||||
pathRepo = strPathAbsolute(pathArg, STR(currentWorkDir));
|
||||
strCatZ(pathOut, "/src");
|
||||
strCatZ(pathBuild, "/src");
|
||||
}
|
||||
}
|
||||
|
||||
// Render config
|
||||
// If the build path was specified
|
||||
if (argListSize >= 3)
|
||||
{
|
||||
const String *const pathArg = STR(argList[2]);
|
||||
|
||||
if (strBeginsWith(pathArg, FSLASH_STR))
|
||||
pathBuild = strPath(pathArg);
|
||||
else
|
||||
pathBuild = strPathAbsolute(pathArg, STR(currentWorkDir));
|
||||
}
|
||||
|
||||
// Render help
|
||||
const Storage *const storageRepo = storagePosixNewP(pathRepo);
|
||||
const Storage *const storageBuild = storagePosixNewP(pathOut, .write = true);
|
||||
const Storage *const storageBuild = storagePosixNewP(pathBuild, .write = true);
|
||||
const BldCfg bldCfg = bldCfgParse(storageRepo);
|
||||
bldHlpRender(storageBuild, bldCfg, bldHlpParse(storageRepo, bldCfg));
|
||||
|
||||
|
@ -23,7 +23,7 @@ configure_file(output: 'build.auto.h', configuration: configuration)
|
||||
####################################################################################################################################
|
||||
# Common source used by all targets
|
||||
####################################################################################################################################
|
||||
src_common = [
|
||||
src_common = files(
|
||||
'common/debug.c',
|
||||
'common/encode.c',
|
||||
'common/error.c',
|
||||
@ -62,7 +62,7 @@ src_common = [
|
||||
'storage/read.c',
|
||||
'storage/storage.c',
|
||||
'storage/write.c',
|
||||
]
|
||||
)
|
||||
|
||||
####################################################################################################################################
|
||||
# Build config target
|
||||
|
148
test/src/build/config/config.yaml
Normal file
148
test/src/build/config/config.yaml
Normal file
@ -0,0 +1,148 @@
|
||||
####################################################################################################################################
|
||||
# Configuration Definition
|
||||
####################################################################################################################################
|
||||
|
||||
####################################################################################################################################
|
||||
# Commands
|
||||
####################################################################################################################################
|
||||
command:
|
||||
help:
|
||||
log-level-default: DEBUG
|
||||
parameter-allowed: true
|
||||
|
||||
test: {}
|
||||
|
||||
noop:
|
||||
internal: true
|
||||
|
||||
version:
|
||||
log-level-default: DEBUG
|
||||
|
||||
####################################################################################################################################
|
||||
# Option groups that are not used but must be present for modules to compile
|
||||
####################################################################################################################################
|
||||
optionGroup:
|
||||
pg: {}
|
||||
repo: {}
|
||||
|
||||
####################################################################################################################################
|
||||
# Options
|
||||
####################################################################################################################################
|
||||
option:
|
||||
# General options
|
||||
#---------------------------------------------------------------------------------------------------------------------------------
|
||||
buffer-size:
|
||||
type: size
|
||||
internal: true
|
||||
default: 64KiB
|
||||
allow-list:
|
||||
- 16KiB
|
||||
- 32KiB
|
||||
- 64KiB
|
||||
- 128KiB
|
||||
- 256KiB
|
||||
- 512KiB
|
||||
- 1MiB
|
||||
|
||||
module:
|
||||
type: string
|
||||
command:
|
||||
test: {}
|
||||
|
||||
neutral-umask:
|
||||
type: boolean
|
||||
internal: true
|
||||
default: true
|
||||
|
||||
repo-path:
|
||||
type: string
|
||||
default: pgbackrest
|
||||
command:
|
||||
test: {}
|
||||
|
||||
scale:
|
||||
type: integer
|
||||
internal: true
|
||||
default: 1
|
||||
allow-range: [1, 1000000000000]
|
||||
command:
|
||||
test: {}
|
||||
|
||||
test:
|
||||
type: integer
|
||||
internal: true
|
||||
required: false
|
||||
allow-range: [1, 999]
|
||||
command:
|
||||
test: {}
|
||||
|
||||
test-path:
|
||||
type: string
|
||||
default: test
|
||||
command:
|
||||
test: {}
|
||||
|
||||
tz:
|
||||
type: string
|
||||
internal: true
|
||||
required: false
|
||||
command:
|
||||
test: {}
|
||||
|
||||
vm:
|
||||
type: string
|
||||
internal: true
|
||||
default: none
|
||||
command:
|
||||
test: {}
|
||||
|
||||
vm-id:
|
||||
type: integer
|
||||
internal: true
|
||||
default: 0
|
||||
allow-range: [0, 1024]
|
||||
command:
|
||||
test: {}
|
||||
|
||||
# Logging options
|
||||
#---------------------------------------------------------------------------------------------------------------------------------
|
||||
log-level:
|
||||
type: string-id
|
||||
default: info
|
||||
allow-list:
|
||||
- off
|
||||
- error
|
||||
- warn
|
||||
- info
|
||||
- detail
|
||||
- debug
|
||||
- trace
|
||||
|
||||
log-level-test:
|
||||
inherit: log-level
|
||||
default: off
|
||||
|
||||
log-timestamp:
|
||||
type: boolean
|
||||
default: true
|
||||
negate: true
|
||||
command: log-level
|
||||
|
||||
# Options that are not used but must be present for modules to compile. All must have a default or not be required.
|
||||
#---------------------------------------------------------------------------------------------------------------------------------
|
||||
compress-level-network: {type: string, required: false, command: {noop: {}}}
|
||||
config: {
|
||||
type: string, internal: true, default: CFGOPTDEF_CONFIG_PATH "/" PROJECT_CONFIG_FILE, default-literal: true, negate: true}
|
||||
config-path: {type: string, required: false, command: {noop: {}}}
|
||||
config-include-path: {
|
||||
type: string, default: CFGOPTDEF_CONFIG_PATH "/" PROJECT_CONFIG_INCLUDE_PATH, default-literal: true, command: {noop: {}}}
|
||||
job-retry: {type: string, required: false, deprecate: {job-retry-old: {}}, command: {noop: {}}}
|
||||
job-retry-interval: {type: string, required: false, command: {noop: {}}}
|
||||
log-level-file: {type: string, required: false, command: {noop: {}}}
|
||||
log-level-stderr: {type: string, required: false, command: {noop: {}}}
|
||||
pg: {type: string, required: false, command: {noop: {}}}
|
||||
pg-path: {type: string, required: false, command: {noop: {}}}
|
||||
repo-type: {type: string, required: false, command: {noop: {}}}
|
||||
repo: {type: string, required: false, command: {noop: {}}}
|
||||
spool-path: {type: string, required: false, command: {noop: {}}}
|
||||
stanza: {type: string, required: false, command: {noop: {}}}
|
205
test/src/build/help/help.xml
Normal file
205
test/src/build/help/help.xml
Normal file
@ -0,0 +1,205 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE doc SYSTEM "doc.dtd">
|
||||
<doc>
|
||||
<config><config-section-list></config-section-list></config>
|
||||
|
||||
<operation>
|
||||
<operation-general>
|
||||
<option-list>
|
||||
<option id="config"><summary></summary><text><p></p></text></option>
|
||||
<option id="config-path"><summary></summary><text><p></p></text></option>
|
||||
<option id="config-include-path"><summary></summary><text><p></p></text></option>
|
||||
<option id="pg"><summary></summary><text><p></p></text></option>
|
||||
<option id="pg-path"><summary></summary><text><p></p></text></option>
|
||||
<option id="compress-level-network"><summary></summary><text><p></p></text></option>
|
||||
<option id="job-retry"><summary></summary><text><p></p></text></option>
|
||||
<option id="job-retry-interval"><summary></summary><text><p></p></text></option>
|
||||
<option id="log-level-file"><summary></summary><text><p></p></text></option>
|
||||
<option id="log-level-stderr"><summary></summary><text><p></p></text></option>
|
||||
<option id="repo"><summary></summary><text><p></p></text></option>
|
||||
<option id="repo-type"><summary></summary><text><p></p></text></option>
|
||||
<option id="spool-path"><summary></summary><text><p></p></text></option>
|
||||
<option id="stanza"><summary></summary><text><p></p></text></option>
|
||||
|
||||
<option id="buffer-size">
|
||||
<summary>Buffer size for I/O operations.</summary>
|
||||
|
||||
<text>
|
||||
<p>Buffer size used for copy, compress, encrypt, and other operations. The number of buffers used depends on options and each operation may use additional memory, e.g. <id>gz</id> compression may use an additional 256KiB of memory.</p>
|
||||
|
||||
<p>Allowed values are <id>16KiB</id>, <id>32KiB</id>, <id>64KiB</id>, <id>128KiB</id>, <id>256KiB</id>, <id>512KiB</id>, and <id>1MiB</id>.</p>
|
||||
</text>
|
||||
|
||||
<example>1MiB</example>
|
||||
</option>
|
||||
|
||||
<option id="log-level">
|
||||
<summary>Level for harness logging.</summary>
|
||||
|
||||
<text>
|
||||
<p>Log level for the test harness (as opposed to the test being run).</p>
|
||||
|
||||
<p>The following log levels are supported:</p>
|
||||
|
||||
<list>
|
||||
<list-item><id>off</id> - No logging at all (not recommended)</list-item>
|
||||
<list-item><id>error</id> - Log only errors</list-item>
|
||||
<list-item><id>warn</id> - Log warnings and errors</list-item>
|
||||
<list-item><id>info</id> - Log info, warnings, and errors</list-item>
|
||||
<list-item><id>detail</id> - Log detail, info, warnings, and errors</list-item>
|
||||
<list-item><id>debug</id> - Log debug, detail, info, warnings, and errors</list-item>
|
||||
<list-item><id>trace</id> - Log trace (very verbose debugging), debug, info, warnings, and errors</list-item>
|
||||
</list>
|
||||
</text>
|
||||
|
||||
<example>error</example>
|
||||
</option>
|
||||
|
||||
<option id="log-level-test">
|
||||
<summary>Level for test logging.</summary>
|
||||
|
||||
<text>
|
||||
<p>Log level for the test being run (as opposed to the test harness).</p>
|
||||
|
||||
<p>Supported log levels are the same as <br-option>log-level</br-option></p>
|
||||
</text>
|
||||
|
||||
<example>error</example>
|
||||
</option>
|
||||
|
||||
<option id="log-timestamp">
|
||||
<summary>Enable timestamp in logging.</summary>
|
||||
|
||||
<text>
|
||||
<p>Enables the timestamp in console and file logging. This option is disabled in special situations such as generating documentation.</p>
|
||||
</text>
|
||||
|
||||
<example>n</example>
|
||||
</option>
|
||||
|
||||
<option id="module">
|
||||
<summary>Module to test.</summary>
|
||||
|
||||
<text>
|
||||
<p>Unit test module to be tested.</p>
|
||||
</text>
|
||||
|
||||
<example>common/error</example>
|
||||
</option>
|
||||
|
||||
<option id="neutral-umask">
|
||||
<summary>Use a neutral umask.</summary>
|
||||
|
||||
<text>
|
||||
<p>Sets the umask to 0000 so modes are created in a sensible way. The default directory mode is 0750 and default file mode is 0640. The lock and log directories set the directory and file mode to 0770 and 0660 respectively.</p>
|
||||
|
||||
<p>To use the executing user's umask instead specify <setting>neutral-umask=n</setting> in the config file or <setting>--no-neutral-umask</setting> on the command line.</p>
|
||||
</text>
|
||||
|
||||
<example>n</example>
|
||||
</option>
|
||||
|
||||
<option id="repo-path">
|
||||
<summary>Path to code repository.</summary>
|
||||
|
||||
<text>
|
||||
<p>Path to the original code repository or a copy.</p>
|
||||
</text>
|
||||
|
||||
<example>n</example>
|
||||
</option>
|
||||
|
||||
<option id="scale">
|
||||
<summary>Scale performance test.</summary>
|
||||
|
||||
<text>
|
||||
<p>Allows performance tests to be scaled from the default.</p>
|
||||
</text>
|
||||
|
||||
<example>10</example>
|
||||
</option>
|
||||
|
||||
<option id="test">
|
||||
<summary>Module test to run.</summary>
|
||||
|
||||
<text>
|
||||
<p>Run an individual test in a module.</p>
|
||||
</text>
|
||||
|
||||
<example>2</example>
|
||||
</option>
|
||||
|
||||
<option id="test-path">
|
||||
<summary>Path where test will run.</summary>
|
||||
|
||||
<text>
|
||||
<p>This path will be managed entirely by the test harness.</p>
|
||||
</text>
|
||||
|
||||
<example>n</example>
|
||||
</option>
|
||||
|
||||
<option id="tz">
|
||||
<summary>Timezone for testing.</summary>
|
||||
|
||||
<text>
|
||||
<p>Used to ensure that different timezones do not change test results.</p>
|
||||
</text>
|
||||
|
||||
<example>America/New_York</example>
|
||||
</option>
|
||||
|
||||
<option id="vm">
|
||||
<summary>VM to run test on.</summary>
|
||||
|
||||
<text>
|
||||
<p>Name of VM to run the test on.</p>
|
||||
</text>
|
||||
|
||||
<example>rh7</example>
|
||||
</option>
|
||||
|
||||
<option id="vm-id">
|
||||
<summary>VM id to run test on.</summary>
|
||||
|
||||
<text>
|
||||
<p>Allows more than one test to run simultaneously.</p>
|
||||
</text>
|
||||
|
||||
<example>3</example>
|
||||
</option>
|
||||
</option-list>
|
||||
</operation-general>
|
||||
|
||||
<command-list>
|
||||
<command id="help">
|
||||
<summary>Get help.</summary>
|
||||
|
||||
<text>
|
||||
<p>Three levels of help are provided. If no command is specified then general help will be displayed. If a command is specified (e.g. <cmd>pgbackrest help backup</cmd>) then a full description of the command will be displayed along with a list of valid options. If an option is specified in addition to a command (e.g. <cmd>pgbackrest help backup type</cmd>) then a full description of the option as it applies to the command will be displayed.</p>
|
||||
</text>
|
||||
</command>
|
||||
|
||||
<!-- Noop command holds options that must be defined but we don't need -->
|
||||
<command id="noop"><summary></summary><text><p></p></text></command>
|
||||
|
||||
<command id="test">
|
||||
<summary>Run a test.</summary>
|
||||
|
||||
<text>
|
||||
<p>By default tests expect to run with the code repository in a subpath named <path>pgbackrest</path>. Tests will be run in a subpath named <path>test</path>.</p>
|
||||
|
||||
<p>A test can be run by using the module option, e.g. <br-option>--module=common/error</br-option>.</p>
|
||||
</text>
|
||||
</command>
|
||||
|
||||
<command id="version">
|
||||
<summary>Get version.</summary>
|
||||
|
||||
<text>
|
||||
<p>Displays installed <backrest/> version.</p>
|
||||
</text>
|
||||
</command>
|
||||
</command-list>
|
||||
</operation>
|
||||
</doc>
|
16
test/src/command/help/meson.build
Normal file
16
test/src/command/help/meson.build
Normal file
@ -0,0 +1,16 @@
|
||||
####################################################################################################################################
|
||||
# Generate help
|
||||
####################################################################################################################################
|
||||
test_help_auto_c_inc = custom_target(
|
||||
'help.auto.c.inc',
|
||||
output: 'help.auto.c.inc',
|
||||
depend_files: [
|
||||
'../../build/config/config.yaml',
|
||||
'../../build/help/help.xml',
|
||||
],
|
||||
command: [
|
||||
build_help,
|
||||
'@CURRENT_SOURCE_DIR@/../../..',
|
||||
'@BUILD_ROOT@/test/src',
|
||||
],
|
||||
)
|
329
test/src/command/test/build.c
Normal file
329
test/src/command/test/build.c
Normal file
@ -0,0 +1,329 @@
|
||||
/***********************************************************************************************************************************
|
||||
Test Build Handler
|
||||
***********************************************************************************************************************************/
|
||||
#include "build.auto.h"
|
||||
|
||||
#include "build/common/render.h"
|
||||
#include "command/test/build.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/log.h"
|
||||
#include "common/user.h"
|
||||
#include "storage/posix/storage.h"
|
||||
#include "version.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Object type
|
||||
***********************************************************************************************************************************/
|
||||
struct TestBuild
|
||||
{
|
||||
TestBuildPub pub; // Publicly accessible variables
|
||||
};
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Constants
|
||||
***********************************************************************************************************************************/
|
||||
#define MESON_COMMENT_BLOCK \
|
||||
"############################################################################################################################" \
|
||||
"########"
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
TestBuild *
|
||||
testBldNew(
|
||||
const String *const pathRepo, const String *const pathTest, const String *const vm, const unsigned int vmId,
|
||||
const String *const moduleName, const unsigned int test, const uint64_t scale, const LogLevel logLevel, const bool logTime,
|
||||
const String *const timeZone)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(STRING, pathRepo);
|
||||
FUNCTION_LOG_PARAM(STRING, pathTest);
|
||||
FUNCTION_LOG_PARAM(STRING, vm);
|
||||
FUNCTION_LOG_PARAM(UINT, vmId);
|
||||
FUNCTION_LOG_PARAM(STRING, moduleName);
|
||||
FUNCTION_LOG_PARAM(UINT, test);
|
||||
FUNCTION_LOG_PARAM(UINT64, scale);
|
||||
FUNCTION_LOG_PARAM(ENUM, logLevel);
|
||||
FUNCTION_LOG_PARAM(BOOL, logTime);
|
||||
FUNCTION_LOG_PARAM(STRING, timeZone);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
ASSERT(pathRepo != NULL);
|
||||
ASSERT(pathTest != NULL);
|
||||
ASSERT(vm != NULL);
|
||||
ASSERT(moduleName != NULL);
|
||||
ASSERT(scale != 0);
|
||||
|
||||
TestBuild *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(TestBuild, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
// Create object
|
||||
this = OBJ_NEW_ALLOC();
|
||||
|
||||
*this = (TestBuild)
|
||||
{
|
||||
.pub =
|
||||
{
|
||||
.pathRepo = strDup(pathRepo),
|
||||
.pathTest = strDup(pathTest),
|
||||
.vm = strDup(vm),
|
||||
.vmId = vmId,
|
||||
.moduleName = strDup(moduleName),
|
||||
.test = test,
|
||||
.scale = scale,
|
||||
.logLevel = logLevel,
|
||||
.logTime = logTime,
|
||||
.timeZone = strDup(timeZone),
|
||||
},
|
||||
};
|
||||
|
||||
this->pub.storageRepo = storagePosixNewP(testBldPathRepo(this));
|
||||
this->pub.storageTest = storagePosixNewP(testBldPathTest(this));
|
||||
|
||||
// Find the module to test
|
||||
this->pub.module = lstFind(testDefParse(testBldStorageRepo(this)).moduleList, &this->pub.moduleName);
|
||||
CHECK(AssertError, this->pub.module != NULL, "unable to find module");
|
||||
}
|
||||
OBJ_NEW_END();
|
||||
|
||||
FUNCTION_LOG_RETURN(TEST_BUILD, this);
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Write files into the test path and keep a list of files written
|
||||
***********************************************************************************************************************************/
|
||||
static void
|
||||
testBldWrite(const Storage *const storage, StringList *const fileList, const char *const file, const Buffer *const content)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(STORAGE, storage);
|
||||
FUNCTION_LOG_PARAM(STRING_LIST, fileList);
|
||||
FUNCTION_LOG_PARAM(STRINGZ, file);
|
||||
FUNCTION_LOG_PARAM(BUFFER, content);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
// Only write if the content has changed
|
||||
const Buffer *const current = storageGetP(storageNewReadP(storage, STR(file), .ignoreMissing = true));
|
||||
|
||||
if (current == NULL || !bufEq(content, current))
|
||||
storagePutP(storageNewWriteP(storage, STR(file)), content);
|
||||
|
||||
strLstAddZ(fileList, file);
|
||||
}
|
||||
MEM_CONTEXT_TEMP_END();
|
||||
|
||||
FUNCTION_LOG_RETURN_VOID();
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
void
|
||||
testBldUnit(TestBuild *const this)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(TEST_BUILD, this);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
ASSERT(this != NULL);
|
||||
|
||||
userInit();
|
||||
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
const Storage *const storageUnit = storagePosixNewP(
|
||||
strNewFmt("%s/unit-%u", strZ(testBldPathTest(this)), testBldVmId(this)), .write = true);
|
||||
const Storage *const storageTestId = storagePosixNewP(
|
||||
strNewFmt("%s/test-%u", strZ(testBldPathTest(this)), testBldVmId(this)), .write = true);
|
||||
StringList *const storageUnitList = strLstNew();
|
||||
|
||||
// Copy meson_options.txt
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
testBldWrite(
|
||||
storageUnit, storageUnitList, "meson_options.txt",
|
||||
storageGetP(storageNewReadP(testBldStorageRepo(this), STRDEF("meson_options.txt"))));
|
||||
|
||||
// Build meson.build
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
String *const mesonBuild = strCatBuf(
|
||||
strNew(), storageGetP(storageNewReadP(testBldStorageRepo(this), STRDEF("meson.build"))));
|
||||
|
||||
// Comment out subdirs that are not used for testing
|
||||
strReplace(mesonBuild, STRDEF("subdir('"), STRDEF("# subdir('"));
|
||||
|
||||
// Write build.auto.in
|
||||
strCatZ(
|
||||
mesonBuild,
|
||||
"\n"
|
||||
MESON_COMMENT_BLOCK "\n"
|
||||
"# Write configuration\n"
|
||||
MESON_COMMENT_BLOCK "\n"
|
||||
"configure_file(output: 'build.auto.h', configuration: configuration)\n"
|
||||
"\n"
|
||||
"add_global_arguments('-DERROR_MESSAGE_BUFFER_SIZE=131072', language : 'c')\n");
|
||||
|
||||
// Configure features
|
||||
if (testBldModule(this)->feature != NULL)
|
||||
strCatFmt(mesonBuild, "add_global_arguments('-DHRN_INTEST_%s', language : 'c')\n", strZ(testBldModule(this)->feature));
|
||||
|
||||
if (testBldModule(this)->featureList != NULL)
|
||||
{
|
||||
for (unsigned int featureIdx = 0; featureIdx < strLstSize(testBldModule(this)->featureList); featureIdx++)
|
||||
{
|
||||
strCatFmt(
|
||||
mesonBuild, "add_global_arguments('-DHRN_FEATURE_%s', language : 'c')\n",
|
||||
strZ(strLstGet(testBldModule(this)->featureList, featureIdx)));
|
||||
}
|
||||
}
|
||||
|
||||
// Add compiler flags
|
||||
if (testBldModule(this)->flag != NULL)
|
||||
strCatFmt(mesonBuild, "add_global_arguments('%s', language : 'c')\n", strZ(testBldModule(this)->flag));
|
||||
|
||||
// Build unit test
|
||||
strCatZ(
|
||||
mesonBuild,
|
||||
"\n"
|
||||
MESON_COMMENT_BLOCK "\n"
|
||||
"# Unit test\n"
|
||||
MESON_COMMENT_BLOCK "\n"
|
||||
"executable(\n"
|
||||
" 'test-unit',\n");
|
||||
|
||||
for (unsigned int dependIdx = 0; dependIdx < strLstSize(testBldModule(this)->dependList); dependIdx++)
|
||||
{
|
||||
strCatFmt(
|
||||
mesonBuild, " '%s/src/%s.c',\n", strZ(testBldPathRepo(this)),
|
||||
strZ(strLstGet(testBldModule(this)->dependList, dependIdx)));
|
||||
}
|
||||
|
||||
strCatFmt(
|
||||
mesonBuild,
|
||||
" '%s/test/src/common/harnessTest.c',\n"
|
||||
" 'test.c',\n"
|
||||
" include_directories:\n"
|
||||
" include_directories(\n"
|
||||
" '.',\n"
|
||||
" '%s/test/src',\n"
|
||||
" '%s/src',\n"
|
||||
" ),\n"
|
||||
")\n",
|
||||
strZ(testBldPathRepo(this)), strZ(testBldPathRepo(this)), strZ(testBldPathRepo(this)));
|
||||
|
||||
testBldWrite(storageUnit, storageUnitList, "meson.build", BUFSTR(mesonBuild));
|
||||
|
||||
// Build test.c
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
String *const testC = strCatBuf(
|
||||
strNew(), storageGetP(storageNewReadP(testBldStorageRepo(this), STRDEF("test/src/test.c"))));
|
||||
|
||||
// Files to test/include
|
||||
StringList *const testIncludeFileList = strLstNew();
|
||||
|
||||
if (testBldModule(this)->coverageList != NULL)
|
||||
{
|
||||
for (unsigned int coverageIdx = 0; coverageIdx < lstSize(testBldModule(this)->coverageList); coverageIdx++)
|
||||
{
|
||||
const TestDefCoverage *const coverage = lstGet(testBldModule(this)->coverageList, coverageIdx);
|
||||
|
||||
if (coverage->coverable)
|
||||
strLstAdd(testIncludeFileList, coverage->name);
|
||||
}
|
||||
}
|
||||
|
||||
if (testBldModule(this)->includeList != NULL)
|
||||
{
|
||||
for (unsigned int includeIdx = 0; includeIdx < strLstSize(testBldModule(this)->includeList); includeIdx++)
|
||||
strLstAdd(testIncludeFileList, strLstGet(testBldModule(this)->includeList, includeIdx));
|
||||
}
|
||||
|
||||
String *const testIncludeFile = strNew();
|
||||
|
||||
for (unsigned int testIncludeFileIdx = 0; testIncludeFileIdx < strLstSize(testIncludeFileList); testIncludeFileIdx++)
|
||||
{
|
||||
if (testIncludeFileIdx != 0)
|
||||
strCatChr(testIncludeFile, '\n');
|
||||
|
||||
strCatFmt(
|
||||
testIncludeFile, "#include \"%s/src/%s.c\"", strZ(testBldPathRepo(this)),
|
||||
strZ(strLstGet(testIncludeFileList, testIncludeFileIdx)));
|
||||
}
|
||||
|
||||
strReplace(testC, STRDEF("{[C_INCLUDE]}"), testIncludeFile);
|
||||
|
||||
// Test path
|
||||
strReplace(testC, STRDEF("{[C_TEST_PATH]}"), storagePathP(storageTestId, NULL));
|
||||
|
||||
// Harness data path
|
||||
const String *const pathHarnessData = strNewFmt("%s/data-%u", strZ(testBldPathTest(this)), testBldVmId(this));
|
||||
strReplace(testC, STRDEF("{[C_HRN_PATH]}"), pathHarnessData);
|
||||
|
||||
// Harness repo path
|
||||
strReplace(testC, STRDEF("{[C_HRN_PATH_REPO]}"), testBldPathRepo(this));
|
||||
|
||||
// Path to the project exe when it exists
|
||||
const String *const pathProjectExe = storagePathP(
|
||||
testBldStorageTest(this),
|
||||
strNewFmt("bin/%s%s/" PROJECT_BIN, strZ(testBldVm(this)), strEqZ(testBldVm(this), "none") ? "/src" : ""));
|
||||
strReplace(testC, STRDEF("{[C_TEST_PROJECT_EXE]}"), pathProjectExe);
|
||||
|
||||
// Path to source -- used to construct __FILENAME__ tests
|
||||
strReplace(testC, STRDEF("{[C_TEST_PGB_PATH]}"), testBldPathRepo(this));
|
||||
|
||||
// Test log level
|
||||
strReplace(
|
||||
testC, STRDEF("{[C_LOG_LEVEL_TEST]}"),
|
||||
bldEnum("logLevel", strLower(strNewZ(logLevelStr(testBldLogLevel(this))))));
|
||||
|
||||
// Log time/timestamp
|
||||
strReplace(testC, STRDEF("{[C_TEST_TIMING]}"), STR(cvtBoolToConstZ(testBldLogTime(this))));
|
||||
|
||||
// Test timezone
|
||||
strReplace(
|
||||
testC, STRDEF("{[C_TEST_TZ]}"),
|
||||
testBldTimeZone(this) == NULL ?
|
||||
STRDEF("// No timezone specified") : strNewFmt("setenv(\"TZ\", \"%s\", true);", strZ(testBldTimeZone(this))));
|
||||
|
||||
// Scale performance test
|
||||
strReplace(testC, STRDEF("{[C_TEST_SCALE]}"), strNewFmt("%" PRIu64, testBldScale(this)));
|
||||
|
||||
// Does this test run in a container?
|
||||
strReplace(testC, STRDEF("{[C_TEST_CONTAINER]}"), STR(cvtBoolToConstZ(testBldModule(this)->containerRequired)));
|
||||
|
||||
// User/group info
|
||||
strReplace(testC, STRDEF("{[C_TEST_GROUP]}"), groupName());
|
||||
strReplace(testC, STRDEF("{[C_TEST_GROUP_ID]}"), strNewFmt("%u", groupId()));
|
||||
strReplace(testC, STRDEF("{[C_TEST_USER]}"), userName());
|
||||
strReplace(testC, STRDEF("{[C_TEST_USER_ID]}"), strNewFmt("%u", userId()));
|
||||
|
||||
// Test id
|
||||
strReplace(testC, STRDEF("{[C_TEST_IDX]}"), strNewFmt("%u", testBldVmId(this)));
|
||||
|
||||
// Include test file
|
||||
strReplace(
|
||||
testC, STRDEF("{[C_TEST_INCLUDE]}"),
|
||||
strNewFmt(
|
||||
"#include \"%s/test/src/module/%sTest.c\"", strZ(testBldPathRepo(this)),
|
||||
strZ(bldEnum(NULL, testBldModuleName(this)))));
|
||||
|
||||
// Test list
|
||||
String *const testList = strNew();
|
||||
|
||||
for (unsigned int testIdx = 0; testIdx < testBldModule(this)->total; testIdx++)
|
||||
{
|
||||
if (testIdx != 0)
|
||||
strCatZ(testList, "\n ");
|
||||
|
||||
strCatFmt(
|
||||
testList, "hrnAdd(%3u, %8s);", testIdx + 1,
|
||||
cvtBoolToConstZ(testBldTest(this) == 0 || testBldTest(this) == testIdx + 1));
|
||||
}
|
||||
|
||||
strReplace(testC, STRDEF("{[C_TEST_LIST]}"), testList);
|
||||
|
||||
// Write file
|
||||
testBldWrite(storageUnit, storageUnitList, "test.c", BUFSTR(testC));
|
||||
}
|
||||
MEM_CONTEXT_TEMP_END();
|
||||
|
||||
FUNCTION_LOG_RETURN_VOID();
|
||||
}
|
160
test/src/command/test/build.h
Normal file
160
test/src/command/test/build.h
Normal file
@ -0,0 +1,160 @@
|
||||
/***********************************************************************************************************************************
|
||||
Test Build Handler
|
||||
***********************************************************************************************************************************/
|
||||
#ifndef TEST_COMMAND_TEST_BUILD_H
|
||||
#define TEST_COMMAND_TEST_BUILD_H
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Object type
|
||||
***********************************************************************************************************************************/
|
||||
typedef struct TestBuild TestBuild;
|
||||
|
||||
#include "command/test/define.h"
|
||||
#include "common/logLevel.h"
|
||||
#include "common/type/object.h"
|
||||
#include "common/type/string.h"
|
||||
#include "storage/storage.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Constructors
|
||||
***********************************************************************************************************************************/
|
||||
TestBuild *testBldNew(
|
||||
const String *pathRepo, const String *pathTest, const String *const vm, unsigned int vmId, const String *moduleName,
|
||||
unsigned int test, uint64_t scale, LogLevel logLevel, bool logTime, const String *timeZone);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Getters/Setters
|
||||
***********************************************************************************************************************************/
|
||||
typedef struct TestBuildPub
|
||||
{
|
||||
const String *pathRepo; // Code repository path
|
||||
const String *pathTest; // Test path
|
||||
const Storage *storageRepo; // Repository storage
|
||||
const Storage *storageTest; // Test storage
|
||||
const String *vm; // Vm to run the test on
|
||||
unsigned int vmId; // Vm id (0-based) to run the test on
|
||||
const String *moduleName; // Module to run
|
||||
const TestDefModule *module; // Module definition
|
||||
unsigned int test; // Specific test to run (0 if all)
|
||||
LogLevel logLevel; // Test log level
|
||||
bool logTime; // Log times/timestamps
|
||||
uint64_t scale; // Scale performance test
|
||||
const String *timeZone; // Test in timezone
|
||||
TestDef tstDef; // Test definitions
|
||||
} TestBuildPub;
|
||||
|
||||
// Repository path
|
||||
__attribute__((always_inline)) static inline const String *
|
||||
testBldPathRepo(const TestBuild *const this)
|
||||
{
|
||||
return THIS_PUB(TestBuild)->pathRepo;
|
||||
}
|
||||
|
||||
// Test path
|
||||
__attribute__((always_inline)) static inline const String *
|
||||
testBldPathTest(const TestBuild *const this)
|
||||
{
|
||||
return THIS_PUB(TestBuild)->pathTest;
|
||||
}
|
||||
|
||||
// Repository storage
|
||||
__attribute__((always_inline)) static inline const Storage *
|
||||
testBldStorageRepo(const TestBuild *const this)
|
||||
{
|
||||
return THIS_PUB(TestBuild)->storageRepo;
|
||||
}
|
||||
|
||||
// Test storage
|
||||
__attribute__((always_inline)) static inline const Storage *
|
||||
testBldStorageTest(const TestBuild *const this)
|
||||
{
|
||||
return THIS_PUB(TestBuild)->storageTest;
|
||||
}
|
||||
|
||||
// Vm
|
||||
__attribute__((always_inline)) static inline const String *
|
||||
testBldVm(const TestBuild *const this)
|
||||
{
|
||||
return THIS_PUB(TestBuild)->vm;
|
||||
}
|
||||
|
||||
// Vm id
|
||||
__attribute__((always_inline)) static inline unsigned int
|
||||
testBldVmId(const TestBuild *const this)
|
||||
{
|
||||
return THIS_PUB(TestBuild)->vmId;
|
||||
}
|
||||
|
||||
|
||||
// Test Definition
|
||||
__attribute__((always_inline)) static inline const TestDefModule *
|
||||
testBldModule(const TestBuild *const this)
|
||||
{
|
||||
return THIS_PUB(TestBuild)->module;
|
||||
}
|
||||
|
||||
// Module to run
|
||||
__attribute__((always_inline)) static inline const String *
|
||||
testBldModuleName(const TestBuild *const this)
|
||||
{
|
||||
return THIS_PUB(TestBuild)->moduleName;
|
||||
}
|
||||
|
||||
// Specific test to run
|
||||
__attribute__((always_inline)) static inline unsigned int
|
||||
testBldTest(const TestBuild *const this)
|
||||
{
|
||||
return THIS_PUB(TestBuild)->test;
|
||||
}
|
||||
|
||||
// Log level
|
||||
__attribute__((always_inline)) static inline LogLevel
|
||||
testBldLogLevel(const TestBuild *const this)
|
||||
{
|
||||
return THIS_PUB(TestBuild)->logLevel;
|
||||
}
|
||||
|
||||
// Log time/timestamps
|
||||
__attribute__((always_inline)) static inline bool
|
||||
testBldLogTime(const TestBuild *const this)
|
||||
{
|
||||
return THIS_PUB(TestBuild)->logTime;
|
||||
}
|
||||
|
||||
// Test in timezone
|
||||
__attribute__((always_inline)) static inline const String *
|
||||
testBldTimeZone(const TestBuild *const this)
|
||||
{
|
||||
return THIS_PUB(TestBuild)->timeZone;
|
||||
}
|
||||
|
||||
// Scale
|
||||
__attribute__((always_inline)) static inline uint64_t
|
||||
testBldScale(const TestBuild *const this)
|
||||
{
|
||||
return THIS_PUB(TestBuild)->scale;
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Functions
|
||||
***********************************************************************************************************************************/
|
||||
void testBldUnit(TestBuild *this);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Destructor
|
||||
***********************************************************************************************************************************/
|
||||
__attribute__((always_inline)) static inline void
|
||||
testBuildFree(TestBuild *const this)
|
||||
{
|
||||
objFree(this);
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Macros for function logging
|
||||
***********************************************************************************************************************************/
|
||||
#define FUNCTION_LOG_TEST_BUILD_TYPE \
|
||||
TestBuild *
|
||||
#define FUNCTION_LOG_TEST_BUILD_FORMAT(value, buffer, bufferSize) \
|
||||
objToLog(value, "TestBuild", buffer, bufferSize)
|
||||
|
||||
#endif
|
256
test/src/command/test/define.c
Normal file
256
test/src/command/test/define.c
Normal file
@ -0,0 +1,256 @@
|
||||
/***********************************************************************************************************************************
|
||||
Parse Define Yaml
|
||||
***********************************************************************************************************************************/
|
||||
#include "build.auto.h"
|
||||
|
||||
#include <yaml.h>
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/log.h"
|
||||
#include "storage/posix/storage.h"
|
||||
|
||||
#include "build/common/yaml.h"
|
||||
#include "command/test/define.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Parse module list
|
||||
***********************************************************************************************************************************/
|
||||
static void
|
||||
testDefParseModuleList(Yaml *const yaml, List *const moduleList)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(YAML, yaml);
|
||||
FUNCTION_LOG_PARAM(LIST, moduleList);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
// Global lists to be copied to next test
|
||||
StringList *const globalDependList = strLstNew();
|
||||
StringList *const globalFeatureList = strLstNew();
|
||||
|
||||
// Module list
|
||||
YAML_SEQ_BEGIN(yaml)
|
||||
{
|
||||
// Module
|
||||
YAML_MAP_BEGIN(yaml)
|
||||
{
|
||||
// Module name
|
||||
yamlScalarNextCheckZ(yaml, "name");
|
||||
const String *const moduleName = yamlScalarNext(yaml).value;
|
||||
|
||||
// Submodule List
|
||||
yamlScalarNextCheckZ(yaml, "test");
|
||||
|
||||
YAML_SEQ_BEGIN(yaml)
|
||||
{
|
||||
TestDefModule testDefModule = {0};
|
||||
StringList *includeList = NULL;
|
||||
List *coverageList = NULL;
|
||||
|
||||
// Submodule
|
||||
YAML_MAP_BEGIN(yaml)
|
||||
{
|
||||
YamlEvent subModuleDef = yamlEventNext(yaml);
|
||||
|
||||
if (strEqZ(subModuleDef.value, "binReq"))
|
||||
{
|
||||
testDefModule.binRequired = yamlBoolParse(yamlScalarNext(yaml));
|
||||
}
|
||||
else if (strEqZ(subModuleDef.value, "containerReq"))
|
||||
{
|
||||
testDefModule.containerRequired = yamlBoolParse(yamlScalarNext(yaml));
|
||||
}
|
||||
else if (strEqZ(subModuleDef.value, "coverage"))
|
||||
{
|
||||
coverageList = lstNewP(sizeof(TestDefCoverage), .comparator = lstComparatorStr);
|
||||
|
||||
YAML_SEQ_BEGIN(yaml)
|
||||
{
|
||||
TestDefCoverage testDefCoverage = {0};
|
||||
|
||||
if (yamlEventPeek(yaml).type == yamlEventTypeScalar)
|
||||
{
|
||||
testDefCoverage.name = yamlScalarNext(yaml).value;
|
||||
testDefCoverage.coverable = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
YAML_MAP_BEGIN(yaml)
|
||||
{
|
||||
testDefCoverage.name = yamlScalarNext(yaml).value;
|
||||
yamlScalarNextCheckZ(yaml, "noCode");
|
||||
}
|
||||
YAML_MAP_END();
|
||||
}
|
||||
|
||||
MEM_CONTEXT_OBJ_BEGIN(coverageList)
|
||||
{
|
||||
testDefCoverage.name = strDup(testDefCoverage.name);
|
||||
lstAdd(coverageList, &testDefCoverage);
|
||||
}
|
||||
MEM_CONTEXT_OBJ_END();
|
||||
|
||||
// Also add to the global depend list
|
||||
if (testDefCoverage.coverable)
|
||||
strLstAddIfMissing(globalDependList, testDefCoverage.name);
|
||||
}
|
||||
YAML_SEQ_END();
|
||||
}
|
||||
else if (strEqZ(subModuleDef.value, "define"))
|
||||
{
|
||||
testDefModule.flag = yamlScalarNext(yaml).value;
|
||||
}
|
||||
else if (strEqZ(subModuleDef.value, "depend"))
|
||||
{
|
||||
YAML_SEQ_BEGIN(yaml)
|
||||
{
|
||||
strLstAddIfMissing(globalDependList, yamlEventNext(yaml).value);
|
||||
}
|
||||
YAML_SEQ_END();
|
||||
}
|
||||
else if (strEqZ(subModuleDef.value, "feature"))
|
||||
{
|
||||
testDefModule.feature = yamlScalarNext(yaml).value;
|
||||
}
|
||||
else if (strEqZ(subModuleDef.value, "harness"))
|
||||
{
|
||||
if (yamlEventPeek(yaml).type == yamlEventTypeScalar)
|
||||
{
|
||||
yamlScalarNext(yaml);
|
||||
}
|
||||
else
|
||||
{
|
||||
YAML_MAP_BEGIN(yaml)
|
||||
{
|
||||
yamlScalarNextCheckZ(yaml, "name");
|
||||
yamlScalarNext(yaml);
|
||||
|
||||
yamlScalarNextCheckZ(yaml, "shim");
|
||||
|
||||
YAML_MAP_BEGIN(yaml)
|
||||
{
|
||||
yamlScalarNext(yaml);
|
||||
|
||||
if (yamlEventPeek(yaml).type == yamlEventTypeScalar)
|
||||
{
|
||||
yamlScalarNext(yaml);
|
||||
}
|
||||
else
|
||||
{
|
||||
YAML_MAP_BEGIN(yaml)
|
||||
{
|
||||
yamlScalarNextCheckZ(yaml, "function");
|
||||
|
||||
YAML_SEQ_BEGIN(yaml)
|
||||
{
|
||||
yamlScalarNext(yaml);
|
||||
}
|
||||
YAML_SEQ_END();
|
||||
}
|
||||
YAML_MAP_END();
|
||||
}
|
||||
}
|
||||
YAML_MAP_END();
|
||||
}
|
||||
YAML_MAP_END();
|
||||
}
|
||||
}
|
||||
else if (strEqZ(subModuleDef.value, "include"))
|
||||
{
|
||||
includeList = strLstNew();
|
||||
|
||||
YAML_SEQ_BEGIN(yaml)
|
||||
{
|
||||
strLstAdd(includeList, yamlEventNext(yaml).value);
|
||||
}
|
||||
YAML_SEQ_END();
|
||||
}
|
||||
else if (strEqZ(subModuleDef.value, "name"))
|
||||
{
|
||||
testDefModule.name = strNewFmt("%s/%s", strZ(moduleName), strZ(yamlScalarNext(yaml).value));
|
||||
}
|
||||
else if (strEqZ(subModuleDef.value, "total"))
|
||||
{
|
||||
testDefModule.total = cvtZToUInt(strZ(yamlScalarNext(yaml).value));
|
||||
}
|
||||
else
|
||||
{
|
||||
THROW_FMT(
|
||||
FormatError, "unexpected scalar '%s' at line %zu, column %zu", strZ(subModuleDef.value),
|
||||
subModuleDef.line, subModuleDef.column);
|
||||
}
|
||||
}
|
||||
YAML_MAP_END();
|
||||
|
||||
// Depend list is the global list minus the coverage and include lists
|
||||
StringList *const dependList = strLstNew();
|
||||
|
||||
for (unsigned int dependIdx = 0; dependIdx < strLstSize(globalDependList); dependIdx++)
|
||||
{
|
||||
const String *const depend = strLstGet(globalDependList, dependIdx);
|
||||
|
||||
if ((coverageList == NULL || !lstExists(coverageList, &depend)) &&
|
||||
(includeList == NULL || !strLstExists(includeList, depend)))
|
||||
{
|
||||
strLstAdd(dependList, depend);
|
||||
}
|
||||
}
|
||||
|
||||
// Add test module
|
||||
MEM_CONTEXT_OBJ_BEGIN(moduleList)
|
||||
{
|
||||
testDefModule.name = strDup(testDefModule.name);
|
||||
testDefModule.coverageList = lstMove(coverageList, memContextCurrent());
|
||||
testDefModule.flag = strDup(testDefModule.flag);
|
||||
testDefModule.includeList = strLstMove(includeList, memContextCurrent());
|
||||
|
||||
if (strLstSize(dependList) > 0)
|
||||
testDefModule.dependList = strLstMove(dependList, memContextCurrent());
|
||||
|
||||
if (testDefModule.feature != NULL)
|
||||
testDefModule.feature = strUpper(strDup(testDefModule.feature));
|
||||
|
||||
if (strLstSize(globalFeatureList) > 0)
|
||||
testDefModule.featureList = strLstDup(globalFeatureList);
|
||||
}
|
||||
MEM_CONTEXT_OBJ_END();
|
||||
|
||||
lstAdd(moduleList, &testDefModule);
|
||||
|
||||
// Add feature to global list
|
||||
if (testDefModule.feature != NULL)
|
||||
strLstAdd(globalFeatureList, testDefModule.feature);
|
||||
}
|
||||
YAML_SEQ_END();
|
||||
}
|
||||
YAML_MAP_END();
|
||||
}
|
||||
YAML_SEQ_END();
|
||||
|
||||
FUNCTION_LOG_RETURN_VOID();
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
TestDef
|
||||
testDefParse(const Storage *const storageRepo)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(STORAGE, storageRepo);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
// Module list
|
||||
List *const moduleList = lstNewP(sizeof(TestDefModule), .comparator = lstComparatorStr);
|
||||
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
// Initialize yaml
|
||||
Yaml *const yaml = yamlNew(storageGetP(storageNewReadP(storageRepo, STRDEF("test/define.yaml"))));
|
||||
yamlEventNextCheck(yaml, yamlEventTypeMapBegin);
|
||||
|
||||
// Parse unit tests
|
||||
yamlScalarNextCheckZ(yaml, "unit");
|
||||
testDefParseModuleList(yaml, moduleList);
|
||||
}
|
||||
MEM_CONTEXT_TEMP_END();
|
||||
|
||||
FUNCTION_LOG_RETURN_STRUCT((TestDef){.moduleList = moduleList});
|
||||
}
|
42
test/src/command/test/define.h
Normal file
42
test/src/command/test/define.h
Normal file
@ -0,0 +1,42 @@
|
||||
/***********************************************************************************************************************************
|
||||
Parse Define Yaml
|
||||
***********************************************************************************************************************************/
|
||||
#ifndef TEST_COMMAND_TEST_DEFINE_H
|
||||
#define TEST_COMMAND_TEST_DEFINE_H
|
||||
|
||||
#include "common/type/list.h"
|
||||
#include "common/type/string.h"
|
||||
#include "storage/storage.h"
|
||||
|
||||
typedef struct TestDefCoverage
|
||||
{
|
||||
const String *name; // Code module name
|
||||
bool coverable; // Does this code module include coverable code?
|
||||
} TestDefCoverage;
|
||||
|
||||
typedef struct TestDefModule
|
||||
{
|
||||
const String *name; // Test module name
|
||||
unsigned int total; // Total sub-tests
|
||||
bool binRequired; // Is a binary required to run this test?
|
||||
bool containerRequired; // Is a container required to run this test?
|
||||
const String *flag; // Compilation flags
|
||||
const String *feature; // Does this module introduce a feature?
|
||||
const StringList *featureList; // Features to include in this module
|
||||
const List *coverageList; // Code modules covered by this test module
|
||||
const StringList *dependList; // Code modules that this test module depends on
|
||||
const StringList *includeList; // Additional code modules to include in the test module
|
||||
} TestDefModule;
|
||||
|
||||
typedef struct TestDef
|
||||
{
|
||||
const List *moduleList; // Module list
|
||||
} TestDef;
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Functions
|
||||
***********************************************************************************************************************************/
|
||||
// Parse define.yaml
|
||||
TestDef testDefParse(const Storage *const storageRepo);
|
||||
|
||||
#endif
|
74
test/src/command/test/test.c
Normal file
74
test/src/command/test/test.c
Normal file
@ -0,0 +1,74 @@
|
||||
/***********************************************************************************************************************************
|
||||
Test Command
|
||||
***********************************************************************************************************************************/
|
||||
#include "build.auto.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "command/test/build.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/log.h"
|
||||
#include "config/config.h"
|
||||
#include "storage/posix/storage.h"
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
void
|
||||
cmdTest(
|
||||
const String *const pathRepo, const String *const pathTest, const String *const vm, const unsigned int vmId,
|
||||
const String *const moduleName, const unsigned int test, const uint64_t scale, const LogLevel logLevel, const bool logTime,
|
||||
const String *const timeZone)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(STRING, pathRepo);
|
||||
FUNCTION_LOG_PARAM(STRING, pathTest);
|
||||
FUNCTION_LOG_PARAM(STRING, vm);
|
||||
FUNCTION_LOG_PARAM(UINT, vmId);
|
||||
FUNCTION_LOG_PARAM(STRING, moduleName);
|
||||
FUNCTION_LOG_PARAM(UINT, test);
|
||||
FUNCTION_LOG_PARAM(UINT64, scale);
|
||||
FUNCTION_LOG_PARAM(ENUM, logLevel);
|
||||
FUNCTION_LOG_PARAM(BOOL, logTime);
|
||||
FUNCTION_LOG_PARAM(STRING, timeZone);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
// Build unit test
|
||||
TestBuild *const testBld = testBldNew(pathRepo, pathTest, vm, vmId, moduleName, test, scale, logLevel, logTime, timeZone);
|
||||
testBldUnit(testBld);
|
||||
|
||||
// Remove and recreate the test path
|
||||
const Storage *const storageTestId = storagePosixNewP(
|
||||
strNewFmt("%s/test-%u", strZ(testBldPathTest(testBld)), testBldVmId(testBld)), .write = true);
|
||||
storagePathRemoveP(storageTestId, NULL, .recurse = true);
|
||||
storagePathCreateP(storageTestId, NULL);
|
||||
|
||||
// Meson setup
|
||||
const String *const pathUnit = strNewFmt("%s/unit-%u", strZ(testBldPathTest(testBld)), testBldVmId(testBld));
|
||||
const String *const pathUnitBuild = strNewFmt("%s/build", strZ(pathUnit));
|
||||
|
||||
if (!storageExistsP(testBldStorageTest(testBld), strNewFmt("%s/build.ninja", strZ(pathUnitBuild))))
|
||||
{
|
||||
const char *const mesonSetup = zNewFmt(
|
||||
"meson setup -Dwerror=true -Dfatal-errors=true -Dbuildtype=debug %s %s", strZ(pathUnitBuild), strZ(pathUnit));
|
||||
|
||||
if (system(mesonSetup) != 0)
|
||||
THROW_FMT(ExecuteError, "unable to execute: %s", mesonSetup);
|
||||
}
|
||||
|
||||
// Ninja build
|
||||
const char *const ninjaBuild = zNewFmt("ninja -C %s", strZ(pathUnitBuild));
|
||||
|
||||
if (system(ninjaBuild) != 0)
|
||||
THROW_FMT(ExecuteError, "unable to execute: %s", ninjaBuild);
|
||||
|
||||
// Unit test
|
||||
const char *const unitTest = zNewFmt("%s/test-unit", strZ(pathUnitBuild));
|
||||
|
||||
if (system(unitTest) != 0)
|
||||
THROW_FMT(ExecuteError, "unable to execute: %s", unitTest);
|
||||
}
|
||||
MEM_CONTEXT_TEMP_END();
|
||||
|
||||
FUNCTION_LOG_RETURN_VOID();
|
||||
}
|
19
test/src/command/test/test.h
Normal file
19
test/src/command/test/test.h
Normal file
@ -0,0 +1,19 @@
|
||||
/***********************************************************************************************************************************
|
||||
Test Command
|
||||
|
||||
Perform a test.
|
||||
***********************************************************************************************************************************/
|
||||
#ifndef TEST_COMMAND_TEST_TEST_H
|
||||
#define TEST_COMMAND_TEST_TEST_H
|
||||
|
||||
#include "common/logLevel.h"
|
||||
#include "common/type/string.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Functions
|
||||
***********************************************************************************************************************************/
|
||||
void cmdTest(
|
||||
const String *pathRepo, const String *pathTest, const String *const vm, unsigned int vmId, const String *moduleName,
|
||||
unsigned int test, uint64_t scale, LogLevel logLevel, bool logTime, const String *timeZone);
|
||||
|
||||
#endif
|
@ -33,6 +33,8 @@ There should not be any code outside the HRN_FORK_CHILD_BEGIN/END() and HRN_FORK
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <common/type/param.h>
|
||||
|
||||
#include <common/harnessLog.h>
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
|
129
test/src/config/load.c
Normal file
129
test/src/config/load.c
Normal file
@ -0,0 +1,129 @@
|
||||
/***********************************************************************************************************************************
|
||||
Configuration Load
|
||||
***********************************************************************************************************************************/
|
||||
#include "build.auto.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "command/command.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/io/io.h"
|
||||
#include "common/log.h"
|
||||
#include "config/config.intern.h"
|
||||
#include "storage/posix/storage.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Load log settings
|
||||
***********************************************************************************************************************************/
|
||||
static void
|
||||
cfgLoadLogSetting(void)
|
||||
{
|
||||
FUNCTION_LOG_VOID(logLevelTrace);
|
||||
|
||||
// Initialize logging
|
||||
LogLevel logLevelConsole = logLevelOff;
|
||||
bool logTimestamp = true;
|
||||
|
||||
if (cfgOptionValid(cfgOptLogLevel))
|
||||
logLevelConsole = logLevelEnum(cfgOptionStrId(cfgOptLogLevel));
|
||||
|
||||
if (cfgOptionValid(cfgOptLogTimestamp))
|
||||
logTimestamp = cfgOptionBool(cfgOptLogTimestamp);
|
||||
|
||||
logInit(logLevelConsole, logLevelOff, logLevelOff, logTimestamp, 0, 1, false);
|
||||
|
||||
FUNCTION_LOG_RETURN_VOID();
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Update options that have complex rules
|
||||
***********************************************************************************************************************************/
|
||||
static void
|
||||
cfgLoadUpdateOption(void)
|
||||
{
|
||||
FUNCTION_LOG_VOID(logLevelTrace);
|
||||
|
||||
// Get current working dir
|
||||
char currentWorkDir[1024];
|
||||
THROW_ON_SYS_ERROR(getcwd(currentWorkDir, sizeof(currentWorkDir)) == NULL, FormatError, "unable to get cwd");
|
||||
|
||||
// Invalidate config option so it does not show up in option list
|
||||
cfgOptionInvalidate(cfgOptConfig);
|
||||
|
||||
// If repo-path is relative then make it absolute
|
||||
const String *const repoPath = cfgOptionStr(cfgOptRepoPath);
|
||||
|
||||
if (!strBeginsWithZ(repoPath, "/"))
|
||||
cfgOptionSet(cfgOptRepoPath, cfgOptionSource(cfgOptRepoPath), VARSTR(strNewFmt("%s/%s", currentWorkDir, strZ(repoPath))));
|
||||
|
||||
// If test-path is relative then make it absolute
|
||||
const String *const testPath = cfgOptionStr(cfgOptTestPath);
|
||||
|
||||
if (!strBeginsWithZ(testPath, "/"))
|
||||
cfgOptionSet(cfgOptTestPath, cfgOptionSource(cfgOptTestPath), VARSTR(strNewFmt("%s/%s", currentWorkDir, strZ(testPath))));
|
||||
|
||||
FUNCTION_LOG_RETURN_VOID();
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
void
|
||||
cfgLoad(unsigned int argListSize, const char *argList[])
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(UINT, argListSize);
|
||||
FUNCTION_LOG_PARAM(CHARPY, argList);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
// Make a copy of the arguments so they can be manipulated
|
||||
StringList *const argListNew = strLstNew();
|
||||
|
||||
for (unsigned int argListIdx = 0; argListIdx < argListSize; argListIdx++)
|
||||
strLstAddZ(argListNew, argList[argListIdx]);
|
||||
|
||||
// Explicitly set --no-config so a stray config file will not be loaded
|
||||
strLstAddZ(argListNew, "--no-" CFGOPT_CONFIG);
|
||||
|
||||
// Parse config from command line
|
||||
TRY_BEGIN()
|
||||
{
|
||||
configParse(storagePosixNewP(FSLASH_STR), strLstSize(argListNew), strLstPtr(argListNew), true);
|
||||
}
|
||||
CATCH(CommandRequiredError)
|
||||
{
|
||||
strLstAddZ(argListNew, CFGCMD_TEST);
|
||||
configParse(storagePosixNewP(FSLASH_STR), strLstSize(argListNew), strLstPtr(argListNew), true);
|
||||
}
|
||||
TRY_END();
|
||||
|
||||
// Error on noop command. This command is required to hold options that must be declared but are unused by test.
|
||||
if (cfgCommand() == cfgCmdNoop)
|
||||
THROW(CommandInvalidError, "invalid command '" CFGCMD_NOOP "'");
|
||||
|
||||
// If a command is set
|
||||
if (cfgCommand() != cfgCmdNone && cfgCommand() != cfgCmdHelp && cfgCommand() != cfgCmdVersion)
|
||||
{
|
||||
// Load the log settings
|
||||
if (!cfgCommandHelp())
|
||||
cfgLoadLogSetting();
|
||||
|
||||
// Neutralize the umask to make the repository file/path modes more consistent
|
||||
if (cfgOptionValid(cfgOptNeutralUmask) && cfgOptionBool(cfgOptNeutralUmask))
|
||||
umask(0000);
|
||||
|
||||
// Set IO buffer size
|
||||
if (cfgOptionValid(cfgOptBufferSize))
|
||||
ioBufferSizeSet(cfgOptionUInt(cfgOptBufferSize));
|
||||
|
||||
// Update options that have complex rules
|
||||
cfgLoadUpdateOption();
|
||||
|
||||
// Begin the command
|
||||
cmdBegin();
|
||||
}
|
||||
}
|
||||
MEM_CONTEXT_TEMP_END();
|
||||
|
||||
FUNCTION_LOG_RETURN_VOID();
|
||||
}
|
13
test/src/config/load.h
Normal file
13
test/src/config/load.h
Normal file
@ -0,0 +1,13 @@
|
||||
/***********************************************************************************************************************************
|
||||
Test Configuration Load
|
||||
***********************************************************************************************************************************/
|
||||
#ifndef TEST_CONFIG_LOAD_H
|
||||
#define TEST_CONFIG_LOAD_H
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Functions
|
||||
***********************************************************************************************************************************/
|
||||
// Load the configuration
|
||||
void cfgLoad(unsigned int argListSize, const char *argList[]);
|
||||
|
||||
#endif
|
15
test/src/config/meson.build
Normal file
15
test/src/config/meson.build
Normal file
@ -0,0 +1,15 @@
|
||||
####################################################################################################################################
|
||||
# Generate config
|
||||
####################################################################################################################################
|
||||
test_parse_auto_c_inc = custom_target(
|
||||
'parse.auto.c.inc',
|
||||
output : 'parse.auto.c.inc',
|
||||
depend_files: [
|
||||
'../build/config/config.yaml',
|
||||
],
|
||||
command : [
|
||||
build_config,
|
||||
'@CURRENT_SOURCE_DIR@/../..',
|
||||
'@BUILD_ROOT@/test',
|
||||
],
|
||||
)
|
108
test/src/main.c
Normal file
108
test/src/main.c
Normal file
@ -0,0 +1,108 @@
|
||||
/***********************************************************************************************************************************
|
||||
Main
|
||||
***********************************************************************************************************************************/
|
||||
#include "build.auto.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "command/command.h"
|
||||
#include "command/exit.h"
|
||||
#include "command/help/help.h"
|
||||
#include "command/test/test.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/error.h"
|
||||
#include "common/log.h"
|
||||
#include "common/macro.h"
|
||||
#include "common/memContext.h"
|
||||
#include "common/stat.h"
|
||||
#include "config/load.h"
|
||||
#include "config/parse.h"
|
||||
#include "storage/posix/storage.h"
|
||||
#include "version.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Include automatically generated help data
|
||||
***********************************************************************************************************************************/
|
||||
#include "command/help/help.auto.c.inc"
|
||||
|
||||
int
|
||||
main(int argListSize, const char *argList[])
|
||||
{
|
||||
// Set stack trace and mem context error cleanup handlers
|
||||
static const ErrorHandlerFunction errorHandlerList[] = {stackTraceClean, memContextClean};
|
||||
errorHandlerSet(errorHandlerList, LENGTH_OF(errorHandlerList));
|
||||
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(INT, argListSize);
|
||||
FUNCTION_LOG_PARAM(CHARPY, argList);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
// Initialize command with the start time
|
||||
cmdInit();
|
||||
|
||||
// Initialize statistics collector
|
||||
statInit();
|
||||
|
||||
// Initialize exit handler
|
||||
exitInit();
|
||||
|
||||
// Process commands
|
||||
volatile int result = 0;
|
||||
volatile bool error = false;
|
||||
|
||||
TRY_BEGIN()
|
||||
{
|
||||
// Load the configuration
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
cfgLoad((unsigned int)argListSize, argList);
|
||||
|
||||
// Display help
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
if (cfgCommandHelp())
|
||||
{
|
||||
cmdHelp(BUF(helpData, sizeof(helpData)));
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (cfgCommand())
|
||||
{
|
||||
// Test
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
case cfgCmdTest:
|
||||
{
|
||||
cmdTest(
|
||||
cfgOptionStr(cfgOptRepoPath), cfgOptionStr(cfgOptTestPath), cfgOptionStr(cfgOptVm),
|
||||
cfgOptionUInt(cfgOptVmId), cfgOptionStr(cfgOptModule),
|
||||
cfgOptionTest(cfgOptTest) ? cfgOptionUInt(cfgOptTest) : 0, cfgOptionUInt64(cfgOptScale),
|
||||
logLevelEnum(cfgOptionStrId(cfgOptLogLevelTest)), cfgOptionBool(cfgOptLogTimestamp),
|
||||
cfgOptionStrNull(cfgOptTz));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Display version
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
case cfgCmdVersion:
|
||||
printf(PROJECT_NAME " Test " PROJECT_VERSION "\n");
|
||||
fflush(stdout);
|
||||
break;
|
||||
|
||||
// Error on commands that should have already been handled
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
case cfgCmdHelp:
|
||||
case cfgCmdNone:
|
||||
case cfgCmdNoop:
|
||||
THROW_FMT(AssertError, "'%s' command should have been handled", cfgCommandName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
CATCH_FATAL()
|
||||
{
|
||||
error = true;
|
||||
result = exitSafe(result, true, 0);
|
||||
}
|
||||
TRY_END();
|
||||
|
||||
FUNCTION_LOG_RETURN(INT, error ? result : exitSafe(result, false, 0));
|
||||
}
|
63
test/src/meson.build
Normal file
63
test/src/meson.build
Normal file
@ -0,0 +1,63 @@
|
||||
####################################################################################################################################
|
||||
# Write configuration
|
||||
####################################################################################################################################
|
||||
configure_file(output: 'build.auto.h', configuration: configuration)
|
||||
|
||||
####################################################################################################################################
|
||||
# Build config target
|
||||
####################################################################################################################################
|
||||
# build parse.auto.c.inc
|
||||
subdir('config')
|
||||
|
||||
alias_target('test-build-config', test_parse_auto_c_inc)
|
||||
|
||||
####################################################################################################################################
|
||||
# Build help target
|
||||
####################################################################################################################################
|
||||
# build help.auto.c.inc
|
||||
subdir('command/help')
|
||||
|
||||
alias_target('test-build-help', test_help_auto_c_inc)
|
||||
|
||||
####################################################################################################################################
|
||||
# test target
|
||||
####################################################################################################################################
|
||||
src_test = [
|
||||
'../../src/build/common/render.c',
|
||||
'../../src/build/common/yaml.c',
|
||||
'../../src/command/command.c',
|
||||
'../../src/command/exit.c',
|
||||
'../../src/command/help/help.c',
|
||||
'../../src/common/compress/bz2/common.c',
|
||||
'../../src/common/compress/bz2/decompress.c',
|
||||
'../../src/common/ini.c',
|
||||
'../../src/common/io/fd.c',
|
||||
'../../src/common/io/fdRead.c',
|
||||
'../../src/common/io/fdWrite.c',
|
||||
'../../src/common/lock.c',
|
||||
'../../src/common/stat.c',
|
||||
'../../src/common/type/json.c',
|
||||
'../../src/config/config.c',
|
||||
'../../src/config/parse.c',
|
||||
'command/test/build.c',
|
||||
'command/test/define.c',
|
||||
'command/test/test.c',
|
||||
'config/load.c',
|
||||
'main.c',
|
||||
]
|
||||
|
||||
test_pgbackrest = executable(
|
||||
'test-pgbackrest',
|
||||
src_common,
|
||||
src_test,
|
||||
test_help_auto_c_inc,
|
||||
test_parse_auto_c_inc,
|
||||
include_directories: include_directories('.', '../../src'),
|
||||
dependencies: [
|
||||
lib_bz2,
|
||||
lib_yaml,
|
||||
],
|
||||
build_by_default: false,
|
||||
)
|
||||
|
||||
alias_target('test-pgbackrest', test_pgbackrest)
|
@ -5,6 +5,11 @@ This wrapper runs the C unit tests.
|
||||
***********************************************************************************************************************************/
|
||||
#include "build.auto.h"
|
||||
|
||||
// Enable FUNCTION_TEST*() macros for enhanced debugging
|
||||
#ifndef DEBUG_TEST_TRACE
|
||||
#define DEBUG_TEST_TRACE
|
||||
#endif
|
||||
|
||||
// This must be before all includes except build.auto.h
|
||||
#ifdef HRN_FEATURE_MEMCONTEXT
|
||||
#define DEBUG_MEM
|
||||
|
Loading…
Reference in New Issue
Block a user