mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2024-12-12 10:04:14 +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;
|
||||
|
||||
# Use the new C test harness?
|
||||
$self->{bTestC} =
|
||||
$self->{oTest}->{&TEST_C} && !$self->{bCoverageUnit} && !$self->{bProfile} &&
|
||||
$self->{oTest}->{&TEST_TYPE} ne TESTDEF_PERFORMANCE;
|
||||
$self->{bTestC} = $self->{oTest}->{&TEST_C} && !$self->{bProfile} && $self->{oTest}->{&TEST_TYPE} ne TESTDEF_PERFORMANCE;
|
||||
|
||||
# Setup the path where unit test will be built
|
||||
$self->{strUnitPath} =
|
||||
@ -249,13 +247,17 @@ sub run
|
||||
# Build filename for valgrind suppressions
|
||||
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 =
|
||||
($self->{oTest}->{&TEST_VM} ne VM_NONE ? "docker exec -i -u ${\TEST_USER} ${strImage} bash -l -c '" : '') .
|
||||
" \\\n" .
|
||||
$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} .
|
||||
' --vm=' . $self->{oTest}->{&TEST_VM} . ' --vm-id=' . $self->{iVmIdx} . ' test ' .
|
||||
$self->{oTest}->{&TEST_MODULE} . '/' . $self->{oTest}->{&TEST_NAME} . " && \\\n" .
|
||||
' --vm=' . $self->{oTest}->{&TEST_VM} . ' --vm-id=' . $self->{iVmIdx} .
|
||||
($bCoverage ? '' : ' --no-coverage') . ' test ' . $self->{oTest}->{&TEST_MODULE} . '/' .
|
||||
$self->{oTest}->{&TEST_NAME} . " && \\\n" .
|
||||
# Allow stderr to be copied to stderr and stdout
|
||||
"exec 3>&1 && \\\n" .
|
||||
# Test with valgrind when requested
|
||||
@ -865,7 +867,9 @@ sub end
|
||||
$self->{oStorageTest}, $self->{oTest}->{&TEST_MODULE}, $self->{oTest}->{&TEST_NAME},
|
||||
$self->{oTest}->{&TEST_VM} ne VM_NONE, $self->{bCoverageSummary},
|
||||
$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
|
||||
|
@ -45,6 +45,13 @@ option:
|
||||
- 512KiB
|
||||
- 1MiB
|
||||
|
||||
coverage:
|
||||
type: boolean
|
||||
default: true
|
||||
negate: true
|
||||
command:
|
||||
test: {}
|
||||
|
||||
neutral-umask:
|
||||
type: boolean
|
||||
internal: true
|
||||
|
@ -33,6 +33,16 @@
|
||||
<example>1MiB</example>
|
||||
</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">
|
||||
<summary>Level for harness logging.</summary>
|
||||
|
||||
|
@ -31,7 +31,7 @@ TestBuild *
|
||||
testBldNew(
|
||||
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 String *const timeZone)
|
||||
const String *const timeZone, const bool coverage)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(STRING, pathRepo);
|
||||
@ -44,6 +44,7 @@ testBldNew(
|
||||
FUNCTION_LOG_PARAM(ENUM, logLevel);
|
||||
FUNCTION_LOG_PARAM(BOOL, logTime);
|
||||
FUNCTION_LOG_PARAM(STRING, timeZone);
|
||||
FUNCTION_LOG_PARAM(BOOL, coverage);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
ASSERT(pathRepo != NULL);
|
||||
@ -73,6 +74,7 @@ testBldNew(
|
||||
.logLevel = logLevel,
|
||||
.logTime = logTime,
|
||||
.timeZone = strDup(timeZone),
|
||||
.coverage = coverage,
|
||||
},
|
||||
};
|
||||
|
||||
@ -363,6 +365,14 @@ testBldUnit(TestBuild *const this)
|
||||
if (module->flag != NULL)
|
||||
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
|
||||
strCatZ(
|
||||
mesonBuild,
|
||||
@ -536,7 +546,7 @@ testBldUnit(TestBuild *const this)
|
||||
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(module->containerRequired)));
|
||||
strReplace(testC, STRDEF("{[C_TEST_CONTAINER]}"), STR(cvtBoolToConstZ(!strEqZ(testBldVm(this), "none"))));
|
||||
|
||||
// User/group info
|
||||
strReplace(testC, STRDEF("{[C_TEST_GROUP]}"), groupName());
|
||||
|
@ -20,7 +20,7 @@ Constructors
|
||||
***********************************************************************************************************************************/
|
||||
TestBuild *testBldNew(
|
||||
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
|
||||
@ -39,6 +39,7 @@ typedef struct TestBuildPub
|
||||
bool logTime; // Log times/timestamps
|
||||
uint64_t scale; // Scale performance test
|
||||
const String *timeZone; // Test in timezone
|
||||
bool coverage; // Generate coverage?
|
||||
TestDef tstDef; // Test definitions
|
||||
} TestBuildPub;
|
||||
|
||||
@ -120,6 +121,13 @@ testBldTimeZone(const TestBuild *const this)
|
||||
return THIS_PUB(TestBuild)->timeZone;
|
||||
}
|
||||
|
||||
// Generate coverage?
|
||||
__attribute__((always_inline)) static inline bool
|
||||
testBldCoverage(const TestBuild *const this)
|
||||
{
|
||||
return THIS_PUB(TestBuild)->coverage;
|
||||
}
|
||||
|
||||
// Scale
|
||||
__attribute__((always_inline)) static inline uint64_t
|
||||
testBldScale(const TestBuild *const this)
|
||||
|
@ -74,7 +74,7 @@ void
|
||||
cmdTest(
|
||||
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 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_PARAM(STRING, pathRepo);
|
||||
@ -89,6 +89,7 @@ cmdTest(
|
||||
FUNCTION_LOG_PARAM(STRING, timeZone);
|
||||
FUNCTION_LOG_PARAM(BOOL, repoCopy);
|
||||
FUNCTION_LOG_PARAM(BOOL, valgrind);
|
||||
FUNCTION_LOG_PARAM(BOOL, coverage);
|
||||
FUNCTION_LOG_PARAM(BOOL, run);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
@ -188,7 +189,7 @@ cmdTest(
|
||||
// Process test list
|
||||
unsigned int errorTotal = 0;
|
||||
bool buildRetry = false;
|
||||
const char *buildTypeLast = NULL;
|
||||
String *const mesonSetupLast = strNew();
|
||||
|
||||
for (unsigned int moduleIdx = 0; moduleIdx < strLstSize(moduleList); moduleIdx++)
|
||||
{
|
||||
@ -201,6 +202,7 @@ cmdTest(
|
||||
// Build unit test
|
||||
const String *const pathUnit = strNewFmt("%s/unit-%u/%s", strZ(pathTest), vmId, strZ(vm));
|
||||
const String *const pathUnitBuild = strNewFmt("%s/build", strZ(pathUnit));
|
||||
const Storage *const storageUnitBuild = storagePosixNewP(pathUnitBuild, .write = true);
|
||||
const TimeMSec buildTimeBegin = timeMSec();
|
||||
TimeMSec buildTimeEnd;
|
||||
TestBuild *testBld;
|
||||
@ -209,35 +211,52 @@ cmdTest(
|
||||
{
|
||||
// Build unit
|
||||
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);
|
||||
|
||||
// Meson setup
|
||||
const char *buildType = "debug";
|
||||
String *const mesonSetup = strCatZ(strNew(), "-Dbuildtype=");
|
||||
|
||||
if (module->flag != NULL)
|
||||
{
|
||||
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))))
|
||||
{
|
||||
LOG_DETAIL("meson setup");
|
||||
|
||||
cmdTestExec(
|
||||
strNewFmt(
|
||||
"meson setup -Dwerror=true -Dfatal-errors=true -Dbuildtype=%s %s %s", buildType,
|
||||
strZ(pathUnitBuild), strZ(pathUnit)));
|
||||
|
||||
buildTypeLast = buildType;
|
||||
"meson setup -Dwerror=true -Dfatal-errors=true %s %s %s", strZ(mesonSetup), strZ(pathUnitBuild),
|
||||
strZ(pathUnit)));
|
||||
}
|
||||
|
||||
// Reconfigure as needed
|
||||
if (buildType != buildTypeLast)
|
||||
// Else reconfigure as needed
|
||||
else if (!strEq(mesonSetup, mesonSetupLast))
|
||||
{
|
||||
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
|
||||
|
@ -15,6 +15,6 @@ Functions
|
||||
void cmdTest(
|
||||
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,
|
||||
bool run);
|
||||
bool coverage, bool run);
|
||||
|
||||
#endif
|
||||
|
@ -75,7 +75,7 @@ main(int argListSize, const char *argList[])
|
||||
cfgOptionUInt(cfgOptVmId), cfgCommandParam(), cfgOptionTest(cfgOptTest) ? cfgOptionUInt(cfgOptTest) : 0,
|
||||
cfgOptionUInt64(cfgOptScale), logLevelEnum(cfgOptionStrId(cfgOptLogLevelTest)),
|
||||
cfgOptionBool(cfgOptLogTimestamp), cfgOptionStrNull(cfgOptTz), cfgOptionBool(cfgOptRepoCopy),
|
||||
cfgOptionBool(cfgOptValgrind), cfgOptionBool(cfgOptRun));
|
||||
cfgOptionBool(cfgOptValgrind), cfgOptionBool(cfgOptCoverage), cfgOptionBool(cfgOptRun));
|
||||
|
||||
break;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user