mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-01-18 04:58:51 +02:00
Add coverage to C test harness.
Coverage reports are still generated in Perl, but all the settings have been added to the C harness to generate raw coverage data.
This commit is contained in:
parent
c99ea54f17
commit
1e83f2a022
@ -115,9 +115,7 @@ sub new
|
|||||||
$self->{iTry} = 0;
|
$self->{iTry} = 0;
|
||||||
|
|
||||||
# Use the new C test harness?
|
# Use the new C test harness?
|
||||||
$self->{bTestC} =
|
$self->{bTestC} = $self->{oTest}->{&TEST_C} && !$self->{bProfile} && $self->{oTest}->{&TEST_TYPE} ne TESTDEF_PERFORMANCE;
|
||||||
$self->{oTest}->{&TEST_C} && !$self->{bCoverageUnit} && !$self->{bProfile} &&
|
|
||||||
$self->{oTest}->{&TEST_TYPE} ne TESTDEF_PERFORMANCE;
|
|
||||||
|
|
||||||
# Setup the path where unit test will be built
|
# Setup the path where unit test will be built
|
||||||
$self->{strUnitPath} =
|
$self->{strUnitPath} =
|
||||||
@ -249,13 +247,17 @@ sub run
|
|||||||
# Build filename for valgrind suppressions
|
# Build filename for valgrind suppressions
|
||||||
my $strValgrindSuppress = $self->{strRepoPath} . '/test/src/valgrind.suppress.' . $self->{oTest}->{&TEST_VM};
|
my $strValgrindSuppress = $self->{strRepoPath} . '/test/src/valgrind.suppress.' . $self->{oTest}->{&TEST_VM};
|
||||||
|
|
||||||
|
# Is coverage enabled?
|
||||||
|
my $bCoverage = vmCoverageC($self->{oTest}->{&TEST_VM}) && $self->{bCoverageUnit};
|
||||||
|
|
||||||
$strCommand =
|
$strCommand =
|
||||||
($self->{oTest}->{&TEST_VM} ne VM_NONE ? "docker exec -i -u ${\TEST_USER} ${strImage} bash -l -c '" : '') .
|
($self->{oTest}->{&TEST_VM} ne VM_NONE ? "docker exec -i -u ${\TEST_USER} ${strImage} bash -l -c '" : '') .
|
||||||
" \\\n" .
|
" \\\n" .
|
||||||
$self->{strTestPath} . '/build/' . $self->{oTest}->{&TEST_VM} . '/test/src/test-pgbackrest --no-run' .
|
$self->{strTestPath} . '/build/' . $self->{oTest}->{&TEST_VM} . '/test/src/test-pgbackrest --no-run' .
|
||||||
' --no-repo-copy --repo-path=' . $self->{strTestPath} . '/repo' . ' --test-path=' . $self->{strTestPath} .
|
' --no-repo-copy --repo-path=' . $self->{strTestPath} . '/repo' . ' --test-path=' . $self->{strTestPath} .
|
||||||
' --vm=' . $self->{oTest}->{&TEST_VM} . ' --vm-id=' . $self->{iVmIdx} . ' test ' .
|
' --vm=' . $self->{oTest}->{&TEST_VM} . ' --vm-id=' . $self->{iVmIdx} .
|
||||||
$self->{oTest}->{&TEST_MODULE} . '/' . $self->{oTest}->{&TEST_NAME} . " && \\\n" .
|
($bCoverage ? '' : ' --no-coverage') . ' test ' . $self->{oTest}->{&TEST_MODULE} . '/' .
|
||||||
|
$self->{oTest}->{&TEST_NAME} . " && \\\n" .
|
||||||
# Allow stderr to be copied to stderr and stdout
|
# Allow stderr to be copied to stderr and stdout
|
||||||
"exec 3>&1 && \\\n" .
|
"exec 3>&1 && \\\n" .
|
||||||
# Test with valgrind when requested
|
# Test with valgrind when requested
|
||||||
@ -865,7 +867,9 @@ sub end
|
|||||||
$self->{oStorageTest}, $self->{oTest}->{&TEST_MODULE}, $self->{oTest}->{&TEST_NAME},
|
$self->{oStorageTest}, $self->{oTest}->{&TEST_MODULE}, $self->{oTest}->{&TEST_NAME},
|
||||||
$self->{oTest}->{&TEST_VM} ne VM_NONE, $self->{bCoverageSummary},
|
$self->{oTest}->{&TEST_VM} ne VM_NONE, $self->{bCoverageSummary},
|
||||||
$self->{oTest}->{&TEST_VM} eq VM_NONE ? undef : $strImage, $self->{strTestPath}, "$self->{strTestPath}/temp",
|
$self->{oTest}->{&TEST_VM} eq VM_NONE ? undef : $strImage, $self->{strTestPath}, "$self->{strTestPath}/temp",
|
||||||
$self->{strUnitPath}, $self->{strBackRestBase} . '/test/result');
|
-e "$self->{strUnitPath}/build/test-unit.p" ?
|
||||||
|
"$self->{strUnitPath}/build/test-unit.p" : "$self->{strUnitPath}/build/test-unit\@exe",
|
||||||
|
$self->{strBackRestBase} . '/test/result');
|
||||||
}
|
}
|
||||||
|
|
||||||
# Record elapsed time
|
# Record elapsed time
|
||||||
|
@ -45,6 +45,13 @@ option:
|
|||||||
- 512KiB
|
- 512KiB
|
||||||
- 1MiB
|
- 1MiB
|
||||||
|
|
||||||
|
coverage:
|
||||||
|
type: boolean
|
||||||
|
default: true
|
||||||
|
negate: true
|
||||||
|
command:
|
||||||
|
test: {}
|
||||||
|
|
||||||
neutral-umask:
|
neutral-umask:
|
||||||
type: boolean
|
type: boolean
|
||||||
internal: true
|
internal: true
|
||||||
|
@ -33,6 +33,16 @@
|
|||||||
<example>1MiB</example>
|
<example>1MiB</example>
|
||||||
</option>
|
</option>
|
||||||
|
|
||||||
|
<option id="coverage">
|
||||||
|
<summary>Generate code coverage.</summary>
|
||||||
|
|
||||||
|
<text>
|
||||||
|
<p>Coverage helps determine that tests adequately test the code.</p>
|
||||||
|
</text>
|
||||||
|
|
||||||
|
<example>n</example>
|
||||||
|
</option>
|
||||||
|
|
||||||
<option id="log-level">
|
<option id="log-level">
|
||||||
<summary>Level for harness logging.</summary>
|
<summary>Level for harness logging.</summary>
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ TestBuild *
|
|||||||
testBldNew(
|
testBldNew(
|
||||||
const String *const pathRepo, const String *const pathTest, const String *const vm, const unsigned int vmId,
|
const String *const pathRepo, const String *const pathTest, const String *const vm, const unsigned int vmId,
|
||||||
const TestDefModule *const module, const unsigned int test, const uint64_t scale, const LogLevel logLevel, const bool logTime,
|
const TestDefModule *const module, const unsigned int test, const uint64_t scale, const LogLevel logLevel, const bool logTime,
|
||||||
const String *const timeZone)
|
const String *const timeZone, const bool coverage)
|
||||||
{
|
{
|
||||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||||
FUNCTION_LOG_PARAM(STRING, pathRepo);
|
FUNCTION_LOG_PARAM(STRING, pathRepo);
|
||||||
@ -44,6 +44,7 @@ testBldNew(
|
|||||||
FUNCTION_LOG_PARAM(ENUM, logLevel);
|
FUNCTION_LOG_PARAM(ENUM, logLevel);
|
||||||
FUNCTION_LOG_PARAM(BOOL, logTime);
|
FUNCTION_LOG_PARAM(BOOL, logTime);
|
||||||
FUNCTION_LOG_PARAM(STRING, timeZone);
|
FUNCTION_LOG_PARAM(STRING, timeZone);
|
||||||
|
FUNCTION_LOG_PARAM(BOOL, coverage);
|
||||||
FUNCTION_LOG_END();
|
FUNCTION_LOG_END();
|
||||||
|
|
||||||
ASSERT(pathRepo != NULL);
|
ASSERT(pathRepo != NULL);
|
||||||
@ -73,6 +74,7 @@ testBldNew(
|
|||||||
.logLevel = logLevel,
|
.logLevel = logLevel,
|
||||||
.logTime = logTime,
|
.logTime = logTime,
|
||||||
.timeZone = strDup(timeZone),
|
.timeZone = strDup(timeZone),
|
||||||
|
.coverage = coverage,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -363,6 +365,14 @@ testBldUnit(TestBuild *const this)
|
|||||||
if (module->flag != NULL)
|
if (module->flag != NULL)
|
||||||
strCatFmt(mesonBuild, "add_global_arguments('%s', language : 'c')\n", strZ(module->flag));
|
strCatFmt(mesonBuild, "add_global_arguments('%s', language : 'c')\n", strZ(module->flag));
|
||||||
|
|
||||||
|
// Add coverage
|
||||||
|
if (testBldCoverage(this))
|
||||||
|
strCatZ(mesonBuild, "add_global_arguments('-DDEBUG_COVERAGE', language : 'c')\n");
|
||||||
|
|
||||||
|
// Add container flag
|
||||||
|
if (!strEqZ(testBldVm(this), "none"))
|
||||||
|
strCatZ(mesonBuild, "add_global_arguments('-DTEST_CONTAINER_REQUIRED', language : 'c')\n");
|
||||||
|
|
||||||
// Build unit test
|
// Build unit test
|
||||||
strCatZ(
|
strCatZ(
|
||||||
mesonBuild,
|
mesonBuild,
|
||||||
@ -536,7 +546,7 @@ testBldUnit(TestBuild *const this)
|
|||||||
strReplace(testC, STRDEF("{[C_TEST_SCALE]}"), strNewFmt("%" PRIu64, testBldScale(this)));
|
strReplace(testC, STRDEF("{[C_TEST_SCALE]}"), strNewFmt("%" PRIu64, testBldScale(this)));
|
||||||
|
|
||||||
// Does this test run in a container?
|
// Does this test run in a container?
|
||||||
strReplace(testC, STRDEF("{[C_TEST_CONTAINER]}"), STR(cvtBoolToConstZ(module->containerRequired)));
|
strReplace(testC, STRDEF("{[C_TEST_CONTAINER]}"), STR(cvtBoolToConstZ(!strEqZ(testBldVm(this), "none"))));
|
||||||
|
|
||||||
// User/group info
|
// User/group info
|
||||||
strReplace(testC, STRDEF("{[C_TEST_GROUP]}"), groupName());
|
strReplace(testC, STRDEF("{[C_TEST_GROUP]}"), groupName());
|
||||||
|
@ -20,7 +20,7 @@ Constructors
|
|||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
TestBuild *testBldNew(
|
TestBuild *testBldNew(
|
||||||
const String *pathRepo, const String *pathTest, const String *const vm, unsigned int vmId, const TestDefModule *module,
|
const String *pathRepo, const String *pathTest, const String *const vm, unsigned int vmId, const TestDefModule *module,
|
||||||
unsigned int test, uint64_t scale, LogLevel logLevel, bool logTime, const String *timeZone);
|
unsigned int test, uint64_t scale, LogLevel logLevel, bool logTime, const String *timeZone, bool coverage);
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
Getters/Setters
|
Getters/Setters
|
||||||
@ -39,6 +39,7 @@ typedef struct TestBuildPub
|
|||||||
bool logTime; // Log times/timestamps
|
bool logTime; // Log times/timestamps
|
||||||
uint64_t scale; // Scale performance test
|
uint64_t scale; // Scale performance test
|
||||||
const String *timeZone; // Test in timezone
|
const String *timeZone; // Test in timezone
|
||||||
|
bool coverage; // Generate coverage?
|
||||||
TestDef tstDef; // Test definitions
|
TestDef tstDef; // Test definitions
|
||||||
} TestBuildPub;
|
} TestBuildPub;
|
||||||
|
|
||||||
@ -120,6 +121,13 @@ testBldTimeZone(const TestBuild *const this)
|
|||||||
return THIS_PUB(TestBuild)->timeZone;
|
return THIS_PUB(TestBuild)->timeZone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generate coverage?
|
||||||
|
__attribute__((always_inline)) static inline bool
|
||||||
|
testBldCoverage(const TestBuild *const this)
|
||||||
|
{
|
||||||
|
return THIS_PUB(TestBuild)->coverage;
|
||||||
|
}
|
||||||
|
|
||||||
// Scale
|
// Scale
|
||||||
__attribute__((always_inline)) static inline uint64_t
|
__attribute__((always_inline)) static inline uint64_t
|
||||||
testBldScale(const TestBuild *const this)
|
testBldScale(const TestBuild *const this)
|
||||||
|
@ -74,7 +74,7 @@ void
|
|||||||
cmdTest(
|
cmdTest(
|
||||||
const String *const pathRepo, const String *const pathTest, const String *const vm, const unsigned int vmId,
|
const String *const pathRepo, const String *const pathTest, const String *const vm, const unsigned int vmId,
|
||||||
const StringList *moduleFilterList, const unsigned int test, const uint64_t scale, const LogLevel logLevel,
|
const StringList *moduleFilterList, const unsigned int test, const uint64_t scale, const LogLevel logLevel,
|
||||||
const bool logTime, const String *const timeZone, const bool repoCopy, const bool valgrind, const bool run)
|
const bool logTime, const String *const timeZone, const bool repoCopy, const bool valgrind, const bool coverage, const bool run)
|
||||||
{
|
{
|
||||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||||
FUNCTION_LOG_PARAM(STRING, pathRepo);
|
FUNCTION_LOG_PARAM(STRING, pathRepo);
|
||||||
@ -89,6 +89,7 @@ cmdTest(
|
|||||||
FUNCTION_LOG_PARAM(STRING, timeZone);
|
FUNCTION_LOG_PARAM(STRING, timeZone);
|
||||||
FUNCTION_LOG_PARAM(BOOL, repoCopy);
|
FUNCTION_LOG_PARAM(BOOL, repoCopy);
|
||||||
FUNCTION_LOG_PARAM(BOOL, valgrind);
|
FUNCTION_LOG_PARAM(BOOL, valgrind);
|
||||||
|
FUNCTION_LOG_PARAM(BOOL, coverage);
|
||||||
FUNCTION_LOG_PARAM(BOOL, run);
|
FUNCTION_LOG_PARAM(BOOL, run);
|
||||||
FUNCTION_LOG_END();
|
FUNCTION_LOG_END();
|
||||||
|
|
||||||
@ -188,7 +189,7 @@ cmdTest(
|
|||||||
// Process test list
|
// Process test list
|
||||||
unsigned int errorTotal = 0;
|
unsigned int errorTotal = 0;
|
||||||
bool buildRetry = false;
|
bool buildRetry = false;
|
||||||
const char *buildTypeLast = NULL;
|
String *const mesonSetupLast = strNew();
|
||||||
|
|
||||||
for (unsigned int moduleIdx = 0; moduleIdx < strLstSize(moduleList); moduleIdx++)
|
for (unsigned int moduleIdx = 0; moduleIdx < strLstSize(moduleList); moduleIdx++)
|
||||||
{
|
{
|
||||||
@ -201,6 +202,7 @@ cmdTest(
|
|||||||
// Build unit test
|
// Build unit test
|
||||||
const String *const pathUnit = strNewFmt("%s/unit-%u/%s", strZ(pathTest), vmId, strZ(vm));
|
const String *const pathUnit = strNewFmt("%s/unit-%u/%s", strZ(pathTest), vmId, strZ(vm));
|
||||||
const String *const pathUnitBuild = strNewFmt("%s/build", strZ(pathUnit));
|
const String *const pathUnitBuild = strNewFmt("%s/build", strZ(pathUnit));
|
||||||
|
const Storage *const storageUnitBuild = storagePosixNewP(pathUnitBuild, .write = true);
|
||||||
const TimeMSec buildTimeBegin = timeMSec();
|
const TimeMSec buildTimeBegin = timeMSec();
|
||||||
TimeMSec buildTimeEnd;
|
TimeMSec buildTimeEnd;
|
||||||
TestBuild *testBld;
|
TestBuild *testBld;
|
||||||
@ -209,35 +211,52 @@ cmdTest(
|
|||||||
{
|
{
|
||||||
// Build unit
|
// Build unit
|
||||||
testBld = testBldNew(
|
testBld = testBldNew(
|
||||||
pathRepoCopy, pathTest, vm, vmId, module, test, scale, logLevel, logTime, timeZone);
|
pathRepoCopy, pathTest, vm, vmId, module, test, scale, logLevel, logTime, timeZone, coverage);
|
||||||
testBldUnit(testBld);
|
testBldUnit(testBld);
|
||||||
|
|
||||||
// Meson setup
|
// Meson setup
|
||||||
const char *buildType = "debug";
|
String *const mesonSetup = strCatZ(strNew(), "-Dbuildtype=");
|
||||||
|
|
||||||
if (module->flag != NULL)
|
if (module->flag != NULL)
|
||||||
{
|
{
|
||||||
ASSERT(strEqZ(module->flag, "-DNDEBUG"));
|
ASSERT(strEqZ(module->flag, "-DNDEBUG"));
|
||||||
buildType = "release";
|
strCatZ(mesonSetup, "release");
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
strCatZ(mesonSetup, "debug");
|
||||||
|
|
||||||
|
strCatFmt(mesonSetup, " -Db_coverage=%s", cvtBoolToConstZ(coverage));
|
||||||
|
|
||||||
if (!storageExistsP(testBldStorageTest(testBld), strNewFmt("%s/build.ninja", strZ(pathUnitBuild))))
|
if (!storageExistsP(testBldStorageTest(testBld), strNewFmt("%s/build.ninja", strZ(pathUnitBuild))))
|
||||||
{
|
{
|
||||||
LOG_DETAIL("meson setup");
|
LOG_DETAIL("meson setup");
|
||||||
|
|
||||||
cmdTestExec(
|
cmdTestExec(
|
||||||
strNewFmt(
|
strNewFmt(
|
||||||
"meson setup -Dwerror=true -Dfatal-errors=true -Dbuildtype=%s %s %s", buildType,
|
"meson setup -Dwerror=true -Dfatal-errors=true %s %s %s", strZ(mesonSetup), strZ(pathUnitBuild),
|
||||||
strZ(pathUnitBuild), strZ(pathUnit)));
|
strZ(pathUnit)));
|
||||||
|
|
||||||
buildTypeLast = buildType;
|
|
||||||
}
|
}
|
||||||
|
// Else reconfigure as needed
|
||||||
// Reconfigure as needed
|
else if (!strEq(mesonSetup, mesonSetupLast))
|
||||||
if (buildType != buildTypeLast)
|
|
||||||
{
|
{
|
||||||
LOG_DETAIL("meson configure");
|
LOG_DETAIL("meson configure");
|
||||||
cmdTestExec(strNewFmt("meson configure -Dbuildtype=%s %s", buildType, strZ(pathUnitBuild)));
|
|
||||||
buildTypeLast = buildType;
|
cmdTestExec(strNewFmt("meson configure %s %s", strZ(mesonSetup), strZ(pathUnitBuild)));
|
||||||
|
}
|
||||||
|
|
||||||
|
strCat(strTrunc(mesonSetupLast), mesonSetup);
|
||||||
|
|
||||||
|
// Remove old coverage data. Note that coverage can be in different paths depending on the meson version.
|
||||||
|
const String *const pathCoverage = storagePathExistsP(storageUnitBuild, STRDEF("test-unit.p")) ?
|
||||||
|
STRDEF("test-unit.p") : STRDEF("test-unit@exe");
|
||||||
|
|
||||||
|
StorageIterator *const storageItr = storageNewItrP(
|
||||||
|
storageUnitBuild, pathCoverage, .expression = STRDEF("\\.gcda$"));
|
||||||
|
|
||||||
|
while (storageItrMore(storageItr))
|
||||||
|
{
|
||||||
|
storageRemoveP(
|
||||||
|
storageUnitBuild, strNewFmt("%s/%s", strZ(pathCoverage), strZ(storageItrNext(storageItr).name)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ninja build
|
// Ninja build
|
||||||
|
@ -15,6 +15,6 @@ Functions
|
|||||||
void cmdTest(
|
void cmdTest(
|
||||||
const String *pathRepo, const String *pathTest, const String *const vm, unsigned int vmId, const StringList *moduleFilterList,
|
const String *pathRepo, const String *pathTest, const String *const vm, unsigned int vmId, const StringList *moduleFilterList,
|
||||||
unsigned int test, uint64_t scale, LogLevel logLevel, bool logTime, const String *timeZone, bool repoCopy, bool valgrind,
|
unsigned int test, uint64_t scale, LogLevel logLevel, bool logTime, const String *timeZone, bool repoCopy, bool valgrind,
|
||||||
bool run);
|
bool coverage, bool run);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -75,7 +75,7 @@ main(int argListSize, const char *argList[])
|
|||||||
cfgOptionUInt(cfgOptVmId), cfgCommandParam(), cfgOptionTest(cfgOptTest) ? cfgOptionUInt(cfgOptTest) : 0,
|
cfgOptionUInt(cfgOptVmId), cfgCommandParam(), cfgOptionTest(cfgOptTest) ? cfgOptionUInt(cfgOptTest) : 0,
|
||||||
cfgOptionUInt64(cfgOptScale), logLevelEnum(cfgOptionStrId(cfgOptLogLevelTest)),
|
cfgOptionUInt64(cfgOptScale), logLevelEnum(cfgOptionStrId(cfgOptLogLevelTest)),
|
||||||
cfgOptionBool(cfgOptLogTimestamp), cfgOptionStrNull(cfgOptTz), cfgOptionBool(cfgOptRepoCopy),
|
cfgOptionBool(cfgOptLogTimestamp), cfgOptionStrNull(cfgOptTz), cfgOptionBool(cfgOptRepoCopy),
|
||||||
cfgOptionBool(cfgOptValgrind), cfgOptionBool(cfgOptRun));
|
cfgOptionBool(cfgOptValgrind), cfgOptionBool(cfgOptCoverage), cfgOptionBool(cfgOptRun));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user